@@ -180,7 +180,7 @@ export async function ssrTransform(
180
180
// 3. convert references to import bindings & import.meta references
181
181
walk ( ast , {
182
182
onIdentifier ( id , parent , parentStack ) {
183
- const grandparent = parentStack [ parentStack . length - 2 ]
183
+ const grandparent = parentStack [ 1 ]
184
184
const binding = idToImportMap . get ( id . name )
185
185
if ( ! binding ) {
186
186
return
@@ -203,7 +203,7 @@ export async function ssrTransform(
203
203
if ( ! declaredConst . has ( id . name ) ) {
204
204
declaredConst . add ( id . name )
205
205
// locate the top-most node containing the class declaration
206
- const topNode = parentStack [ 1 ]
206
+ const topNode = parentStack [ parentStack . length - 2 ]
207
207
s . prependRight ( topNode . start , `const ${ id . name } = ${ binding } ;\n` )
208
208
}
209
209
} else {
@@ -266,33 +266,32 @@ function walk(
266
266
{ onIdentifier, onImportMeta, onDynamicImport } : Visitors
267
267
) {
268
268
const parentStack : Node [ ] = [ ]
269
- const scope : Record < string , number > = Object . create ( null )
270
269
const scopeMap = new WeakMap < _Node , Set < string > > ( )
270
+ const identifiers : [ id : any , stack : Node [ ] ] [ ] = [ ]
271
271
272
272
const setScope = ( node : FunctionNode , name : string ) => {
273
273
let scopeIds = scopeMap . get ( node )
274
274
if ( scopeIds && scopeIds . has ( name ) ) {
275
275
return
276
276
}
277
- if ( name in scope ) {
278
- scope [ name ] ++
279
- } else {
280
- scope [ name ] = 1
281
- }
282
277
if ( ! scopeIds ) {
283
278
scopeIds = new Set ( )
284
279
scopeMap . set ( node , scopeIds )
285
280
}
286
281
scopeIds . add ( name )
287
282
}
288
283
284
+ function isInScope ( name : string , parents : Node [ ] ) {
285
+ return parents . some ( ( node ) => node && scopeMap . get ( node ) ?. has ( name ) )
286
+ }
287
+
289
288
; ( eswalk as any ) ( root , {
290
289
enter ( node : Node , parent : Node | null ) {
291
290
if ( node . type === 'ImportDeclaration' ) {
292
291
return this . skip ( )
293
292
}
294
293
295
- parent && parentStack . push ( parent )
294
+ parent && parentStack . unshift ( parent )
296
295
297
296
if ( node . type === 'MetaProperty' && node . meta . name === 'import' ) {
298
297
onImportMeta ( node )
@@ -301,8 +300,12 @@ function walk(
301
300
}
302
301
303
302
if ( node . type === 'Identifier' ) {
304
- if ( ! scope [ node . name ] && isRefIdentifier ( node , parent ! , parentStack ) ) {
305
- onIdentifier ( node , parent ! , parentStack )
303
+ if (
304
+ ! isInScope ( node . name , parentStack ) &&
305
+ isRefIdentifier ( node , parent ! , parentStack )
306
+ ) {
307
+ // record the identifier, for DFS -> BFS
308
+ identifiers . push ( [ node , parentStack . slice ( 0 ) ] )
306
309
}
307
310
} else if ( isFunction ( node ) ) {
308
311
// If it is a function declaration, it could be shadowing an import
@@ -372,18 +375,15 @@ function walk(
372
375
} ,
373
376
374
377
leave ( node : Node , parent : Node | null ) {
375
- parent && parentStack . pop ( )
376
- const scopeIds = scopeMap . get ( node )
377
- if ( scopeIds ) {
378
- scopeIds . forEach ( ( id : string ) => {
379
- scope [ id ] --
380
- if ( scope [ id ] === 0 ) {
381
- delete scope [ id ]
382
- }
383
- } )
384
- }
378
+ parent && parentStack . shift ( )
385
379
}
386
380
} )
381
+
382
+ // emit the identifier events in BFS so the hoisted declarations
383
+ // can be captured correctly
384
+ identifiers . forEach ( ( [ node , stack ] ) => {
385
+ if ( ! isInScope ( node . name , stack ) ) onIdentifier ( node , stack [ 0 ] , stack )
386
+ } )
387
387
}
388
388
389
389
function isRefIdentifier ( id : Identifier , parent : _Node , parentStack : _Node [ ] ) {
@@ -459,12 +459,7 @@ function isFunction(node: _Node): node is FunctionNode {
459
459
}
460
460
461
461
function findParentFunction ( parentStack : _Node [ ] ) : FunctionNode | undefined {
462
- for ( let i = parentStack . length - 1 ; i >= 0 ; i -- ) {
463
- const node = parentStack [ i ]
464
- if ( isFunction ( node ) ) {
465
- return node
466
- }
467
- }
462
+ return parentStack . find ( ( i ) => isFunction ( i ) ) as FunctionNode
468
463
}
469
464
470
465
function isInDestructuringAssignment (
@@ -475,15 +470,7 @@ function isInDestructuringAssignment(
475
470
parent &&
476
471
( parent . type === 'Property' || parent . type === 'ArrayPattern' )
477
472
) {
478
- let i = parentStack . length
479
- while ( i -- ) {
480
- const p = parentStack [ i ]
481
- if ( p . type === 'AssignmentExpression' ) {
482
- return true
483
- } else if ( p . type !== 'Property' && ! p . type . endsWith ( 'Pattern' ) ) {
484
- break
485
- }
486
- }
473
+ return parentStack . some ( ( i ) => i . type === 'AssignmentExpression' )
487
474
}
488
475
return false
489
476
}
0 commit comments