Skip to main content

swc_ecma_utils/
constructor.rs

1use 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        // skip
43    }
44
45    fn visit_mut_function(&mut self, _: &mut Function) {
46        // skip
47    }
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}