File tree Expand file tree Collapse file tree 2 files changed +65
-3
lines changed
packages/internal/src/steps/generic Expand file tree Collapse file tree 2 files changed +65
-3
lines changed Original file line number Diff line number Diff line change @@ -63,6 +63,36 @@ describe('generic plugin', () => {
6363 const result = schema . execute ( 'world' )
6464 expect ( result ) . toEqual ( { value : 'world' } )
6565 } )
66+
67+ it ( 'should handle recursive structures using generic' , ( ) => {
68+ interface MyNode {
69+ id : number
70+ children ?: MyNode [ ]
71+ }
72+
73+ const nodeSchema = v . object ( {
74+ id : v . number ( ) ,
75+ // Required to use a factory function with specifying return type `any` to avoid circular type reference.
76+ children : [ v . array ( v . generic < { output : MyNode } > ( ( ) : any => nodeSchema ) ) ] ,
77+ } )
78+
79+ const result = nodeSchema . execute ( {
80+ id : 1 ,
81+ children : [
82+ { id : 2 } ,
83+ { id : 3 , children : [ { id : 4 } ] } ,
84+ ] ,
85+ } )
86+ expect ( result ) . toEqual ( {
87+ value : {
88+ id : 1 ,
89+ children : [
90+ { id : 2 } ,
91+ { id : 3 , children : [ { id : 4 } ] } ,
92+ ] ,
93+ } ,
94+ } )
95+ } )
6696 } )
6797
6898 describe ( 'integration with other steps' , ( ) => {
Original file line number Diff line number Diff line change @@ -61,9 +61,41 @@ export const generic = implStepPlugin<PluginDef>({
6161 utils : { addStep } ,
6262 params : [ stepOrFactory ] ,
6363 } ) => {
64- const step = typeof stepOrFactory === 'function' ? stepOrFactory ( ) : stepOrFactory
65- for ( const s of step [ '~core' ] . runtimeSteps ) {
66- addStep ( s )
64+ // Handle factory function
65+ if ( typeof stepOrFactory === 'function' ) {
66+ addStep ( ( lastResult ) => {
67+ const runtimeSteps = stepOrFactory ( ) [ '~core' ] . runtimeSteps
68+ const len = runtimeSteps . length
69+ let result : any = lastResult
70+ let isAsync = false
71+
72+ for ( let i = 0 ; i < len ; i ++ ) {
73+ if ( isAsync ) {
74+ // Already in async mode, skip synchronous execution
75+ continue
76+ }
77+ // Execute step synchronously
78+ result = runtimeSteps [ i ] ! ( result )
79+ // Check if current result is a promise
80+ if ( result instanceof Promise ) {
81+ isAsync = true
82+ // Once we hit async, chain all remaining steps
83+ for ( let j = i + 1 ; j < len ; j ++ ) {
84+ result = result . then ( runtimeSteps [ j ] ! )
85+ }
86+ return result
87+ }
88+ }
89+ return result
90+ } )
91+ }
92+ // Handle direct step
93+ else {
94+ const runtimeSteps = stepOrFactory [ '~core' ] . runtimeSteps
95+ const len = runtimeSteps . length
96+ for ( let i = 0 ; i < len ; i ++ ) {
97+ addStep ( runtimeSteps [ i ] ! )
98+ }
6799 }
68100 } ,
69101} )
You can’t perform that action at this time.
0 commit comments