@@ -50,7 +50,7 @@ export type IsEmptyObjectTypeProps<
5050
5151export type QueryObjectType <
5252 T extends MinimalObjectType ,
53- Q extends $ . TypeFlag . Query ,
53+ Q ,
5454 P extends ObjectTypeProps = T [ "props" ] ,
5555> =
5656 unknown extends Any < T >
@@ -101,6 +101,29 @@ export class MinimalObjectType<
101101 override readonly kind = "object" as const ;
102102}
103103
104+ type ObjectTypeIteratorItem = {
105+ type : $ . Type ;
106+ objectType : ObjectType | undefined ;
107+ name : string ;
108+ path : string [ ] ;
109+ value : any ;
110+ } ;
111+
112+ type ObjectTypeIteratorOptions = {
113+ data ?: any ;
114+ parentPath ?: string [ ] ;
115+ followData ?: boolean ;
116+ } ;
117+
118+ type ObjectTypeCreatorOptions = ObjectTypeIteratorOptions & {
119+ map ?: (
120+ data : ObjectTypeIteratorItem & {
121+ pathName : string ;
122+ } ,
123+ ) => any ;
124+ output ?: Record < string , any > ;
125+ } ;
126+
104127export class ObjectType <
105128 P extends ObjectTypeProps = ObjectTypeProps ,
106129 F extends $ . TypeFlag . Options = { } ,
@@ -168,41 +191,82 @@ export class ObjectType<
168191 const { props, ...otherOptions } = options ;
169192 return new ObjectType ( props , otherOptions ) ;
170193 }
171- createWith (
172- data : any ,
173- mapper ?: ( data : {
174- name : string ;
175- selfName : string ;
176- path : string [ ] ;
177- type : $ . Type ;
178- value : any ;
179- } ) => any ,
180- parentPath ?: string [ ] ,
181- output : Record < string , any > = { } ,
182- ) : any {
183- for ( const name in this . props ) {
194+
195+ private * createIterator (
196+ options : ObjectTypeIteratorOptions = { } ,
197+ ) : Generator < ObjectTypeIteratorItem , void , unknown > {
198+ const entry = options . followData ? options . data : this . props ;
199+ for ( const name in entry ) {
184200 const type = this . props [ name ] as any as $ . Type ;
185- const path = [ ...( parentPath || [ ] ) , name ] ;
186- const value = data ?. [ name ] ;
201+ if ( ! type ) continue ;
202+ const path = [ ...( options . parentPath || [ ] ) , name ] ;
203+ const value = options . data ?. [ name ] ;
204+ yield {
205+ type,
206+ path,
207+ name,
208+ value,
209+ objectType : kindOf ( type , ObjectType ) ? type : undefined ,
210+ } ;
211+ }
212+ }
213+ createWith ( options : ObjectTypeCreatorOptions = { } ) : any {
214+ const output = options . output ?? { } ;
215+ const it = this . createIterator ( options ) ;
216+ for ( const item of it ) {
217+ if (
218+ item . objectType &&
219+ ( ! ! item . value ||
220+ ( ! item . type . options . nullable && ! item . type . options . optional ) )
221+ ) {
222+ output [ item . name ] = item . objectType . createWith ( {
223+ ...options ,
224+ data : item . value ,
225+ output : undefined ,
226+ parentPath : item . path ,
227+ } ) ;
228+ } else {
229+ let pathName : string | undefined ;
230+ const newValue = options . map
231+ ? options . map ( {
232+ ...item ,
233+ get pathName ( ) {
234+ return pathName || ( pathName = item . path . join ( "." ) ) ;
235+ } ,
236+ } )
237+ : item . value ;
238+ if ( newValue !== undefined ) output [ item . name ] = newValue ;
239+ }
240+ }
241+ return output ;
242+ }
243+
244+ async createWithAsync ( options : ObjectTypeCreatorOptions = { } ) : Promise < any > {
245+ const output = options . output ?? { } ;
246+ const it = this . createIterator ( options ) ;
247+ for ( const item of it ) {
187248 if (
188- kindOf ( type , ObjectType ) &&
189- ( ! ! value || ( ! type . options . nullable && ! type . options . optional ) )
249+ item . objectType &&
250+ ( ! ! item . value ||
251+ ( ! item . type . options . nullable && ! item . type . options . optional ) )
190252 ) {
191- output [ name ] = type . createWith ( value , mapper , path ) ;
253+ output [ item . name ] = await item . objectType . createWithAsync ( {
254+ ...options ,
255+ data : item . value ,
256+ output : undefined ,
257+ parentPath : item . path ,
258+ } ) ;
192259 } else {
193260 let pathName : string | undefined ;
194- const newValue = mapper
195- ? mapper ( {
196- path,
197- type,
198- value,
199- selfName : name ,
200- get name ( ) {
201- return pathName || ( pathName = path . join ( "." ) ) ;
261+ const newValue = options . map
262+ ? await options . map ( {
263+ ...item ,
264+ get pathName ( ) {
265+ return pathName || ( pathName = item . path . join ( "." ) ) ;
202266 } ,
203267 } )
204- : value ;
205- if ( newValue !== undefined ) output [ name ] = newValue ;
268+ : item . value ;
269+ if ( newValue !== undefined ) output [ item . name ] = newValue ;
206270 }
207271 }
208272 return output ;
@@ -268,6 +332,13 @@ export class ObjectType<
268332 ) ,
269333 } ;
270334 }
335+ fit ( data : InferType < this> ) : InferType < this> {
336+ return this . createWith ( {
337+ data,
338+ followData : true ,
339+ map : ( { value } ) => value ,
340+ } ) ;
341+ }
271342 pick < Input extends ObjectTypeMask < P > > (
272343 input : Input ,
273344 ) : DeepProjectObjectType < this, Input > {
@@ -450,14 +521,13 @@ export class ObjectType<
450521 }
451522 iterateProps (
452523 cb : ( name : string , type : $ . Type ) => void | false ,
453- parentNames : string [ ] = [ ] ,
524+ parentPath : string [ ] = [ ] ,
454525 ) {
455- for ( const name in this . props ) {
456- const type = this . props [ name ] as any as $ . Type ;
457- const names = [ ...parentNames , name ] ;
458- if ( kindOf ( type , ObjectType ) ) {
459- type . iterateProps ( cb , names ) ;
460- } else if ( cb ( names . join ( "." ) , type ) === false ) {
526+ const it = this . createIterator ( { parentPath } ) ;
527+ for ( const item of it ) {
528+ if ( item . objectType ) {
529+ item . objectType . iterateProps ( cb , item . path ) ;
530+ } else if ( cb ( item . path . join ( "." ) , item . type ) === false ) {
461531 break ;
462532 }
463533 }
0 commit comments