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