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"), #[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}