swc_estree_compat/babelify/
module_decl.rs

1use copyless::BoxHelper;
2use serde::{Deserialize, Serialize};
3use swc_ecma_ast::{
4    DefaultDecl, ExportAll, ExportDecl, ExportDefaultDecl, ExportDefaultExpr,
5    ExportDefaultSpecifier, ExportNamedSpecifier, ExportNamespaceSpecifier, ExportSpecifier, Expr,
6    ImportDecl, ImportDefaultSpecifier, ImportNamedSpecifier, ImportSpecifier,
7    ImportStarAsSpecifier, Lit, ModuleDecl, ModuleExportName, NamedExport, ObjectLit, Prop,
8    PropName, PropOrSpread,
9};
10use swc_estree_ast::{
11    ExportAllDeclaration, ExportDefaultDeclType, ExportDefaultDeclaration,
12    ExportDefaultSpecifier as BabelExportDefaultSpecifier, ExportKind, ExportNamedDeclaration,
13    ExportNamespaceSpecifier as BabelExportNamespaceSpecifier,
14    ExportSpecifier as BabelExportSpecifier, ExportSpecifierType, IdOrString, ImportAttribute,
15    ImportDeclaration, ImportDefaultSpecifier as BabelImportDefaultSpecifier, ImportKind,
16    ImportNamespaceSpecifier, ImportSpecifier as BabelImportSpecifier, ImportSpecifierType,
17    ModuleDeclaration, ModuleExportNameType, TSExportAssignment, TSImportEqualsDeclaration,
18    TSNamespaceExportDeclaration,
19};
20
21use crate::babelify::{Babelify, Context};
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub enum ModuleDeclOutput {
25    Import(ImportDeclaration),
26    ExportDefault(ExportDefaultDeclaration),
27    ExportNamed(ExportNamedDeclaration),
28    ExportAll(ExportAllDeclaration),
29    TsImportEquals(TSImportEqualsDeclaration),
30    TsExportAssignment(TSExportAssignment),
31    TsNamespaceExport(TSNamespaceExportDeclaration),
32}
33
34impl Babelify for ModuleDecl {
35    type Output = ModuleDeclOutput;
36
37    fn babelify(self, ctx: &Context) -> Self::Output {
38        match self {
39            ModuleDecl::Import(i) => ModuleDeclOutput::Import(i.babelify(ctx)),
40            ModuleDecl::ExportDecl(e) => ModuleDeclOutput::ExportNamed(e.babelify(ctx)),
41            ModuleDecl::ExportNamed(n) => ModuleDeclOutput::ExportNamed(n.babelify(ctx)),
42            ModuleDecl::ExportDefaultDecl(e) => ModuleDeclOutput::ExportDefault(e.babelify(ctx)),
43            ModuleDecl::ExportDefaultExpr(e) => ModuleDeclOutput::ExportDefault(e.babelify(ctx)),
44            ModuleDecl::ExportAll(a) => ModuleDeclOutput::ExportAll(a.babelify(ctx)),
45            ModuleDecl::TsImportEquals(i) => ModuleDeclOutput::TsImportEquals(i.babelify(ctx)),
46            ModuleDecl::TsExportAssignment(a) => {
47                ModuleDeclOutput::TsExportAssignment(a.babelify(ctx))
48            }
49            ModuleDecl::TsNamespaceExport(e) => {
50                ModuleDeclOutput::TsNamespaceExport(e.babelify(ctx))
51            }
52        }
53    }
54}
55
56impl From<ModuleDeclOutput> for ModuleDeclaration {
57    fn from(module: ModuleDeclOutput) -> Self {
58        match module {
59            ModuleDeclOutput::Import(i) => ModuleDeclaration::Import(i),
60            ModuleDeclOutput::ExportDefault(e) => ModuleDeclaration::ExportDefault(e),
61            ModuleDeclOutput::ExportNamed(n) => ModuleDeclaration::ExportNamed(n),
62            ModuleDeclOutput::ExportAll(a) => ModuleDeclaration::ExportAll(a),
63            _ => panic!(
64                "illegal conversion: Cannot convert {:?} to ModuleDeclaration",
65                &module
66            ),
67        }
68    }
69}
70
71impl Babelify for ExportDefaultExpr {
72    type Output = ExportDefaultDeclaration;
73
74    fn babelify(self, ctx: &Context) -> Self::Output {
75        ExportDefaultDeclaration {
76            base: ctx.base(self.span),
77            declaration: ExportDefaultDeclType::Expr(
78                Box::alloc().init(self.expr.babelify(ctx).into()),
79            ),
80        }
81    }
82}
83
84impl Babelify for ExportDecl {
85    type Output = ExportNamedDeclaration;
86
87    fn babelify(self, ctx: &Context) -> Self::Output {
88        ExportNamedDeclaration {
89            base: ctx.base(self.span),
90            declaration: Some(Box::alloc().init(self.decl.babelify(ctx))),
91            specifiers: Default::default(),
92            source: Default::default(),
93            with: Default::default(),
94            export_kind: Default::default(),
95        }
96    }
97}
98
99fn convert_import_attrs(
100    asserts: Option<Box<ObjectLit>>,
101    ctx: &Context,
102) -> Option<Vec<ImportAttribute>> {
103    asserts.map(|obj| {
104        let obj_span = obj.span;
105
106        obj.props
107            .into_iter()
108            .map(|prop_or_spread| {
109                let prop = match prop_or_spread {
110                    PropOrSpread::Prop(p) => p,
111                    _ => panic!(
112                        "illegal conversion: Cannot convert {:?} to Prop",
113                        &prop_or_spread
114                    ),
115                };
116                let (key, val) = match *prop {
117                    Prop::KeyValue(keyval) => {
118                        let key = match keyval.key {
119                            PropName::Ident(i) => IdOrString::Id(i.babelify(ctx)),
120                            PropName::Str(s) => IdOrString::String(s.babelify(ctx)),
121                            _ => panic!(
122                                "illegal conversion: Cannot convert {:?} to Prop::KeyValue",
123                                &keyval.key
124                            ),
125                        };
126                        let val = match *keyval.value {
127                            Expr::Lit(lit) => match lit {
128                                Lit::Str(s) => s.babelify(ctx),
129                                _ => panic!(
130                                    "illegal conversion: Cannot convert {:?} to Expr::Lit",
131                                    &lit
132                                ),
133                            },
134                            _ => panic!(
135                                "illegal conversion: Cannot convert {:?} to Expr::Lit",
136                                &keyval.value
137                            ),
138                        };
139                        (key, val)
140                    }
141                    _ => panic!(
142                        "illegal conversion: Cannot convert {:?} to key, value",
143                        &prop
144                    ),
145                };
146                ImportAttribute {
147                    base: ctx.base(obj_span),
148                    key,
149                    value: val,
150                }
151            })
152            .collect()
153    })
154}
155
156impl Babelify for ImportDecl {
157    type Output = ImportDeclaration;
158
159    fn babelify(self, ctx: &Context) -> Self::Output {
160        ImportDeclaration {
161            base: ctx.base(self.span),
162            specifiers: self.specifiers.babelify(ctx),
163            source: self.src.babelify(ctx),
164            with: convert_import_attrs(self.with, ctx),
165            import_kind: if self.type_only {
166                Some(ImportKind::Type)
167            } else {
168                None
169            },
170            phase: self.phase.babelify(ctx),
171        }
172    }
173}
174
175impl Babelify for swc_ecma_ast::ImportPhase {
176    type Output = Option<swc_estree_ast::ImportPhase>;
177
178    fn babelify(self, _: &Context) -> Self::Output {
179        match self {
180            Self::Evaluation => None,
181            Self::Source => Some(swc_estree_ast::ImportPhase::Source),
182            Self::Defer => Some(swc_estree_ast::ImportPhase::Defer),
183        }
184    }
185}
186
187impl Babelify for ExportAll {
188    type Output = ExportAllDeclaration;
189
190    fn babelify(self, ctx: &Context) -> Self::Output {
191        ExportAllDeclaration {
192            base: ctx.base(self.span),
193            source: self.src.babelify(ctx),
194            with: convert_import_attrs(self.with, ctx),
195            export_kind: if self.type_only {
196                Some(ExportKind::Type)
197            } else {
198                None
199            },
200        }
201    }
202}
203
204impl Babelify for NamedExport {
205    type Output = ExportNamedDeclaration;
206
207    fn babelify(self, ctx: &Context) -> Self::Output {
208        ExportNamedDeclaration {
209            base: ctx.base(self.span),
210            declaration: Default::default(),
211            specifiers: self.specifiers.babelify(ctx),
212            source: self.src.map(|s| s.babelify(ctx)),
213            with: convert_import_attrs(self.with, ctx),
214            export_kind: if self.type_only {
215                Some(ExportKind::Type)
216            } else {
217                None
218            },
219        }
220    }
221}
222
223impl Babelify for ExportDefaultDecl {
224    type Output = ExportDefaultDeclaration;
225
226    fn babelify(self, ctx: &Context) -> Self::Output {
227        ExportDefaultDeclaration {
228            base: ctx.base(self.span),
229            declaration: self.decl.babelify(ctx),
230        }
231    }
232}
233
234impl Babelify for DefaultDecl {
235    type Output = ExportDefaultDeclType;
236
237    fn babelify(self, ctx: &Context) -> Self::Output {
238        match self {
239            DefaultDecl::Class(c) => ExportDefaultDeclType::Class(c.babelify(ctx).into()),
240            DefaultDecl::Fn(f) => ExportDefaultDeclType::Func(f.babelify(ctx).into()),
241            DefaultDecl::TsInterfaceDecl(_) => panic!("unimplemented"), /* TODO(dwoznicki): Babel expects a TSDeclareFunction here, which does not map cleanly to TsInterfaceDecl expected by swc */
242        }
243    }
244}
245
246impl Babelify for ImportSpecifier {
247    type Output = ImportSpecifierType;
248
249    fn babelify(self, ctx: &Context) -> Self::Output {
250        match self {
251            ImportSpecifier::Named(s) => ImportSpecifierType::Import(s.babelify(ctx)),
252            ImportSpecifier::Default(s) => ImportSpecifierType::Default(s.babelify(ctx)),
253            ImportSpecifier::Namespace(s) => ImportSpecifierType::Namespace(s.babelify(ctx)),
254        }
255    }
256}
257
258impl Babelify for ImportDefaultSpecifier {
259    type Output = BabelImportDefaultSpecifier;
260
261    fn babelify(self, ctx: &Context) -> Self::Output {
262        BabelImportDefaultSpecifier {
263            base: ctx.base(self.span),
264            local: self.local.babelify(ctx),
265        }
266    }
267}
268
269impl Babelify for ImportStarAsSpecifier {
270    type Output = ImportNamespaceSpecifier;
271
272    fn babelify(self, ctx: &Context) -> Self::Output {
273        ImportNamespaceSpecifier {
274            base: ctx.base(self.span),
275            local: self.local.babelify(ctx),
276        }
277    }
278}
279
280impl Babelify for ImportNamedSpecifier {
281    type Output = BabelImportSpecifier;
282
283    fn babelify(self, ctx: &Context) -> Self::Output {
284        BabelImportSpecifier {
285            base: ctx.base(self.span),
286            local: self.local.clone().babelify(ctx),
287            imported: self
288                .imported
289                .unwrap_or(ModuleExportName::Ident(self.local))
290                .babelify(ctx),
291            import_kind: if self.is_type_only {
292                Some(ImportKind::Type)
293            } else {
294                None
295            },
296        }
297    }
298}
299
300impl Babelify for ExportSpecifier {
301    type Output = ExportSpecifierType;
302
303    fn babelify(self, ctx: &Context) -> Self::Output {
304        match self {
305            ExportSpecifier::Named(s) => ExportSpecifierType::Export(s.babelify(ctx)),
306            ExportSpecifier::Default(s) => ExportSpecifierType::Default(s.babelify(ctx)),
307            ExportSpecifier::Namespace(s) => ExportSpecifierType::Namespace(s.babelify(ctx)),
308        }
309    }
310}
311
312impl Babelify for ExportNamespaceSpecifier {
313    type Output = BabelExportNamespaceSpecifier;
314
315    fn babelify(self, ctx: &Context) -> Self::Output {
316        BabelExportNamespaceSpecifier {
317            base: ctx.base(self.span),
318            exported: self.name.babelify(ctx),
319        }
320    }
321}
322
323impl Babelify for ExportDefaultSpecifier {
324    type Output = BabelExportDefaultSpecifier;
325
326    fn babelify(self, ctx: &Context) -> Self::Output {
327        let exported = self.exported.babelify(ctx);
328        BabelExportDefaultSpecifier {
329            base: exported.base.clone(),
330            exported,
331        }
332    }
333}
334
335impl Babelify for ExportNamedSpecifier {
336    type Output = BabelExportSpecifier;
337
338    fn babelify(self, ctx: &Context) -> Self::Output {
339        BabelExportSpecifier {
340            base: ctx.base(self.span),
341            local: self.orig.clone().babelify(ctx),
342            exported: self.exported.unwrap_or(self.orig).babelify(ctx),
343            export_kind: if self.is_type_only {
344                ExportKind::Type
345            } else {
346                ExportKind::Value
347            },
348        }
349    }
350}
351
352impl Babelify for ModuleExportName {
353    type Output = ModuleExportNameType;
354
355    fn babelify(self, ctx: &Context) -> Self::Output {
356        match self {
357            ModuleExportName::Ident(ident) => ModuleExportNameType::Ident(ident.babelify(ctx)),
358            ModuleExportName::Str(..) => unimplemented!("module string names unimplemented"),
359        }
360    }
361}