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 if let Callee::Expr(expr) = &e.callee {
61 if let Expr::Member(member_expr) = &**expr {
62 if let (Expr::Ident(obj), MemberProp::Ident(prop)) =
63 (&*member_expr.obj, &member_expr.prop)
64 {
65 if &*obj.sym == "Object" && &*prop.sym == "defineProperty" {
66 if let Some(ExprOrSpread { expr: expr0, .. }) = e.args.first() {
67 if let Expr::Ident(arg0) = &**expr0 {
68 if &*arg0.sym == "exports" {
69 if let Some(ExprOrSpread { expr: expr1, .. }) =
70 e.args.get(1)
71 {
72 if let Expr::Lit(Lit::Str(arg1)) = &**expr1 {
73 if &*arg1.value == "__esModule" {
74 self.found = true;
75 return;
76 }
77 }
78 }
79 }
80 }
81 }
82 }
83 }
84 }
85 }
86 }
87
88 e.callee.visit_with(self);
89 }
90
91 fn visit_class_method(&mut self, n: &ClassMethod) {
92 let old_ignore_module = self.ignore_module;
93 let old_ignore_exports = self.ignore_exports;
94
95 self.adjust_state(n.function.params.iter().map(|v| &v.pat));
96
97 n.visit_children_with(self);
98
99 self.ignore_module = old_ignore_module;
100 self.ignore_exports = old_ignore_exports;
101 }
102
103 fn visit_function(&mut self, n: &Function) {
104 let old_ignore_module = self.ignore_module;
105 let old_ignore_exports = self.ignore_exports;
106
107 self.adjust_state(n.params.iter().map(|v| &v.pat));
108
109 n.visit_children_with(self);
110
111 self.ignore_module = old_ignore_module;
112 self.ignore_exports = old_ignore_exports;
113 }
114
115 fn visit_member_expr(&mut self, e: &MemberExpr) {
116 if let Expr::Ident(obj) = &*e.obj {
117 if let MemberProp::Ident(prop) = &e.prop {
118 if (!self.ignore_module && &*obj.sym == "module" && &*prop.sym == "exports")
120 || (!self.ignore_exports && &*obj.sym == "exports")
121 {
122 self.found = true;
123 return;
124 }
125 }
126 }
127
128 e.obj.visit_with(self);
129 e.prop.visit_with(self);
130 }
131
132 fn visit_method_prop(&mut self, n: &MethodProp) {
133 let old_ignore_module = self.ignore_module;
134 let old_ignore_exports = self.ignore_exports;
135
136 self.adjust_state(n.function.params.iter().map(|v| &v.pat));
137
138 n.visit_children_with(self);
139
140 self.ignore_module = old_ignore_module;
141 self.ignore_exports = old_ignore_exports;
142 }
143
144 fn visit_module_decl(&mut self, n: &ModuleDecl) {
145 match n {
146 ModuleDecl::Import(_) => {}
147 _ => {
148 self.is_esm = true;
149 }
150 }
151 }
152}