@@ -44,234 +44,18 @@ export function walk<T extends object>(
4444 hooks :
4545 | ( ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void ) // Old API, enter only
4646 | {
47- enter : ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void
48- exit : ( node : T , ctx : VisitContext < T > ) => ExitResult < T > | void
49- }
50- | {
51- enter : ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void
52- exit ?: never
53- }
54- | {
55- enter ?: never
56- exit : ( node : T , ctx : VisitContext < T > ) => ExitResult < T > | void
47+ enter ?: ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void
48+ exit ?: ( node : T , ctx : VisitContext < T > ) => ExitResult < T > | void
5749 } ,
5850) : void {
59- if ( typeof hooks === 'function' ) walkEnter ( ast , hooks )
60- else if ( hooks . enter && hooks . exit ) walkEnterExit ( ast , hooks . enter , hooks . exit )
61- else if ( hooks . enter ) walkEnter ( ast , hooks . enter )
62- else if ( hooks . exit ) walkExit ( ast , hooks . exit )
63- }
64-
65- function walkEnter < T extends { nodes ?: T [ ] } > (
66- ast : T [ ] ,
67- enter : ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void ,
68- ) {
69- let stack : [ nodes : T [ ] , offset : number , parent : Parent < T > | null ] [ ] = [ [ ast , 0 , null ] ]
70- let ctx : VisitContext < T > = {
71- parent : null ,
72- depth : 0 ,
73- path ( ) {
74- let path : T [ ] = [ ]
75-
76- for ( let i = 1 ; i < stack . length ; i ++ ) {
77- let parent = stack [ i ] [ 2 ]
78- if ( parent ) path . push ( parent )
79- }
80-
81- return path
82- } ,
83- }
84-
85- while ( stack . length > 0 ) {
86- let depth = stack . length - 1
87- let frame = stack [ depth ]
88- let nodes = frame [ 0 ]
89- let offset = frame [ 1 ]
90- let parent = frame [ 2 ]
91-
92- // Done with this level
93- if ( offset >= nodes . length ) {
94- stack . pop ( )
95- continue
96- }
97-
98- let node = nodes [ offset ]
99-
100- ctx . parent = parent
101- ctx . depth = depth
102-
103- let result = enter ( node , ctx ) ?? WalkAction . Continue
104-
105- switch ( result . kind ) {
106- case WalkKind . Continue : {
107- if ( node . nodes && node . nodes . length > 0 ) {
108- stack . push ( [ node . nodes , 0 , node as Parent < T > ] )
109- }
110-
111- stack [ depth ] [ 1 ] ++ // Advance to next sibling
112- continue
113- }
114-
115- case WalkKind . Stop :
116- return // Stop immediately
117-
118- case WalkKind . Skip :
119- stack [ depth ] [ 1 ] ++ // Advance to next sibling
120- continue
121-
122- case WalkKind . Replace : {
123- // Replace current node, with new nodes. No need to change the offset
124- // because we want to re-visit the current index, which now contains the
125- // new nodes.
126- nodes . splice ( offset , 1 , ...result . nodes )
127- continue
128- }
129-
130- case WalkKind . ReplaceStop : {
131- nodes . splice ( offset , 1 , ...result . nodes ) // Replace current node
132- return // Stop immediately
133- }
134-
135- case WalkKind . ReplaceSkip : {
136- nodes . splice ( offset , 1 , ...result . nodes ) // Replace current node
137- stack [ depth ] [ 1 ] += result . nodes . length // Advance to next sibling past replacements
138- continue
139- }
140-
141- default : {
142- result satisfies never
143-
144- throw new Error (
145- // @ts -expect-error `result.kind` could still be filled in with an invalid value
146- `Invalid \`WalkAction.${ WalkKind [ result . kind ] ?? `Unknown(${ result . kind } )` } \` in enter.` ,
147- )
148- }
149- }
150- }
51+ if ( typeof hooks === 'function' ) walkImplementation ( ast , hooks )
52+ else walkImplementation ( ast , hooks . enter , hooks . exit )
15153}
15254
153- function walkExit < T extends { nodes ?: T [ ] } > (
55+ function walkImplementation < T extends { nodes ?: T [ ] } > (
15456 ast : T [ ] ,
155- exit : ( node : T , ctx : VisitContext < T > ) => ExitResult < T > | void ,
156- ) {
157- let stack : [ nodes : T [ ] , offset : number , parent : Parent < T > | null ] [ ] = [ [ ast , 0 , null ] ]
158- let ctx : VisitContext < T > = {
159- parent : null ,
160- depth : 0 ,
161- path ( ) {
162- let path : T [ ] = [ ]
163-
164- for ( let i = 1 ; i < stack . length ; i ++ ) {
165- let parent = stack [ i ] [ 2 ]
166- if ( parent ) path . push ( parent )
167- }
168-
169- return path
170- } ,
171- }
172-
173- while ( stack . length > 0 ) {
174- let depth = stack . length - 1
175- let frame = stack [ depth ]
176- let nodes = frame [ 0 ]
177- let offset = frame [ 1 ]
178- let parent = frame [ 2 ]
179-
180- // Done with this level
181- if ( offset >= nodes . length ) {
182- stack . pop ( )
183- continue
184- }
185-
186- ctx . parent = parent
187- ctx . depth = depth
188-
189- // "Enter" phase. We need to enter the AST so we can go back up again
190- if ( offset >= 0 ) {
191- let node = nodes [ offset ]
192-
193- if ( node . nodes && node . nodes . length > 0 ) {
194- stack [ depth ] [ 1 ] = ~ offset // Prepare for actual exit phase
195- stack . push ( [ node . nodes , 0 , node as Parent < T > ] )
196- continue
197- }
198-
199- // Leaf node: run exit immediately
200- let result = exit ( node , ctx ) ?? WalkAction . Continue
201-
202- switch ( result . kind ) {
203- case WalkKind . Continue : {
204- stack [ depth ] [ 1 ] ++ // Advance to next sibling
205- continue
206- }
207-
208- case WalkKind . Stop :
209- return // Stop immediately
210-
211- case WalkKind . ReplaceStop : {
212- nodes . splice ( offset , 1 , ...result . nodes )
213- return // Stop immediately
214- }
215-
216- case WalkKind . Replace :
217- case WalkKind . ReplaceSkip : {
218- nodes . splice ( offset , 1 , ...result . nodes )
219- stack [ depth ] [ 1 ] += result . nodes . length
220- continue
221- }
222-
223- default : {
224- result satisfies never
225- throw new Error (
226- // @ts -expect-error `result.kind` could still be filled in with an invalid value
227- `Invalid \`WalkAction.${ WalkKind [ result . kind ] ?? `Unknown(${ result . kind } )` } \` in exit (leaf).` ,
228- )
229- }
230- }
231- }
232-
233- // Actual exit phase for nodes[~offset]
234- let index = ~ offset
235- let node = nodes [ index ]
236-
237- let result = exit ( node , ctx ) ?? WalkAction . Continue
238-
239- switch ( result . kind ) {
240- case WalkKind . Continue : {
241- stack [ depth ] [ 1 ] = index + 1 // Advance to next sibling
242- continue
243- }
244-
245- case WalkKind . Stop :
246- return // Stop immediately
247-
248- case WalkKind . ReplaceStop : {
249- nodes . splice ( index , 1 , ...result . nodes )
250- return // Stop immediately
251- }
252-
253- case WalkKind . Replace :
254- case WalkKind . ReplaceSkip : {
255- nodes . splice ( index , 1 , ...result . nodes )
256- stack [ depth ] [ 1 ] = index + result . nodes . length // Advance to next sibling past replacements
257- continue
258- }
259-
260- default : {
261- result satisfies never
262- throw new Error (
263- // @ts -expect-error `result.kind` could still be filled in with an invalid value
264- `Invalid \`WalkAction.${ WalkKind [ result . kind ] ?? `Unknown(${ result . kind } )` } \` in exit.` ,
265- )
266- }
267- }
268- }
269- }
270-
271- function walkEnterExit < T extends { nodes ?: T [ ] } > (
272- ast : T [ ] ,
273- enter : ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void ,
274- exit : ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void ,
57+ enter : ( node : T , ctx : VisitContext < T > ) => EnterResult < T > | void = ( ) => WalkAction . Continue ,
58+ exit : ( node : T , ctx : VisitContext < T > ) => ExitResult < T > | void = ( ) => WalkAction . Continue ,
27559) {
27660 let stack : [ nodes : T [ ] , offset : number , parent : Parent < T > | null ] [ ] = [ [ ast , 0 , null ] ]
27761 let ctx : VisitContext < T > = {
@@ -313,88 +97,24 @@ function walkEnterExit<T extends { nodes?: T[] }>(
31397 switch ( result . kind ) {
31498 case WalkKind . Continue : {
31599 if ( node . nodes && node . nodes . length > 0 ) {
316- stack [ depth ] [ 1 ] = ~ offset // Prepare for exit phase, same offset
317100 stack . push ( [ node . nodes , 0 , node as Parent < T > ] )
318- continue
319101 }
320102
321- // Already a leaf node, can immediately exit
322- {
323- let result = exit ( node , ctx ) ?? WalkAction . Continue
324-
325- switch ( result . kind ) {
326- case WalkKind . Continue :
327- case WalkKind . Skip :
328- stack [ depth ] [ 1 ] ++ // Advance to next sibling
329- continue
330-
331- case WalkKind . Stop :
332- return // Stop immediately
333-
334- case WalkKind . ReplaceStop :
335- nodes . splice ( offset , 1 , ...result . nodes )
336- return // Stop immediately
337-
338- case WalkKind . Replace :
339- case WalkKind . ReplaceSkip :
340- nodes . splice ( offset , 1 , ...result . nodes )
341- stack [ depth ] [ 1 ] += result . nodes . length // Advance to next sibling past replacements
342- continue
343-
344- default : {
345- result satisfies never
346- throw new Error (
347- // @ts -expect-error r.kind may be invalid
348- `Invalid \`WalkAction.${ WalkKind [ result . kind ] ?? `Unknown(${ result . kind } )` } \` in exit (leaf).` ,
349- )
350- }
351- }
352- }
103+ frame [ 1 ] = ~ offset // Prepare for exit phase, same offset
104+ continue
353105 }
354106
355107 case WalkKind . Stop :
356108 return // Stop immediately
357109
358110 case WalkKind . Skip : {
359- let result = exit ( node , ctx ) ?? WalkAction . Continue
360-
361- switch ( result . kind ) {
362- case WalkKind . Continue :
363- case WalkKind . Skip :
364- stack [ depth ] [ 1 ] ++
365- continue
366-
367- case WalkKind . Stop :
368- return // Stop immediately
369-
370- case WalkKind . Replace :
371- nodes . splice ( offset , 1 , ...result . nodes )
372- stack [ depth ] [ 1 ] += result . nodes . length // don't visit replacements' exits
373- continue
374-
375- case WalkKind . ReplaceStop :
376- nodes . splice ( offset , 1 , ...result . nodes )
377- return // Stop immediately
378-
379- case WalkKind . ReplaceSkip :
380- nodes . splice ( offset , 1 , ...result . nodes )
381- stack [ depth ] [ 1 ] += result . nodes . length // don't visit replacements' exits
382- continue
383-
384- default : {
385- result satisfies never
386- throw new Error (
387- // @ts -expect-error r.kind may be invalid
388- `Invalid \`WalkAction.${ WalkKind [ result . kind ] ?? `Unknown(${ result . kind } )` } \` in exit (skip).` ,
389- )
390- }
391- }
111+ frame [ 1 ] = ~ offset // Prepare for exit phase, same offset
112+ continue
392113 }
393114
394115 case WalkKind . Replace : {
395- // Replace current node; re-visit current index (enter on first replacement)
396116 nodes . splice ( offset , 1 , ...result . nodes )
397- continue
117+ continue // Re-process at same offset
398118 }
399119
400120 case WalkKind . ReplaceStop : {
@@ -404,7 +124,7 @@ function walkEnterExit<T extends { nodes?: T[] }>(
404124
405125 case WalkKind . ReplaceSkip : {
406126 nodes . splice ( offset , 1 , ...result . nodes )
407- stack [ depth ] [ 1 ] += result . nodes . length // Advance to next sibling past replacements
127+ frame [ 1 ] += result . nodes . length // Advance to next sibling past replacements
408128 continue
409129 }
410130
@@ -426,16 +146,15 @@ function walkEnterExit<T extends { nodes?: T[] }>(
426146
427147 switch ( result . kind ) {
428148 case WalkKind . Continue :
429- case WalkKind . Skip :
430- stack [ depth ] [ 1 ] = index + 1 // Advance to next sibling
149+ frame [ 1 ] = index + 1 // Advance to next sibling
431150 continue
432151
433152 case WalkKind . Stop :
434153 return // Stop immediately
435154
436155 case WalkKind . Replace : {
437156 nodes . splice ( index , 1 , ...result . nodes )
438- stack [ depth ] [ 1 ] = index + result . nodes . length // Advance to next sibling past replacements
157+ frame [ 1 ] = index + result . nodes . length // Advance to next sibling past replacements
439158 continue
440159 }
441160
@@ -446,7 +165,7 @@ function walkEnterExit<T extends { nodes?: T[] }>(
446165
447166 case WalkKind . ReplaceSkip : {
448167 nodes . splice ( index , 1 , ...result . nodes )
449- stack [ depth ] [ 1 ] = index + result . nodes . length // Advance to next sibling past replacements
168+ frame [ 1 ] = index + result . nodes . length // Advance to next sibling past replacements
450169 continue
451170 }
452171
0 commit comments