@@ -26,6 +26,8 @@ type StepWithParentSequenceOrName = StepWithParentSequence | string;
2626
2727export type StepChildrenResolver = ( step : Step ) => StepChildren | null ;
2828
29+ export type StepForEachCallback = ( step : Step , index : number , parentSequence : Sequence ) => void | boolean ;
30+
2931export class DefinitionWalker {
3032 private readonly resolvers : StepChildrenResolver [ ] ;
3133
@@ -34,7 +36,8 @@ export class DefinitionWalker {
3436 }
3537
3638 /**
37- * Returns children of the step.
39+ * Returns children of the step. If the step doesn't have children, returns null.
40+ * @param step The step.
3841 */
3942 public getChildren ( step : Step ) : StepChildren | null {
4043 const count = this . resolvers . length ;
@@ -47,10 +50,24 @@ export class DefinitionWalker {
4750 return null ;
4851 }
4952
50- public getParents ( definition : Definition , needle : Sequence | Step ) : StepOrName [ ] {
53+ /**
54+ * Returns the parents of the step or the sequence.
55+ * @param definition The definition.
56+ * @param needle The step, stepId or sequence to find.
57+ * @returns The parents of the step or the sequence.
58+ */
59+ public getParents ( definition : Definition , needle : Sequence | Step | string ) : StepOrName [ ] {
5160 const result : StepWithParentSequenceOrName [ ] = [ ] ;
52- const searchSequence = Array . isArray ( needle ) ? needle : null ;
53- const searchStepId = ! searchSequence ? ( needle as Step ) . id : null ;
61+
62+ let searchSequence : Sequence | null = null ;
63+ let searchStepId : string | null = null ;
64+ if ( Array . isArray ( needle ) ) {
65+ searchSequence = needle ;
66+ } else if ( typeof needle === 'string' ) {
67+ searchStepId = needle ;
68+ } else {
69+ searchStepId = needle . id ;
70+ }
5471
5572 if ( this . find ( definition . sequence , searchSequence , searchStepId , result ) ) {
5673 result . reverse ( ) ;
@@ -87,6 +104,11 @@ export class DefinitionWalker {
87104 return this . getParentSequence ( definition , stepId ) . step ;
88105 }
89106
107+ public forEach ( sequenceOrDefinition : Sequence | Definition , callback : StepForEachCallback ) {
108+ const sequence = Array . isArray ( sequenceOrDefinition ) ? sequenceOrDefinition : sequenceOrDefinition . sequence ;
109+ this . iterate ( sequence , callback ) ;
110+ }
111+
90112 private find (
91113 sequence : Sequence ,
92114 needSequence : Sequence | null ,
@@ -139,4 +161,45 @@ export class DefinitionWalker {
139161 }
140162 return false ;
141163 }
164+
165+ private iterate ( sequence : Sequence , callback : StepForEachCallback ) : boolean {
166+ const count = sequence . length ;
167+ for ( let index = 0 ; index < count ; index ++ ) {
168+ const step = sequence [ index ] ;
169+ if ( callback ( step , index , sequence ) === false ) {
170+ return false ;
171+ }
172+
173+ const children = this . getChildren ( step ) ;
174+ if ( children ) {
175+ switch ( children . type ) {
176+ case StepChildrenType . sequence :
177+ {
178+ const childSequence = children . items as Sequence ;
179+ if ( this . iterate ( childSequence , callback ) === false ) {
180+ return false ;
181+ }
182+ }
183+ break ;
184+
185+ case StepChildrenType . branches :
186+ {
187+ const branches = children . items as Branches ;
188+ const branchNames = Object . keys ( branches ) ;
189+ for ( const branchName of branchNames ) {
190+ const parentSequence = branches [ branchName ] ;
191+ if ( this . iterate ( parentSequence , callback ) === false ) {
192+ return false ;
193+ }
194+ }
195+ }
196+ break ;
197+
198+ default :
199+ throw new Error ( `Step children type ${ children . type } is not supported` ) ;
200+ }
201+ }
202+ }
203+ return true ;
204+ }
142205}
0 commit comments