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))]
149#[cfg_attr(swc_ast_unknown, non_exhaustive)]
150pub enum ImportPhase {
151    #[default]
152    #[cfg_attr(feature = "serde-impl", serde(rename = "evaluation"))]
153    Evaluation,
154    #[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
155    Source,
156    #[cfg_attr(feature = "serde-impl", serde(rename = "defer"))]
157    Defer,
158}
159
160impl Take for ImportDecl {
161    fn dummy() -> Self {
162        ImportDecl {
163            span: DUMMY_SP,
164            specifiers: Take::dummy(),
165            src: Take::dummy(),
166            type_only: Default::default(),
167            with: Take::dummy(),
168            phase: Default::default(),
169        }
170    }
171}
172
173/// `export * from 'mod'`
174#[ast_node("ExportAllDeclaration")]
175#[derive(Eq, Hash, EqIgnoreSpan)]
176#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
177#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
178pub struct ExportAll {
179    pub span: Span,
180
181    #[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
182    pub src: Box<Str>,
183
184    #[cfg_attr(feature = "serde-impl", serde(rename = "typeOnly"))]
185    pub type_only: bool,
186
187    #[cfg_attr(feature = "serde-impl", serde(default))]
188    pub with: Option<Box<ObjectLit>>,
189}
190
191impl Take for ExportAll {
192    fn dummy() -> Self {
193        Self {
194            span: DUMMY_SP,
195            src: Take::dummy(),
196            type_only: Default::default(),
197            with: Take::dummy(),
198        }
199    }
200}
201
202/// `export { foo } from 'mod'`
203/// `export { foo as bar } from 'mod'`
204#[ast_node("ExportNamedDeclaration")]
205#[derive(Eq, Hash, EqIgnoreSpan)]
206#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
207#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
208pub struct NamedExport {
209    pub span: Span,
210
211    pub specifiers: Vec<ExportSpecifier>,
212
213    #[cfg_attr(feature = "serde-impl", serde(rename = "source"))]
214    pub src: Option<Box<Str>>,
215
216    #[cfg_attr(feature = "serde-impl", serde(rename = "typeOnly"))]
217    pub type_only: bool,
218
219    #[cfg_attr(feature = "serde-impl", serde(default))]
220    pub with: Option<Box<ObjectLit>>,
221}
222
223impl Take for NamedExport {
224    fn dummy() -> Self {
225        Self {
226            span: DUMMY_SP,
227            specifiers: Take::dummy(),
228            src: Take::dummy(),
229            type_only: Default::default(),
230            with: Take::dummy(),
231        }
232    }
233}
234
235#[ast_node("ExportDefaultDeclaration")]
236#[derive(Eq, Hash, EqIgnoreSpan)]
237#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
238#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
239pub struct ExportDefaultDecl {
240    pub span: Span,
241
242    pub decl: DefaultDecl,
243}
244
245#[ast_node]
246#[derive(Eq, Hash, Is, EqIgnoreSpan)]
247#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
248#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
249pub enum DefaultDecl {
250    #[tag("ClassExpression")]
251    Class(ClassExpr),
252
253    #[tag("FunctionExpression")]
254    #[is(name = "fn_expr")]
255    Fn(FnExpr),
256
257    #[tag("TsInterfaceDeclaration")]
258    TsInterfaceDecl(Box<TsInterfaceDecl>),
259}
260
261#[ast_node]
262#[derive(Eq, Hash, Is, EqIgnoreSpan)]
263#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
264#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
265pub enum ImportSpecifier {
266    #[tag("ImportSpecifier")]
267    Named(ImportNamedSpecifier),
268    #[tag("ImportDefaultSpecifier")]
269    Default(ImportDefaultSpecifier),
270    #[tag("ImportNamespaceSpecifier")]
271    Namespace(ImportStarAsSpecifier),
272}
273
274impl ImportSpecifier {
275    pub fn is_type_only(&self) -> bool {
276        match self {
277            ImportSpecifier::Named(named) => named.is_type_only,
278            ImportSpecifier::Default(..) | ImportSpecifier::Namespace(..) => false,
279        }
280    }
281
282    pub fn local(&self) -> &Ident {
283        match self {
284            ImportSpecifier::Named(named) => &named.local,
285            ImportSpecifier::Default(default) => &default.local,
286            ImportSpecifier::Namespace(ns) => &ns.local,
287        }
288    }
289
290    pub fn local_mut(&mut self) -> &mut Ident {
291        match self {
292            ImportSpecifier::Named(named) => &mut named.local,
293            ImportSpecifier::Default(default) => &mut default.local,
294            ImportSpecifier::Namespace(ns) => &mut ns.local,
295        }
296    }
297}
298
299/// e.g. `import foo from 'mod.js'`
300#[ast_node("ImportDefaultSpecifier")]
301#[derive(Eq, Hash, EqIgnoreSpan)]
302#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
303#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
304pub struct ImportDefaultSpecifier {
305    pub span: Span,
306
307    pub local: Ident,
308}
309/// e.g. `import * as foo from 'mod.js'`.
310#[ast_node("ImportNamespaceSpecifier")]
311#[derive(Eq, Hash, EqIgnoreSpan)]
312#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
313#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
314pub struct ImportStarAsSpecifier {
315    pub span: Span,
316
317    pub local: Ident,
318}
319/// e.g. local = foo, imported = None `import { foo } from 'mod.js'`
320/// e.g. local = bar, imported = Some(foo) for `import { foo as bar } from
321/// 'mod.js'`
322#[ast_node("ImportSpecifier")]
323#[derive(Eq, Hash, EqIgnoreSpan)]
324#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
325#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
326pub struct ImportNamedSpecifier {
327    pub span: Span,
328
329    pub local: Ident,
330
331    #[cfg_attr(feature = "serde-impl", serde(default))]
332    pub imported: Option<ModuleExportName>,
333
334    #[cfg_attr(feature = "serde-impl", serde(default))]
335    pub is_type_only: bool,
336}
337
338#[ast_node]
339#[derive(Eq, Hash, Is, EqIgnoreSpan)]
340#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
341#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
342pub enum ExportSpecifier {
343    #[tag("ExportNamespaceSpecifier")]
344    Namespace(ExportNamespaceSpecifier),
345
346    #[tag("ExportDefaultSpecifier")]
347    Default(ExportDefaultSpecifier),
348
349    #[tag("ExportSpecifier")]
350    Named(ExportNamedSpecifier),
351}
352
353/// `export * as foo from 'src';`
354#[ast_node("ExportNamespaceSpecifier")]
355#[derive(Eq, Hash, EqIgnoreSpan)]
356#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
357#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
358pub struct ExportNamespaceSpecifier {
359    pub span: Span,
360
361    pub name: ModuleExportName,
362}
363
364// export v from 'mod';
365#[ast_node("ExportDefaultSpecifier")]
366#[derive(Eq, Hash, EqIgnoreSpan)]
367#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
368#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
369pub struct ExportDefaultSpecifier {
370    #[span]
371    pub exported: Ident,
372}
373
374#[ast_node("ExportSpecifier")]
375#[derive(Eq, Hash, EqIgnoreSpan)]
376#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
377#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
378pub struct ExportNamedSpecifier {
379    pub span: Span,
380    /// `foo` in `export { foo as bar }`
381    pub orig: ModuleExportName,
382    /// `Some(bar)` in `export { foo as bar }`
383    #[cfg_attr(feature = "serde-impl", serde(default))]
384    pub exported: Option<ModuleExportName>,
385    /// `type` in `export { type foo as bar }`
386    #[cfg_attr(feature = "serde-impl", serde(default))]
387    pub is_type_only: bool,
388}
389
390#[ast_node]
391#[derive(Eq, Hash, EqIgnoreSpan)]
392#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
393#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
394// https://tc39.es/ecma262/#prod-ModuleExportName
395pub enum ModuleExportName {
396    #[tag("Identifier")]
397    Ident(Ident),
398
399    #[tag("StringLiteral")]
400    Str(Str),
401}
402
403bridge_from!(ModuleExportName, Ident, BindingIdent);
404bridge_from!(ModuleExportName, Ident, IdentName);
405
406impl ModuleExportName {
407    /// Get the atom of the export name.
408    pub fn atom(&self) -> &Atom {
409        match self {
410            ModuleExportName::Ident(i) => &i.sym,
411            ModuleExportName::Str(s) => &s.value,
412        }
413    }
414}