swc_ecma_compat_es2015/
arrow.rs

1use std::mem;
2
3use swc_common::{util::take::Take, Mark, SyntaxContext, DUMMY_SP};
4use swc_ecma_ast::*;
5use swc_ecma_utils::{
6    function::{init_this, FnEnvHoister},
7    prepend_stmt,
8};
9use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, InjectVars, VisitMut, VisitMutWith};
10use swc_trace_macro::swc_trace;
11
12/// Compile ES2015 arrow functions to ES5
13///
14///# Example
15///
16///## In
17/// ```js
18/// var a = () => {};
19/// var a = (b) => b;ß
20///
21/// const double = [1,2,3].map((num) => num * 2);
22/// console.log(double); // [2,4,6]
23///
24/// var bob = {
25///   _name: "Bob",
26///   _friends: ["Sally", "Tom"],
27///   printFriends() {
28///     this._friends.forEach(f =>
29///       console.log(this._name + " knows " + f));
30///   }
31/// };
32/// console.log(bob.printFriends());
33/// ```
34///
35///## Out
36///```js
37/// var a = function () {};
38/// var a = function (b) {
39///   return b;
40/// };
41///
42/// const double = [1, 2, 3].map(function (num) {
43///   return num * 2;
44/// });
45/// console.log(double); // [2,4,6]
46///
47/// var bob = {
48///   _name: "Bob",
49///   _friends: ["Sally", "Tom"],
50///   printFriends() {
51///     var _this = this;
52///
53///     this._friends.forEach(function (f) {
54///       return console.log(_this._name + " knows " + f);
55///     });
56///   }
57/// };
58/// console.log(bob.printFriends());
59/// ```
60pub fn arrow(unresolved_mark: Mark) -> impl Pass + VisitMut + InjectVars {
61    visit_mut_pass(Arrow {
62        in_subclass: false,
63        hoister: FnEnvHoister::new(SyntaxContext::empty().apply_mark(unresolved_mark)),
64    })
65}
66
67#[derive(Default)]
68struct Arrow {
69    in_subclass: bool,
70    hoister: FnEnvHoister,
71}
72
73#[swc_trace]
74impl VisitMut for Arrow {
75    noop_visit_mut_type!(fail);
76
77    fn visit_mut_class(&mut self, c: &mut Class) {
78        let old = self.in_subclass;
79
80        if c.super_class.is_some() {
81            self.in_subclass = true;
82        }
83        c.visit_mut_children_with(self);
84        self.in_subclass = old;
85    }
86
87    fn visit_mut_constructor(&mut self, c: &mut Constructor) {
88        c.params.visit_mut_children_with(self);
89
90        if let Some(BlockStmt { span: _, stmts, .. }) = &mut c.body {
91            let old_rep = self.hoister.take();
92
93            stmts.visit_mut_children_with(self);
94
95            if self.in_subclass {
96                let (decl, this_id) =
97                    mem::replace(&mut self.hoister, old_rep).to_stmt_in_subclass();
98
99                if let Some(stmt) = decl {
100                    if let Some(this_id) = this_id {
101                        init_this(stmts, &this_id)
102                    }
103                    prepend_stmt(stmts, stmt);
104                }
105            } else {
106                let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
107
108                if let Some(stmt) = decl {
109                    prepend_stmt(stmts, stmt);
110                }
111            }
112        }
113    }
114
115    fn visit_mut_expr(&mut self, expr: &mut Expr) {
116        match expr {
117            Expr::Arrow(ArrowExpr {
118                span,
119                params,
120                body,
121                is_async,
122                is_generator,
123                ..
124            }) => {
125                params.visit_mut_with(self);
126                params.visit_mut_with(&mut self.hoister);
127
128                let params: Vec<Param> = params
129                    .take()
130                    .into_iter()
131                    .map(|pat| Param {
132                        span: DUMMY_SP,
133                        decorators: Default::default(),
134                        pat,
135                    })
136                    .collect();
137
138                body.visit_mut_with(self);
139
140                body.visit_mut_with(&mut self.hoister);
141
142                let fn_expr = Function {
143                    decorators: Vec::new(),
144                    span: *span,
145                    params,
146                    is_async: *is_async,
147                    is_generator: *is_generator,
148                    body: Some(match &mut **body {
149                        BlockStmtOrExpr::BlockStmt(block) => block.take(),
150                        BlockStmtOrExpr::Expr(expr) => BlockStmt {
151                            span: DUMMY_SP,
152                            stmts: vec![Stmt::Return(ReturnStmt {
153                                // this is needed so
154                                // () => /* 123 */ 1 would become
155                                // function { return /*123 */ 123 }
156                                span: DUMMY_SP,
157                                arg: Some(expr.take()),
158                            })],
159                            ..Default::default()
160                        },
161                        #[cfg(swc_ast_unknown)]
162                        _ => panic!("unable to access unknown nodes"),
163                    }),
164                    ..Default::default()
165                }
166                .into();
167
168                *expr = fn_expr;
169            }
170            _ => {
171                expr.visit_mut_children_with(self);
172            }
173        }
174    }
175
176    fn visit_mut_function(&mut self, f: &mut Function) {
177        let old_rep = self.hoister.take();
178
179        f.visit_mut_children_with(self);
180
181        let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
182
183        if let (Some(body), Some(stmt)) = (&mut f.body, decl) {
184            prepend_stmt(&mut body.stmts, stmt);
185        }
186    }
187
188    fn visit_mut_getter_prop(&mut self, f: &mut GetterProp) {
189        f.key.visit_mut_with(self);
190
191        if let Some(body) = &mut f.body {
192            let old_rep = self.hoister.take();
193
194            body.visit_mut_with(self);
195
196            let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
197
198            if let Some(stmt) = decl {
199                prepend_stmt(&mut body.stmts, stmt);
200            }
201        }
202    }
203
204    fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
205        stmts.visit_mut_children_with(self);
206
207        let decl = self.hoister.take().to_stmt();
208
209        if let Some(stmt) = decl {
210            prepend_stmt(stmts, stmt.into());
211        }
212    }
213
214    fn visit_mut_script(&mut self, script: &mut Script) {
215        script.visit_mut_children_with(self);
216
217        let decl = self.hoister.take().to_stmt();
218
219        if let Some(stmt) = decl {
220            prepend_stmt(&mut script.body, stmt);
221        }
222    }
223
224    fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
225        f.key.visit_mut_with(self);
226        f.param.visit_mut_with(self);
227
228        if let Some(body) = &mut f.body {
229            let old_rep = self.hoister.take();
230
231            body.visit_mut_with(self);
232
233            let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
234
235            if let Some(stmt) = decl {
236                prepend_stmt(&mut body.stmts, stmt);
237            }
238        }
239    }
240}
241
242impl InjectVars for Arrow {
243    fn take_vars(&mut self) -> Vec<VarDeclarator> {
244        self.hoister.take().to_decl()
245    }
246}