swc_ecma_transforms_compat/
class_fields_use_set.rs1use std::mem;
2
3use swc_common::{util::take::Take, Span, Spanned, DUMMY_SP};
4use swc_ecma_ast::*;
5use swc_ecma_utils::{
6 constructor::inject_after_super, default_constructor_with_span, is_literal,
7 is_simple_pure_expr, private_ident, prop_name_to_member_prop, ExprFactory, ModuleItemLike,
8 StmtLike,
9};
10use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
11
12pub fn class_fields_use_set(pure_getters: bool) -> impl Pass {
88 visit_mut_pass(ClassFieldsUseSet { pure_getters })
89}
90
91#[derive(Debug)]
92struct ClassFieldsUseSet {
93 pure_getters: bool,
94}
95
96impl VisitMut for ClassFieldsUseSet {
97 noop_visit_mut_type!(fail);
98
99 fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
100 self.visit_mut_stmts_like(n);
101 }
102
103 fn visit_mut_stmts(&mut self, n: &mut Vec<Stmt>) {
104 self.visit_mut_stmts_like(n);
105 }
106
107 fn visit_mut_class(&mut self, n: &mut Class) {
108 n.visit_mut_children_with(self);
110
111 let mut fields_handler: FieldsHandler = FieldsHandler {
112 super_call_span: n.super_class.as_ref().map(|_| n.span),
113 };
114
115 n.body.visit_mut_with(&mut fields_handler);
116 }
117}
118
119impl ClassFieldsUseSet {
120 fn visit_mut_stmts_like<T>(&mut self, n: &mut Vec<T>)
121 where
122 T: StmtLike
123 + ModuleItemLike
124 + VisitMutWith<Self>
125 + VisitMutWith<ComputedFieldsHandler>
126 + From<Stmt>,
127 {
128 let mut stmts = Vec::with_capacity(n.len());
129
130 let mut computed_fields_handler = ComputedFieldsHandler {
131 var_decls: Default::default(),
132 static_init_blocks: Default::default(),
133 pure_getters: self.pure_getters,
134 };
135
136 for mut stmt in n.drain(..) {
137 stmt.visit_mut_with(&mut computed_fields_handler);
138
139 let var_decls = computed_fields_handler.var_decls.take();
140
141 if !var_decls.is_empty() {
142 stmts.push(T::from(
143 VarDecl {
144 span: DUMMY_SP,
145 kind: VarDeclKind::Let,
146 declare: false,
147 decls: var_decls,
148 ..Default::default()
149 }
150 .into(),
151 ))
152 }
153
154 stmt.visit_mut_with(self);
155
156 stmts.push(stmt);
157 }
158 *n = stmts;
159 }
160}
161
162#[derive(Debug)]
163struct FieldsHandler {
164 super_call_span: Option<Span>,
165}
166
167impl VisitMut for FieldsHandler {
168 noop_visit_mut_type!(fail);
169
170 fn visit_mut_class(&mut self, _: &mut Class) {
171 }
176
177 fn visit_mut_class_members(&mut self, n: &mut Vec<ClassMember>) {
178 let mut constructor_inits = Vec::new();
179
180 for member in n.iter_mut() {
181 match member {
182 ClassMember::ClassProp(ClassProp {
183 ref span,
184 ref is_static,
185 key,
186 value,
187 ..
188 }) => {
189 if let Some(value) = value.take() {
190 let init_expr: Expr = AssignExpr {
191 span: *span,
192 op: op!("="),
193 left: MemberExpr {
194 span: DUMMY_SP,
195 obj: ThisExpr::dummy().into(),
196 prop: prop_name_to_member_prop(key.take()),
197 }
198 .into(),
199 right: value,
200 }
201 .into();
202
203 if *is_static {
204 *member = StaticBlock {
205 span: DUMMY_SP,
206 body: BlockStmt {
207 span: DUMMY_SP,
208 stmts: vec![init_expr.into_stmt()],
209 ..Default::default()
210 },
211 }
212 .into();
213
214 continue;
215 } else {
216 constructor_inits.push(init_expr.into());
217 }
218 }
219
220 member.take();
221 }
222 ClassMember::PrivateProp(PrivateProp {
223 ref span,
224 is_static: false,
225 key,
226 value,
227 ..
228 }) => {
229 if let Some(value) = value.take() {
230 let init_expr: Expr = AssignExpr {
231 span: *span,
232 op: op!("="),
233 left: MemberExpr {
234 span: DUMMY_SP,
235 obj: ThisExpr::dummy().into(),
236 prop: MemberProp::PrivateName(key.clone()),
237 }
238 .into(),
239 right: value,
240 }
241 .into();
242
243 constructor_inits.push(init_expr.into());
244 }
245 }
246 _ => {}
247 }
248 }
249
250 if constructor_inits.is_empty() {
251 return;
252 }
253
254 if let Some(c) = n.iter_mut().find_map(|m| m.as_mut_constructor()) {
255 inject_after_super(c, constructor_inits.take());
256 } else {
257 let mut c = default_constructor_with_span(
258 self.super_call_span.is_some(),
259 self.super_call_span.span(),
260 );
261 inject_after_super(&mut c, constructor_inits.take());
262 n.push(c.into());
263 }
264 }
265}
266
267#[derive(Debug)]
268struct ComputedFieldsHandler {
269 var_decls: Vec<VarDeclarator>,
270 static_init_blocks: Vec<Stmt>,
271 pure_getters: bool,
272}
273
274impl VisitMut for ComputedFieldsHandler {
275 noop_visit_mut_type!(fail);
276
277 fn visit_mut_class_prop(&mut self, n: &mut ClassProp) {
278 match &mut n.key {
279 PropName::Computed(ComputedPropName { expr, .. })
280 if !is_literal(expr) && !is_simple_pure_expr(expr, self.pure_getters) =>
281 {
282 let ref_key = private_ident!("prop");
283 let mut computed_expr = ref_key.clone().into();
284
285 mem::swap(expr, &mut computed_expr);
286
287 self.var_decls.push(VarDeclarator {
288 span: DUMMY_SP,
289 name: ref_key.clone().into(),
290 init: None,
291 definite: false,
292 });
293
294 self.static_init_blocks.push({
295 let assign_expr = computed_expr.make_assign_to(op!("="), ref_key.into());
296
297 assign_expr.into_stmt()
298 });
299 }
300 _ => (),
301 }
302 }
303
304 fn visit_mut_class_member(&mut self, n: &mut ClassMember) {
305 if n.is_class_prop() {
306 n.visit_mut_children_with(self);
307 }
308 }
309
310 fn visit_mut_class_members(&mut self, n: &mut Vec<ClassMember>) {
311 n.visit_mut_children_with(self);
312
313 if !self.static_init_blocks.is_empty() {
314 n.insert(
315 0,
316 StaticBlock {
317 span: DUMMY_SP,
318 body: BlockStmt {
319 span: DUMMY_SP,
320 stmts: self.static_init_blocks.take(),
321 ..Default::default()
322 },
323 }
324 .into(),
325 );
326 }
327 }
328}