next_custom_transforms/transforms/
cjs_finder.rs1use swc_core::ecma::{
2 ast::*,
3 visit::{Visit, VisitWith},
4};
5
6pub fn contains_cjs(m: &Module) -> bool {
7 let mut v = CjsFinder::default();
8 m.visit_with(&mut v);
9 v.found && !v.is_esm
10}
11
12#[derive(Copy, Clone, Default)]
13struct CjsFinder {
14 found: bool,
15 is_esm: bool,
16 ignore_module: bool,
17 ignore_exports: bool,
18}
19
20impl CjsFinder {
21 fn adjust_state<'a, I>(&mut self, iter: I)
24 where
25 I: Iterator<Item = &'a Pat>,
26 {
27 iter.for_each(|p| {
28 if let Pat::Ident(i) = p {
29 if &*i.id.sym == "module" {
30 self.ignore_module = true;
31 }
32 if &*i.id.sym == "exports" {
33 self.ignore_exports = true;
34 }
35 }
36 })
37 }
38}
39
40impl Visit for CjsFinder {
43 fn visit_arrow_expr(&mut self, n: &ArrowExpr) {
44 let old_ignore_module = self.ignore_module;
45 let old_ignore_exports = self.ignore_exports;
46
47 self.adjust_state(n.params.iter());
48
49 n.visit_children_with(self);
50
51 self.ignore_module = old_ignore_module;
52 self.ignore_exports = old_ignore_exports;
53 }
54
55 fn visit_call_expr(&mut self, e: &CallExpr) {
59 if !self.ignore_exports
60 && let Callee::Expr(expr) = &e.callee
61 && let Expr::Member(member_expr) = &**expr
62 && let (Expr::Ident(obj), MemberProp::Ident(prop)) =
63 (&*member_expr.obj, &member_expr.prop)
64 && &*obj.sym == "Object"
65 && &*prop.sym == "defineProperty"
66 && let Some(ExprOrSpread { expr: expr0, .. }) = e.args.first()
67 && let Expr::Ident(arg0) = &**expr0
68 && &*arg0.sym == "exports"
69 && let Some(ExprOrSpread { expr: expr1, .. }) = e.args.get(1)
70 && let Expr::Lit(Lit::Str(arg1)) = &**expr1
71 && &*arg1.value == "__esModule"
72 {
73 self.found = true;
74 return;
75 }
76
77 e.callee.visit_with(self);
78 }
79
80 fn visit_class_method(&mut self, n: &ClassMethod) {
81 let old_ignore_module = self.ignore_module;
82 let old_ignore_exports = self.ignore_exports;
83
84 self.adjust_state(n.function.params.iter().map(|v| &v.pat));
85
86 n.visit_children_with(self);
87
88 self.ignore_module = old_ignore_module;
89 self.ignore_exports = old_ignore_exports;
90 }
91
92 fn visit_function(&mut self, n: &Function) {
93 let old_ignore_module = self.ignore_module;
94 let old_ignore_exports = self.ignore_exports;
95
96 self.adjust_state(n.params.iter().map(|v| &v.pat));
97
98 n.visit_children_with(self);
99
100 self.ignore_module = old_ignore_module;
101 self.ignore_exports = old_ignore_exports;
102 }
103
104 fn visit_member_expr(&mut self, e: &MemberExpr) {
105 if let Expr::Ident(obj) = &*e.obj
106 && let MemberProp::Ident(prop) = &e.prop
107 {
108 if (!self.ignore_module && &*obj.sym == "module" && &*prop.sym == "exports")
110 || (!self.ignore_exports && &*obj.sym == "exports")
111 {
112 self.found = true;
113 return;
114 }
115 }
116
117 e.obj.visit_with(self);
118 e.prop.visit_with(self);
119 }
120
121 fn visit_method_prop(&mut self, n: &MethodProp) {
122 let old_ignore_module = self.ignore_module;
123 let old_ignore_exports = self.ignore_exports;
124
125 self.adjust_state(n.function.params.iter().map(|v| &v.pat));
126
127 n.visit_children_with(self);
128
129 self.ignore_module = old_ignore_module;
130 self.ignore_exports = old_ignore_exports;
131 }
132
133 fn visit_module_decl(&mut self, n: &ModuleDecl) {
134 match n {
135 ModuleDecl::Import(_) => {}
136 _ => {
137 self.is_esm = true;
138 }
139 }
140 }
141}