@@ -558,61 +558,54 @@ namespace ts {
558
558
* and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure.
559
559
*/
560
560
export function forEachChildRecursively < T > ( rootNode : Node , cbNode : ( node : Node , parent : Node ) => T | "skip" | undefined , cbNodes ?: ( nodes : NodeArray < Node > , parent : Node ) => T | "skip" | undefined ) : T | undefined {
561
-
562
- const stack : Node [ ] = [ rootNode ] ;
563
- while ( stack . length ) {
564
- const parent = stack . pop ( ) ! ;
565
- const res = visitAllPossibleChildren ( parent , gatherPossibleChildren ( parent ) ) ;
566
- if ( res ) {
567
- return res ;
568
- }
569
- }
570
-
571
- return ;
572
-
573
- function gatherPossibleChildren ( node : Node ) {
574
- const children : ( Node | NodeArray < Node > ) [ ] = [ ] ;
575
- forEachChild ( node , addWorkItem , addWorkItem ) ; // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal
576
- return children ;
577
-
578
- function addWorkItem ( n : Node | NodeArray < Node > ) {
579
- children . unshift ( n ) ;
580
- }
581
- }
582
-
583
- function visitAllPossibleChildren ( parent : Node , children : readonly ( Node | NodeArray < Node > ) [ ] ) {
584
- for ( const child of children ) {
585
- if ( isArray ( child ) ) {
586
- if ( cbNodes ) {
587
- const res = cbNodes ( child , parent ) ;
588
- if ( res ) {
589
- if ( res === "skip" ) continue ;
590
- return res ;
591
- }
592
- }
593
-
594
- for ( let i = child . length - 1 ; i >= 0 ; i -- ) {
595
- const realChild = child [ i ] ;
596
- const res = cbNode ( realChild , parent ) ;
597
- if ( res ) {
598
- if ( res === "skip" ) continue ;
599
- return res ;
600
- }
601
- stack . push ( realChild ) ;
602
- }
603
- }
604
- else {
605
- stack . push ( child ) ;
606
- const res = cbNode ( child , parent ) ;
561
+ const queue : ( Node | NodeArray < Node > ) [ ] = gatherPossibleChildren ( rootNode ) ;
562
+ const parents : Node [ ] = [ ] ; // tracks parent references for elements in queue
563
+ while ( parents . length < queue . length ) {
564
+ parents . push ( rootNode ) ;
565
+ }
566
+ while ( queue . length !== 0 ) {
567
+ const current = queue . pop ( ) ! ;
568
+ const parent = parents . pop ( ) ! ;
569
+ if ( isArray ( current ) ) {
570
+ if ( cbNodes ) {
571
+ const res = cbNodes ( current , parent ) ;
607
572
if ( res ) {
608
573
if ( res === "skip" ) continue ;
609
574
return res ;
610
575
}
611
576
}
577
+ for ( let i = current . length - 1 ; i >= 0 ; -- i ) {
578
+ queue . push ( current [ i ] ) ;
579
+ parents . push ( parent ) ;
580
+ }
581
+ }
582
+ else {
583
+ const res = cbNode ( current , parent ) ;
584
+ if ( res ) {
585
+ if ( res === "skip" ) continue ;
586
+ return res ;
587
+ }
588
+ if ( current . kind >= SyntaxKind . FirstNode ) {
589
+ // add children in reverse order to the queue, so popping gives the first child
590
+ for ( const child of gatherPossibleChildren ( current ) ) {
591
+ queue . push ( child ) ;
592
+ parents . push ( current ) ;
593
+ }
594
+ }
612
595
}
613
596
}
614
597
}
615
598
599
+ function gatherPossibleChildren ( node : Node ) {
600
+ const children : ( Node | NodeArray < Node > ) [ ] = [ ] ;
601
+ forEachChild ( node , addWorkItem , addWorkItem ) ; // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal
602
+ return children ;
603
+
604
+ function addWorkItem ( n : Node | NodeArray < Node > ) {
605
+ children . unshift ( n ) ;
606
+ }
607
+ }
608
+
616
609
export function createSourceFile ( fileName : string , sourceText : string , languageVersion : ScriptTarget , setParentNodes = false , scriptKind ?: ScriptKind ) : SourceFile {
617
610
tracing . push ( tracing . Phase . Parse , "createSourceFile" , { path : fileName } , /*separateBeginAndEnd*/ true ) ;
618
611
performance . mark ( "beforeParse" ) ;
0 commit comments