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