swc_ecma_compat_es2022/
static_blocks.rs1use rustc_hash::FxHashSet;
2use swc_atoms::Atom;
3use swc_common::{source_map::PLACEHOLDER_SP, util::take::Take};
4use swc_ecma_ast::*;
5use swc_ecma_utils::ExprFactory;
6use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
7use swc_trace_macro::swc_trace;
8
9struct ClassStaticBlock;
10
11pub fn static_blocks() -> impl Pass {
12 visit_mut_pass(ClassStaticBlock)
13}
14
15#[swc_trace]
16impl ClassStaticBlock {
17 fn transform_static_block(
18 &mut self,
19 mut static_block: StaticBlock,
20 private_id: Atom,
21 ) -> PrivateProp {
22 let mut stmts = static_block.body.stmts.take();
23 let span = static_block.span;
24
25 let value = if stmts.len() == 1 && stmts[0].is_expr() {
28 stmts[0].take().expr().map(|expr_stmt| expr_stmt.expr)
29 } else {
30 static_block.body.stmts = stmts;
31
32 let expr = CallExpr {
33 callee: ArrowExpr {
34 body: Box::new(BlockStmtOrExpr::BlockStmt(static_block.body)),
35 ..Default::default()
36 }
37 .as_callee(),
38 ..Default::default()
39 }
40 .into();
41
42 Some(Box::new(expr))
43 };
44
45 PrivateProp {
46 span,
47 is_static: true,
48 key: PrivateName {
49 span: PLACEHOLDER_SP,
50 name: private_id,
51 },
52 value,
53 ..Default::default()
54 }
55 }
56}
57
58#[swc_trace]
59impl VisitMut for ClassStaticBlock {
60 noop_visit_mut_type!(fail);
61
62 fn visit_mut_class(&mut self, class: &mut Class) {
63 class.visit_mut_children_with(self);
64
65 let mut private_names = FxHashSet::default();
66 for member in &class.body {
67 if let ClassMember::PrivateProp(private_property) = member {
68 private_names.insert(private_property.key.name.clone());
69 }
70 }
71
72 let mut count = 0;
73 for member in class.body.iter_mut() {
74 if let ClassMember::StaticBlock(static_block) = member {
75 if static_block.body.stmts.is_empty() {
76 *member = ClassMember::dummy();
77 continue;
78 }
79
80 let static_block_private_id = generate_uid(&private_names, &mut count);
81 *member = self
82 .transform_static_block(static_block.take(), static_block_private_id)
83 .into();
84 };
85 }
86 }
87}
88
89fn generate_uid(deny_list: &FxHashSet<Atom>, i: &mut u32) -> Atom {
90 *i += 1;
91
92 let mut uid: Atom = if *i == 1 {
93 "_".to_string()
94 } else {
95 format!("_{i}")
96 }
97 .into();
98 while deny_list.contains(&uid) {
99 *i += 1;
100 uid = format!("_{i}").into();
101 }
102
103 uid
104}