swc_ecma_utils/
constructor.rs1use std::{iter, mem};
2
3use swc_common::{util::take::Take, DUMMY_SP};
4use swc_ecma_ast::*;
5use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
6
7use crate::ExprFactory;
8
9pub fn inject_after_super(c: &mut Constructor, exprs: Vec<Box<Expr>>) {
10 if exprs.is_empty() {
11 return;
12 }
13
14 let body = c.body.as_mut().expect("constructor should have a body");
15
16 let mut injector = Injector {
17 exprs,
18 ..Default::default()
19 };
20
21 body.visit_mut_with(&mut injector);
22
23 if !injector.injected {
24 let exprs = injector.exprs.take();
25 body.stmts
26 .splice(0..0, exprs.into_iter().map(|e| e.into_stmt()));
27 }
28}
29
30#[derive(Default)]
31struct Injector {
32 exprs: Vec<Box<Expr>>,
33 ignore_return_value: bool,
34
35 injected: bool,
36}
37
38impl VisitMut for Injector {
39 noop_visit_mut_type!();
40
41 fn visit_mut_constructor(&mut self, _: &mut Constructor) {
42 }
44
45 fn visit_mut_function(&mut self, _: &mut Function) {
46 }
48
49 fn visit_mut_expr_stmt(&mut self, node: &mut ExprStmt) {
50 let ignore_return_value = mem::replace(&mut self.ignore_return_value, true);
51 node.visit_mut_children_with(self);
52 self.ignore_return_value = ignore_return_value;
53 }
54
55 fn visit_mut_seq_expr(&mut self, node: &mut SeqExpr) {
56 if let Some(mut tail) = node.exprs.pop() {
57 let ignore_return_value = mem::replace(&mut self.ignore_return_value, true);
58 node.visit_mut_children_with(self);
59 self.ignore_return_value = ignore_return_value;
60 tail.visit_mut_with(self);
61 node.exprs.push(tail);
62 }
63 }
64
65 fn visit_mut_expr(&mut self, node: &mut Expr) {
66 let ignore_return_value = self.ignore_return_value;
67 if !matches!(node, Expr::Paren(..) | Expr::Seq(..)) {
68 self.ignore_return_value = false;
69 }
70 node.visit_mut_children_with(self);
71 self.ignore_return_value = ignore_return_value;
72
73 if let Expr::Call(CallExpr {
74 callee: Callee::Super(..),
75 ..
76 }) = node
77 {
78 self.injected = true;
79
80 let super_call = node.take();
81 let exprs = self.exprs.clone();
82
83 let exprs = iter::once(Box::new(super_call)).chain(exprs);
84
85 *node = if ignore_return_value {
86 SeqExpr {
87 span: DUMMY_SP,
88 exprs: exprs.collect(),
89 }
90 .into()
91 } else {
92 let array = ArrayLit {
93 span: DUMMY_SP,
94 elems: exprs.map(ExprOrSpread::from).map(Some).collect(),
95 };
96
97 MemberExpr {
98 span: DUMMY_SP,
99 obj: array.into(),
100 prop: ComputedPropName {
101 span: DUMMY_SP,
102 expr: 0.into(),
103 }
104 .into(),
105 }
106 .into()
107 }
108 }
109 }
110}