@@ -8,41 +8,48 @@ import type { GetPointerPriorityFn, WalkFn } from './types/walk';
88 * added to the graph.
99 */
1010const walkDeclarations : WalkFn = ( graph , callback , options ) => {
11- const pointers = Array . from ( graph . nodes . keys ( ) ) ;
12-
1311 if ( options ?. preferGroups && options . preferGroups . length ) {
14- // Precompute each pointer's group once so matchPointerToGroup is not called
15- // O(groups × pointers) times.
16- const pointerGroup = new Map < string , string | undefined > ( ) ;
17- if ( options . matchPointerToGroup ) {
18- for ( const pointer of pointers ) {
19- const result = options . matchPointerToGroup ( pointer ) ;
20- pointerGroup . set ( pointer , result . matched ? result . kind : undefined ) ;
12+ // Single pass: bucket each pointer into its group (or unmatched).
13+ // This avoids re-scanning all pointers K times (once per preferred group).
14+ const buckets = new Map < string , string [ ] > ( ) ;
15+ for ( const kind of options . preferGroups ) {
16+ if ( ! buckets . has ( kind ) ) {
17+ buckets . set ( kind , [ ] ) ;
2118 }
2219 }
20+ const unmatched : string [ ] = [ ] ;
2321
24- // emit nodes that match each preferred group in order
25- const emitted = new Set < string > ( ) ;
26- for ( const kind of options . preferGroups ) {
27- for ( const pointer of pointers ) {
28- if ( pointerGroup . get ( pointer ) === kind ) {
29- emitted . add ( pointer ) ;
30- callback ( pointer , graph . nodes . get ( pointer ) ! ) ;
22+ for ( const pointer of graph . nodes . keys ( ) ) {
23+ if ( options . matchPointerToGroup ) {
24+ const result = options . matchPointerToGroup ( pointer ) ;
25+ if ( result . matched ) {
26+ const bucket = buckets . get ( result . kind ) ;
27+ // kind not in preferGroups → treat as unmatched
28+ ( bucket ?? unmatched ) . push ( pointer ) ;
29+ continue ;
3130 }
3231 }
32+ unmatched . push ( pointer ) ;
3333 }
3434
35- // emit anything not covered by the preferGroups (in declaration order)
36- for ( const pointer of pointers ) {
37- if ( emitted . has ( pointer ) ) continue ;
35+ // emit in group order, then unmatched in declaration order
36+ const emittedGroups = new Set < string > ( ) ;
37+ for ( const kind of options . preferGroups ) {
38+ if ( emittedGroups . has ( kind ) ) continue ;
39+ emittedGroups . add ( kind ) ;
40+ for ( const pointer of buckets . get ( kind ) ! ) {
41+ callback ( pointer , graph . nodes . get ( pointer ) ! ) ;
42+ }
43+ }
44+ for ( const pointer of unmatched ) {
3845 callback ( pointer , graph . nodes . get ( pointer ) ! ) ;
3946 }
4047 return ;
4148 }
4249
43- // fallback: simple declaration order
44- for ( const pointer of pointers ) {
45- callback ( pointer , graph . nodes . get ( pointer ) ! ) ;
50+ // fallback: simple declaration order, no need to materialise an array
51+ for ( const [ pointer , node ] of graph . nodes ) {
52+ callback ( pointer , node ) ;
4653 }
4754} ;
4855
0 commit comments