1use rustc_hash::FxHashMap;
2use swc_atoms::{atom, Atom};
3use swc_common::{
4 errors::HANDLER, source_map::PURE_SP, util::take::Take, Mark, Span, Spanned, SyntaxContext,
5 DUMMY_SP,
6};
7use swc_ecma_ast::*;
8use swc_ecma_transforms_base::{helper, perf::Check};
9use swc_ecma_transforms_classes::super_field::SuperFieldAccessFolder;
10use swc_ecma_transforms_macros::fast_path;
11use swc_ecma_utils::{
12 alias_ident_for, alias_if_required, constructor::inject_after_super,
13 default_constructor_with_span, is_literal, prepend_stmt, private_ident, quote_ident,
14 replace_ident, ExprFactory, ModuleItemLike, StmtLike,
15};
16use swc_ecma_visit::{
17 noop_visit_mut_type, noop_visit_type, visit_mut_pass, Visit, VisitMut, VisitMutWith, VisitWith,
18};
19use swc_trace_macro::swc_trace;
20
21use self::{
22 class_name_tdz::ClassNameTdzFolder,
23 member_init::{MemberInit, MemberInitRecord, PrivAccessor, PrivMethod, PrivProp, PubProp},
24 private_field::{
25 dup_private_method, visit_private_in_expr, BrandCheckHandler, Private,
26 PrivateAccessVisitor, PrivateKind, PrivateRecord,
27 },
28 this_in_static::{NewTargetInProp, ThisInStaticFolder},
29 used_name::UsedNameCollector,
30};
31
32mod class_name_tdz;
33mod member_init;
34mod private_field;
35mod this_in_static;
36mod used_name;
37
38pub fn class_properties(config: Config, unresolved_mark: Mark) -> impl Pass {
46 visit_mut_pass(ClassProperties {
47 c: config,
48 private: PrivateRecord::new(),
49 extra: ClassExtra::default(),
50 unresolved_mark,
51 })
52}
53
54#[derive(Debug, Default, Clone, Copy)]
55pub struct Config {
56 pub private_as_properties: bool,
57 pub set_public_fields: bool,
58 pub constant_super: bool,
59 pub no_document_all: bool,
60 pub pure_getter: bool,
61}
62
63struct ClassProperties {
64 extra: ClassExtra,
65 c: Config,
66 private: PrivateRecord,
67 unresolved_mark: Mark,
68}
69
70#[derive(Default)]
71struct ClassExtra {
72 lets: Vec<VarDeclarator>,
73 vars: Vec<VarDeclarator>,
74 stmts: Vec<Stmt>,
75}
76
77#[swc_trace]
78impl ClassExtra {
79 fn prepend_with<T: StmtLike>(self, stmts: &mut Vec<T>) {
80 if !self.vars.is_empty() {
81 prepend_stmt(
82 stmts,
83 T::from(Stmt::from(VarDecl {
84 span: DUMMY_SP,
85 kind: VarDeclKind::Var,
86 decls: self.vars,
87 ..Default::default()
88 })),
89 )
90 }
91
92 if !self.lets.is_empty() {
93 prepend_stmt(
94 stmts,
95 T::from(Stmt::from(VarDecl {
96 span: DUMMY_SP,
97 kind: VarDeclKind::Let,
98 decls: self.lets,
99 ..Default::default()
100 })),
101 )
102 }
103
104 stmts.extend(self.stmts.into_iter().map(|stmt| stmt.into()))
105 }
106
107 fn merge_with<T: StmtLike>(self, stmts: &mut Vec<T>, class: T) {
108 if !self.vars.is_empty() {
109 stmts.push(T::from(Stmt::from(VarDecl {
110 span: DUMMY_SP,
111 kind: VarDeclKind::Var,
112 decls: self.vars,
113 ..Default::default()
114 })))
115 }
116
117 if !self.lets.is_empty() {
118 stmts.push(T::from(
119 VarDecl {
120 span: DUMMY_SP,
121 kind: VarDeclKind::Let,
122 decls: self.lets,
123 ..Default::default()
124 }
125 .into(),
126 ));
127 }
128
129 stmts.push(class);
130
131 stmts.extend(self.stmts.into_iter().map(|stmt| stmt.into()))
132 }
133}
134
135impl Take for ClassExtra {
136 fn dummy() -> Self {
137 Self::default()
138 }
139}
140
141#[swc_trace]
142#[fast_path(ShouldWork)]
143impl VisitMut for ClassProperties {
144 noop_visit_mut_type!(fail);
145
146 fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
147 self.visit_mut_stmt_like(n);
148
149 self.extra.take().prepend_with(n)
150 }
151
152 fn visit_mut_stmts(&mut self, n: &mut Vec<Stmt>) {
153 let old = self.extra.take();
154 self.visit_mut_stmt_like(n);
155
156 self.extra.take().prepend_with(n);
157
158 self.extra = old;
159 }
160
161 fn visit_mut_block_stmt_or_expr(&mut self, body: &mut BlockStmtOrExpr) {
162 match body {
163 BlockStmtOrExpr::Expr(expr) if expr.is_class() => {
164 let ClassExpr { ident, class } = expr.take().class().unwrap();
165
166 let mut stmts = Vec::new();
167 let ident = ident.unwrap_or_else(|| private_ident!("_class"));
168 let (decl, extra) = self.visit_mut_class_as_decl(ident.clone(), class);
169
170 extra.merge_with(&mut stmts, decl.into());
171
172 stmts.push(
173 ReturnStmt {
174 span: DUMMY_SP,
175 arg: Some(ident.into()),
176 }
177 .into(),
178 );
179
180 *body = BlockStmtOrExpr::BlockStmt(BlockStmt {
181 span: DUMMY_SP,
182 stmts,
183 ..Default::default()
184 });
185 }
186 _ => body.visit_mut_children_with(self),
187 };
188 }
189
190 fn visit_mut_expr(&mut self, expr: &mut Expr) {
191 if let Expr::Class(ClassExpr {
192 ident: orig_ident,
193 class,
194 }) = expr
195 {
196 let ident = private_ident!(orig_ident
197 .clone()
198 .map(|id| Atom::from(format!("_{}", id.sym)))
199 .unwrap_or(atom!("_class")));
200 let (decl, ClassExtra { lets, vars, stmts }) =
201 self.visit_mut_class_as_decl(ident.clone(), class.take());
202
203 let class = ClassExpr {
204 ident: orig_ident.clone(),
205 class: decl.class,
206 }
207 .into();
208 if vars.is_empty() && lets.is_empty() && stmts.is_empty() {
209 *expr = class;
210 return;
211 }
212
213 let mut exprs = Vec::new();
214
215 for mut var in vars {
216 let init = var.init.take();
217 if let Some(init) = init {
218 exprs.push(
219 AssignExpr {
220 span: var.span,
221 op: op!("="),
222 left: var.name.clone().try_into().unwrap(),
223 right: init,
224 }
225 .into(),
226 )
227 }
228 self.extra.vars.push(var);
229 }
230
231 for mut var in lets {
232 let init = var.init.take();
233 if let Some(init) = init {
234 exprs.push(
235 AssignExpr {
236 span: var.span,
237 op: op!("="),
238 left: var.name.clone().try_into().unwrap(),
239 right: init,
240 }
241 .into(),
242 )
243 }
244 self.extra.lets.push(var);
245 }
246
247 let mut extra_value = false;
248 if !stmts.is_empty() {
249 extra_value = true;
250 self.extra.vars.push(VarDeclarator {
251 span: DUMMY_SP,
252 name: ident.clone().into(),
253 init: None,
254 definite: false,
255 });
256 exprs.push(
257 AssignExpr {
258 span: DUMMY_SP,
259 left: ident.clone().into(),
260 op: op!("="),
261 right: class.into(),
262 }
263 .into(),
264 );
265 } else {
266 exprs.push(class.into());
267 }
268
269 for mut stmt in stmts {
270 if let Some(orig_ident) = orig_ident {
271 replace_ident(&mut stmt, orig_ident.clone().into(), &ident);
272 }
273 match stmt {
274 Stmt::Expr(e) => exprs.push(e.expr),
275 Stmt::Decl(Decl::Var(v)) => {
276 for mut decl in v.decls {
277 let init = decl.init.take();
278
279 if let Some(init) = init {
280 exprs.push(
281 AssignExpr {
282 span: decl.span,
283 op: op!("="),
284 left: decl.name.clone().try_into().unwrap(),
285 right: init,
286 }
287 .into(),
288 )
289 }
290
291 self.extra.vars.push(decl)
292 }
293 }
294 _ => self.extra.stmts.push(stmt),
295 }
296 }
297
298 if extra_value {
299 exprs.push(Box::new(ident.into()))
300 }
301
302 *expr = SeqExpr {
303 span: DUMMY_SP,
304 exprs,
305 }
306 .into()
307 } else {
308 expr.visit_mut_children_with(self);
309 };
310 }
311}
312
313#[swc_trace]
314impl ClassProperties {
315 fn visit_mut_stmt_like<T>(&mut self, stmts: &mut Vec<T>)
316 where
317 T: StmtLike + ModuleItemLike + VisitMutWith<Self> + From<Stmt>,
318 {
319 let mut buf = Vec::with_capacity(stmts.len());
320
321 for stmt in stmts.drain(..) {
322 match T::try_into_stmt(stmt) {
323 Err(node) => match node.try_into_module_decl() {
324 Ok(mut decl) => {
325 match decl {
326 ModuleDecl::ExportDefaultDecl(ExportDefaultDecl {
327 span,
328 decl: DefaultDecl::Class(ClassExpr { ident, class }),
329 ..
330 }) => {
331 let ident = ident.unwrap_or_else(|| private_ident!("_class"));
332
333 let (decl, extra) =
334 self.visit_mut_class_as_decl(ident.clone(), class);
335
336 extra.merge_with(&mut buf, T::from(decl.into()));
337
338 buf.push(
339 match T::try_from_module_decl(
340 NamedExport {
341 span,
342 specifiers: vec![ExportNamedSpecifier {
343 span: DUMMY_SP,
344 orig: ModuleExportName::Ident(ident),
345 exported: Some(ModuleExportName::Ident(
346 private_ident!("default"),
347 )),
348 is_type_only: false,
349 }
350 .into()],
351 src: None,
352 type_only: false,
353 with: None,
354 }
355 .into(),
356 ) {
357 Ok(t) => t,
358 Err(..) => unreachable!(),
359 },
360 );
361 }
362 ModuleDecl::ExportDecl(ExportDecl {
363 span,
364 decl:
365 Decl::Class(ClassDecl {
366 ident,
367 declare: false,
368 class,
369 }),
370 ..
371 }) => {
372 let (decl, extra) = self.visit_mut_class_as_decl(ident, class);
373 extra.merge_with(
374 &mut buf,
375 match T::try_from_module_decl(
376 ExportDecl {
377 span,
378 decl: decl.into(),
379 }
380 .into(),
381 ) {
382 Ok(t) => t,
383 Err(..) => unreachable!(),
384 },
385 )
386 }
387 _ => {
388 decl.visit_mut_children_with(self);
389 buf.push(match T::try_from_module_decl(decl) {
390 Ok(t) => t,
391 Err(..) => unreachable!(),
392 })
393 }
394 };
395 }
396 Err(..) => unreachable!(),
397 },
398 Ok(mut stmt) => {
399 match stmt {
401 Stmt::Decl(Decl::Class(ClassDecl {
402 ident,
403 class,
404 declare: false,
405 })) => {
406 let (decl, extra) = self.visit_mut_class_as_decl(ident, class);
407 extra.merge_with(&mut buf, T::from(decl.into()))
408 }
409 _ => {
410 stmt.visit_mut_children_with(self);
411 buf.push(T::from(stmt))
412 }
413 }
414 }
415 }
416 }
417
418 *stmts = buf;
419 }
420}
421
422#[swc_trace]
423impl ClassProperties {
424 fn visit_mut_class_as_decl(
425 &mut self,
426 class_ident: Ident,
427 mut class: Box<Class>,
428 ) -> (ClassDecl, ClassExtra) {
429 let private = Private {
431 mark: Mark::fresh(Mark::root()),
432 class_name: class_ident.clone(),
433 ident: {
434 let mut private_map = FxHashMap::default();
435
436 for member in class.body.iter() {
437 match member {
438 ClassMember::PrivateMethod(method) => {
439 if let Some(kind) = private_map.get_mut(&method.key.name) {
440 if dup_private_method(kind, method) {
441 let error =
442 format!("duplicate private name #{}.", method.key.name);
443 HANDLER.with(|handler| {
444 handler.struct_span_err(method.key.span, &error).emit()
445 });
446 } else {
447 match method.kind {
448 MethodKind::Getter => kind.has_getter = true,
449 MethodKind::Setter => kind.has_setter = true,
450 MethodKind::Method => unreachable!(),
451 }
452 }
453 } else {
454 private_map.insert(
455 method.key.name.clone(),
456 PrivateKind {
457 is_method: true,
458 is_static: method.is_static,
459 has_getter: method.kind == MethodKind::Getter,
460 has_setter: method.kind == MethodKind::Setter,
461 },
462 );
463 }
464 }
465
466 ClassMember::PrivateProp(prop) => {
467 if private_map.contains_key(&prop.key.name) {
468 let error = format!("duplicate private name #{}.", prop.key.name);
469 HANDLER.with(|handler| {
470 handler.struct_span_err(prop.key.span, &error).emit()
471 });
472 } else {
473 private_map.insert(
474 prop.key.name.clone(),
475 PrivateKind {
476 is_method: false,
477 is_static: prop.is_static,
478 has_getter: false,
479 has_setter: false,
480 },
481 );
482 };
483 }
484
485 _ => (),
486 };
487 }
488
489 private_map
490 },
491 };
492
493 self.private.push(private);
494
495 class.visit_mut_children_with(self);
497
498 let has_super = class.super_class.is_some();
499
500 let mut constructor_inits = MemberInitRecord::new(self.c);
501 let mut vars = Vec::new();
502 let mut lets = Vec::new();
503 let mut extra_inits = MemberInitRecord::new(self.c);
504 let mut private_method_fn_decls = Vec::new();
505 let mut members = Vec::new();
506 let mut constructor = None;
507 let mut used_names = Vec::new();
508 let mut used_key_names = Vec::new();
509 let mut super_ident = None;
510
511 class.body.visit_mut_with(&mut BrandCheckHandler {
512 private: &self.private,
513 });
514
515 let should_create_vars_for_method_names = class.body.iter().any(|m| match m {
516 ClassMember::Constructor(_)
517 | ClassMember::PrivateMethod(_)
518 | ClassMember::TsIndexSignature(_)
519 | ClassMember::Empty(_) => false,
520
521 ClassMember::Method(m) => contains_super(&m.key),
522
523 ClassMember::ClassProp(_)
524 | ClassMember::AutoAccessor(_)
525 | ClassMember::PrivateProp(_)
526 | ClassMember::StaticBlock(_) => true,
527 });
528
529 for member in class.body {
530 match member {
531 ClassMember::Empty(..) | ClassMember::TsIndexSignature(..) => members.push(member),
532
533 ClassMember::Method(method) => {
534 let key = match method.key {
536 PropName::Computed(ComputedPropName {
537 span: c_span,
538 mut expr,
539 }) if should_create_vars_for_method_names && !is_literal(&*expr) => {
540 vars.extend(visit_private_in_expr(
541 &mut expr,
542 &self.private,
543 self.c,
544 self.unresolved_mark,
545 ));
546
547 expr.visit_mut_with(&mut ClassNameTdzFolder {
548 class_name: &class_ident,
549 });
550 let ident = alias_ident_for(&expr, "tmp");
551 lets.push(VarDeclarator {
553 span: DUMMY_SP,
554 name: ident.clone().into(),
555 init: Some(expr),
556 definite: false,
557 });
558 PropName::Computed(ComputedPropName {
561 span: c_span,
562 expr: ident.into(),
563 })
564 }
565 _ => method.key,
566 };
567 members.push(ClassMember::Method(ClassMethod { key, ..method }))
568 }
569
570 ClassMember::ClassProp(mut prop) => {
571 let prop_span = prop.span();
572 prop.key.visit_mut_with(&mut ClassNameTdzFolder {
573 class_name: &class_ident,
574 });
575
576 if !prop.is_static {
577 prop.key.visit_with(&mut UsedNameCollector {
578 used_names: &mut used_key_names,
579 });
580
581 prop.value.visit_with(&mut UsedNameCollector {
582 used_names: &mut used_names,
583 });
584 }
585
586 match &mut prop.key {
587 PropName::Computed(key) if !is_literal(&key.expr) => {
588 vars.extend(visit_private_in_expr(
589 &mut key.expr,
590 &self.private,
591 self.c,
592 self.unresolved_mark,
593 ));
594 let (ident, aliased) = if let Expr::Ident(i) = &*key.expr {
595 if used_key_names.contains(&i.sym) {
596 (alias_ident_for(&key.expr, "_ref"), true)
597 } else {
598 alias_if_required(&key.expr, "_ref")
599 }
600 } else {
601 alias_if_required(&key.expr, "_ref")
602 };
603 if aliased {
604 lets.push(VarDeclarator {
606 span: DUMMY_SP,
607 name: ident.clone().into(),
608 init: Some(key.expr.take()),
609 definite: false,
610 });
611 }
612 *key.expr = ident.into();
613 }
614 _ => (),
615 };
616
617 let mut value = prop.value.unwrap_or_else(|| Expr::undefined(prop_span));
618
619 value.visit_mut_with(&mut NewTargetInProp);
620
621 vars.extend(visit_private_in_expr(
622 &mut value,
623 &self.private,
624 self.c,
625 self.unresolved_mark,
626 ));
627
628 if prop.is_static {
629 if let (Some(super_class), None) = (&mut class.super_class, &super_ident) {
630 let (ident, aliased) = alias_if_required(&*super_class, "_ref");
631 super_ident = Some(ident.clone());
632
633 if aliased {
634 vars.push(VarDeclarator {
635 span: DUMMY_SP,
636 name: ident.clone().into(),
637 init: None,
638 definite: false,
639 });
640 let span = super_class.span();
641 **super_class = AssignExpr {
642 span,
643 op: op!("="),
644 left: ident.into(),
645 right: super_class.take(),
646 }
647 .into()
648 }
649 }
650
651 value.visit_mut_with(&mut SuperFieldAccessFolder {
652 class_name: &class_ident,
653 constructor_this_mark: None,
654 is_static: true,
655 folding_constructor: false,
656 in_injected_define_property_call: false,
657 in_nested_scope: false,
658 this_alias_mark: None,
659 constant_super: self.c.constant_super,
660 super_class: &super_ident,
661 in_pat: false,
662 });
663 value.visit_mut_with(&mut ThisInStaticFolder {
664 ident: class_ident.clone(),
665 });
666 }
667
668 let init = MemberInit::PubProp(PubProp {
669 span: prop_span,
670 name: prop.key,
671 value,
672 });
673 if prop.is_static {
674 extra_inits.push(init);
675 } else {
676 constructor_inits.push(init);
677 }
678 }
679 ClassMember::PrivateProp(mut prop) => {
680 let prop_span = prop.span();
681
682 let ident = Ident::new(
683 format!("_{}", prop.key.name).into(),
684 prop.key.span,
686 SyntaxContext::empty().apply_mark(self.private.cur_mark()),
687 );
688
689 if let Some(value) = &mut prop.value {
690 value.visit_mut_with(&mut NewTargetInProp);
691
692 if prop.is_static {
693 value.visit_mut_with(&mut SuperFieldAccessFolder {
694 class_name: &class_ident,
695 constructor_this_mark: None,
696 is_static: true,
697 folding_constructor: false,
698 in_injected_define_property_call: false,
699 in_nested_scope: false,
700 this_alias_mark: None,
701 constant_super: self.c.constant_super,
702 super_class: &super_ident,
703 in_pat: false,
704 });
705 }
706 vars.extend(visit_private_in_expr(
707 &mut *value,
708 &self.private,
709 self.c,
710 self.unresolved_mark,
711 ));
712 }
713
714 prop.value.visit_with(&mut UsedNameCollector {
715 used_names: &mut used_names,
716 });
717 if prop.is_static {
718 prop.value.visit_mut_with(&mut ThisInStaticFolder {
719 ident: class_ident.clone(),
720 });
721 }
722
723 let value = prop.value.unwrap_or_else(|| Expr::undefined(prop_span));
724
725 if prop.is_static && prop.key.span.is_placeholder() {
726 let init = MemberInit::StaticBlock(value);
727 extra_inits.push(init);
728 continue;
729 }
730
731 let init = MemberInit::PrivProp(PrivProp {
732 span: prop_span,
733 name: ident.clone(),
734 value,
735 });
736 let span = PURE_SP;
737 if self.c.private_as_properties {
738 vars.push(VarDeclarator {
739 span: DUMMY_SP,
740 definite: false,
741 name: ident.clone().into(),
742 init: Some(
743 CallExpr {
744 span,
745 callee: helper!(class_private_field_loose_key),
746 args: vec![ident.sym.as_arg()],
747 ..Default::default()
748 }
749 .into(),
750 ),
751 });
752 } else if !prop.is_static {
753 vars.push(VarDeclarator {
754 span: DUMMY_SP,
755 definite: false,
756 name: ident.into(),
757 init: Some(
758 NewExpr {
759 span,
760 callee: Box::new(quote_ident!("WeakMap").into()),
761 args: Some(Default::default()),
762 ..Default::default()
763 }
764 .into(),
765 ),
766 });
767 };
768 if prop.is_static {
769 extra_inits.push(init);
770 } else {
771 constructor_inits.push(init);
772 };
773 }
774
775 ClassMember::Constructor(c) => {
776 constructor = Some(c);
777 }
778
779 ClassMember::PrivateMethod(mut method) => {
780 let is_static = method.is_static;
781 let prop_span = method.span;
782
783 let fn_name = Ident::new(
784 match method.kind {
785 MethodKind::Getter => format!("get_{}", method.key.name).into(),
786 MethodKind::Setter => format!("set_{}", method.key.name).into(),
787 MethodKind::Method => {
788 if method.key.name.is_reserved_in_any() {
789 format!("__{}", method.key.name).into()
790 } else {
791 method.key.name.clone()
792 }
793 }
794 },
795 method.span,
796 SyntaxContext::empty().apply_mark(self.private.cur_mark()),
797 );
798
799 let weak_coll_var = Ident::new(
800 format!("_{}", method.key.name).into(),
801 method.key.span,
803 SyntaxContext::empty().apply_mark(self.private.cur_mark()),
804 );
805 method.function.visit_with(&mut UsedNameCollector {
806 used_names: &mut used_names,
807 });
808
809 let extra_collect = match (method.kind, is_static) {
810 (MethodKind::Getter | MethodKind::Setter, false) => {
811 let is_getter = method.kind == MethodKind::Getter;
812 let inserted =
813 constructor_inits.push(MemberInit::PrivAccessor(PrivAccessor {
814 span: prop_span,
815 name: weak_coll_var.clone(),
816 getter: if is_getter {
817 Some(fn_name.clone())
818 } else {
819 None
820 },
821 setter: if !is_getter {
822 Some(fn_name.clone())
823 } else {
824 None
825 },
826 }));
827
828 if inserted {
829 Some(quote_ident!("WeakMap"))
830 } else {
831 None
832 }
833 }
834 (MethodKind::Getter | MethodKind::Setter, true) => {
835 let is_getter = method.kind == MethodKind::Getter;
836 let inserted =
837 extra_inits.push(MemberInit::PrivAccessor(PrivAccessor {
838 span: prop_span,
839 name: weak_coll_var.clone(),
840 getter: if is_getter {
841 Some(fn_name.clone())
842 } else {
843 None
844 },
845 setter: if !is_getter {
846 Some(fn_name.clone())
847 } else {
848 None
849 },
850 }));
851 if inserted && self.c.private_as_properties {
852 Some(IdentName::default())
853 } else {
854 None
855 }
856 }
857
858 (MethodKind::Method, false) => {
859 constructor_inits.push(MemberInit::PrivMethod(PrivMethod {
860 span: prop_span,
861 name: weak_coll_var.clone(),
862 fn_name: if self.c.private_as_properties {
863 fn_name.clone()
864 } else {
865 Ident::dummy()
866 },
867 }));
868 Some(quote_ident!("WeakSet"))
869 }
870 (MethodKind::Method, true) => {
871 if self.c.private_as_properties {
872 extra_inits.push(MemberInit::PrivMethod(PrivMethod {
873 span: prop_span,
874 name: weak_coll_var.clone(),
875 fn_name: fn_name.clone(),
876 }));
877 Some(Default::default())
878 } else {
879 None
880 }
881 }
882 };
883
884 if let Some(extra) = extra_collect {
885 let span = PURE_SP;
886 vars.push(VarDeclarator {
887 span: DUMMY_SP,
888 definite: false,
889 name: weak_coll_var.clone().into(),
890 init: Some(Box::new(if self.c.private_as_properties {
891 CallExpr {
892 span,
893 callee: helper!(class_private_field_loose_key),
894 args: vec![weak_coll_var.sym.as_arg()],
895 ..Default::default()
896 }
897 .into()
898 } else {
899 NewExpr {
900 span,
901 callee: extra.into(),
902 args: Some(Default::default()),
903 ..Default::default()
904 }
905 .into()
906 })),
907 })
908 };
909
910 method.function.visit_mut_with(&mut SuperFieldAccessFolder {
911 class_name: &class_ident,
912 constructor_this_mark: None,
913 is_static,
914 folding_constructor: false,
915 in_injected_define_property_call: false,
916 in_nested_scope: false,
917 this_alias_mark: None,
918 constant_super: self.c.constant_super,
919 super_class: &super_ident,
920 in_pat: false,
921 });
922
923 private_method_fn_decls.push(
924 FnDecl {
925 ident: fn_name,
926 function: method.function,
927 declare: false,
928 }
929 .into(),
930 )
931 }
932
933 ClassMember::StaticBlock(..) => {
934 unreachable!("static_blocks pass should remove this")
935 }
936
937 ClassMember::AutoAccessor(..) => {
938 unreachable!("auto_accessor pass should remove this")
939 }
940 }
941 }
942
943 let constructor =
944 self.process_constructor(class.span, constructor, has_super, constructor_inits);
945 if let Some(c) = constructor {
946 members.push(ClassMember::Constructor(c));
947 }
948
949 private_method_fn_decls.visit_mut_with(&mut PrivateAccessVisitor {
950 private: &self.private,
951 vars: Vec::new(),
952 private_access_type: Default::default(),
953 c: self.c,
954 unresolved_mark: self.unresolved_mark,
955 });
956
957 let mut extra_stmts = extra_inits.into_init_static(class_ident.clone());
958
959 extra_stmts.extend(private_method_fn_decls);
960
961 members.visit_mut_with(&mut PrivateAccessVisitor {
962 private: &self.private,
963 vars: Vec::new(),
964 private_access_type: Default::default(),
965 c: self.c,
966 unresolved_mark: self.unresolved_mark,
967 });
968
969 self.private.pop();
970
971 (
972 ClassDecl {
973 ident: class_ident,
974 declare: false,
975 class: Class {
976 body: members,
977 ..*class
978 }
979 .into(),
980 },
981 ClassExtra {
982 vars,
983 lets,
984 stmts: extra_stmts,
985 },
986 )
987 }
988
989 #[allow(clippy::vec_box)]
1019 fn process_constructor(
1020 &mut self,
1021 class_span: Span,
1022 constructor: Option<Constructor>,
1023 has_super: bool,
1024 constructor_exprs: MemberInitRecord,
1025 ) -> Option<Constructor> {
1026 let constructor = constructor.or_else(|| {
1027 if constructor_exprs.record.is_empty() {
1028 None
1029 } else {
1030 Some(default_constructor_with_span(has_super, class_span))
1031 }
1032 });
1033
1034 if let Some(mut c) = constructor {
1035 let constructor_exprs = constructor_exprs.into_init();
1036 inject_after_super(&mut c, constructor_exprs);
1038 Some(c)
1039 } else {
1040 None
1041 }
1042 }
1043}
1044
1045#[derive(Default)]
1046struct ShouldWork {
1047 found: bool,
1048}
1049
1050#[swc_trace]
1051impl Visit for ShouldWork {
1052 noop_visit_type!(fail);
1053
1054 fn visit_class_method(&mut self, _: &ClassMethod) {
1055 self.found = true;
1056 }
1057
1058 fn visit_class_prop(&mut self, _: &ClassProp) {
1059 self.found = true;
1060 }
1061
1062 fn visit_private_prop(&mut self, _: &PrivateProp) {
1063 self.found = true;
1064 }
1065
1066 fn visit_private_method(&mut self, _: &PrivateMethod) {
1067 self.found = true;
1068 }
1069
1070 fn visit_constructor(&mut self, _: &Constructor) {
1071 self.found = true;
1072 }
1073}
1074
1075impl Check for ShouldWork {
1076 fn should_handle(&self) -> bool {
1077 self.found
1078 }
1079}
1080
1081struct SuperVisitor {
1083 found: bool,
1084}
1085
1086impl Visit for SuperVisitor {
1087 noop_visit_type!(fail);
1088
1089 fn visit_constructor(&mut self, _: &Constructor) {}
1091
1092 fn visit_fn_decl(&mut self, _: &FnDecl) {}
1094
1095 fn visit_fn_expr(&mut self, _: &FnExpr) {}
1097
1098 fn visit_function(&mut self, _: &Function) {}
1100
1101 fn visit_getter_prop(&mut self, n: &GetterProp) {
1103 n.key.visit_with(self);
1104 }
1105
1106 fn visit_method_prop(&mut self, n: &MethodProp) {
1108 n.key.visit_with(self);
1109 n.function.visit_with(self);
1110 }
1111
1112 fn visit_setter_prop(&mut self, n: &SetterProp) {
1114 n.key.visit_with(self);
1115 n.param.visit_with(self);
1116 }
1117
1118 fn visit_super(&mut self, _: &Super) {
1119 self.found = true;
1120 }
1121}
1122
1123fn contains_super<N>(body: &N) -> bool
1124where
1125 N: VisitWith<SuperVisitor>,
1126{
1127 let mut visitor = SuperVisitor { found: false };
1128 body.visit_with(&mut visitor);
1129 visitor.found
1130}