@@ -99,7 +99,11 @@ export class LineCursor extends Marker {
9999 if ( ! curNode ) {
100100 return null ;
101101 }
102- const newNode = this . getNextNode ( curNode , this . validLineNode . bind ( this ) ) ;
102+ const newNode = this . getNextNode (
103+ curNode ,
104+ this . validLineNode . bind ( this ) ,
105+ true ,
106+ ) ;
103107
104108 if ( newNode ) {
105109 this . setCurNode ( newNode ) ;
@@ -119,7 +123,11 @@ export class LineCursor extends Marker {
119123 if ( ! curNode ) {
120124 return null ;
121125 }
122- const newNode = this . getNextNode ( curNode , this . validInLineNode . bind ( this ) ) ;
126+ const newNode = this . getNextNode (
127+ curNode ,
128+ this . validInLineNode . bind ( this ) ,
129+ true ,
130+ ) ;
123131
124132 if ( newNode ) {
125133 this . setCurNode ( newNode ) ;
@@ -138,11 +146,10 @@ export class LineCursor extends Marker {
138146 if ( ! curNode ) {
139147 return null ;
140148 }
141- const newNode = this . getPreviousNode (
149+ const newNode = this . getPreviousNodeImpl (
142150 curNode ,
143151 this . validLineNode . bind ( this ) ,
144152 ) ;
145-
146153 if ( newNode ) {
147154 this . setCurNode ( newNode ) ;
148155 }
@@ -161,7 +168,7 @@ export class LineCursor extends Marker {
161168 if ( ! curNode ) {
162169 return null ;
163170 }
164- const newNode = this . getPreviousNode (
171+ const newNode = this . getPreviousNodeImpl (
165172 curNode ,
166173 this . validInLineNode . bind ( this ) ,
167174 ) ;
@@ -184,6 +191,7 @@ export class LineCursor extends Marker {
184191 const rightNode = this . getNextNode (
185192 curNode ,
186193 this . validInLineNode . bind ( this ) ,
194+ false ,
187195 ) ;
188196 return this . validLineNode ( rightNode ) ;
189197 }
@@ -299,28 +307,46 @@ export class LineCursor extends Marker {
299307 * should be traversed.
300308 * @returns The next node in the traversal.
301309 */
302- getNextNode (
310+ private getNextNodeImpl (
303311 node : ASTNode | null ,
304312 isValid : ( p1 : ASTNode | null ) => boolean ,
305313 ) : ASTNode | null {
306- if ( ! node ) {
307- return null ;
308- }
309- const newNode = node . in ( ) || node . next ( ) ;
310- if ( isValid ( newNode ) ) {
311- return newNode ;
312- } else if ( newNode ) {
313- return this . getNextNode ( newNode , isValid ) ;
314- }
315- const siblingOrParentSibling = this . findSiblingOrParentSibling ( node . out ( ) ) ;
316- if ( isValid ( siblingOrParentSibling ) ) {
317- return siblingOrParentSibling ;
318- } else if ( siblingOrParentSibling ) {
319- return this . getNextNode ( siblingOrParentSibling , isValid ) ;
320- }
314+ if ( ! node ) return null ;
315+ let newNode = node . in ( ) || node . next ( ) ;
316+ if ( isValid ( newNode ) ) return newNode ;
317+ if ( newNode ) return this . getNextNodeImpl ( newNode , isValid ) ;
318+
319+ newNode = this . findSiblingOrParentSibling ( node . out ( ) ) ;
320+ if ( isValid ( newNode ) ) return newNode ;
321+ if ( newNode ) return this . getNextNodeImpl ( newNode , isValid ) ;
321322 return null ;
322323 }
323324
325+ /**
326+ * Get the next node in the AST, optionally allowing for loopback.
327+ *
328+ * @param node The current position in the AST.
329+ * @param isValid A function true/false depending on whether the given node
330+ * should be traversed.
331+ * @param loop Whether to loop around to the beginning of the workspace if
332+ * novalid node was found.
333+ * @returns The next node in the traversal.
334+ */
335+ getNextNode (
336+ node : ASTNode | null ,
337+ isValid : ( p1 : ASTNode | null ) => boolean ,
338+ loop : boolean ,
339+ ) : ASTNode | null {
340+ if ( ! node ) return null ;
341+
342+ const potential = this . getNextNodeImpl ( node , isValid ) ;
343+ if ( potential || ! loop ) return potential ;
344+ // Loop back.
345+ const firstNode = this . getFirstNode ( ) ;
346+ if ( isValid ( firstNode ) ) return firstNode ;
347+ return this . getNextNodeImpl ( firstNode , isValid ) ;
348+ }
349+
324350 /**
325351 * Reverses the pre order traversal in order to find the previous node. This
326352 * will allow a user to easily navigate the entire Blockly AST without having
@@ -332,28 +358,50 @@ export class LineCursor extends Marker {
332358 * @returns The previous node in the traversal or null if no previous node
333359 * exists.
334360 */
335- getPreviousNode (
361+ private getPreviousNodeImpl (
336362 node : ASTNode | null ,
337363 isValid : ( p1 : ASTNode | null ) => boolean ,
338364 ) : ASTNode | null {
339- if ( ! node ) {
340- return null ;
341- }
365+ if ( ! node ) return null ;
342366 let newNode : ASTNode | null = node . prev ( ) ;
343367
344368 if ( newNode ) {
345369 newNode = this . getRightMostChild ( newNode ) ;
346370 } else {
347371 newNode = node . out ( ) ;
348372 }
349- if ( isValid ( newNode ) ) {
350- return newNode ;
351- } else if ( newNode ) {
352- return this . getPreviousNode ( newNode , isValid ) ;
353- }
373+
374+ if ( isValid ( newNode ) ) return newNode ;
375+ if ( newNode ) return this . getPreviousNodeImpl ( newNode , isValid ) ;
354376 return null ;
355377 }
356378
379+ /**
380+ * Get the previous node in the AST, optionally allowing for loopback.
381+ *
382+ * @param node The current position in the AST.
383+ * @param isValid A function true/false depending on whether the given node
384+ * should be traversed.
385+ * @param loop Whether to loop around to the end of the workspace if no
386+ * valid node was found.
387+ * @returns The previous node in the traversal or null if no previous node
388+ * exists.
389+ */
390+ getPreviousNode (
391+ node : ASTNode | null ,
392+ isValid : ( p1 : ASTNode | null ) => boolean ,
393+ loop : boolean ,
394+ ) : ASTNode | null {
395+ if ( ! node ) return null ;
396+
397+ const potential = this . getPreviousNodeImpl ( node , isValid ) ;
398+ if ( potential || ! loop ) return potential ;
399+ // Loop back.
400+ const lastNode = this . getLastNode ( ) ;
401+ if ( isValid ( lastNode ) ) return lastNode ;
402+ return this . getPreviousNodeImpl ( lastNode , isValid ) ;
403+ }
404+
357405 /**
358406 * From the given node find either the next valid sibling or the parent's
359407 * next sibling.
@@ -362,13 +410,9 @@ export class LineCursor extends Marker {
362410 * @returns The next sibling node, the parent's next sibling, or null.
363411 */
364412 private findSiblingOrParentSibling ( node : ASTNode | null ) : ASTNode | null {
365- if ( ! node ) {
366- return null ;
367- }
413+ if ( ! node ) return null ;
368414 const nextNode = node . next ( ) ;
369- if ( nextNode ) {
370- return nextNode ;
371- }
415+ if ( nextNode ) return nextNode ;
372416 return this . findSiblingOrParentSibling ( node . out ( ) ) ;
373417 }
374418
@@ -381,9 +425,7 @@ export class LineCursor extends Marker {
381425 */
382426 private getRightMostChild ( node : ASTNode ) : ASTNode | null {
383427 let newNode = node . in ( ) ;
384- if ( ! newNode ) {
385- return node ;
386- }
428+ if ( ! newNode ) return node ;
387429 for (
388430 let nextNode : ASTNode | null = newNode ;
389431 nextNode ;
@@ -787,9 +829,13 @@ export class LineCursor extends Marker {
787829 // Iterate until you fall off the end of the stack.
788830 while ( nextNode ) {
789831 prevNode = nextNode ;
790- nextNode = this . getNextNode ( prevNode , ( node ) => {
791- return ! ! node ;
792- } ) ;
832+ nextNode = this . getNextNode (
833+ prevNode ,
834+ ( node ) => {
835+ return ! ! node ;
836+ } ,
837+ false ,
838+ ) ;
793839 }
794840 return prevNode ;
795841 }
0 commit comments