swc_ecma_compat_bugfixes/
async_arrows_in_class.rs1use swc_common::{util::take::Take, Mark, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_compat_es2015::arrow;
4use swc_ecma_utils::prepend_stmt;
5use swc_ecma_visit::{fold_pass, standard_only_fold, Fold, FoldWith, InjectVars, VisitMutWith};
6use swc_trace_macro::swc_trace;
7
8pub fn async_arrows_in_class(unresolved_mark: Mark) -> impl Pass {
16 fold_pass(AsyncArrowsInClass {
17 unresolved_mark,
18 ..Default::default()
19 })
20}
21#[derive(Default, Clone)]
22struct AsyncArrowsInClass {
23 in_class_method: bool,
24 unresolved_mark: Mark,
25 vars: Vec<VarDeclarator>,
26}
27
28#[swc_trace]
30impl Fold for AsyncArrowsInClass {
31 standard_only_fold!();
32
33 fn fold_class_method(&mut self, n: ClassMethod) -> ClassMethod {
34 self.in_class_method = true;
35 let res = n.fold_children_with(self);
36 self.in_class_method = false;
37 res
38 }
39
40 fn fold_constructor(&mut self, n: Constructor) -> Constructor {
41 self.in_class_method = true;
42 let res = n.fold_children_with(self);
43 self.in_class_method = false;
44 res
45 }
46
47 fn fold_expr(&mut self, n: Expr) -> Expr {
48 let mut n = n.fold_children_with(self);
49 if !self.in_class_method {
50 return n;
51 }
52
53 match n {
54 Expr::Arrow(ref a) => {
55 if a.is_async {
56 let mut v = arrow(self.unresolved_mark);
57 n.visit_mut_with(&mut v);
58 self.vars.extend(v.take_vars());
59 n
60 } else {
61 n
62 }
63 }
64 _ => n,
65 }
66 }
67
68 fn fold_module_items(&mut self, stmts: Vec<ModuleItem>) -> Vec<ModuleItem> {
69 let mut stmts = stmts.fold_children_with(self);
70 if !self.vars.is_empty() {
71 prepend_stmt(
72 &mut stmts,
73 VarDecl {
74 span: DUMMY_SP,
75 kind: VarDeclKind::Var,
76 declare: false,
77 decls: self.vars.take(),
78 ..Default::default()
79 }
80 .into(),
81 );
82 }
83
84 stmts
85 }
86
87 fn fold_stmts(&mut self, stmts: Vec<Stmt>) -> Vec<Stmt> {
88 let mut stmts = stmts.fold_children_with(self);
89 if !self.vars.is_empty() {
90 prepend_stmt(
91 &mut stmts,
92 VarDecl {
93 span: DUMMY_SP,
94 kind: VarDeclKind::Var,
95 declare: false,
96 decls: self.vars.take(),
97 ..Default::default()
98 }
99 .into(),
100 );
101 }
102
103 stmts
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use swc_ecma_transforms_base::resolver;
110 use swc_ecma_transforms_testing::test;
111
112 use super::*;
113
114 fn tr() -> impl Pass {
115 let unresolved = Mark::new();
116 (
117 resolver(unresolved, Mark::new(), false),
118 async_arrows_in_class(unresolved),
119 )
120 }
121
122 test!(
123 ::swc_ecma_parser::Syntax::default(),
124 |_| tr(),
125 async_arrows,
126 r#"
127 class Foo {
128 constructor() {
129 this.x = async () => await 1;
130 }
131 bar() {
132 (async () => { })();
133 }
134 }"#
135 );
136
137 test!(
138 ::swc_ecma_parser::Syntax::default(),
139 |_| tr(),
140 callback,
141 r#"
142 class Foo {
143 foo() {
144 bar(async () => await 1);
145 }
146 }"#
147 );
148
149 test!(
150 ::swc_ecma_parser::Syntax::default(),
151 |_| tr(),
152 this,
153 r#"
154 class Foo {
155 constructor() {
156 this.x = () => async () => await this;
157 }
158 }"#
159 );
160
161 test!(
165 ::swc_ecma_parser::Syntax::default(),
166 |_| tr(),
167 non_async_arrow,
168 r#"
169 class Foo {
170 constructor() {
171 this.x = () => {};
172 }
173 }"#
174 );
175
176 test!(
177 ::swc_ecma_parser::Syntax::default(),
178 |_| tr(),
179 non_class_async_arrow,
180 "let x = async () => await 1;"
181 );
182}