swc_ecma_transforms_react/jsx_self/
mod.rs1use swc_common::DUMMY_SP;
2use swc_ecma_ast::*;
3use swc_ecma_transforms_base::perf::Parallel;
4use swc_ecma_utils::quote_ident;
5use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
6
7#[cfg(test)]
8mod tests;
9
10pub fn jsx_self(dev: bool) -> impl Pass {
14 visit_mut_pass(JsxSelf {
15 dev,
16 ctx: Default::default(),
17 })
18}
19
20#[derive(Clone, Copy, Default)]
22struct Context {
23 in_constructor: bool,
24 in_derived_class: bool,
25}
26
27#[derive(Clone, Copy)]
28struct JsxSelf {
29 dev: bool,
30 ctx: Context,
31}
32
33impl JsxSelf {
34 fn with_in_constructor<N: VisitMutWith<JsxSelf>>(&mut self, in_constructor: bool, n: &mut N) {
35 let old = self.ctx;
36 self.ctx.in_constructor = in_constructor;
37 n.visit_mut_children_with(self);
38 self.ctx = old;
39 }
40}
41
42impl Parallel for JsxSelf {
43 fn create(&self) -> Self {
44 *self
45 }
46
47 fn merge(&mut self, _: Self) {}
48}
49
50impl VisitMut for JsxSelf {
51 noop_visit_mut_type!();
52
53 fn visit_mut_class(&mut self, n: &mut Class) {
54 let old = self.ctx;
55 self.ctx.in_derived_class = n.super_class.is_some();
56 n.visit_mut_children_with(self);
57 self.ctx = old;
58 }
59
60 fn visit_mut_fn_decl(&mut self, n: &mut FnDecl) {
61 self.with_in_constructor(false, n);
62 }
63
64 fn visit_mut_fn_expr(&mut self, n: &mut FnExpr) {
65 self.with_in_constructor(false, n);
66 }
67
68 fn visit_mut_prop(&mut self, n: &mut Prop) {
69 match n {
70 Prop::Getter(_) | Prop::Setter(_) | Prop::Method(_) => {
71 self.with_in_constructor(false, n)
72 }
73 _ => n.visit_mut_children_with(self),
74 }
75 }
76
77 fn visit_mut_class_member(&mut self, n: &mut ClassMember) {
78 match n {
79 ClassMember::Constructor(_) => self.with_in_constructor(true, n),
80 ClassMember::Method(_)
81 | ClassMember::PrivateMethod(_)
82 | ClassMember::StaticBlock(_) => self.with_in_constructor(false, n),
83 _ => n.visit_mut_children_with(self),
84 }
85 }
86
87 fn visit_mut_jsx_opening_element(&mut self, n: &mut JSXOpeningElement) {
88 if !self.dev {
89 return;
90 }
91
92 if self.ctx.in_constructor && self.ctx.in_derived_class {
94 return;
95 }
96
97 n.attrs.push(JSXAttrOrSpread::JSXAttr(JSXAttr {
98 span: DUMMY_SP,
99 name: JSXAttrName::Ident(quote_ident!("__self")),
100 value: Some(JSXAttrValue::JSXExprContainer(JSXExprContainer {
101 span: DUMMY_SP,
102 expr: JSXExpr::Expr(Box::new(ThisExpr { span: DUMMY_SP }.into())),
103 })),
104 }));
105 }
106}