1use anyhow::Context;
2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};
4use swc_atoms::Atom;
5use swc_common::{Mark, Span, SyntaxContext, DUMMY_SP};
6use swc_ecma_ast::*;
7use swc_ecma_utils::{
8 member_expr, private_ident, quote_ident, quote_str, var::VarCollector, ExprFactory,
9};
10use swc_ecma_visit::{fold_pass, standard_only_fold, Fold, FoldWith, VisitWith};
11
12pub use super::util::Config as InnerConfig;
13use crate::{
14 path::Resolver,
15 top_level_this::top_level_this,
16 util::{local_name_for_src, use_strict},
17 wtf8::{normalize_wtf8_atom, wtf8_to_cow_str},
18};
19#[derive(Debug, Clone, Default, Serialize, Deserialize)]
20#[serde(deny_unknown_fields, rename_all = "camelCase")]
21pub struct Config {
22 #[serde(default)]
23 pub allow_top_level_this: bool,
24
25 #[serde(flatten, default)]
26 pub config: InnerConfig,
27}
28
29struct SystemJs {
30 unresolved_mark: Mark,
31 resolver: Resolver,
32 config: Config,
33
34 declare_var_idents: Vec<Ident>,
35 export_map: FxHashMap<Id, Vec<Atom>>,
36 export_names: Vec<Atom>,
37 export_values: Vec<Box<Expr>>,
38 tla: bool,
39 enter_async_fn: u32,
40 root_fn_decl_idents: Vec<Ident>,
41 module_item_meta_list: Vec<ModuleItemMeta>,
42 import_idents: Vec<Id>,
43 export_ident: Ident,
44 context_ident: Ident,
45}
46
47pub fn system_js(resolver: Resolver, unresolved_mark: Mark, config: Config) -> impl Pass {
48 fold_pass(SystemJs {
49 unresolved_mark,
50 resolver,
51 config,
52 declare_var_idents: Vec::new(),
53 export_map: Default::default(),
54 export_names: Vec::new(),
55 export_values: Vec::new(),
56 tla: false,
57 enter_async_fn: 0,
58 root_fn_decl_idents: Vec::new(),
59 module_item_meta_list: Vec::new(),
60 import_idents: Vec::new(),
61 export_ident: private_ident!("_export"),
62 context_ident: private_ident!("_context"),
63 })
64}
65
66struct ModuleItemMeta {
67 export_names: Vec<Atom>,
68 export_values: Vec<Box<Expr>>,
69 has_export_all: bool,
70 src: Atom,
71 setter_fn_stmts: Vec<Stmt>,
72}
73
74impl SystemJs {
75 fn export_call(&self, name: Atom, span: Span, expr: Expr) -> CallExpr {
76 CallExpr {
77 span,
78 callee: self.export_ident.clone().as_callee(),
79 args: vec![quote_str!(name).as_arg(), expr.as_arg()],
80 ..Default::default()
81 }
82 }
83
84 fn fold_module_name_ident(&mut self, ident: Ident) -> Expr {
85 if &*ident.sym == "__moduleName" && ident.ctxt.outer() == self.unresolved_mark {
86 return self
87 .context_ident
88 .clone()
89 .make_member(quote_ident!("id"))
90 .into();
91 }
92 ident.into()
93 }
94
95 fn replace_assign_expr(&mut self, assign_expr: AssignExpr) -> Expr {
96 match &assign_expr.left {
97 AssignTarget::Simple(pat_or_expr) => match pat_or_expr {
98 SimpleAssignTarget::Ident(ident) => {
99 for (k, v) in self.export_map.iter() {
100 if ident.ctxt == k.1 && ident.sym == k.0 {
101 let mut expr = assign_expr.into();
102 for value in v.iter() {
103 expr = self.export_call(value.clone(), DUMMY_SP, expr).into();
104 }
105 return expr;
106 }
107 }
108 assign_expr.into()
109 }
110 _ => assign_expr.into(),
111 },
112 AssignTarget::Pat(pat) => {
113 let mut to: Vec<Id> = Vec::new();
114 pat.visit_with(&mut VarCollector { to: &mut to });
115
116 match pat {
117 AssignTargetPat::Object(..) | AssignTargetPat::Array(..) => {
118 let mut exprs = vec![Box::new(Expr::Assign(assign_expr))];
119
120 for to in to {
121 for (k, v) in self.export_map.iter() {
122 if to == *k {
123 for _ in v.iter() {
124 exprs.push(
125 self.export_call(
126 to.0.clone(),
127 DUMMY_SP,
128 Ident::new(to.0.clone(), DUMMY_SP, to.1).into(),
129 )
130 .into(),
131 );
132 }
133 break;
134 }
135 }
136 }
137 SeqExpr {
138 span: DUMMY_SP,
139 exprs,
140 }
141 .into()
142 }
143 _ => assign_expr.into(),
144 }
145 }
146 #[cfg(swc_ast_unknown)]
147 _ => panic!("unable to access unknown nodes"),
148 }
149 }
150
151 fn replace_update_expr(&mut self, update_expr: UpdateExpr) -> Expr {
152 if !update_expr.prefix {
153 match &*update_expr.arg {
154 Expr::Ident(ident) => {
155 for (k, v) in self.export_map.iter() {
156 if ident.ctxt == k.1 && ident.sym == k.0 {
157 let mut expr = BinExpr {
158 span: DUMMY_SP,
159 op: op!(bin, "+"),
160 left: UnaryExpr {
161 span: DUMMY_SP,
162 op: op!(unary, "+"),
163 arg: Box::new(Expr::Ident(ident.clone())),
164 }
165 .into(),
166 right: 1.0.into(),
167 }
168 .into();
169 for value in v.iter() {
170 expr = self.export_call(value.clone(), DUMMY_SP, expr).into();
171 }
172 return SeqExpr {
173 span: DUMMY_SP,
174 exprs: vec![Box::new(expr), Box::new(Expr::Update(update_expr))],
175 }
176 .into();
177 }
178 }
179 update_expr.into()
180 }
181 _ => update_expr.into(),
182 }
183 } else {
184 update_expr.into()
185 }
186 }
187
188 fn add_export_name(&mut self, key: Id, value: Atom) {
189 let mut find = false;
190 for (k, v) in self.export_map.iter_mut() {
191 if key == *k {
192 v.push(value.clone());
193 find = true;
194 break;
195 }
196 }
197 if !find {
198 self.export_map.insert(key, vec![value]);
199 }
200 }
201
202 fn add_declare_var_idents(&mut self, ident: &Ident) {
203 self.declare_var_idents.push(ident.clone());
204 }
205
206 fn build_export_call(
207 &mut self,
208 export_names: &mut Vec<Atom>,
209 export_values: &mut Vec<Box<Expr>>,
210 ) -> Vec<Stmt> {
211 match export_names.len() {
212 0 => Vec::new(),
213 1 => vec![self
214 .export_call(export_names.remove(0), DUMMY_SP, *export_values.remove(0))
215 .into_stmt()],
216 _ => {
217 let mut props = Vec::new();
218 for (sym, value) in export_names.drain(..).zip(export_values.drain(..)) {
219 props.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
220 key: match Ident::verify_symbol(&sym) {
221 Ok(..) => PropName::Ident(quote_ident!(sym)),
222 Err(..) => PropName::Str(quote_str!(sym)),
223 },
224 value,
225 }))));
226 }
227 vec![CallExpr {
228 span: DUMMY_SP,
229 callee: self.export_ident.clone().as_callee(),
230 args: vec![ObjectLit {
231 span: DUMMY_SP,
232 props,
233 }
234 .as_arg()],
235 ..Default::default()
236 }
237 .into_stmt()]
238 }
239 }
240 }
241
242 fn build_module_item_export_all(&mut self, mut meta: ModuleItemMeta) -> Vec<Stmt> {
243 if !meta.has_export_all {
244 meta.setter_fn_stmts.append(
245 &mut self.build_export_call(&mut meta.export_names, &mut meta.export_values),
246 );
247 } else {
248 let export_obj = quote_ident!("exportObj");
249 let key_ident = quote_ident!("key");
250 let target = quote_ident!(local_name_for_src(&meta.src));
251 meta.setter_fn_stmts.push(
252 VarDecl {
253 kind: VarDeclKind::Var,
254 decls: vec![VarDeclarator {
255 span: DUMMY_SP,
256 name: export_obj.clone().into(),
257 init: Some(Box::new(Expr::Object(ObjectLit {
258 span: DUMMY_SP,
259 props: Vec::new(),
260 }))),
261 definite: false,
262 }],
263 ..Default::default()
264 }
265 .into(),
266 );
267 meta.setter_fn_stmts.push(
268 ForInStmt {
269 span: DUMMY_SP,
270 left: VarDecl {
271 kind: VarDeclKind::Var,
272 decls: vec![VarDeclarator {
273 span: DUMMY_SP,
274 name: key_ident.clone().into(),
275 init: None,
276 definite: false,
277 }],
278 ..Default::default()
279 }
280 .into(),
281 right: target.clone().into(),
282
283 body: Box::new(Stmt::Block(BlockStmt {
284 span: DUMMY_SP,
285 stmts: vec![Stmt::If(IfStmt {
286 span: DUMMY_SP,
287 test: Box::new(Expr::Bin(BinExpr {
288 span: DUMMY_SP,
289 op: op!("&&"),
290 left: Box::new(
291 key_ident
292 .clone()
293 .make_bin(op!("!=="), quote_str!("default")),
294 ),
295 right: Box::new(
296 key_ident
297 .clone()
298 .make_bin(op!("!=="), quote_str!("__esModule")),
299 ),
300 })),
301 cons: Box::new(Stmt::Block(BlockStmt {
302 stmts: vec![AssignExpr {
303 span: DUMMY_SP,
304 op: op!("="),
305 left: export_obj
306 .clone()
307 .computed_member(key_ident.clone())
308 .into(),
309 right: target.computed_member(key_ident).into(),
310 }
311 .into_stmt()],
312 ..Default::default()
313 })),
314 alt: None,
315 })],
316
317 ..Default::default()
318 })),
319 }
320 .into(),
321 );
322 for (sym, value) in meta
323 .export_names
324 .drain(..)
325 .zip(meta.export_values.drain(..))
326 {
327 meta.setter_fn_stmts.push(
328 AssignExpr {
329 span: DUMMY_SP,
330 op: op!("="),
331 left: export_obj.clone().make_member(quote_ident!(sym)).into(),
332 right: value,
333 }
334 .into_stmt(),
335 );
336 }
337 meta.setter_fn_stmts.push(
338 CallExpr {
339 span: DUMMY_SP,
340 callee: self.export_ident.clone().as_callee(),
341 args: vec![export_obj.as_arg()],
342 ..Default::default()
343 }
344 .into_stmt(),
345 );
346 }
347
348 meta.setter_fn_stmts
349 }
350
351 fn add_module_item_meta(&mut self, mut m: ModuleItemMeta) {
352 match self
353 .module_item_meta_list
354 .iter()
355 .position(|i| m.src.eq(&i.src))
356 {
357 Some(index) => {
358 let mut meta = self.module_item_meta_list.remove(index);
359 meta.setter_fn_stmts.append(&mut m.setter_fn_stmts);
360 meta.export_names.append(&mut m.export_names);
361 meta.export_values.append(&mut m.export_values);
362 if m.has_export_all {
363 meta.has_export_all = m.has_export_all;
364 }
365 self.module_item_meta_list.insert(index, meta);
366 }
367 None => {
368 self.module_item_meta_list.push(m);
369 }
370 }
371 }
372
373 #[allow(clippy::boxed_local)]
374 fn hoist_var_decl(&mut self, var_decl: Box<VarDecl>) -> Option<Expr> {
375 let mut exprs = Vec::new();
376 for var_declarator in var_decl.decls {
377 let mut tos: Vec<Id> = Vec::new();
378 var_declarator.visit_with(&mut VarCollector { to: &mut tos });
379
380 for (sym, ctxt) in tos {
381 if var_declarator.init.is_none() {
382 for (k, v) in self.export_map.iter_mut() {
383 if (sym.clone(), ctxt) == *k {
384 for value in v.iter() {
385 self.export_names.push(value.clone());
386 self.export_values.push(Expr::undefined(DUMMY_SP));
387 }
388 break;
389 }
390 }
391 }
392 self.declare_var_idents
393 .push(Ident::new(sym, DUMMY_SP, ctxt));
394 }
395
396 if let Some(init) = var_declarator.init {
397 exprs.push(
398 AssignExpr {
399 span: DUMMY_SP,
400 op: op!("="),
401 left: var_declarator.name.try_into().unwrap(),
402 right: init,
403 }
404 .into(),
405 );
406 }
407 }
408 match exprs.len() {
409 0 => None,
410 _ => Some(
411 SeqExpr {
412 span: DUMMY_SP,
413 exprs,
414 }
415 .into(),
416 ),
417 }
418 }
419
420 fn hoist_for_var_decl(&mut self, var_decl_or_pat: ForHead) -> ForHead {
421 if let ForHead::VarDecl(mut var_decl) = var_decl_or_pat {
422 if var_decl.kind == VarDeclKind::Var {
423 let var_declarator = var_decl.decls.remove(0);
424 let mut tos: Vec<Id> = Vec::new();
425 var_declarator.visit_with(&mut VarCollector { to: &mut tos });
426
427 for to in tos {
428 if var_declarator.init.is_none() {
429 for (k, v) in self.export_map.iter_mut() {
430 if to == *k {
431 for value in v.iter() {
432 self.export_names.push(value.clone());
433 self.export_values.push(Expr::undefined(DUMMY_SP));
434 }
435 break;
436 }
437 }
438 }
439 self.declare_var_idents
440 .push(Ident::new(to.0, DUMMY_SP, to.1));
441 }
442
443 ForHead::Pat(var_declarator.name.into())
444 } else {
445 ForHead::VarDecl(var_decl)
446 }
447 } else {
448 var_decl_or_pat
449 }
450 }
451
452 fn hoist_variables(&mut self, stmt: Stmt) -> Stmt {
453 match stmt {
454 Stmt::Decl(decl) => {
455 if let Decl::Var(var_decl) = decl {
456 if let Some(expr) = self.hoist_var_decl(var_decl) {
458 expr.into_stmt()
459 } else {
460 EmptyStmt { span: DUMMY_SP }.into()
461 }
462 } else {
466 decl.into()
467 }
468 }
469 Stmt::For(for_stmt) => {
470 if let Some(init) = for_stmt.init {
471 if let VarDeclOrExpr::VarDecl(var_decl) = init {
472 if var_decl.kind == VarDeclKind::Var {
473 ForStmt {
474 init: self
475 .hoist_var_decl(var_decl)
476 .map(|expr| VarDeclOrExpr::Expr(Box::new(expr))),
477 ..for_stmt
478 }
479 .into()
480 } else {
481 ForStmt {
482 init: Some(VarDeclOrExpr::VarDecl(var_decl)),
483 ..for_stmt
484 }
485 .into()
486 }
487 } else {
488 ForStmt {
489 init: Some(init),
490 ..for_stmt
491 }
492 .into()
493 }
494 } else {
495 for_stmt.into()
496 }
497 }
498 Stmt::ForIn(for_in_stmt) => ForInStmt {
499 left: self.hoist_for_var_decl(for_in_stmt.left),
500 ..for_in_stmt
501 }
502 .into(),
503 Stmt::ForOf(for_of_stmt) => ForOfStmt {
504 left: self.hoist_for_var_decl(for_of_stmt.left),
505 ..for_of_stmt
506 }
507 .into(),
508 _ => stmt,
509 }
510 }
511}
512
513impl Fold for SystemJs {
514 standard_only_fold!();
515
516 fn fold_call_expr(&mut self, expr: CallExpr) -> CallExpr {
517 let expr = expr.fold_children_with(self);
518
519 match expr.callee {
520 Callee::Import(_) => CallExpr {
521 callee: self
522 .context_ident
523 .clone()
524 .make_member(quote_ident!("import"))
525 .as_callee(),
526 ..expr
527 },
528 _ => expr,
529 }
530 }
531
532 fn fold_expr(&mut self, expr: Expr) -> Expr {
533 let expr = expr.fold_children_with(self);
534
535 match expr {
536 Expr::Ident(ident) => self.fold_module_name_ident(ident),
537 Expr::Assign(assign) => {
538 let assign_expr = AssignExpr {
539 right: match *assign.right {
540 Expr::Ident(ident) => Box::new(self.fold_module_name_ident(ident)),
541 Expr::Assign(AssignExpr {
542 op: AssignOp::Assign,
543 ..
544 }) => {
545 return self.replace_assign_expr(AssignExpr {
546 right: assign.right,
547 ..assign
548 });
549 }
550 _ => assign.right,
551 },
552 ..assign
553 }
554 .fold_with(self);
555 self.replace_assign_expr(assign_expr)
556 }
557 Expr::Update(update) => self.replace_update_expr(update),
558 Expr::Call(call) => match call.callee {
559 Callee::Import(_) => CallExpr {
560 args: call.args.fold_with(self),
561 callee: self
562 .context_ident
563 .clone()
564 .make_member(quote_ident!("import"))
565 .as_callee(),
566 ..call
567 }
568 .into(),
569 _ => call.into(),
570 },
571 Expr::MetaProp(meta_prop_expr) => match meta_prop_expr.kind {
572 MetaPropKind::ImportMeta => self
573 .context_ident
574 .clone()
575 .make_member(quote_ident!("meta"))
576 .into(),
577 _ => meta_prop_expr.into(),
578 },
579 Expr::Await(await_expr) => {
580 if self.enter_async_fn == 0 {
581 self.tla = true;
582 }
583
584 await_expr.into()
585 }
586 _ => expr,
587 }
588 }
589
590 fn fold_fn_decl(&mut self, fn_decl: FnDecl) -> FnDecl {
591 let is_async = fn_decl.function.is_async;
592 if is_async {
593 self.enter_async_fn += 1;
594 }
595 let fold_fn_expr = fn_decl.fold_children_with(self);
596 if is_async {
597 self.enter_async_fn -= 1;
598 }
599 fold_fn_expr
600 }
601
602 fn fold_prop(&mut self, prop: Prop) -> Prop {
603 let prop = prop.fold_children_with(self);
604
605 match prop {
606 Prop::Shorthand(shorthand) => Prop::KeyValue(KeyValueProp {
607 key: PropName::Ident(shorthand.clone().into()),
608 value: Box::new(self.fold_module_name_ident(shorthand)),
609 }),
610 Prop::KeyValue(key_value_prop) => Prop::KeyValue(KeyValueProp {
611 key: key_value_prop.key,
612 value: match *key_value_prop.value {
613 Expr::Ident(ident) => Box::new(self.fold_module_name_ident(ident)),
614 _ => key_value_prop.value,
615 },
616 }),
617 _ => prop,
618 }
619 }
620
621 fn fold_module(&mut self, module: Module) -> Module {
622 let module = {
623 let mut module = module;
624 if !self.config.allow_top_level_this {
625 top_level_this(&mut module, *Expr::undefined(DUMMY_SP));
626 }
627 module
628 };
629 let mut before_body_stmts: Vec<Stmt> = Vec::new();
630 let mut execute_stmts = Vec::new();
631
632 for item in &module.body {
634 if let ModuleItem::Stmt(Stmt::Decl(Decl::Fn(fn_decl))) = item {
635 self.root_fn_decl_idents.push(fn_decl.ident.clone());
636 }
637 }
638
639 for item in module.body {
640 match item {
641 ModuleItem::ModuleDecl(decl) => match decl {
642 ModuleDecl::Import(import) => {
643 let src = match &self.resolver {
644 Resolver::Real { resolver, base } => {
645 let spec = wtf8_to_cow_str(&import.src.value);
646 resolver
647 .resolve_import(base, &spec)
648 .with_context(|| {
649 format!(
650 "failed to resolve import `{}`",
651 import.src.value.to_string_lossy()
652 )
653 })
654 .unwrap()
655 }
656 Resolver::Default => normalize_wtf8_atom(&import.src.value),
657 };
658
659 let source_alias = local_name_for_src(&src);
660
661 let mut setter_fn_stmts = Vec::new();
662
663 for specifier in import.specifiers {
664 match specifier {
665 ImportSpecifier::Default(specifier) => {
666 self.import_idents.push(specifier.local.to_id());
667 self.add_declare_var_idents(&specifier.local);
668 setter_fn_stmts.push(
669 AssignExpr {
670 span: specifier.span,
671 op: op!("="),
672 left: specifier.local.into(),
673 right: quote_ident!(source_alias.clone())
674 .make_member(quote_ident!("default"))
675 .into(),
676 }
677 .into_stmt(),
678 );
679 }
680 ImportSpecifier::Named(specifier) => {
681 self.add_declare_var_idents(&specifier.local);
682 setter_fn_stmts.push(
683 AssignExpr {
684 span: specifier.span,
685 op: op!("="),
686 left: specifier.local.clone().into(),
687 right: MemberExpr {
688 span: DUMMY_SP,
689 obj: Box::new(
690 quote_ident!(source_alias.clone()).into(),
691 ),
692 prop: match specifier.imported {
693 Some(m) => get_module_export_member_prop(&m),
694 None => {
695 MemberProp::Ident(specifier.local.into())
696 }
697 },
698 }
699 .into(),
700 }
701 .into_stmt(),
702 );
703 }
704 ImportSpecifier::Namespace(specifier) => {
705 self.import_idents.push(specifier.local.to_id());
706 self.add_declare_var_idents(&specifier.local);
707 setter_fn_stmts.push(
708 AssignExpr {
709 span: specifier.span,
710 op: op!("="),
711 left: specifier.local.into(),
712 right: quote_ident!(source_alias.clone()).into(),
713 }
714 .into_stmt(),
715 );
716 }
717 #[cfg(swc_ast_unknown)]
718 _ => panic!("unable to access unknown nodes"),
719 }
720 }
721
722 self.add_module_item_meta(ModuleItemMeta {
723 export_names: Vec::new(),
724 export_values: Vec::new(),
725 has_export_all: false,
726 src: src.clone(),
727 setter_fn_stmts,
728 });
729 }
730 ModuleDecl::ExportNamed(decl) => match decl.src {
731 Some(s) => {
732 let src = match &self.resolver {
733 Resolver::Real { resolver, base } => {
734 let spec = wtf8_to_cow_str(&s.value);
735 resolver
736 .resolve_import(base, &spec)
737 .with_context(|| {
738 format!(
739 "failed to resolve import `{}`",
740 s.value.to_string_lossy()
741 )
742 })
743 .unwrap()
744 }
745 Resolver::Default => normalize_wtf8_atom(&s.value),
746 };
747 for specifier in decl.specifiers {
748 let source_alias = local_name_for_src(&src);
749 let mut export_names = Vec::new();
750 let mut export_values = Vec::new();
751
752 match specifier {
753 ExportSpecifier::Named(specifier) => {
754 export_names.push(match &specifier.exported {
755 Some(m) => get_module_export_name(m).0,
756 None => get_module_export_name(&specifier.orig).0,
757 });
758 export_values.push(
759 MemberExpr {
760 span: DUMMY_SP,
761 obj: Box::new(
762 quote_ident!(source_alias.clone()).into(),
763 ),
764 prop: get_module_export_member_prop(
765 &specifier.orig,
766 ),
767 }
768 .into(),
769 );
770 }
771 ExportSpecifier::Default(specifier) => {
772 export_names.push(specifier.exported.sym.clone());
773 export_values.push(
774 quote_ident!(source_alias.clone())
775 .make_member(quote_ident!("default"))
776 .into(),
777 );
778 }
779 ExportSpecifier::Namespace(specifier) => {
780 export_names
781 .push(get_module_export_name(&specifier.name).0);
782 export_values
783 .push(quote_ident!(source_alias.clone()).into());
784 }
785 #[cfg(swc_ast_unknown)]
786 _ => panic!("unable to access unknown nodes"),
787 }
788
789 self.add_module_item_meta(ModuleItemMeta {
790 export_names,
791 export_values,
792 has_export_all: false,
793 src: src.clone(),
794 setter_fn_stmts: Vec::new(),
795 });
796 }
797 }
798 None => {
799 for specifier in decl.specifiers {
800 if let ExportSpecifier::Named(specifier) = specifier {
801 let id = get_module_export_name(&specifier.orig);
802
803 if self.root_fn_decl_idents.iter().any(|i| i.sym == id.0) {
804 self.export_names.push(match &specifier.exported {
806 Some(m) => get_module_export_name(m).0,
807 None => id.0.clone(),
808 });
809 self.export_values.push(Box::new(get_module_export_expr(
810 &specifier.orig,
811 )));
812 }
813 if self.import_idents.contains(&id) {
814 execute_stmts.push(
815 self.export_call(
816 id.0.clone(),
817 DUMMY_SP,
818 match &specifier.exported {
819 Some(m) => get_module_export_expr(m),
820 None => get_module_export_expr(&specifier.orig),
821 },
822 )
823 .into_stmt(),
824 );
825 }
826 self.add_export_name(
827 id,
828 match specifier.exported {
829 Some(m) => get_module_export_name(&m).0,
830 None => get_module_export_name(&specifier.orig).0,
831 },
832 );
833 }
834 }
835 }
836 },
837 ModuleDecl::ExportDecl(decl) => {
838 match decl.decl {
839 Decl::Class(class_decl) => {
840 let ident = class_decl.ident;
841 self.export_names.push(ident.sym.clone());
842 self.export_values.push(Expr::undefined(DUMMY_SP));
843 self.add_declare_var_idents(&ident);
844 self.add_export_name(ident.to_id(), ident.sym.clone());
845 execute_stmts.push(
846 AssignExpr {
847 span: DUMMY_SP,
848 op: op!("="),
849 left: ident.clone().into(),
850 right: ClassExpr {
851 ident: Some(ident.clone()),
852 class: class_decl.class,
853 }
854 .into(),
855 }
856 .into_stmt(),
857 );
858 }
859 Decl::Fn(fn_decl) => {
860 self.export_names.push(fn_decl.ident.sym.clone());
861 self.export_values.push(fn_decl.ident.clone().into());
862 self.add_export_name(
863 fn_decl.ident.to_id(),
864 fn_decl.ident.sym.clone(),
865 );
866 before_body_stmts.push(fn_decl.into());
867 }
868 Decl::Var(var_decl) => {
869 let mut decl = VarDecl {
870 decls: Vec::new(),
871 ..*var_decl
872 };
873 for var_declarator in var_decl.decls {
874 let mut tos: Vec<Id> = Vec::new();
875 var_declarator.visit_with(&mut VarCollector { to: &mut tos });
876 for to in tos {
877 let ident = Ident::new(to.0.clone(), DUMMY_SP, to.1);
878 self.add_export_name(to, ident.sym.clone());
879 }
880 decl.decls.push(var_declarator);
881 }
882 execute_stmts.push(decl.into());
883 }
884 _ => {}
885 };
886 }
887 ModuleDecl::ExportDefaultDecl(decl) => {
888 match decl.decl {
889 DefaultDecl::Class(class_expr) => {
890 if let Some(ident) = &class_expr.ident {
891 self.export_names.push("default".into());
892 self.export_values.push(Expr::undefined(DUMMY_SP));
893 self.add_declare_var_idents(ident);
894 self.add_export_name(ident.to_id(), "default".into());
895 execute_stmts.push(
896 AssignExpr {
897 span: DUMMY_SP,
898 op: op!("="),
899 left: ident.clone().into(),
900 right: class_expr.into(),
901 }
902 .into_stmt(),
903 );
904 } else {
905 self.export_names.push("default".into());
906 self.export_values.push(class_expr.into());
907 }
908 }
909 DefaultDecl::Fn(fn_expr) => {
910 if let Some(ident) = &fn_expr.ident {
911 self.export_names.push("default".into());
912 self.export_values.push(ident.clone().into());
913 self.add_export_name(ident.to_id(), "default".into());
914 before_body_stmts.push(
915 FnDecl {
916 ident: ident.clone(),
917 declare: false,
918 function: fn_expr.function,
919 }
920 .into(),
921 );
922 } else {
923 self.export_names.push("default".into());
924 self.export_values.push(fn_expr.into());
925 }
926 }
927 _ => {}
928 };
929 }
930 ModuleDecl::ExportDefaultExpr(expr) => {
931 execute_stmts.push(
932 self.export_call("default".into(), expr.span, *expr.expr)
933 .into_stmt(),
934 );
935 }
936 ModuleDecl::ExportAll(decl) => {
937 self.add_module_item_meta(ModuleItemMeta {
938 export_names: Vec::new(),
939 export_values: Vec::new(),
940 has_export_all: true,
941 src: normalize_wtf8_atom(&decl.src.value),
942 setter_fn_stmts: Vec::new(),
943 });
944 }
945 _ => {}
946 },
947 ModuleItem::Stmt(stmt) => match stmt {
948 Stmt::Decl(decl) => match decl {
949 Decl::Class(class_decl) => {
950 self.add_declare_var_idents(&class_decl.ident);
951 execute_stmts.push(
952 AssignExpr {
953 span: DUMMY_SP,
954 op: op!("="),
955 left: class_decl.ident.clone().into(),
956 right: ClassExpr {
957 ident: Some(class_decl.ident.clone()),
958 class: class_decl.class,
959 }
960 .into(),
961 }
962 .into_stmt(),
963 );
964 }
965 Decl::Fn(fn_decl) => {
966 before_body_stmts.push(fn_decl.into());
967 }
968 _ => execute_stmts.push(decl.into()),
969 },
970 _ => execute_stmts.push(stmt),
971 },
972 #[cfg(swc_ast_unknown)]
973 _ => panic!("unable to access unknown nodes"),
974 }
975 }
976
977 before_body_stmts = before_body_stmts
982 .into_iter()
983 .map(|s| s.fold_with(self))
984 .collect();
985
986 execute_stmts = execute_stmts
987 .into_iter()
988 .map(|s| self.hoist_variables(s).fold_with(self))
989 .filter(|s| !matches!(s, Stmt::Empty(_)))
990 .collect();
991
992 if !self.export_names.is_empty() {
996 let mut export_names = self.export_names.drain(..).collect();
997 let mut export_values = self.export_values.drain(..).collect();
998 before_body_stmts
999 .append(&mut self.build_export_call(&mut export_names, &mut export_values));
1000 }
1001
1002 let mut setters = ArrayLit {
1003 span: DUMMY_SP,
1004 elems: Vec::new(),
1005 };
1006
1007 let mut dep_module_names = ArrayLit {
1008 span: DUMMY_SP,
1009 elems: Vec::new(),
1010 };
1011
1012 let module_item_meta_list: Vec<ModuleItemMeta> =
1013 self.module_item_meta_list.drain(..).collect();
1014 for meta in module_item_meta_list {
1015 dep_module_names
1016 .elems
1017 .push(Some(quote_str!(meta.src.clone()).as_arg()));
1018 setters.elems.push(Some(
1019 Function {
1020 params: vec![Param {
1021 span: DUMMY_SP,
1022 decorators: Default::default(),
1023 pat: quote_ident!(local_name_for_src(&meta.src)).into(),
1024 }],
1025 span: DUMMY_SP,
1026 body: Some(BlockStmt {
1027 span: DUMMY_SP,
1028 stmts: self.build_module_item_export_all(meta),
1029 ..Default::default()
1030 }),
1031 is_generator: false,
1032 is_async: false,
1033 ..Default::default()
1034 }
1035 .as_arg(),
1036 ));
1037 }
1038
1039 let execute = Box::new(Function {
1040 params: Vec::new(),
1041 decorators: Default::default(),
1042 span: DUMMY_SP,
1043 body: Some(BlockStmt {
1044 stmts: execute_stmts,
1045 ..Default::default()
1046 }),
1047 is_generator: false,
1048 is_async: self.tla,
1049 ..Default::default()
1050 });
1051
1052 let return_stmt = ReturnStmt {
1053 span: DUMMY_SP,
1054 arg: Some(
1055 ObjectLit {
1056 span: DUMMY_SP,
1057 props: vec![
1058 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
1059 key: quote_ident!("setters").into(),
1060 value: Box::new(Expr::Array(setters)),
1061 }))),
1062 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
1063 key: quote_ident!("execute").into(),
1064 value: Box::new(Expr::Fn(FnExpr {
1065 ident: None,
1066 function: execute,
1067 })),
1068 }))),
1069 ],
1070 }
1071 .into(),
1072 ),
1073 };
1074
1075 let mut function_stmts = vec![use_strict()];
1076
1077 if !self.declare_var_idents.is_empty() {
1078 function_stmts.push(
1079 VarDecl {
1080 span: DUMMY_SP,
1081 kind: VarDeclKind::Var,
1082 declare: false,
1083 decls: self
1084 .declare_var_idents
1085 .iter()
1086 .map(|i| VarDeclarator {
1087 span: i.span,
1088 name: i.clone().into(),
1089 init: None,
1090 definite: false,
1091 })
1092 .collect(),
1093 ..Default::default()
1094 }
1095 .into(),
1096 );
1097 }
1098 function_stmts.append(&mut before_body_stmts);
1099 function_stmts.push(return_stmt.into());
1100
1101 let function = Box::new(Function {
1102 params: vec![
1103 Param {
1104 span: DUMMY_SP,
1105 decorators: Default::default(),
1106 pat: self.export_ident.clone().into(),
1107 },
1108 Param {
1109 span: DUMMY_SP,
1110 decorators: Default::default(),
1111 pat: self.context_ident.clone().into(),
1112 },
1113 ],
1114 decorators: Default::default(),
1115 span: DUMMY_SP,
1116 body: Some(BlockStmt {
1117 span: DUMMY_SP,
1118 stmts: function_stmts,
1119 ..Default::default()
1120 }),
1121 is_generator: false,
1122 is_async: false,
1123 ..Default::default()
1124 });
1125
1126 Module {
1127 body: vec![CallExpr {
1128 span: DUMMY_SP,
1129 callee: member_expr!(Default::default(), Default::default(), System.register)
1130 .as_callee(),
1131 args: vec![
1132 dep_module_names.as_arg(),
1133 FnExpr {
1134 ident: None,
1135 function,
1136 }
1137 .as_arg(),
1138 ],
1139 ..Default::default()
1140 }
1141 .into_stmt()
1142 .into()],
1143 ..module
1144 }
1145 }
1146}
1147
1148#[inline]
1149fn get_module_export_name(module_export_name: &ModuleExportName) -> Id {
1150 match &module_export_name {
1151 ModuleExportName::Ident(ident) => ident.to_id(),
1152 ModuleExportName::Str(s) => (s.value.to_atom_lossy().into_owned(), SyntaxContext::empty()),
1153 #[cfg(swc_ast_unknown)]
1154 _ => panic!("unable to access unknown nodes"),
1155 }
1156}
1157
1158#[inline]
1159fn get_module_export_expr(module_export_name: &ModuleExportName) -> Expr {
1160 match &module_export_name {
1161 ModuleExportName::Ident(ident) => ident.clone().into(),
1162 ModuleExportName::Str(s) => {
1163 Lit::Str(quote_str!(s.value.to_atom_lossy().into_owned())).into()
1164 }
1165 #[cfg(swc_ast_unknown)]
1166 _ => panic!("unable to access unknown nodes"),
1167 }
1168}
1169
1170#[inline]
1171fn get_module_export_member_prop(module_export_name: &ModuleExportName) -> MemberProp {
1172 match &module_export_name {
1173 ModuleExportName::Ident(ident) => MemberProp::Ident(ident.clone().into()),
1174 ModuleExportName::Str(s) => MemberProp::Computed(ComputedPropName {
1175 span: s.span,
1176 expr: Lit::Str(quote_str!(s.value.to_atom_lossy().into_owned())).into(),
1177 }),
1178 #[cfg(swc_ast_unknown)]
1179 _ => panic!("unable to access unknown nodes"),
1180 }
1181}