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