@@ -165,25 +165,6 @@ export default function(babel) {
165
165
return false ;
166
166
}
167
167
168
- let hookCalls = new WeakMap ( ) ;
169
-
170
- function recordHookCall ( functionNode , hookCallPath , hookName ) {
171
- if ( ! hookCalls . has ( functionNode ) ) {
172
- hookCalls . set ( functionNode , [ ] ) ;
173
- }
174
- let hookCallsForFn = hookCalls . get ( functionNode ) ;
175
- let key = '' ;
176
- if ( hookCallPath . parent . type === 'VariableDeclarator' ) {
177
- // TODO: if there is no LHS, consider some other heuristic.
178
- key = hookCallPath . parentPath . get ( 'id' ) . getSource ( ) ;
179
- }
180
- hookCallsForFn . push ( {
181
- name : hookName ,
182
- callee : hookCallPath . node . callee ,
183
- key,
184
- } ) ;
185
- }
186
-
187
168
function isBuiltinHook ( hookName ) {
188
169
switch ( hookName ) {
189
170
case 'useState' :
@@ -236,9 +217,64 @@ export default function(babel) {
236
217
237
218
let seenForRegistration = new WeakSet ( ) ;
238
219
let seenForSignature = new WeakSet ( ) ;
239
- let seenForHookCalls = new WeakSet ( ) ;
240
220
let seenForOutro = new WeakSet ( ) ;
241
221
222
+ let hookCalls = new WeakMap ( ) ;
223
+ const HookCallsVisitor = {
224
+ CallExpression ( path ) {
225
+ const node = path . node ;
226
+ const callee = node . callee ;
227
+
228
+ // Note: this visitor MUST NOT mutate the tree in any way.
229
+ // It runs early in a separate traversal and should be very fast.
230
+
231
+ let name = null ;
232
+ switch ( callee . type ) {
233
+ case 'Identifier' :
234
+ name = callee . name ;
235
+ break ;
236
+ case 'MemberExpression' :
237
+ name = callee . property . name ;
238
+ break ;
239
+ }
240
+ if ( name === null || ! / ^ u s e [ A - Z ] / . test ( name ) ) {
241
+ return ;
242
+ }
243
+ const fnScope = path . scope . getFunctionParent ( ) ;
244
+ if ( fnScope === null ) {
245
+ return ;
246
+ }
247
+
248
+ // This is a Hook call. Record it.
249
+ const fnNode = fnScope . block ;
250
+ if ( ! hookCalls . has ( fnNode ) ) {
251
+ hookCalls . set ( fnNode , [ ] ) ;
252
+ }
253
+ let hookCallsForFn = hookCalls . get ( fnNode ) ;
254
+ let key = '' ;
255
+ if ( path . parent . type === 'VariableDeclarator' ) {
256
+ // TODO: if there is no LHS, consider some other heuristic.
257
+ key = path . parentPath . get ( 'id' ) . getSource ( ) ;
258
+ }
259
+
260
+ // Some built-in Hooks reset on edits to arguments.
261
+ const args = path . get ( 'arguments' ) ;
262
+ if ( name === 'useState' && args . length > 0 ) {
263
+ // useState second argument is initial state.
264
+ key += '(' + args [ 0 ] . getSource ( ) + ')' ;
265
+ } else if ( name === 'useReducer' && args . length > 1 ) {
266
+ // useReducer second argument is initial state.
267
+ key += '(' + args [ 1 ] . getSource ( ) + ')' ;
268
+ }
269
+
270
+ hookCallsForFn . push ( {
271
+ callee : path . node . callee ,
272
+ name,
273
+ key,
274
+ } ) ;
275
+ } ,
276
+ } ;
277
+
242
278
return {
243
279
visitor : {
244
280
ExportDefaultDeclaration ( path ) {
@@ -289,6 +325,7 @@ export default function(babel) {
289
325
} ,
290
326
FunctionDeclaration : {
291
327
enter ( path ) {
328
+ return ;
292
329
const node = path . node ;
293
330
let programPath ;
294
331
let insertAfterPath ;
@@ -342,6 +379,7 @@ export default function(babel) {
342
379
) ;
343
380
} ,
344
381
exit ( path ) {
382
+ //return;
345
383
const node = path . node ;
346
384
const id = node . id ;
347
385
if ( id === null ) {
@@ -358,7 +396,7 @@ export default function(babel) {
358
396
return ;
359
397
}
360
398
seenForSignature . add ( node ) ;
361
- // Don't muatte the tree above this point.
399
+
362
400
363
401
// Unlike with __register__, this needs to work for nested
364
402
// declarations too. So we need to search for a path where
@@ -438,6 +476,7 @@ export default function(babel) {
438
476
} ,
439
477
} ,
440
478
VariableDeclaration ( path ) {
479
+ return ;
441
480
const node = path . node ;
442
481
let programPath ;
443
482
let insertAfterPath ;
@@ -510,39 +549,16 @@ export default function(babel) {
510
549
} ,
511
550
) ;
512
551
} ,
513
- CallExpression ( path ) {
514
- const node = path . node ;
515
- const callee = node . callee ;
516
-
517
- let name = null ;
518
- switch ( callee . type ) {
519
- case 'Identifier' :
520
- name = callee . name ;
521
- break ;
522
- case 'MemberExpression' :
523
- name = callee . property . name ;
524
- break ;
525
- }
526
- if ( name === null || ! / ^ u s e [ A - Z ] / . test ( name ) ) {
527
- return ;
528
- }
529
-
530
- // Make sure we're not recording the same calls twice.
531
- // This can happen if another Babel plugin replaces parents.
532
- if ( seenForHookCalls . has ( node ) ) {
533
- return ;
534
- }
535
- seenForHookCalls . add ( node ) ;
536
- // Don't mutate the tree above this point.
537
-
538
- const fn = path . scope . getFunctionParent ( ) ;
539
- if ( fn === null ) {
540
- return ;
541
- }
542
- recordHookCall ( fn . block , path , name ) ;
543
- } ,
544
552
Program : {
553
+ enter ( path ) {
554
+ // This is a separate early visitor because we need to collect Hook calls
555
+ // and "const [foo, setFoo] = ..." signatures before the destructuring
556
+ // transform mangles them. This extra traversal is not ideal for perf,
557
+ // but it's the best we can do until we stop transpiling destructuring.
558
+ path . traverse ( HookCallsVisitor ) ;
559
+ } ,
545
560
exit ( path ) {
561
+ return ;
546
562
const registrations = registrationsByProgramPath . get ( path ) ;
547
563
if ( registrations === undefined ) {
548
564
return ;
0 commit comments