swc_ecma_transforms_proposal/
decorator_impl.rs

1use std::{collections::VecDeque, iter::once, mem::take};
2
3use rustc_hash::FxHashMap;
4use swc_atoms::{atom, Atom};
5use swc_common::{util::take::Take, Mark, Spanned, SyntaxContext, DUMMY_SP};
6use swc_ecma_ast::*;
7use swc_ecma_transforms_base::{helper, helper_expr};
8use swc_ecma_utils::{
9    alias_ident_for, constructor::inject_after_super, default_constructor_with_span,
10    is_maybe_branch_directive, private_ident, prop_name_to_expr_value, quote_ident, replace_ident,
11    stack_size::maybe_grow_default, ExprFactory, IdentRenamer,
12};
13use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
14
15use crate::DecoratorVersion;
16
17pub(crate) fn decorator_impl(version: DecoratorVersion) -> impl Pass {
18    visit_mut_pass(DecoratorPass {
19        version,
20        ..Default::default()
21    })
22}
23
24#[derive(Default)]
25struct DecoratorPass {
26    /// Variables without initializer.
27    extra_vars: Vec<VarDeclarator>,
28
29    extra_lets: Vec<VarDeclarator>,
30
31    state: ClassState,
32
33    /// Prepended before the class
34    pre_class_inits: Vec<Box<Expr>>,
35
36    rename_map: FxHashMap<Id, Id>,
37
38    extra_exports: Vec<ExportSpecifier>,
39
40    #[allow(unused)]
41    version: DecoratorVersion,
42}
43
44#[derive(Default)]
45struct ClassState {
46    private_id_index: u32,
47
48    static_lhs: Vec<Ident>,
49    proto_lhs: Vec<Ident>,
50
51    /// If not empty, `initProto` should be injected to the constructor.
52    init_proto: Option<Ident>,
53    init_proto_args: Vec<Option<ExprOrSpread>>,
54
55    init_static: Option<Ident>,
56    init_static_args: Vec<Option<ExprOrSpread>>,
57
58    /// Injected into static blocks.
59    extra_stmts: Vec<Stmt>,
60
61    class_lhs: Vec<Option<Pat>>,
62    class_decorators: Vec<Option<ExprOrSpread>>,
63
64    super_class: Option<Ident>,
65}
66
67impl DecoratorPass {
68    fn preserve_side_effect_of_decorators(
69        &mut self,
70        decorators: Vec<Decorator>,
71    ) -> Vec<Option<ExprOrSpread>> {
72        decorators
73            .into_iter()
74            .map(|e| Some(self.preserve_side_effect_of_decorator(e.expr).as_arg()))
75            .collect()
76    }
77
78    fn preserve_side_effect_of_decorator(&mut self, dec: Box<Expr>) -> Box<Expr> {
79        if dec.is_ident() || dec.is_arrow() || dec.is_fn_expr() {
80            return dec;
81        }
82
83        let ident = private_ident!("_dec");
84        self.extra_vars.push(VarDeclarator {
85            span: DUMMY_SP,
86            name: ident.clone().into(),
87            init: None,
88            definite: false,
89        });
90        self.pre_class_inits.push(
91            AssignExpr {
92                span: DUMMY_SP,
93                op: op!("="),
94                left: ident.clone().into(),
95                right: dec,
96            }
97            .into(),
98        );
99
100        ident.into()
101    }
102
103    /// Moves `cur_inits` to `extra_stmts`.
104    fn consume_inits(&mut self) {
105        if self.state.init_proto_args.is_empty()
106            && self.state.init_static_args.is_empty()
107            && self.state.init_proto.is_none()
108            && self.state.init_static.is_none()
109            && self.state.class_decorators.is_empty()
110        {
111            return;
112        }
113
114        let mut e_lhs = Vec::new();
115        let mut combined_args = vec![ThisExpr { span: DUMMY_SP }.as_arg()];
116
117        for id in self
118            .state
119            .static_lhs
120            .drain(..)
121            .chain(self.state.proto_lhs.drain(..))
122        {
123            e_lhs.push(Some(id.into()));
124        }
125
126        if let Some(init) = self.state.init_proto.clone() {
127            self.extra_vars.push(VarDeclarator {
128                span: DUMMY_SP,
129                name: init.clone().into(),
130                init: None,
131                definite: false,
132            });
133
134            e_lhs.push(Some(init.into()));
135        }
136
137        if let Some(init) = self.state.init_static.clone() {
138            self.extra_vars.push(VarDeclarator {
139                span: DUMMY_SP,
140                name: init.clone().into(),
141                init: None,
142                definite: false,
143            });
144
145            e_lhs.push(Some(init.into()));
146        }
147
148        combined_args.push(
149            ArrayLit {
150                span: DUMMY_SP,
151                elems: self
152                    .state
153                    .init_static_args
154                    .drain(..)
155                    .chain(self.state.init_proto_args.drain(..))
156                    .collect(),
157            }
158            .as_arg(),
159        );
160
161        combined_args.push(
162            ArrayLit {
163                span: DUMMY_SP,
164                elems: self.state.class_decorators.take(),
165            }
166            .as_arg(),
167        );
168
169        if let Some(super_class) = self.state.super_class.as_ref() {
170            combined_args.push(super_class.clone().as_arg());
171        }
172
173        let e_pat = if e_lhs.is_empty() {
174            None
175        } else {
176            Some(ObjectPatProp::KeyValue(KeyValuePatProp {
177                key: PropName::Ident(atom!("e").into()),
178                value: ArrayPat {
179                    span: DUMMY_SP,
180                    elems: e_lhs,
181                    type_ann: Default::default(),
182                    optional: false,
183                }
184                .into(),
185            }))
186        };
187
188        let c_pat = if self.state.class_lhs.is_empty() {
189            None
190        } else {
191            Some(ObjectPatProp::KeyValue(KeyValuePatProp {
192                key: PropName::Ident(atom!("c").into()),
193                value: ArrayPat {
194                    span: DUMMY_SP,
195                    elems: self.state.class_lhs.take(),
196                    type_ann: Default::default(),
197                    optional: false,
198                }
199                .into(),
200            }))
201        };
202
203        let expr = AssignExpr {
204            span: DUMMY_SP,
205            op: op!("="),
206            left: ObjectPat {
207                span: DUMMY_SP,
208                props: e_pat.into_iter().chain(c_pat).collect(),
209                optional: false,
210                type_ann: None,
211            }
212            .into(),
213            right: Box::new(
214                CallExpr {
215                    span: DUMMY_SP,
216                    callee: helper!(apply_decs_2203_r),
217                    args: combined_args,
218                    ..Default::default()
219                }
220                .into(),
221            ),
222        }
223        .into();
224
225        self.state.extra_stmts.push(
226            ExprStmt {
227                span: DUMMY_SP,
228                expr,
229            }
230            .into(),
231        );
232
233        if let Some(init) = self.state.init_static.take() {
234            self.state.extra_stmts.push(
235                ExprStmt {
236                    span: DUMMY_SP,
237                    expr: CallExpr {
238                        span: DUMMY_SP,
239                        callee: init.as_callee(),
240                        args: vec![ThisExpr { span: DUMMY_SP }.as_arg()],
241                        ..Default::default()
242                    }
243                    .into(),
244                }
245                .into(),
246            );
247        }
248    }
249
250    /// Returns (name, initilaizer_name)
251    fn initializer_name(&mut self, name: &mut PropName, prefix: &str) -> (Box<Expr>, Ident) {
252        match name {
253            PropName::Ident(i) => (
254                Lit::Str(Str {
255                    span: i.span,
256                    value: i.sym.clone().into(),
257                    raw: None,
258                })
259                .into(),
260                Ident::new(
261                    format!("_{prefix}_{}", i.sym).into(),
262                    i.span,
263                    SyntaxContext::empty().apply_mark(Mark::new()),
264                ),
265            ),
266            PropName::Computed(c) if c.expr.is_ident() => match &*c.expr {
267                Expr::Ident(i) => (
268                    i.clone().into(),
269                    Ident::new(
270                        format!("_{prefix}_{}", i.sym).into(),
271                        i.span,
272                        SyntaxContext::empty().apply_mark(Mark::new()),
273                    ),
274                ),
275                _ => {
276                    unreachable!()
277                }
278            },
279            _ => {
280                let key_ident = private_ident!(name.span(), "_computedKey");
281                self.extra_vars.push(VarDeclarator {
282                    span: DUMMY_SP,
283                    name: key_ident.clone().into(),
284                    init: None,
285                    definite: false,
286                });
287
288                self.pre_class_inits.push(
289                    AssignExpr {
290                        span: DUMMY_SP,
291                        op: op!("="),
292                        left: key_ident.clone().into(),
293                        right: Box::new(prop_name_to_expr_value(name.take())),
294                    }
295                    .into(),
296                );
297                *name = PropName::Computed(ComputedPropName {
298                    span: DUMMY_SP,
299                    expr: key_ident.clone().into(),
300                });
301
302                let init = Ident::new(
303                    format!("_{prefix}_computedKey").into(),
304                    key_ident.span,
305                    SyntaxContext::empty().apply_mark(Mark::new()),
306                );
307
308                (key_ident.into(), init)
309            }
310        }
311    }
312
313    fn ensure_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor {
314        let mut insert_index = 0;
315        for (i, member) in c.body.iter().enumerate() {
316            if let ClassMember::Constructor(constructor) = member {
317                // decorators occur before typescript's type strip, so skip ctor overloads
318                if constructor.body.is_some() {
319                    if let Some(ClassMember::Constructor(c)) = c.body.get_mut(i) {
320                        return c;
321                    } else {
322                        unreachable!()
323                    }
324                } else {
325                    insert_index = i + 1;
326                }
327            }
328        }
329
330        c.body.insert(
331            insert_index,
332            default_constructor_with_span(c.super_class.is_some(), c.span).into(),
333        );
334
335        if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) {
336            c
337        } else {
338            unreachable!()
339        }
340    }
341
342    fn ensure_identity_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor {
343        let mut insert_index = 0;
344        for (i, member) in c.body.iter().enumerate() {
345            if let ClassMember::Constructor(constructor) = member {
346                // decorators occur before typescript's type strip, so skip ctor overloads
347                if constructor.body.is_some() {
348                    if let Some(ClassMember::Constructor(c)) = c.body.get_mut(i) {
349                        return c;
350                    } else {
351                        unreachable!()
352                    }
353                } else {
354                    insert_index = i + 1;
355                }
356            }
357        }
358
359        c.body.insert(
360            insert_index,
361            ClassMember::Constructor(Constructor {
362                span: DUMMY_SP,
363                key: PropName::Ident(atom!("constructor").into()),
364                params: Vec::new(),
365                body: Some(BlockStmt {
366                    span: DUMMY_SP,
367                    stmts: Vec::new(),
368                    ..Default::default()
369                }),
370                ..Default::default()
371            }),
372        );
373
374        if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) {
375            c
376        } else {
377            unreachable!()
378        }
379    }
380
381    fn handle_super_class(&mut self, class: &mut Class) {
382        if let Some(super_class) = class.super_class.take() {
383            let id = alias_ident_for(&super_class, "_super");
384            self.extra_vars.push(VarDeclarator {
385                span: DUMMY_SP,
386                name: id.clone().into(),
387                init: None,
388                definite: false,
389            });
390
391            class.super_class = Some(
392                AssignExpr {
393                    span: DUMMY_SP,
394                    op: AssignOp::Assign,
395                    left: id.clone().into(),
396                    right: super_class,
397                }
398                .into(),
399            );
400
401            self.state.super_class = Some(id);
402        }
403    }
404
405    fn handle_class_expr(&mut self, class: &mut Class, ident: Option<&Ident>) -> Ident {
406        debug_assert!(
407            !class.decorators.is_empty(),
408            "handle_class_decorator should be called only when decorators are present"
409        );
410
411        let init_class = private_ident!("_initClass");
412
413        self.extra_vars.push(VarDeclarator {
414            span: DUMMY_SP,
415            name: init_class.clone().into(),
416            init: None,
417            definite: false,
418        });
419
420        let new_class_name = ident.as_ref().map_or_else(
421            || private_ident!("_class"),
422            |i| private_ident!(format!("_{}", i.sym)),
423        );
424
425        if let Some(ident) = ident {
426            replace_ident(&mut class.body, ident.to_id(), &new_class_name);
427        }
428
429        self.state
430            .class_lhs
431            .push(Some(new_class_name.clone().into()));
432        self.state.class_lhs.push(Some(init_class.clone().into()));
433
434        self.extra_vars.push(VarDeclarator {
435            span: DUMMY_SP,
436            name: new_class_name.clone().into(),
437            init: None,
438            definite: false,
439        });
440
441        let decorators = self.preserve_side_effect_of_decorators(class.decorators.take());
442        self.state.class_decorators.extend(decorators);
443        self.handle_super_class(class);
444
445        {
446            let call_stmt = CallExpr {
447                span: DUMMY_SP,
448                callee: init_class.as_callee(),
449                args: Vec::new(),
450                ..Default::default()
451            }
452            .into_stmt();
453
454            class.body.push(ClassMember::StaticBlock(StaticBlock {
455                span: DUMMY_SP,
456                body: BlockStmt {
457                    span: DUMMY_SP,
458                    stmts: vec![call_stmt],
459                    ..Default::default()
460                },
461            }));
462        }
463
464        new_class_name
465    }
466
467    // This function will call `visit` internally.
468    fn handle_class_decl(&mut self, c: &mut ClassDecl) -> Stmt {
469        let old_state = take(&mut self.state);
470
471        let decorators = self.preserve_side_effect_of_decorators(c.class.decorators.take());
472
473        let init_class = private_ident!("_initClass");
474
475        self.extra_vars.push(VarDeclarator {
476            span: DUMMY_SP,
477            name: init_class.clone().into(),
478            init: None,
479            definite: false,
480        });
481
482        let preserved_class_name = c.ident.clone().into_private();
483        let new_class_name = private_ident!(format!("_{}", c.ident.sym));
484
485        self.extra_lets.push(VarDeclarator {
486            span: DUMMY_SP,
487            name: new_class_name.clone().into(),
488            init: None,
489            definite: false,
490        });
491
492        self.rename_map
493            .insert(c.ident.to_id(), new_class_name.to_id());
494
495        self.state
496            .class_lhs
497            .push(Some(new_class_name.clone().into()));
498        self.state.class_lhs.push(Some(init_class.clone().into()));
499
500        self.state.class_decorators.extend(decorators);
501        self.handle_super_class(&mut c.class);
502
503        let mut body = c.class.body.take();
504
505        let has_static_member = body.iter().any(|m| match m {
506            ClassMember::Method(m) => m.is_static,
507            ClassMember::PrivateMethod(m) => m.is_static,
508            ClassMember::AutoAccessor(m) => m.is_static,
509            ClassMember::ClassProp(ClassProp { is_static, .. })
510            | ClassMember::PrivateProp(PrivateProp { is_static, .. }) => *is_static,
511            ClassMember::StaticBlock(_) => true,
512            _ => false,
513        });
514
515        if has_static_member {
516            let mut last_static_block = None;
517
518            self.process_decorators_of_class_members(&mut body);
519
520            // Move static blocks into property initializers
521            for m in body.iter_mut() {
522                match m {
523                    ClassMember::ClassProp(ClassProp { value, .. })
524                    | ClassMember::PrivateProp(PrivateProp { value, .. }) => {
525                        if let Some(value) = value {
526                            if let Some(last_static_block) = last_static_block.take() {
527                                **value = SeqExpr {
528                                    span: DUMMY_SP,
529                                    exprs: vec![
530                                        Box::new(Expr::Call(CallExpr {
531                                            span: DUMMY_SP,
532                                            callee: ArrowExpr {
533                                                span: DUMMY_SP,
534                                                params: Vec::new(),
535                                                body: Box::new(BlockStmtOrExpr::BlockStmt(
536                                                    BlockStmt {
537                                                        span: DUMMY_SP,
538                                                        stmts: last_static_block,
539                                                        ..Default::default()
540                                                    },
541                                                )),
542                                                is_async: false,
543                                                is_generator: false,
544                                                ..Default::default()
545                                            }
546                                            .as_callee(),
547                                            args: Vec::new(),
548                                            ..Default::default()
549                                        })),
550                                        value.take(),
551                                    ],
552                                }
553                                .into()
554                            }
555                        }
556                    }
557                    ClassMember::StaticBlock(s) => match &mut last_static_block {
558                        None => {
559                            last_static_block = Some(s.body.stmts.take());
560                        }
561                        Some(v) => {
562                            v.append(&mut s.body.stmts);
563                        }
564                    },
565                    _ => {}
566                }
567            }
568
569            // Drop static blocks
570            body.retain(|m| !matches!(m, ClassMember::StaticBlock(..) | ClassMember::Empty(..)));
571
572            for m in body.iter_mut() {
573                match m {
574                    ClassMember::ClassProp(..)
575                    | ClassMember::PrivateProp(..)
576                    | ClassMember::AutoAccessor(..) => {
577                        replace_ident(m, c.ident.to_id(), &new_class_name);
578                    }
579
580                    _ => {}
581                }
582            }
583
584            let mut inner_class = ClassDecl {
585                ident: c.ident.clone(),
586                declare: Default::default(),
587                class: Box::new(Class {
588                    span: DUMMY_SP,
589                    decorators: Vec::new(),
590                    body,
591                    super_class: c.class.super_class.take(),
592                    ..Default::default()
593                }),
594            };
595
596            inner_class.class.visit_mut_with(self);
597
598            for m in inner_class.class.body.iter_mut() {
599                let mut should_move = false;
600
601                match m {
602                    ClassMember::PrivateProp(p) => {
603                        if p.is_static {
604                            should_move = true;
605                            p.is_static = false;
606                        }
607                    }
608                    ClassMember::PrivateMethod(p) => {
609                        if p.is_static {
610                            should_move = true;
611                            p.is_static = false;
612                        }
613                    }
614
615                    ClassMember::AutoAccessor(p) => {
616                        if p.is_static {
617                            should_move = true;
618                            p.is_static = false;
619                        }
620                    }
621                    _ => (),
622                }
623
624                if should_move {
625                    c.class.body.push(m.take())
626                }
627            }
628
629            c.class.body.insert(
630                0,
631                ClassMember::StaticBlock(StaticBlock {
632                    span: DUMMY_SP,
633                    body: BlockStmt {
634                        span: DUMMY_SP,
635                        stmts: vec![Stmt::Decl(Decl::Class(inner_class))],
636                        ..Default::default()
637                    },
638                }),
639            );
640
641            replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name);
642
643            {
644                let constructor = self.ensure_identity_constructor(&mut c.class);
645
646                let super_call = CallExpr {
647                    span: DUMMY_SP,
648                    callee: Callee::Super(Super { span: DUMMY_SP }),
649                    args: vec![c.ident.clone().as_arg()],
650                    ..Default::default()
651                }
652                .into();
653                let static_call = last_static_block.map(|last| {
654                    CallExpr {
655                        span: DUMMY_SP,
656                        callee: ArrowExpr {
657                            span: DUMMY_SP,
658                            params: Vec::new(),
659                            body: Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt {
660                                span: DUMMY_SP,
661                                stmts: last,
662                                ..Default::default()
663                            })),
664                            is_async: false,
665                            is_generator: false,
666                            ..Default::default()
667                        }
668                        .as_callee(),
669                        args: Vec::new(),
670                        ..Default::default()
671                    }
672                    .into()
673                });
674
675                let init_class_call = CallExpr {
676                    span: DUMMY_SP,
677                    callee: init_class.as_callee(),
678                    args: Vec::new(),
679                    ..Default::default()
680                }
681                .into();
682
683                constructor.body.as_mut().unwrap().stmts.insert(
684                    0,
685                    SeqExpr {
686                        span: DUMMY_SP,
687                        exprs: once(super_call)
688                            .chain(static_call)
689                            .chain(once(init_class_call))
690                            .collect(),
691                    }
692                    .into_stmt(),
693                );
694            }
695
696            let class = Box::new(Class {
697                span: DUMMY_SP,
698                decorators: Vec::new(),
699                body: c.class.body.take(),
700                super_class: Some(Box::new(helper_expr!(identity))),
701                ..Default::default()
702            });
703
704            self.state = old_state;
705
706            return NewExpr {
707                span: DUMMY_SP,
708                callee: ClassExpr { ident: None, class }.into(),
709                args: Some(Vec::new()),
710                ..Default::default()
711            }
712            .into_stmt();
713        }
714        for m in body.iter_mut() {
715            if let ClassMember::Constructor(..) = m {
716                c.class.body.push(m.take());
717            }
718        }
719        body.visit_mut_with(self);
720        c.ident = preserved_class_name.clone();
721        replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name);
722        c.class.body.extend(body);
723        c.visit_mut_with(self);
724        c.class.body.push(ClassMember::StaticBlock(StaticBlock {
725            span: DUMMY_SP,
726            body: BlockStmt {
727                span: DUMMY_SP,
728                stmts: vec![CallExpr {
729                    span: DUMMY_SP,
730                    callee: init_class.as_callee(),
731                    args: Vec::new(),
732                    ..Default::default()
733                }
734                .into_stmt()],
735                ..Default::default()
736            },
737        }));
738        self.state = old_state;
739
740        c.take().into()
741    }
742
743    fn process_decorators(&mut self, decorators: &mut [Decorator]) {
744        decorators.iter_mut().for_each(|dec| {
745            let e = self.preserve_side_effect_of_decorator(dec.expr.take());
746
747            dec.expr = e;
748        })
749    }
750
751    fn process_prop_name(&mut self, name: &mut PropName) {
752        match name {
753            PropName::Ident(..) => {}
754            PropName::Computed(c) if c.expr.is_ident() => {}
755            _ => {
756                let ident = private_ident!("_computedKey");
757                self.extra_vars.push(VarDeclarator {
758                    span: DUMMY_SP,
759                    name: ident.clone().into(),
760                    init: None,
761                    definite: false,
762                });
763
764                self.pre_class_inits.push(
765                    AssignExpr {
766                        span: DUMMY_SP,
767                        op: op!("="),
768                        left: ident.clone().into(),
769                        right: Box::new(prop_name_to_expr_value(name.take())),
770                    }
771                    .into(),
772                );
773                *name = PropName::Computed(ComputedPropName {
774                    span: DUMMY_SP,
775                    expr: ident.into(),
776                });
777            }
778        }
779    }
780
781    fn process_decorators_of_class_members(&mut self, members: &mut [ClassMember]) {
782        for mut m in members {
783            match &mut m {
784                ClassMember::Method(m) if m.function.body.is_some() => {
785                    self.process_decorators(&mut m.function.decorators);
786                    self.process_prop_name(&mut m.key);
787                }
788                ClassMember::PrivateMethod(m) if m.function.body.is_some() => {
789                    self.process_decorators(&mut m.function.decorators);
790                }
791                ClassMember::ClassProp(m) if !m.declare => {
792                    self.process_decorators(&mut m.decorators);
793                    self.process_prop_name(&mut m.key);
794                }
795                ClassMember::PrivateProp(m) => {
796                    self.process_decorators(&mut m.decorators);
797                }
798                ClassMember::AutoAccessor(m) => {
799                    self.process_decorators(&mut m.decorators);
800                }
801
802                _ => {}
803            }
804        }
805    }
806}
807
808impl VisitMut for DecoratorPass {
809    noop_visit_mut_type!();
810
811    fn visit_mut_class(&mut self, n: &mut Class) {
812        let old_stmts = self.state.extra_stmts.take();
813
814        n.visit_mut_children_with(self);
815
816        if let Some(init_proto) = self.state.init_proto.clone() {
817            let init_proto_expr = CallExpr {
818                span: DUMMY_SP,
819                callee: init_proto.clone().as_callee(),
820                args: vec![ThisExpr { span: DUMMY_SP }.as_arg()],
821                ..Default::default()
822            };
823            let mut proto_inited = false;
824            for member in n.body.iter_mut() {
825                if let ClassMember::ClassProp(prop) = member {
826                    if prop.is_static {
827                        continue;
828                    }
829                    if let Some(value) = prop.value.clone() {
830                        prop.value = Some(Expr::from_exprs(vec![
831                            init_proto_expr.clone().into(),
832                            value,
833                        ]));
834
835                        proto_inited = true;
836                        break;
837                    }
838                } else if let ClassMember::PrivateProp(prop) = member {
839                    if prop.is_static {
840                        continue;
841                    }
842                    if let Some(value) = prop.value.clone() {
843                        prop.value = Some(Expr::from_exprs(vec![
844                            init_proto_expr.clone().into(),
845                            value,
846                        ]));
847
848                        proto_inited = true;
849                        break;
850                    }
851                }
852            }
853
854            if !proto_inited {
855                let c = self.ensure_constructor(n);
856
857                inject_after_super(c, vec![Box::new(init_proto_expr.into())])
858            }
859        }
860
861        self.consume_inits();
862
863        if !self.state.extra_stmts.is_empty() {
864            n.body.insert(
865                0,
866                ClassMember::StaticBlock(StaticBlock {
867                    span: DUMMY_SP,
868                    body: BlockStmt {
869                        span: DUMMY_SP,
870                        stmts: self.state.extra_stmts.take(),
871                        ..Default::default()
872                    },
873                }),
874            );
875        }
876
877        self.state.init_proto = None;
878
879        self.state.extra_stmts = old_stmts;
880    }
881
882    fn visit_mut_class_member(&mut self, n: &mut ClassMember) {
883        n.visit_mut_children_with(self);
884
885        if let ClassMember::PrivateMethod(p) = n {
886            if p.function.decorators.is_empty() {
887                return;
888            }
889
890            let decorators = self.preserve_side_effect_of_decorators(p.function.decorators.take());
891            let dec = merge_decorators(decorators);
892
893            let init = private_ident!(format!("_call_{}", p.key.name));
894
895            self.extra_vars.push(VarDeclarator {
896                span: p.span,
897                name: init.clone().into(),
898                init: None,
899                definite: false,
900            });
901
902            if p.is_static {
903                self.state
904                    .init_static
905                    .get_or_insert_with(|| private_ident!("_initStatic"));
906            } else {
907                self.state
908                    .init_proto
909                    .get_or_insert_with(|| private_ident!("_initProto"));
910            }
911
912            let caller = FnExpr {
913                ident: None,
914                function: p.function.clone(),
915            };
916
917            let arg = Some(
918                ArrayLit {
919                    span: DUMMY_SP,
920                    elems: vec![
921                        dec,
922                        Some(
923                            if p.is_static {
924                                match p.kind {
925                                    MethodKind::Method => 7,
926                                    MethodKind::Setter => 9,
927                                    MethodKind::Getter => 8,
928                                    #[cfg(swc_ast_unknown)]
929                                    _ => panic!("unable to access unknown nodes"),
930                                }
931                            } else {
932                                match p.kind {
933                                    MethodKind::Method => 2,
934                                    MethodKind::Setter => 4,
935                                    MethodKind::Getter => 3,
936                                    #[cfg(swc_ast_unknown)]
937                                    _ => panic!("unable to access unknown nodes"),
938                                }
939                            }
940                            .as_arg(),
941                        ),
942                        Some(p.key.name.clone().as_arg()),
943                        Some(caller.as_arg()),
944                    ],
945                }
946                .as_arg(),
947            );
948            if p.is_static {
949                self.state.init_static_args.push(arg);
950            } else {
951                self.state.init_proto_args.push(arg);
952            }
953
954            if p.is_static {
955                self.state.static_lhs.push(init.clone());
956            } else {
957                self.state.proto_lhs.push(init.clone());
958            }
959
960            match p.kind {
961                MethodKind::Method => {
962                    let call_stmt = ReturnStmt {
963                        span: DUMMY_SP,
964                        arg: Some(init.into()),
965                    }
966                    .into();
967
968                    p.kind = MethodKind::Getter;
969                    p.function.body = Some(BlockStmt {
970                        span: DUMMY_SP,
971                        stmts: vec![call_stmt],
972                        ..Default::default()
973                    });
974                }
975                MethodKind::Getter => {
976                    let call_stmt = ReturnStmt {
977                        span: DUMMY_SP,
978                        arg: Some(
979                            CallExpr {
980                                span: DUMMY_SP,
981                                callee: init.as_callee(),
982                                args: vec![ThisExpr { span: DUMMY_SP }.as_arg()],
983                                ..Default::default()
984                            }
985                            .into(),
986                        ),
987                    }
988                    .into();
989
990                    p.function.body = Some(BlockStmt {
991                        span: DUMMY_SP,
992                        stmts: vec![call_stmt],
993                        ..Default::default()
994                    });
995                }
996                MethodKind::Setter => {
997                    let call_stmt = ReturnStmt {
998                        span: DUMMY_SP,
999                        arg: Some(
1000                            CallExpr {
1001                                span: DUMMY_SP,
1002                                callee: init.as_callee(),
1003                                args: vec![
1004                                    ThisExpr { span: DUMMY_SP }.as_arg(),
1005                                    Ident::from(p.function.params[0].pat.as_ident().unwrap())
1006                                        .as_arg(),
1007                                ],
1008                                ..Default::default()
1009                            }
1010                            .into(),
1011                        ),
1012                    }
1013                    .into();
1014
1015                    p.function.body = Some(BlockStmt {
1016                        span: DUMMY_SP,
1017                        stmts: vec![call_stmt],
1018                        ..Default::default()
1019                    });
1020                }
1021                #[cfg(swc_ast_unknown)]
1022                _ => panic!("unable to access unknown nodes"),
1023            }
1024        }
1025    }
1026
1027    fn visit_mut_class_members(&mut self, members: &mut Vec<ClassMember>) {
1028        let mut new = Vec::with_capacity(members.len());
1029
1030        self.process_decorators_of_class_members(members);
1031
1032        for mut m in members.take() {
1033            match m {
1034                ClassMember::AutoAccessor(mut accessor) => {
1035                    accessor.value.visit_mut_with(self);
1036
1037                    let name;
1038                    let init;
1039                    let field_name_like: Atom;
1040                    let private_field = PrivateProp {
1041                        span: DUMMY_SP,
1042                        key: match &mut accessor.key {
1043                            Key::Private(k) => {
1044                                name = Lit::Str(Str {
1045                                    span: DUMMY_SP,
1046                                    value: k.name.clone().into(),
1047                                    raw: None,
1048                                })
1049                                .into();
1050                                init = private_ident!(format!("_init_{}", k.name));
1051                                field_name_like = format!("__{}", k.name).into();
1052
1053                                self.state.private_id_index += 1;
1054                                PrivateName {
1055                                    span: k.span,
1056                                    name: format!("__{}_{}", k.name, self.state.private_id_index)
1057                                        .into(),
1058                                }
1059                            }
1060                            Key::Public(k) => {
1061                                (name, init) = self.initializer_name(k, "init");
1062                                field_name_like = format!("__{}", init.sym)
1063                                    .replacen("init", "private", 1)
1064                                    .into();
1065
1066                                self.state.private_id_index += 1;
1067
1068                                PrivateName {
1069                                    span: init.span,
1070                                    name: format!(
1071                                        "{field_name_like}_{}",
1072                                        self.state.private_id_index
1073                                    )
1074                                    .into(),
1075                                }
1076                            }
1077                            #[cfg(swc_ast_unknown)]
1078                            _ => panic!("unable to access unknown nodes"),
1079                        },
1080                        value: if accessor.decorators.is_empty() {
1081                            accessor.value
1082                        } else {
1083                            let init_call = CallExpr {
1084                                span: DUMMY_SP,
1085                                callee: init.clone().as_callee(),
1086                                args: once(ThisExpr { span: DUMMY_SP }.as_arg())
1087                                    .chain(accessor.value.take().map(|v| v.as_arg()))
1088                                    .collect(),
1089                                ..Default::default()
1090                            }
1091                            .into();
1092
1093                            Some(init_call)
1094                        },
1095                        type_ann: None,
1096                        is_static: accessor.is_static,
1097                        decorators: Default::default(),
1098                        accessibility: Default::default(),
1099                        is_optional: false,
1100                        is_override: false,
1101                        readonly: false,
1102                        definite: false,
1103                        ctxt: Default::default(),
1104                    };
1105
1106                    let mut getter_function = Box::new(Function {
1107                        params: Default::default(),
1108                        decorators: Default::default(),
1109                        span: DUMMY_SP,
1110                        body: Some(BlockStmt {
1111                            span: DUMMY_SP,
1112                            stmts: vec![Stmt::Return(ReturnStmt {
1113                                span: DUMMY_SP,
1114                                arg: Some(Box::new(Expr::Member(MemberExpr {
1115                                    span: DUMMY_SP,
1116                                    obj: ThisExpr { span: DUMMY_SP }.into(),
1117                                    prop: MemberProp::PrivateName(private_field.key.clone()),
1118                                }))),
1119                            })],
1120                            ..Default::default()
1121                        }),
1122                        is_generator: false,
1123                        is_async: false,
1124                        ..Default::default()
1125                    });
1126                    let mut setter_function = {
1127                        let param = private_ident!("_v");
1128
1129                        Box::new(Function {
1130                            params: vec![Param {
1131                                span: DUMMY_SP,
1132                                decorators: Default::default(),
1133                                pat: param.clone().into(),
1134                            }],
1135                            decorators: Default::default(),
1136                            span: DUMMY_SP,
1137                            body: Some(BlockStmt {
1138                                span: DUMMY_SP,
1139                                stmts: vec![Stmt::Expr(ExprStmt {
1140                                    span: DUMMY_SP,
1141                                    expr: Box::new(Expr::Assign(AssignExpr {
1142                                        span: DUMMY_SP,
1143                                        op: op!("="),
1144                                        left: MemberExpr {
1145                                            span: DUMMY_SP,
1146                                            obj: ThisExpr { span: DUMMY_SP }.into(),
1147                                            prop: MemberProp::PrivateName(
1148                                                private_field.key.clone(),
1149                                            ),
1150                                        }
1151                                        .into(),
1152                                        right: param.clone().into(),
1153                                    })),
1154                                })],
1155                                ..Default::default()
1156                            }),
1157                            is_generator: false,
1158                            is_async: false,
1159                            ..Default::default()
1160                        })
1161                    };
1162
1163                    if !accessor.decorators.is_empty() {
1164                        let decorators =
1165                            self.preserve_side_effect_of_decorators(accessor.decorators.take());
1166                        let dec = merge_decorators(decorators);
1167
1168                        self.extra_vars.push(VarDeclarator {
1169                            span: accessor.span,
1170                            name: init.clone().into(),
1171                            init: None,
1172                            definite: false,
1173                        });
1174
1175                        let (getter_var, setter_var) = match &accessor.key {
1176                            Key::Private(_) => (
1177                                Some(private_ident!(format!("_get_{}", field_name_like))),
1178                                Some(private_ident!(format!("_set_{}", field_name_like))),
1179                            ),
1180                            Key::Public(_) => Default::default(),
1181                            #[cfg(swc_ast_unknown)]
1182                            _ => panic!("unable to access unknown nodes"),
1183                        };
1184
1185                        let initialize_init = {
1186                            ArrayLit {
1187                                span: DUMMY_SP,
1188                                elems: match &accessor.key {
1189                                    Key::Private(_) => {
1190                                        let data = vec![
1191                                            dec,
1192                                            Some(if accessor.is_static {
1193                                                6.as_arg()
1194                                            } else {
1195                                                1.as_arg()
1196                                            }),
1197                                            Some(name.as_arg()),
1198                                            Some(
1199                                                FnExpr {
1200                                                    ident: None,
1201                                                    function: getter_function,
1202                                                }
1203                                                .as_arg(),
1204                                            ),
1205                                            Some(
1206                                                FnExpr {
1207                                                    ident: None,
1208                                                    function: setter_function,
1209                                                }
1210                                                .as_arg(),
1211                                            ),
1212                                        ];
1213
1214                                        self.extra_vars.push(VarDeclarator {
1215                                            span: DUMMY_SP,
1216                                            name: getter_var.clone().unwrap().into(),
1217                                            init: None,
1218                                            definite: false,
1219                                        });
1220                                        self.extra_vars.push(VarDeclarator {
1221                                            span: DUMMY_SP,
1222                                            name: setter_var.clone().unwrap().into(),
1223                                            init: None,
1224                                            definite: false,
1225                                        });
1226
1227                                        getter_function = Box::new(Function {
1228                                            params: Vec::new(),
1229                                            span: DUMMY_SP,
1230                                            body: Some(BlockStmt {
1231                                                span: DUMMY_SP,
1232                                                stmts: vec![Stmt::Return(ReturnStmt {
1233                                                    span: DUMMY_SP,
1234                                                    arg: Some(Box::new(Expr::Call(CallExpr {
1235                                                        span: DUMMY_SP,
1236                                                        callee: getter_var
1237                                                            .clone()
1238                                                            .unwrap()
1239                                                            .as_callee(),
1240                                                        args: vec![
1241                                                            ThisExpr { span: DUMMY_SP }.as_arg()
1242                                                        ],
1243                                                        ..Default::default()
1244                                                    }))),
1245                                                })],
1246                                                ..Default::default()
1247                                            }),
1248                                            is_generator: false,
1249                                            is_async: false,
1250                                            ..Default::default()
1251                                        });
1252
1253                                        let param = private_ident!("_v");
1254
1255                                        setter_function = Box::new(Function {
1256                                            params: vec![Param {
1257                                                span: DUMMY_SP,
1258                                                decorators: Default::default(),
1259                                                pat: param.clone().into(),
1260                                            }],
1261                                            decorators: Default::default(),
1262                                            span: DUMMY_SP,
1263                                            body: Some(BlockStmt {
1264                                                span: DUMMY_SP,
1265                                                stmts: vec![Stmt::Expr(ExprStmt {
1266                                                    span: DUMMY_SP,
1267                                                    expr: Box::new(Expr::Call(CallExpr {
1268                                                        span: DUMMY_SP,
1269                                                        callee: setter_var
1270                                                            .clone()
1271                                                            .unwrap()
1272                                                            .as_callee(),
1273                                                        args: vec![
1274                                                            ThisExpr { span: DUMMY_SP }.as_arg(),
1275                                                            param.as_arg(),
1276                                                        ],
1277                                                        ..Default::default()
1278                                                    })),
1279                                                })],
1280                                                ..Default::default()
1281                                            }),
1282                                            is_generator: false,
1283                                            is_async: false,
1284                                            ..Default::default()
1285                                        });
1286
1287                                        data
1288                                    }
1289                                    Key::Public(_) => {
1290                                        vec![
1291                                            dec,
1292                                            Some(if accessor.is_static {
1293                                                6.as_arg()
1294                                            } else {
1295                                                1.as_arg()
1296                                            }),
1297                                            Some(name.as_arg()),
1298                                        ]
1299                                    }
1300                                    #[cfg(swc_ast_unknown)]
1301                                    _ => panic!("unable to access unknown nodes"),
1302                                },
1303                            }
1304                            .as_arg()
1305                        };
1306
1307                        if accessor.is_static {
1308                            self.state.static_lhs.push(init);
1309                            self.state.init_static_args.push(Some(initialize_init));
1310                            self.state
1311                                .static_lhs
1312                                .extend(getter_var.into_iter().chain(setter_var));
1313                        } else {
1314                            self.state.proto_lhs.push(init);
1315                            self.state.init_proto_args.push(Some(initialize_init));
1316                            self.state
1317                                .proto_lhs
1318                                .extend(getter_var.into_iter().chain(setter_var));
1319                        }
1320
1321                        if accessor.is_static {
1322                            self.state
1323                                .init_static
1324                                .get_or_insert_with(|| private_ident!("_initStatic"));
1325                        } else {
1326                            self.state
1327                                .init_proto
1328                                .get_or_insert_with(|| private_ident!("_initProto"));
1329                        }
1330                    }
1331
1332                    match accessor.key {
1333                        Key::Private(key) => {
1334                            let getter = PrivateMethod {
1335                                span: DUMMY_SP,
1336                                key: key.clone(),
1337                                function: getter_function,
1338                                kind: MethodKind::Getter,
1339                                is_static: accessor.is_static,
1340                                accessibility: None,
1341                                is_abstract: false,
1342                                is_optional: false,
1343                                is_override: false,
1344                            };
1345                            let setter = PrivateMethod {
1346                                span: DUMMY_SP,
1347                                key: key.clone(),
1348                                function: setter_function,
1349                                kind: MethodKind::Setter,
1350                                is_static: accessor.is_static,
1351                                accessibility: None,
1352                                is_abstract: false,
1353                                is_optional: false,
1354                                is_override: false,
1355                            };
1356
1357                            new.push(ClassMember::PrivateProp(private_field));
1358                            new.push(ClassMember::PrivateMethod(getter));
1359                            new.push(ClassMember::PrivateMethod(setter));
1360                        }
1361                        Key::Public(key) => {
1362                            let getter = ClassMethod {
1363                                span: DUMMY_SP,
1364                                key: key.clone(),
1365                                function: getter_function,
1366                                kind: MethodKind::Getter,
1367                                is_static: accessor.is_static,
1368                                accessibility: None,
1369                                is_abstract: false,
1370                                is_optional: false,
1371                                is_override: false,
1372                            };
1373                            let setter = ClassMethod {
1374                                span: DUMMY_SP,
1375                                key: key.clone(),
1376                                function: setter_function,
1377                                kind: MethodKind::Setter,
1378                                is_static: accessor.is_static,
1379                                accessibility: None,
1380                                is_abstract: false,
1381                                is_optional: false,
1382                                is_override: false,
1383                            };
1384
1385                            new.push(ClassMember::PrivateProp(private_field));
1386                            new.push(ClassMember::Method(getter));
1387                            new.push(ClassMember::Method(setter));
1388                        }
1389                        #[cfg(swc_ast_unknown)]
1390                        _ => panic!("unable to access unknown nodes"),
1391                    }
1392
1393                    continue;
1394                }
1395
1396                ClassMember::Method(..) | ClassMember::PrivateMethod(..) => {
1397                    m.visit_mut_with(self);
1398                }
1399
1400                _ => {}
1401            }
1402
1403            new.push(m);
1404        }
1405
1406        for mut m in new.take() {
1407            match m {
1408                ClassMember::Method(..)
1409                | ClassMember::PrivateMethod(..)
1410                | ClassMember::AutoAccessor(..) => {}
1411
1412                _ => {
1413                    if !m.span().is_dummy() {
1414                        m.visit_mut_with(self);
1415                    }
1416                }
1417            }
1418
1419            new.push(m);
1420        }
1421
1422        *members = new;
1423    }
1424
1425    fn visit_mut_class_method(&mut self, n: &mut ClassMethod) {
1426        // method without body is TypeScript's method declaration.
1427        if n.function.body.is_none() {
1428            return;
1429        }
1430
1431        n.visit_mut_children_with(self);
1432
1433        if n.function.decorators.is_empty() {
1434            return;
1435        }
1436
1437        let decorators = self.preserve_side_effect_of_decorators(n.function.decorators.take());
1438        let dec = merge_decorators(decorators);
1439
1440        let (name, _init) = self.initializer_name(&mut n.key, "call");
1441
1442        if n.is_static {
1443            self.state
1444                .init_static
1445                .get_or_insert_with(|| private_ident!("_initStatic"));
1446        } else {
1447            self.state
1448                .init_proto
1449                .get_or_insert_with(|| private_ident!("_initProto"));
1450        }
1451
1452        let arg = Some(
1453            ArrayLit {
1454                span: DUMMY_SP,
1455                elems: vec![
1456                    dec,
1457                    Some(
1458                        match (n.is_static, n.kind) {
1459                            (true, MethodKind::Method) => 7,
1460                            (false, MethodKind::Method) => 2,
1461                            (true, MethodKind::Setter) => 9,
1462                            (false, MethodKind::Setter) => 4,
1463                            (true, MethodKind::Getter) => 8,
1464                            (false, MethodKind::Getter) => 3,
1465                            #[cfg(swc_ast_unknown)]
1466                            _ => panic!("unable to access unknown nodes"),
1467                        }
1468                        .as_arg(),
1469                    ),
1470                    Some(name.as_arg()),
1471                ],
1472            }
1473            .as_arg(),
1474        );
1475        if n.is_static {
1476            self.state.init_static_args.push(arg);
1477        } else {
1478            self.state.init_proto_args.push(arg);
1479        }
1480    }
1481
1482    fn visit_mut_class_prop(&mut self, p: &mut ClassProp) {
1483        if p.declare {
1484            return;
1485        }
1486
1487        p.visit_mut_children_with(self);
1488
1489        if p.decorators.is_empty() {
1490            return;
1491        }
1492
1493        let decorators = self.preserve_side_effect_of_decorators(p.decorators.take());
1494        let dec = merge_decorators(decorators);
1495
1496        let (name, init) = self.initializer_name(&mut p.key, "init");
1497
1498        self.extra_vars.push(VarDeclarator {
1499            span: p.span,
1500            name: init.clone().into(),
1501            init: None,
1502            definite: false,
1503        });
1504
1505        p.value = Some(
1506            CallExpr {
1507                span: DUMMY_SP,
1508                callee: init.clone().as_callee(),
1509                args: once(ThisExpr { span: DUMMY_SP }.as_arg())
1510                    .chain(p.value.take().map(|v| v.as_arg()))
1511                    .collect(),
1512
1513                ..Default::default()
1514            }
1515            .into(),
1516        );
1517
1518        let initialize_init = {
1519            Some(
1520                ArrayLit {
1521                    span: DUMMY_SP,
1522                    elems: vec![
1523                        dec,
1524                        Some(if p.is_static { 5.as_arg() } else { 0.as_arg() }),
1525                        Some(name.as_arg()),
1526                    ],
1527                }
1528                .as_arg(),
1529            )
1530        };
1531
1532        if p.is_static {
1533            self.state.static_lhs.push(init);
1534            self.state.init_static_args.push(initialize_init);
1535        } else {
1536            self.state.proto_lhs.push(init);
1537            self.state.init_proto_args.push(initialize_init);
1538        }
1539    }
1540
1541    fn visit_mut_expr(&mut self, e: &mut Expr) {
1542        if let Expr::Class(c) = e {
1543            if !c.class.decorators.is_empty() {
1544                let new = self.handle_class_expr(&mut c.class, c.ident.as_ref());
1545
1546                c.visit_mut_with(self);
1547
1548                *e = SeqExpr {
1549                    span: DUMMY_SP,
1550                    exprs: vec![Box::new(e.take()), Box::new(Expr::Ident(new))],
1551                }
1552                .into();
1553
1554                return;
1555            }
1556        }
1557
1558        maybe_grow_default(|| e.visit_mut_children_with(self));
1559    }
1560
1561    fn visit_mut_module_item(&mut self, s: &mut ModuleItem) {
1562        match s {
1563            ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
1564                span,
1565                decl: Decl::Class(c),
1566            })) if !c.class.decorators.is_empty() => {
1567                let ident = c.ident.clone();
1568                let span = *span;
1569                let new_stmt = self.handle_class_decl(c);
1570
1571                *s = new_stmt.into();
1572                self.extra_exports
1573                    .push(ExportSpecifier::Named(ExportNamedSpecifier {
1574                        span,
1575                        orig: ModuleExportName::Ident(ident),
1576                        exported: None,
1577                        is_type_only: false,
1578                    }));
1579            }
1580            ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(ExportDefaultDecl {
1581                span,
1582                decl: DefaultDecl::Class(c),
1583            })) if !c.class.decorators.is_empty() => {
1584                let ident = c
1585                    .ident
1586                    .get_or_insert_with(|| private_ident!("_default"))
1587                    .clone();
1588
1589                let mut class_decl = c.take().as_class_decl().unwrap();
1590                let new_stmt = self.handle_class_decl(&mut class_decl);
1591
1592                self.extra_exports
1593                    .push(ExportSpecifier::Named(ExportNamedSpecifier {
1594                        span: *span,
1595                        orig: ModuleExportName::Ident(ident),
1596                        exported: Some(quote_ident!("default").into()),
1597                        is_type_only: false,
1598                    }));
1599
1600                *s = new_stmt.into();
1601            }
1602            _ => {
1603                s.visit_mut_children_with(self);
1604            }
1605        }
1606    }
1607
1608    fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
1609        let extra_vars = self.extra_vars.take();
1610        let extra_lets = self.extra_lets.take();
1611        let pre_class_inits = self.pre_class_inits.take();
1612        let extra_exports = self.extra_exports.take();
1613
1614        let mut insert_builder = InsertPassBuilder::new();
1615
1616        for (index, n) in n.iter_mut().enumerate() {
1617            n.visit_mut_with(self);
1618            if !self.extra_lets.is_empty() {
1619                insert_builder.push_back(
1620                    index,
1621                    VarDecl {
1622                        span: DUMMY_SP,
1623                        kind: VarDeclKind::Let,
1624                        decls: self.extra_lets.take(),
1625                        declare: false,
1626                        ..Default::default()
1627                    }
1628                    .into(),
1629                );
1630            }
1631            if !self.pre_class_inits.is_empty() {
1632                insert_builder.push_back(
1633                    index,
1634                    ExprStmt {
1635                        span: DUMMY_SP,
1636                        expr: Expr::from_exprs(self.pre_class_inits.take()),
1637                    }
1638                    .into(),
1639                );
1640            }
1641        }
1642
1643        if !self.extra_vars.is_empty() {
1644            let insert_pos = n
1645                .iter()
1646                .position(|module_item| match module_item {
1647                    ModuleItem::Stmt(stmt) => !is_maybe_branch_directive(stmt),
1648                    ModuleItem::ModuleDecl(_) => true,
1649                    #[cfg(swc_ast_unknown)]
1650                    _ => panic!("unable to access unknown nodes"),
1651                })
1652                .unwrap_or(0);
1653            insert_builder.push_front(
1654                insert_pos,
1655                VarDecl {
1656                    span: DUMMY_SP,
1657                    kind: VarDeclKind::Var,
1658                    decls: self.extra_vars.take(),
1659                    declare: false,
1660                    ..Default::default()
1661                }
1662                .into(),
1663            );
1664        }
1665
1666        if !self.extra_exports.is_empty() {
1667            insert_builder.push_back(
1668                n.len() + 1,
1669                NamedExport {
1670                    span: DUMMY_SP,
1671                    specifiers: self.extra_exports.take(),
1672                    src: None,
1673                    type_only: false,
1674                    with: None,
1675                }
1676                .into(),
1677            );
1678        }
1679
1680        *n = insert_builder.build(n.take());
1681
1682        if !self.rename_map.is_empty() {
1683            n.visit_mut_with(&mut IdentRenamer::new(&self.rename_map));
1684        }
1685
1686        self.extra_vars = extra_vars;
1687        self.extra_lets = extra_lets;
1688        self.pre_class_inits = pre_class_inits;
1689        self.extra_exports = extra_exports;
1690    }
1691
1692    fn visit_mut_private_prop(&mut self, p: &mut PrivateProp) {
1693        p.visit_mut_children_with(self);
1694
1695        if p.decorators.is_empty() {
1696            return;
1697        }
1698
1699        let decorators = self.preserve_side_effect_of_decorators(p.decorators.take());
1700        let dec = merge_decorators(decorators);
1701
1702        let init = private_ident!(format!("_init_{}", p.key.name));
1703
1704        self.extra_vars.push(VarDeclarator {
1705            span: p.span,
1706            name: init.clone().into(),
1707            init: None,
1708            definite: false,
1709        });
1710
1711        p.value = Some(
1712            CallExpr {
1713                span: DUMMY_SP,
1714                callee: init.clone().as_callee(),
1715                args: once(ThisExpr { span: DUMMY_SP }.as_arg())
1716                    .chain(p.value.take().map(|v| v.as_arg()))
1717                    .collect(),
1718                ..Default::default()
1719            }
1720            .into(),
1721        );
1722
1723        let initialize_init = {
1724            let access_expr = MemberExpr {
1725                span: DUMMY_SP,
1726                obj: ThisExpr { span: DUMMY_SP }.into(),
1727                prop: MemberProp::PrivateName(p.key.clone()),
1728            };
1729
1730            let getter = Box::new(Function {
1731                span: DUMMY_SP,
1732                body: Some(BlockStmt {
1733                    span: DUMMY_SP,
1734                    stmts: vec![Stmt::Return(ReturnStmt {
1735                        span: DUMMY_SP,
1736                        arg: Some(access_expr.clone().into()),
1737                    })],
1738                    ..Default::default()
1739                }),
1740                is_async: false,
1741                is_generator: false,
1742                ..Default::default()
1743            });
1744            let settter_arg = private_ident!("value");
1745            let setter = Box::new(Function {
1746                span: DUMMY_SP,
1747                body: Some(BlockStmt {
1748                    span: DUMMY_SP,
1749                    stmts: vec![Stmt::Expr(ExprStmt {
1750                        span: DUMMY_SP,
1751                        expr: Box::new(Expr::Assign(AssignExpr {
1752                            span: DUMMY_SP,
1753                            op: op!("="),
1754                            left: access_expr.into(),
1755                            right: Box::new(Expr::Ident(settter_arg.clone())),
1756                        })),
1757                    })],
1758                    ..Default::default()
1759                }),
1760                is_async: false,
1761                is_generator: false,
1762                decorators: Default::default(),
1763                params: vec![Param {
1764                    span: DUMMY_SP,
1765                    decorators: Default::default(),
1766                    pat: Pat::Ident(settter_arg.into()),
1767                }],
1768                ..Default::default()
1769            });
1770
1771            ArrayLit {
1772                span: DUMMY_SP,
1773                elems: vec![
1774                    dec,
1775                    Some(if p.is_static { 5.as_arg() } else { 0.as_arg() }),
1776                    Some((&*p.key.name).as_arg()),
1777                    Some(
1778                        FnExpr {
1779                            ident: None,
1780                            function: getter,
1781                        }
1782                        .as_arg(),
1783                    ),
1784                    Some(
1785                        FnExpr {
1786                            ident: None,
1787                            function: setter,
1788                        }
1789                        .as_arg(),
1790                    ),
1791                ],
1792            }
1793            .as_arg()
1794        };
1795
1796        if p.is_static {
1797            self.state.static_lhs.push(init);
1798            self.state.init_static_args.push(Some(initialize_init));
1799        } else {
1800            self.state.proto_lhs.push(init);
1801            self.state.init_proto_args.push(Some(initialize_init));
1802        }
1803    }
1804
1805    fn visit_mut_stmt(&mut self, s: &mut Stmt) {
1806        match s {
1807            Stmt::Decl(Decl::Class(c)) if !c.class.decorators.is_empty() => {
1808                *s = self.handle_class_decl(c);
1809            }
1810            _ => {
1811                s.visit_mut_children_with(self);
1812            }
1813        }
1814    }
1815
1816    fn visit_mut_stmts(&mut self, n: &mut Vec<Stmt>) {
1817        let old_state = take(&mut self.state);
1818        let old_pre_class_inits = self.pre_class_inits.take();
1819        let old_extra_lets = self.extra_lets.take();
1820        let old_extra_vars = self.extra_vars.take();
1821
1822        let mut insert_builder = InsertPassBuilder::new();
1823        for (index, n) in n.iter_mut().enumerate() {
1824            n.visit_mut_with(self);
1825            if !self.extra_lets.is_empty() {
1826                insert_builder.push_back(
1827                    index,
1828                    VarDecl {
1829                        span: DUMMY_SP,
1830                        kind: VarDeclKind::Let,
1831                        decls: self.extra_lets.take(),
1832                        declare: false,
1833                        ..Default::default()
1834                    }
1835                    .into(),
1836                );
1837            }
1838            if !self.pre_class_inits.is_empty() {
1839                insert_builder.push_back(
1840                    index,
1841                    ExprStmt {
1842                        span: DUMMY_SP,
1843                        expr: Expr::from_exprs(self.pre_class_inits.take()),
1844                    }
1845                    .into(),
1846                );
1847            }
1848        }
1849
1850        if !self.extra_vars.is_empty() {
1851            let insert_pos = n
1852                .iter()
1853                .position(|stmt| !is_maybe_branch_directive(stmt))
1854                .unwrap_or(0);
1855            insert_builder.push_front(
1856                insert_pos,
1857                VarDecl {
1858                    span: DUMMY_SP,
1859                    kind: VarDeclKind::Var,
1860                    decls: self.extra_vars.take(),
1861                    declare: false,
1862                    ..Default::default()
1863                }
1864                .into(),
1865            );
1866        }
1867
1868        *n = insert_builder.build(n.take());
1869
1870        self.extra_vars = old_extra_vars;
1871        self.extra_lets = old_extra_lets;
1872        self.pre_class_inits = old_pre_class_inits;
1873        self.state = old_state;
1874    }
1875}
1876
1877/// Inserts into a vector on `build()` setting the correct
1878/// capacity. This is useful in scenarios where you're iterating
1879/// a vector to insert and all the inserts are in the order of
1880/// the iteration.
1881struct InsertPassBuilder<T> {
1882    inserts: VecDeque<(usize, T)>,
1883}
1884
1885impl<T> InsertPassBuilder<T> {
1886    pub fn new() -> Self {
1887        Self {
1888            inserts: Default::default(),
1889        }
1890    }
1891
1892    pub fn push_front(&mut self, index: usize, item: T) {
1893        if cfg!(debug_assertions) {
1894            if let Some(past) = self.inserts.front() {
1895                debug_assert!(past.0 >= index, "{} {}", past.0, index);
1896            }
1897        }
1898        self.inserts.push_front((index, item));
1899    }
1900
1901    pub fn push_back(&mut self, index: usize, item: T) {
1902        if cfg!(debug_assertions) {
1903            if let Some(past) = self.inserts.back() {
1904                debug_assert!(past.0 <= index, "{} {}", past.0, index);
1905            }
1906        }
1907        self.inserts.push_back((index, item));
1908    }
1909
1910    pub fn build(mut self, original: Vec<T>) -> Vec<T> {
1911        let capacity = original.len() + self.inserts.len();
1912        let mut new = Vec::with_capacity(capacity);
1913        for (index, item) in original.into_iter().enumerate() {
1914            while self
1915                .inserts
1916                .front()
1917                .map(|(item_index, _)| *item_index == index)
1918                .unwrap_or(false)
1919            {
1920                new.push(self.inserts.pop_front().unwrap().1);
1921            }
1922            new.push(item);
1923        }
1924        new.extend(self.inserts.into_iter().map(|v| v.1));
1925
1926        debug_assert!(new.len() == capacity, "len: {} / {}", new.len(), capacity);
1927        new
1928    }
1929}
1930
1931fn merge_decorators(decorators: Vec<Option<ExprOrSpread>>) -> Option<ExprOrSpread> {
1932    if decorators.len() == 1 {
1933        return decorators.into_iter().next().unwrap();
1934    }
1935
1936    Some(
1937        ArrayLit {
1938            span: DUMMY_SP,
1939            elems: decorators,
1940        }
1941        .as_arg(),
1942    )
1943}