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                    }),
162                    ..Default::default()
163                }
164                .into();
165
166                *expr = fn_expr;
167            }
168            _ => {
169                expr.visit_mut_children_with(self);
170            }
171        }
172    }
173
174    fn visit_mut_function(&mut self, f: &mut Function) {
175        let old_rep = self.hoister.take();
176
177        f.visit_mut_children_with(self);
178
179        let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
180
181        if let (Some(body), Some(stmt)) = (&mut f.body, decl) {
182            prepend_stmt(&mut body.stmts, stmt);
183        }
184    }
185
186    fn visit_mut_getter_prop(&mut self, f: &mut GetterProp) {
187        f.key.visit_mut_with(self);
188
189        if let Some(body) = &mut f.body {
190            let old_rep = self.hoister.take();
191
192            body.visit_mut_with(self);
193
194            let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
195
196            if let Some(stmt) = decl {
197                prepend_stmt(&mut body.stmts, stmt);
198            }
199        }
200    }
201
202    fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
203        stmts.visit_mut_children_with(self);
204
205        let decl = self.hoister.take().to_stmt();
206
207        if let Some(stmt) = decl {
208            prepend_stmt(stmts, stmt.into());
209        }
210    }
211
212    fn visit_mut_script(&mut self, script: &mut Script) {
213        script.visit_mut_children_with(self);
214
215        let decl = self.hoister.take().to_stmt();
216
217        if let Some(stmt) = decl {
218            prepend_stmt(&mut script.body, stmt);
219        }
220    }
221
222    fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
223        f.key.visit_mut_with(self);
224        f.param.visit_mut_with(self);
225
226        if let Some(body) = &mut f.body {
227            let old_rep = self.hoister.take();
228
229            body.visit_mut_with(self);
230
231            let decl = mem::replace(&mut self.hoister, old_rep).to_stmt();
232
233            if let Some(stmt) = decl {
234                prepend_stmt(&mut body.stmts, stmt);
235            }
236        }
237    }
238}
239
240impl InjectVars for Arrow {
241    fn take_vars(&mut self) -> Vec<VarDeclarator> {
242        self.hoister.take().to_decl()
243    }
244}