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 #[cfg(swc_ast_unknown)]
452 _ => panic!("unable to access unknown nodes"),
453 }
454 }
455 } else {
456 private_map.insert(
457 method.key.name.clone(),
458 PrivateKind {
459 is_method: true,
460 is_static: method.is_static,
461 has_getter: method.kind == MethodKind::Getter,
462 has_setter: method.kind == MethodKind::Setter,
463 },
464 );
465 }
466 }
467
468 ClassMember::PrivateProp(prop) => {
469 if private_map.contains_key(&prop.key.name) {
470 let error = format!("duplicate private name #{}.", prop.key.name);
471 HANDLER.with(|handler| {
472 handler.struct_span_err(prop.key.span, &error).emit()
473 });
474 } else {
475 private_map.insert(
476 prop.key.name.clone(),
477 PrivateKind {
478 is_method: false,
479 is_static: prop.is_static,
480 has_getter: false,
481 has_setter: false,
482 },
483 );
484 };
485 }
486
487 ClassMember::AutoAccessor(_) => {
488 }
491
492 _ => (),
493 };
494 }
495
496 private_map
497 },
498 };
499
500 self.private.push(private);
501
502 class.visit_mut_children_with(self);
504
505 let has_super = class.super_class.is_some();
506
507 let mut constructor_inits = MemberInitRecord::new(self.c);
508 let mut vars = Vec::new();
509 let mut lets = Vec::new();
510 let mut extra_inits = MemberInitRecord::new(self.c);
511 let mut private_method_fn_decls = Vec::new();
512 let mut members = Vec::new();
513 let mut constructor = None;
514 let mut used_names = Vec::new();
515 let mut used_key_names = Vec::new();
516 let mut super_ident = None;
517
518 class.body.visit_mut_with(&mut BrandCheckHandler {
519 private: &self.private,
520 });
521
522 let should_create_vars_for_method_names = class.body.iter().any(|m| match m {
523 ClassMember::Constructor(_)
524 | ClassMember::PrivateMethod(_)
525 | ClassMember::TsIndexSignature(_)
526 | ClassMember::Empty(_)
527 | ClassMember::AutoAccessor(_) => false,
528
529 ClassMember::Method(m) => contains_super(&m.key),
530
531 ClassMember::ClassProp(_)
532 | ClassMember::PrivateProp(_)
533 | ClassMember::StaticBlock(_) => true,
534
535 #[cfg(swc_ast_unknown)]
536 _ => panic!("unable to access unknown nodes"),
537 });
538
539 for member in class.body {
540 match member {
541 ClassMember::Empty(..) | ClassMember::TsIndexSignature(..) => members.push(member),
542
543 ClassMember::Method(method) => {
544 let key = match method.key {
546 PropName::Computed(ComputedPropName {
547 span: c_span,
548 mut expr,
549 }) if should_create_vars_for_method_names && !is_literal(&*expr) => {
550 vars.extend(visit_private_in_expr(
551 &mut expr,
552 &self.private,
553 self.c,
554 self.unresolved_mark,
555 ));
556
557 expr.visit_mut_with(&mut ClassNameTdzFolder {
558 class_name: &class_ident,
559 });
560 let ident = alias_ident_for(&expr, "tmp");
561 lets.push(VarDeclarator {
563 span: DUMMY_SP,
564 name: ident.clone().into(),
565 init: Some(expr),
566 definite: false,
567 });
568 PropName::Computed(ComputedPropName {
571 span: c_span,
572 expr: ident.into(),
573 })
574 }
575 _ => method.key,
576 };
577 members.push(ClassMember::Method(ClassMethod { key, ..method }))
578 }
579
580 ClassMember::ClassProp(mut prop) => {
581 let prop_span = prop.span();
582 prop.key.visit_mut_with(&mut ClassNameTdzFolder {
583 class_name: &class_ident,
584 });
585
586 if !prop.is_static {
587 prop.key.visit_with(&mut UsedNameCollector {
588 used_names: &mut used_key_names,
589 });
590
591 prop.value.visit_with(&mut UsedNameCollector {
592 used_names: &mut used_names,
593 });
594 }
595
596 match &mut prop.key {
597 PropName::Computed(key) if !is_literal(&key.expr) => {
598 vars.extend(visit_private_in_expr(
599 &mut key.expr,
600 &self.private,
601 self.c,
602 self.unresolved_mark,
603 ));
604 let (ident, aliased) = if let Expr::Ident(i) = &*key.expr {
605 if used_key_names.contains(&i.sym) {
606 (alias_ident_for(&key.expr, "_ref"), true)
607 } else {
608 alias_if_required(&key.expr, "_ref")
609 }
610 } else {
611 alias_if_required(&key.expr, "_ref")
612 };
613 if aliased {
614 lets.push(VarDeclarator {
616 span: DUMMY_SP,
617 name: ident.clone().into(),
618 init: Some(key.expr.take()),
619 definite: false,
620 });
621 }
622 *key.expr = ident.into();
623 }
624 _ => (),
625 };
626
627 let mut value = prop.value.unwrap_or_else(|| Expr::undefined(prop_span));
628
629 value.visit_mut_with(&mut NewTargetInProp);
630
631 vars.extend(visit_private_in_expr(
632 &mut value,
633 &self.private,
634 self.c,
635 self.unresolved_mark,
636 ));
637
638 if prop.is_static {
639 if let (Some(super_class), None) = (&mut class.super_class, &super_ident) {
640 let (ident, aliased) = alias_if_required(&*super_class, "_ref");
641 super_ident = Some(ident.clone());
642
643 if aliased {
644 vars.push(VarDeclarator {
645 span: DUMMY_SP,
646 name: ident.clone().into(),
647 init: None,
648 definite: false,
649 });
650 let span = super_class.span();
651 **super_class = AssignExpr {
652 span,
653 op: op!("="),
654 left: ident.into(),
655 right: super_class.take(),
656 }
657 .into()
658 }
659 }
660
661 value.visit_mut_with(&mut SuperFieldAccessFolder {
662 class_name: &class_ident,
663 constructor_this_mark: None,
664 is_static: true,
665 folding_constructor: false,
666 in_injected_define_property_call: false,
667 in_nested_scope: false,
668 this_alias_mark: None,
669 constant_super: self.c.constant_super,
670 super_class: &super_ident,
671 in_pat: false,
672 });
673 value.visit_mut_with(&mut ThisInStaticFolder {
674 ident: class_ident.clone(),
675 });
676 }
677
678 let init = MemberInit::PubProp(PubProp {
679 span: prop_span,
680 name: prop.key,
681 value,
682 });
683 if prop.is_static {
684 extra_inits.push(init);
685 } else {
686 constructor_inits.push(init);
687 }
688 }
689 ClassMember::PrivateProp(mut prop) => {
690 let prop_span = prop.span();
691
692 let ident = Ident::new(
693 format!("_{}", prop.key.name).into(),
694 prop.key.span,
696 SyntaxContext::empty().apply_mark(self.private.cur_mark()),
697 );
698
699 if let Some(value) = &mut prop.value {
700 value.visit_mut_with(&mut NewTargetInProp);
701
702 if prop.is_static {
703 value.visit_mut_with(&mut SuperFieldAccessFolder {
704 class_name: &class_ident,
705 constructor_this_mark: None,
706 is_static: true,
707 folding_constructor: false,
708 in_injected_define_property_call: false,
709 in_nested_scope: false,
710 this_alias_mark: None,
711 constant_super: self.c.constant_super,
712 super_class: &super_ident,
713 in_pat: false,
714 });
715 }
716 vars.extend(visit_private_in_expr(
717 &mut *value,
718 &self.private,
719 self.c,
720 self.unresolved_mark,
721 ));
722 }
723
724 prop.value.visit_with(&mut UsedNameCollector {
725 used_names: &mut used_names,
726 });
727 if prop.is_static {
728 prop.value.visit_mut_with(&mut ThisInStaticFolder {
729 ident: class_ident.clone(),
730 });
731 }
732
733 let value = prop.value.unwrap_or_else(|| Expr::undefined(prop_span));
734
735 if prop.is_static && prop.key.span.is_placeholder() {
736 let init = MemberInit::StaticBlock(value);
737 extra_inits.push(init);
738 continue;
739 }
740
741 let init = MemberInit::PrivProp(PrivProp {
742 span: prop_span,
743 name: ident.clone(),
744 value,
745 });
746 let span = PURE_SP;
747 if self.c.private_as_properties {
748 vars.push(VarDeclarator {
749 span: DUMMY_SP,
750 definite: false,
751 name: ident.clone().into(),
752 init: Some(
753 CallExpr {
754 span,
755 callee: helper!(class_private_field_loose_key),
756 args: vec![ident.sym.as_arg()],
757 ..Default::default()
758 }
759 .into(),
760 ),
761 });
762 } else if !prop.is_static {
763 vars.push(VarDeclarator {
764 span: DUMMY_SP,
765 definite: false,
766 name: ident.into(),
767 init: Some(
768 NewExpr {
769 span,
770 callee: Box::new(quote_ident!("WeakMap").into()),
771 args: Some(Default::default()),
772 ..Default::default()
773 }
774 .into(),
775 ),
776 });
777 };
778 if prop.is_static {
779 extra_inits.push(init);
780 } else {
781 constructor_inits.push(init);
782 };
783 }
784
785 ClassMember::Constructor(c) => {
786 constructor = Some(c);
787 }
788
789 ClassMember::PrivateMethod(mut method) => {
790 let is_static = method.is_static;
791 let prop_span = method.span;
792
793 let fn_name = Ident::new(
794 match method.kind {
795 MethodKind::Getter => format!("get_{}", method.key.name).into(),
796 MethodKind::Setter => format!("set_{}", method.key.name).into(),
797 MethodKind::Method => {
798 if method.key.name.is_reserved_in_any() {
799 format!("__{}", method.key.name).into()
800 } else {
801 method.key.name.clone()
802 }
803 }
804 #[cfg(swc_ast_unknown)]
805 _ => panic!("unable to access unknown nodes"),
806 },
807 method.span,
808 SyntaxContext::empty().apply_mark(self.private.cur_mark()),
809 );
810
811 let weak_coll_var = Ident::new(
812 format!("_{}", method.key.name).into(),
813 method.key.span,
815 SyntaxContext::empty().apply_mark(self.private.cur_mark()),
816 );
817 method.function.visit_with(&mut UsedNameCollector {
818 used_names: &mut used_names,
819 });
820
821 let extra_collect = match (method.kind, is_static) {
822 (MethodKind::Getter | MethodKind::Setter, false) => {
823 let is_getter = method.kind == MethodKind::Getter;
824 let inserted =
825 constructor_inits.push(MemberInit::PrivAccessor(PrivAccessor {
826 span: prop_span,
827 name: weak_coll_var.clone(),
828 getter: if is_getter {
829 Some(fn_name.clone())
830 } else {
831 None
832 },
833 setter: if !is_getter {
834 Some(fn_name.clone())
835 } else {
836 None
837 },
838 }));
839
840 if inserted {
841 Some(quote_ident!("WeakMap"))
842 } else {
843 None
844 }
845 }
846 (MethodKind::Getter | MethodKind::Setter, true) => {
847 let is_getter = method.kind == MethodKind::Getter;
848 let inserted =
849 extra_inits.push(MemberInit::PrivAccessor(PrivAccessor {
850 span: prop_span,
851 name: weak_coll_var.clone(),
852 getter: if is_getter {
853 Some(fn_name.clone())
854 } else {
855 None
856 },
857 setter: if !is_getter {
858 Some(fn_name.clone())
859 } else {
860 None
861 },
862 }));
863 if inserted && self.c.private_as_properties {
864 Some(IdentName::default())
865 } else {
866 None
867 }
868 }
869
870 (MethodKind::Method, false) => {
871 constructor_inits.push(MemberInit::PrivMethod(PrivMethod {
872 span: prop_span,
873 name: weak_coll_var.clone(),
874 fn_name: if self.c.private_as_properties {
875 fn_name.clone()
876 } else {
877 Ident::dummy()
878 },
879 }));
880 Some(quote_ident!("WeakSet"))
881 }
882 (MethodKind::Method, true) => {
883 if self.c.private_as_properties {
884 extra_inits.push(MemberInit::PrivMethod(PrivMethod {
885 span: prop_span,
886 name: weak_coll_var.clone(),
887 fn_name: fn_name.clone(),
888 }));
889 Some(Default::default())
890 } else {
891 None
892 }
893 }
894 #[cfg(swc_ast_unknown)]
895 _ => panic!("unable to access unknown nodes"),
896 };
897
898 if let Some(extra) = extra_collect {
899 let span = PURE_SP;
900 vars.push(VarDeclarator {
901 span: DUMMY_SP,
902 definite: false,
903 name: weak_coll_var.clone().into(),
904 init: Some(Box::new(if self.c.private_as_properties {
905 CallExpr {
906 span,
907 callee: helper!(class_private_field_loose_key),
908 args: vec![weak_coll_var.sym.as_arg()],
909 ..Default::default()
910 }
911 .into()
912 } else {
913 NewExpr {
914 span,
915 callee: extra.into(),
916 args: Some(Default::default()),
917 ..Default::default()
918 }
919 .into()
920 })),
921 })
922 };
923
924 method.function.visit_mut_with(&mut SuperFieldAccessFolder {
925 class_name: &class_ident,
926 constructor_this_mark: None,
927 is_static,
928 folding_constructor: false,
929 in_injected_define_property_call: false,
930 in_nested_scope: false,
931 this_alias_mark: None,
932 constant_super: self.c.constant_super,
933 super_class: &super_ident,
934 in_pat: false,
935 });
936
937 private_method_fn_decls.push(
938 FnDecl {
939 ident: fn_name,
940 function: method.function,
941 declare: false,
942 }
943 .into(),
944 )
945 }
946
947 ClassMember::StaticBlock(..) => {
948 unreachable!("static_blocks pass should remove this")
949 }
950
951 ClassMember::AutoAccessor(accessor) => {
952 members.push(ClassMember::AutoAccessor(accessor));
957 }
958
959 #[cfg(swc_ast_unknown)]
960 _ => panic!("unable to access unknown nodes"),
961 }
962 }
963
964 let constructor =
965 self.process_constructor(class.span, constructor, has_super, constructor_inits);
966 if let Some(c) = constructor {
967 members.push(ClassMember::Constructor(c));
968 }
969
970 private_method_fn_decls.visit_mut_with(&mut PrivateAccessVisitor {
971 private: &self.private,
972 vars: Vec::new(),
973 private_access_type: Default::default(),
974 c: self.c,
975 unresolved_mark: self.unresolved_mark,
976 });
977
978 let mut extra_stmts = extra_inits.into_init_static(class_ident.clone());
979
980 extra_stmts.extend(private_method_fn_decls);
981
982 members.visit_mut_with(&mut PrivateAccessVisitor {
983 private: &self.private,
984 vars: Vec::new(),
985 private_access_type: Default::default(),
986 c: self.c,
987 unresolved_mark: self.unresolved_mark,
988 });
989
990 self.private.pop();
991
992 (
993 ClassDecl {
994 ident: class_ident,
995 declare: false,
996 class: Class {
997 body: members,
998 ..*class
999 }
1000 .into(),
1001 },
1002 ClassExtra {
1003 vars,
1004 lets,
1005 stmts: extra_stmts,
1006 },
1007 )
1008 }
1009
1010 #[allow(clippy::vec_box)]
1040 fn process_constructor(
1041 &mut self,
1042 class_span: Span,
1043 constructor: Option<Constructor>,
1044 has_super: bool,
1045 constructor_exprs: MemberInitRecord,
1046 ) -> Option<Constructor> {
1047 let constructor = constructor.or_else(|| {
1048 if constructor_exprs.record.is_empty() {
1049 None
1050 } else {
1051 Some(default_constructor_with_span(has_super, class_span))
1052 }
1053 });
1054
1055 if let Some(mut c) = constructor {
1056 let constructor_exprs = constructor_exprs.into_init();
1057 inject_after_super(&mut c, constructor_exprs);
1059 Some(c)
1060 } else {
1061 None
1062 }
1063 }
1064}
1065
1066#[derive(Default)]
1067struct ShouldWork {
1068 found: bool,
1069}
1070
1071#[swc_trace]
1072impl Visit for ShouldWork {
1073 noop_visit_type!(fail);
1074
1075 fn visit_class_method(&mut self, _: &ClassMethod) {
1076 self.found = true;
1077 }
1078
1079 fn visit_class_prop(&mut self, _: &ClassProp) {
1080 self.found = true;
1081 }
1082
1083 fn visit_private_prop(&mut self, _: &PrivateProp) {
1084 self.found = true;
1085 }
1086
1087 fn visit_private_method(&mut self, _: &PrivateMethod) {
1088 self.found = true;
1089 }
1090
1091 fn visit_constructor(&mut self, _: &Constructor) {
1092 self.found = true;
1093 }
1094
1095 fn visit_auto_accessor(&mut self, _: &AutoAccessor) {
1097 }
1100}
1101
1102impl Check for ShouldWork {
1103 fn should_handle(&self) -> bool {
1104 self.found
1105 }
1106}
1107
1108struct SuperVisitor {
1110 found: bool,
1111}
1112
1113impl Visit for SuperVisitor {
1114 noop_visit_type!(fail);
1115
1116 fn visit_constructor(&mut self, _: &Constructor) {}
1118
1119 fn visit_fn_decl(&mut self, _: &FnDecl) {}
1121
1122 fn visit_fn_expr(&mut self, _: &FnExpr) {}
1124
1125 fn visit_function(&mut self, _: &Function) {}
1127
1128 fn visit_getter_prop(&mut self, n: &GetterProp) {
1130 n.key.visit_with(self);
1131 }
1132
1133 fn visit_method_prop(&mut self, n: &MethodProp) {
1135 n.key.visit_with(self);
1136 n.function.visit_with(self);
1137 }
1138
1139 fn visit_setter_prop(&mut self, n: &SetterProp) {
1141 n.key.visit_with(self);
1142 n.param.visit_with(self);
1143 }
1144
1145 fn visit_super(&mut self, _: &Super) {
1146 self.found = true;
1147 }
1148}
1149
1150fn contains_super<N>(body: &N) -> bool
1151where
1152 N: VisitWith<SuperVisitor>,
1153{
1154 let mut visitor = SuperVisitor { found: false };
1155 body.visit_with(&mut visitor);
1156 visitor.found
1157}