swc_ecma_ast/
module_decl.rs

1use is_macro::Is;
2use swc_atoms::Atom;
3use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span, DUMMY_SP};
4
5use crate::{
6    decl::Decl,
7    expr::{ClassExpr, Expr, FnExpr},
8    ident::Ident,
9    lit::Str,
10    typescript::{TsExportAssignment, TsImportEqualsDecl, TsInterfaceDecl, TsNamespaceExportDecl},
11    BindingIdent, IdentName, ObjectLit,
12};
13
14#[ast_node]
15#[derive(Eq, Hash, Is, EqIgnoreSpan)]
16#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
17#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
18pub enum ModuleDecl {
19    #[tag("ImportDeclaration")]
20    Import(ImportDecl),
21
22    #[tag("ExportDeclaration")]
23    ExportDecl(ExportDecl),
24
25    #[tag("ExportNamedDeclaration")]
26    ExportNamed(NamedExport),
27
28    #[tag("ExportDefaultDeclaration")]
29    ExportDefaultDecl(ExportDefaultDecl),
30
31    #[tag("ExportDefaultExpression")]
32    ExportDefaultExpr(ExportDefaultExpr),
33
34    #[tag("ExportAllDeclaration")]
35    ExportAll(ExportAll),
36
37    #[tag("TsImportEqualsDeclaration")]
38    TsImportEquals(Box<TsImportEqualsDecl>),
39
40    #[tag("TsExportAssignment")]
41    TsExportAssignment(TsExportAssignment),
42
43    #[tag("TsNamespaceExportDeclaration")]
44    TsNamespaceExport(TsNamespaceExportDecl),
45}
46
47boxed!(ModuleDecl, [TsImportEqualsDecl]);
48
49macro_rules! module_decl {
50    ([$($variant:ty),*]) => {
51        $(
52            bridge_from!(crate::ModuleItem, crate::ModuleDecl, $variant);
53        )*
54    };
55}
56
57module_decl!([
58    ImportDecl,
59    ExportDecl,
60    NamedExport,
61    ExportDefaultDecl,
62    ExportDefaultExpr,
63    ExportAll,
64    TsImportEqualsDecl,
65    TsExportAssignment,
66    TsNamespaceExportDecl
67]);
68
69impl Take for ModuleDecl {
70    fn dummy() -> Self {
71        ImportDecl::dummy().into()
72    }
73}
74
75/// Default exports other than **direct** function expression or class
76/// expression.
77///
78///
79/// # Note
80///
81/// ```ts
82/// export default function Foo() {
83/// }
84/// ```
85///
86/// is [`ExportDefaultDecl`] and it's hoisted.
87///
88/// ```ts
89/// export default (function Foo() {
90/// })
91/// ```
92///
93/// is [`ExportDefaultExpr`] and it's not hoisted.
94#[ast_node("ExportDefaultExpression")]
95#[derive(Eq, Hash, EqIgnoreSpan)]
96#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
97#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
98pub struct ExportDefaultExpr {
99    pub span: Span,
100
101    #[cfg_attr(feature = "serde-impl", serde(rename = "expression"))]
102    pub expr: Box<Expr>,
103}
104
105#[ast_node("ExportDeclaration")]
106#[derive(Eq, Hash, EqIgnoreSpan)]
107#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
108#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
109pub struct ExportDecl {
110    pub span: Span,
111
112    #[cfg_attr(feature = "serde-impl", serde(rename = "declaration"))]
113    pub decl: Decl,
114}
115
116#[ast_node("ImportDeclaration")]
117#[derive(Eq, Hash, EqIgnoreSpan)]
118#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
119#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
120pub struct ImportDecl {
121    pub span: Span,
122
123    #[cfg_attr(feature = "serde-impl", serde(default))]
124    pub specifiers: Vec<ImportSpecifier>,
125
126    #[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
127    pub src: Box<Str>,
128
129    #[cfg_attr(feature = "serde-impl", serde(default, rename = "typeOnly"))]
130    pub type_only: bool,
131
132    #[cfg_attr(feature = "serde-impl", serde(default))]
133    pub with: Option<Box<ObjectLit>>,
134
135    #[cfg_attr(feature = "serde-impl", serde(default))]
136    pub phase: ImportPhase,
137}
138
139#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, EqIgnoreSpan)]
140#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
141#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
142#[cfg_attr(
143    any(feature = "rkyv-impl"),
144    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
145)]
146#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
147#[cfg_attr(feature = "rkyv-impl", repr(u32))]
148#[cfg_attr(feature = "serde-impl", derive(serde::Serialize, serde::Deserialize))]
149pub enum ImportPhase {
150    #[default]
151    #[cfg_attr(feature = "serde-impl", serde(rename = "evaluation"))]
152    Evaluation,
153    #[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
154    Source,
155    #[cfg_attr(feature = "serde-impl", serde(rename = "defer"))]
156    Defer,
157}
158
159impl Take for ImportDecl {
160    fn dummy() -> Self {
161        ImportDecl {
162            span: DUMMY_SP,
163            specifiers: Take::dummy(),
164            src: Take::dummy(),
165            type_only: Default::default(),
166            with: Take::dummy(),
167            phase: Default::default(),
168        }
169    }
170}
171
172/// `export * from 'mod'`
173#[ast_node("ExportAllDeclaration")]
174#[derive(Eq, Hash, EqIgnoreSpan)]
175#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
176#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
177pub struct ExportAll {
178    pub span: Span,
179
180    #[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
181    pub src: Box<Str>,
182
183    #[cfg_attr(feature = "serde-impl", serde(rename = "typeOnly"))]
184    pub type_only: bool,
185
186    #[cfg_attr(feature = "serde-impl", serde(default))]
187    pub with: Option<Box<ObjectLit>>,
188}
189
190impl Take for ExportAll {
191    fn dummy() -> Self {
192        Self {
193            span: DUMMY_SP,
194            src: Take::dummy(),
195            type_only: Default::default(),
196            with: Take::dummy(),
197        }
198    }
199}
200
201/// `export { foo } from 'mod'`
202/// `export { foo as bar } from 'mod'`
203#[ast_node("ExportNamedDeclaration")]
204#[derive(Eq, Hash, EqIgnoreSpan)]
205#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
206#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
207pub struct NamedExport {
208    pub span: Span,
209
210    pub specifiers: Vec<ExportSpecifier>,
211
212    #[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
213    pub src: Option<Box<Str>>,
214
215    #[cfg_attr(feature = "serde-impl", serde(rename = "typeOnly"))]
216    pub type_only: bool,
217
218    #[cfg_attr(feature = "serde-impl", serde(default))]
219    pub with: Option<Box<ObjectLit>>,
220}
221
222impl Take for NamedExport {
223    fn dummy() -> Self {
224        Self {
225            span: DUMMY_SP,
226            specifiers: Take::dummy(),
227            src: Take::dummy(),
228            type_only: Default::default(),
229            with: Take::dummy(),
230        }
231    }
232}
233
234#[ast_node("ExportDefaultDeclaration")]
235#[derive(Eq, Hash, EqIgnoreSpan)]
236#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
237#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
238pub struct ExportDefaultDecl {
239    pub span: Span,
240
241    pub decl: DefaultDecl,
242}
243
244#[ast_node]
245#[derive(Eq, Hash, Is, EqIgnoreSpan)]
246#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
247#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
248pub enum DefaultDecl {
249    #[tag("ClassExpression")]
250    Class(ClassExpr),
251
252    #[tag("FunctionExpression")]
253    #[is(name = "fn_expr")]
254    Fn(FnExpr),
255
256    #[tag("TsInterfaceDeclaration")]
257    TsInterfaceDecl(Box<TsInterfaceDecl>),
258}
259
260#[ast_node]
261#[derive(Eq, Hash, Is, EqIgnoreSpan)]
262#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
263#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
264pub enum ImportSpecifier {
265    #[tag("ImportSpecifier")]
266    Named(ImportNamedSpecifier),
267    #[tag("ImportDefaultSpecifier")]
268    Default(ImportDefaultSpecifier),
269    #[tag("ImportNamespaceSpecifier")]
270    Namespace(ImportStarAsSpecifier),
271}
272
273impl ImportSpecifier {
274    pub fn is_type_only(&self) -> bool {
275        match self {
276            ImportSpecifier::Named(named) => named.is_type_only,
277            ImportSpecifier::Default(..) | ImportSpecifier::Namespace(..) => false,
278        }
279    }
280
281    pub fn local(&self) -> &Ident {
282        match self {
283            ImportSpecifier::Named(named) => &named.local,
284            ImportSpecifier::Default(default) => &default.local,
285            ImportSpecifier::Namespace(ns) => &ns.local,
286        }
287    }
288
289    pub fn local_mut(&mut self) -> &mut Ident {
290        match self {
291            ImportSpecifier::Named(named) => &mut named.local,
292            ImportSpecifier::Default(default) => &mut default.local,
293            ImportSpecifier::Namespace(ns) => &mut ns.local,
294        }
295    }
296}
297
298/// e.g. `import foo from 'mod.js'`
299#[ast_node("ImportDefaultSpecifier")]
300#[derive(Eq, Hash, EqIgnoreSpan)]
301#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
302#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
303pub struct ImportDefaultSpecifier {
304    pub span: Span,
305
306    pub local: Ident,
307}
308/// e.g. `import * as foo from 'mod.js'`.
309#[ast_node("ImportNamespaceSpecifier")]
310#[derive(Eq, Hash, EqIgnoreSpan)]
311#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
312#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
313pub struct ImportStarAsSpecifier {
314    pub span: Span,
315
316    pub local: Ident,
317}
318/// e.g. local = foo, imported = None `import { foo } from 'mod.js'`
319/// e.g. local = bar, imported = Some(foo) for `import { foo as bar } from
320/// 'mod.js'`
321#[ast_node("ImportSpecifier")]
322#[derive(Eq, Hash, EqIgnoreSpan)]
323#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
324#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
325pub struct ImportNamedSpecifier {
326    pub span: Span,
327
328    pub local: Ident,
329
330    #[cfg_attr(feature = "serde-impl", serde(default))]
331    pub imported: Option<ModuleExportName>,
332
333    #[cfg_attr(feature = "serde-impl", serde(default))]
334    pub is_type_only: bool,
335}
336
337#[ast_node]
338#[derive(Eq, Hash, Is, EqIgnoreSpan)]
339#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
340#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
341pub enum ExportSpecifier {
342    #[tag("ExportNamespaceSpecifier")]
343    Namespace(ExportNamespaceSpecifier),
344
345    #[tag("ExportDefaultSpecifier")]
346    Default(ExportDefaultSpecifier),
347
348    #[tag("ExportSpecifier")]
349    Named(ExportNamedSpecifier),
350}
351
352/// `export * as foo from 'src';`
353#[ast_node("ExportNamespaceSpecifier")]
354#[derive(Eq, Hash, EqIgnoreSpan)]
355#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
356#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
357pub struct ExportNamespaceSpecifier {
358    pub span: Span,
359
360    pub name: ModuleExportName,
361}
362
363// export v from 'mod';
364#[ast_node("ExportDefaultSpecifier")]
365#[derive(Eq, Hash, EqIgnoreSpan)]
366#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
367#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
368pub struct ExportDefaultSpecifier {
369    #[span]
370    pub exported: Ident,
371}
372
373#[ast_node("ExportSpecifier")]
374#[derive(Eq, Hash, EqIgnoreSpan)]
375#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
376#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
377pub struct ExportNamedSpecifier {
378    pub span: Span,
379    /// `foo` in `export { foo as bar }`
380    pub orig: ModuleExportName,
381    /// `Some(bar)` in `export { foo as bar }`
382    #[cfg_attr(feature = "serde-impl", serde(default))]
383    pub exported: Option<ModuleExportName>,
384    /// `type` in `export { type foo as bar }`
385    #[cfg_attr(feature = "serde-impl", serde(default))]
386    pub is_type_only: bool,
387}
388
389#[ast_node]
390#[derive(Eq, Hash, EqIgnoreSpan)]
391#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
392#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
393// https://tc39.es/ecma262/#prod-ModuleExportName
394pub enum ModuleExportName {
395    #[tag("Identifier")]
396    Ident(Ident),
397
398    #[tag("StringLiteral")]
399    Str(Str),
400}
401
402bridge_from!(ModuleExportName, Ident, BindingIdent);
403bridge_from!(ModuleExportName, Ident, IdentName);
404
405impl ModuleExportName {
406    /// Get the atom of the export name.
407    pub fn atom(&self) -> &Atom {
408        match self {
409            ModuleExportName::Ident(i) => &i.sym,
410            ModuleExportName::Str(s) => &s.value,
411        }
412    }
413}