1
- use swc_ecma_ast:: { Callee , Expr , FnDecl , FnExpr , Pat , Program , ReturnStmt , Stmt , VarDeclarator } ;
1
+ use swc_ecma_ast:: {
2
+ Callee , ExportDefaultDecl , ExportDefaultExpr , Expr , FnDecl , FnExpr , Pat , Program , Stmt ,
3
+ VarDeclarator ,
4
+ } ;
2
5
use swc_ecma_visit:: { Visit , VisitWith } ;
3
6
pub fn is_required ( program : & Program ) -> bool {
4
7
let mut finder = Finder :: default ( ) ;
@@ -31,18 +34,40 @@ impl Visit for Finder {
31
34
node. visit_children_with ( self ) ;
32
35
}
33
36
37
+ fn visit_export_default_decl ( & mut self , node : & ExportDefaultDecl ) {
38
+ let old = self . is_interested ;
39
+
40
+ self . is_interested = true ;
41
+
42
+ node. visit_children_with ( self ) ;
43
+
44
+ self . is_interested = old;
45
+ }
46
+
47
+ fn visit_export_default_expr ( & mut self , node : & ExportDefaultExpr ) {
48
+ let old = self . is_interested ;
49
+
50
+ self . is_interested = true ;
51
+
52
+ node. visit_children_with ( self ) ;
53
+
54
+ self . is_interested = old;
55
+ }
56
+
34
57
fn visit_expr ( & mut self , node : & Expr ) {
35
58
if self . found {
36
59
return ;
37
60
}
38
- if matches ! (
39
- node,
40
- Expr :: JSXMember ( ..)
41
- | Expr :: JSXNamespacedName ( ..)
42
- | Expr :: JSXEmpty ( ..)
43
- | Expr :: JSXElement ( ..)
44
- | Expr :: JSXFragment ( ..)
45
- ) {
61
+ if self . is_interested
62
+ && matches ! (
63
+ node,
64
+ Expr :: JSXMember ( ..)
65
+ | Expr :: JSXNamespacedName ( ..)
66
+ | Expr :: JSXEmpty ( ..)
67
+ | Expr :: JSXElement ( ..)
68
+ | Expr :: JSXFragment ( ..)
69
+ )
70
+ {
46
71
self . found = true ;
47
72
return ;
48
73
}
@@ -52,6 +77,7 @@ impl Visit for Finder {
52
77
53
78
fn visit_fn_decl ( & mut self , node : & FnDecl ) {
54
79
let old = self . is_interested ;
80
+
55
81
self . is_interested = node. ident . sym . starts_with ( "use" )
56
82
|| node. ident . sym . starts_with ( |c : char | c. is_ascii_uppercase ( ) ) ;
57
83
@@ -72,19 +98,6 @@ impl Visit for Finder {
72
98
self . is_interested = old;
73
99
}
74
100
75
- fn visit_return_stmt ( & mut self , node : & ReturnStmt ) {
76
- if self . is_interested {
77
- if let Some ( Expr :: JSXElement ( ..) | Expr :: JSXEmpty ( ..) | Expr :: JSXFragment ( ..) ) =
78
- node. arg . as_deref ( )
79
- {
80
- self . found = true ;
81
- return ;
82
- }
83
- }
84
-
85
- node. visit_children_with ( self ) ;
86
- }
87
-
88
101
fn visit_stmt ( & mut self , node : & Stmt ) {
89
102
if self . found {
90
103
return ;
@@ -95,15 +108,170 @@ impl Visit for Finder {
95
108
fn visit_var_declarator ( & mut self , node : & VarDeclarator ) {
96
109
let old = self . is_interested ;
97
110
98
- if let Pat :: Ident ( ident) = & node. name {
99
- self . is_interested = ident. sym . starts_with ( "use" )
100
- || ident. sym . starts_with ( |c : char | c. is_ascii_uppercase ( ) ) ;
101
- } else {
102
- self . is_interested = false ;
111
+ if matches ! ( node. init. as_deref( ) , Some ( Expr :: Fn ( ..) | Expr :: Arrow ( ..) ) ) {
112
+ if let Pat :: Ident ( ident) = & node. name {
113
+ self . is_interested = ident. sym . starts_with ( "use" )
114
+ || ident. sym . starts_with ( |c : char | c. is_ascii_uppercase ( ) ) ;
115
+ } else {
116
+ self . is_interested = false ;
117
+ }
103
118
}
104
119
105
120
node. visit_children_with ( self ) ;
106
121
107
122
self . is_interested = old;
108
123
}
109
124
}
125
+
126
+ #[ cfg( test) ]
127
+ mod tests {
128
+ use swc_common:: FileName ;
129
+ use swc_ecma_parser:: { parse_file_as_program, EsSyntax , Syntax } ;
130
+ use testing:: run_test2;
131
+
132
+ use super :: * ;
133
+
134
+ fn assert_required ( code : & str , required : bool ) {
135
+ run_test2 ( false , |cm, _| {
136
+ let fm = cm. new_source_file ( FileName :: Custom ( "test.tsx" . into ( ) ) . into ( ) , code. into ( ) ) ;
137
+
138
+ let program = parse_file_as_program (
139
+ & fm,
140
+ Syntax :: Es ( EsSyntax {
141
+ jsx : true ,
142
+ ..Default :: default ( )
143
+ } ) ,
144
+ Default :: default ( ) ,
145
+ Default :: default ( ) ,
146
+ & mut vec ! [ ] ,
147
+ )
148
+ . unwrap ( ) ;
149
+
150
+ assert_eq ! ( is_required( & program) , required) ;
151
+
152
+ Ok ( ( ) )
153
+ } )
154
+ . unwrap ( ) ;
155
+ }
156
+
157
+ #[ test]
158
+ fn lazy_return ( ) {
159
+ assert_required (
160
+ "
161
+ function Foo() {
162
+ const a = <div>Hello</div>;
163
+
164
+ return a
165
+ }
166
+ " ,
167
+ true ,
168
+ ) ;
169
+
170
+ assert_required (
171
+ "
172
+ function Foo() {
173
+ " ,
174
+ false ,
175
+ ) ;
176
+ }
177
+
178
+ #[ test]
179
+ fn return_jsx ( ) {
180
+ assert_required (
181
+ "
182
+ function Foo() {
183
+ return <div>Hello</div>;
184
+ }
185
+ " ,
186
+ true ,
187
+ ) ;
188
+ }
189
+
190
+ #[ test]
191
+ fn use_hooks ( ) {
192
+ assert_required (
193
+ "
194
+ function Foo(props) {
195
+ const [a, b] = useState(0);
196
+
197
+ return props.children;
198
+ }
199
+ " ,
200
+ true ,
201
+ ) ;
202
+ }
203
+
204
+ #[ test]
205
+ fn arrow_function ( ) {
206
+ assert_required (
207
+ "
208
+ const Foo = () => <div>Hello</div>;
209
+ " ,
210
+ true ,
211
+ ) ;
212
+
213
+ assert_required (
214
+ "
215
+ const Foo = () => {
216
+ return <div>Hello</div>;
217
+ };
218
+ " ,
219
+ true ,
220
+ ) ;
221
+ }
222
+
223
+ #[ test]
224
+ fn export_const_arrow_function ( ) {
225
+ assert_required (
226
+ "
227
+ export const Foo = () => <div>Hello</div>;
228
+ " ,
229
+ true ,
230
+ ) ;
231
+
232
+ assert_required (
233
+ "
234
+ export const Foo = () => {
235
+ return <div>Hello</div>;
236
+ };
237
+ " ,
238
+ true ,
239
+ ) ;
240
+ }
241
+
242
+ #[ test]
243
+ fn normal_arrow_function ( ) {
244
+ assert_required (
245
+ "
246
+ const Foo = () => {
247
+ const a = 1;
248
+ console.log(a);
249
+ };
250
+ " ,
251
+ false ,
252
+ ) ;
253
+ }
254
+
255
+ #[ test]
256
+ fn export_default_arrow_function ( ) {
257
+ assert_required (
258
+ "
259
+ export default () => <div>Hello</div>;
260
+ " ,
261
+ true ,
262
+ ) ;
263
+ }
264
+
265
+ #[ test]
266
+ fn not_required_arrow_function ( ) {
267
+ assert_required (
268
+ "
269
+ export default () => {
270
+ const a = 1;
271
+ console.log(a);
272
+ };
273
+ " ,
274
+ false ,
275
+ ) ;
276
+ }
277
+ }
0 commit comments