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