1- import type { DefineExpectedValchecker , DefineStepMethod , DefineStepMethodMeta , ExecutionIssue , ExecutionResult , InferAsync , InferIssue , InferOutput , MessageHandler , Next , TStepPluginDef , Use , Valchecker } from '../../core'
1+ import type { DefineExpectedValchecker , DefineStepMethod , DefineStepMethodMeta , ExecutionIssue , InferAsync , InferIssue , InferOutput , MessageHandler , Next , TStepPluginDef , Use , Valchecker } from '../../core'
22import type { IsEqual , IsExactlyAnyOrUnknown , Simplify , ValueOf } from '../../shared'
33import { implStepPlugin } from '../../core'
44
@@ -97,6 +97,19 @@ export const looseObject = implStepPlugin<PluginDef>({
9797 utils : { addSuccessStep, success, resolveMessage, failure, isFailure, prependIssuePath } ,
9898 params : [ struct , message ] ,
9999 } ) => {
100+ // Pre-compute metadata for each property to avoid repeated lookups
101+ const keys = Reflect . ownKeys ( struct )
102+ const keysLen = keys . length
103+ const propsMeta : Array < { key : PropertyKey , isOptional : boolean , schema : Use < Valchecker > } > = [ ]
104+
105+ for ( let i = 0 ; i < keysLen ; i ++ ) {
106+ const key = keys [ i ] !
107+ const prop = struct [ key ] !
108+ const isOptional = Array . isArray ( prop )
109+ const schema = isOptional ? prop [ 0 ] ! : prop
110+ propsMeta . push ( { key, isOptional, schema } )
111+ }
112+
100113 addSuccessStep ( ( value ) => {
101114 if ( typeof value !== 'object' || value == null || Array . isArray ( value ) ) {
102115 return failure ( {
@@ -113,61 +126,79 @@ export const looseObject = implStepPlugin<PluginDef>({
113126 } )
114127 }
115128
116- // Optimized: Direct processing without Pipe overhead
117- const knownKeys = Array . from ( Reflect . ownKeys ( struct ) )
118129 const issues : ExecutionIssue < any , any > [ ] = [ ]
119130 const output : Record < PropertyKey , any > = Object . defineProperties (
120131 { } ,
121132 Object . getOwnPropertyDescriptors ( value ) ,
122133 )
123134
124- const processPropResult = ( result : ExecutionResult , key : string | symbol ) => {
125- if ( isFailure ( result ) ) {
126- // Optimize: Avoid spread + map by using direct loop
127- for ( const issue of result . issues ! ) {
128- issues . push ( prependIssuePath ( issue , [ key ] ) )
129- }
130- }
131- else {
132- output [ key ] = result . value !
133- }
134- }
135-
135+ // Inline processPropResult for better performance
136136 // Process properties synchronously until we hit async
137- for ( let i = 0 ; i < knownKeys . length ; i ++ ) {
138- const key = knownKeys [ i ] !
139- const isOptional = Array . isArray ( struct [ key ] ! )
140- const propSchema = Array . isArray ( struct [ key ] ! ) ? struct [ key ] ! [ 0 ] ! : struct [ key ] !
137+ for ( let i = 0 ; i < keysLen ; i ++ ) {
138+ const { key, isOptional, schema } = propsMeta [ i ] !
141139 const propValue = ( value as any ) [ key ]
142140
143141 const propResult = ( isOptional && propValue === void 0 )
144142 ? success ( propValue )
145- : propSchema [ '~execute' ] ( propValue )
143+ : schema [ '~execute' ] ( propValue )
146144
147145 if ( propResult instanceof Promise ) {
148146 // Hit async, chain remaining properties
149- let chain = propResult . then ( r => processPropResult ( r , key ) )
150-
151- for ( let j = i + 1 ; j < knownKeys . length ; j ++ ) {
152- const jKey = knownKeys [ j ] !
153- const jIsOptional = Array . isArray ( struct [ jKey ] ! )
154- const jPropSchema = Array . isArray ( struct [ jKey ] ! ) ? struct [ jKey ] ! [ 0 ] ! : struct [ jKey ] !
155- const jPropValue = ( value as any ) [ jKey ]
147+ let chain = propResult . then ( ( r ) => {
148+ if ( isFailure ( r ) ) {
149+ for ( const issue of r . issues ! ) {
150+ issues . push ( prependIssuePath ( issue , [ key ] ) )
151+ }
152+ }
153+ else {
154+ output [ key ] = r . value !
155+ }
156+ } )
157+
158+ for ( let j = i + 1 ; j < keysLen ; j ++ ) {
159+ const nextMeta = propsMeta [ j ] !
160+ const nextPropValue = ( value as any ) [ nextMeta . key ]
156161
157162 chain = chain . then ( ( ) => {
158- const jPropResult = ( jIsOptional && jPropValue === void 0 )
159- ? success ( jPropValue )
160- : jPropSchema [ '~execute' ] ( jPropValue )
161- return jPropResult instanceof Promise
162- ? jPropResult . then ( r => processPropResult ( r , jKey ) )
163- : ( processPropResult ( jPropResult , jKey ) , undefined )
163+ const nextPropResult = ( nextMeta . isOptional && nextPropValue === void 0 )
164+ ? success ( nextPropValue )
165+ : nextMeta . schema [ '~execute' ] ( nextPropValue )
166+
167+ if ( nextPropResult instanceof Promise ) {
168+ return nextPropResult . then ( ( r ) => {
169+ if ( isFailure ( r ) ) {
170+ for ( const issue of r . issues ! ) {
171+ issues . push ( prependIssuePath ( issue , [ nextMeta . key ] ) )
172+ }
173+ }
174+ else {
175+ output [ nextMeta . key ] = r . value !
176+ }
177+ } )
178+ }
179+
180+ if ( isFailure ( nextPropResult ) ) {
181+ for ( const issue of nextPropResult . issues ! ) {
182+ issues . push ( prependIssuePath ( issue , [ nextMeta . key ] ) )
183+ }
184+ }
185+ else {
186+ output [ nextMeta . key ] = nextPropResult . value !
187+ }
164188 } )
165189 }
166190
167191 return chain . then ( ( ) => issues . length > 0 ? failure ( issues ) : success ( output ) )
168192 }
169193
170- processPropResult ( propResult , key )
194+ if ( isFailure ( propResult ) ) {
195+ for ( const issue of propResult . issues ! ) {
196+ issues . push ( prependIssuePath ( issue , [ key ] ) )
197+ }
198+ }
199+ else {
200+ output [ key ] = propResult . value !
201+ }
171202 }
172203
173204 return issues . length > 0 ? failure ( issues ) : success ( output )
0 commit comments