@@ -20,6 +20,14 @@ const getRegex = (pattern: string) => {
2020} ;
2121
2222const findMatchedType = ( type_union : TypeUnion , property : unknown ) => {
23+ if ( property === undefined ) {
24+ const schema_with_default = type_union . find ( ( schema ) => schema . default !== undefined ) ;
25+
26+ if ( schema_with_default ) return schema_with_default ;
27+
28+ return type_union [ 0 ] ;
29+ }
30+
2331 const matched = type_union . find ( ( schema ) => {
2432 if ( property === null ) return schema . nullable ;
2533
@@ -34,25 +42,35 @@ const findMatchedType = (type_union: TypeUnion, property: unknown) => {
3442} ;
3543
3644const findMatchedSchema = ( schema_union : SchemaUnion , properties : Record < string , unknown > ) => {
37- const matched = schema_union . find ( ( schemaRecord ) => {
38- const first_key = Object . keys ( schemaRecord ) [ 0 ] ;
39-
40- if ( ! first_key ) return false ;
41-
42- const first_type = schemaRecord [ first_key ] ;
43- const target_type = Array . isArray ( first_type ) ? first_type [ 0 ] : first_type ;
44- const property = properties [ first_key ] ;
45+ let best_match = schema_union [ 0 ] ;
46+ let max_score = - 1 ;
4547
46- if ( property === null ) return target_type . nullable ;
48+ for ( const schema_record of schema_union ) {
49+ let score = 0 ;
4750
48- if ( target_type . type === 'date' ) return typeof property === 'string' || property instanceof Date ;
49- if ( target_type . type === 'array' ) return Array . isArray ( property ) ;
50- if ( target_type . type === 'object' ) return typeof property === 'object' && ! Array . isArray ( property ) ;
51+ for ( const key of Object . keys ( schema_record ) ) {
52+ const property = properties [ key ] ;
53+ const schema_def = schema_record [ key ] ;
54+ const target_type = Array . isArray ( schema_def ) ? findMatchedType ( schema_def , property ) : schema_def ;
55+
56+ if ( property === null ) {
57+ if ( target_type . nullable ) {
58+ score ++ ;
59+ } else score -= 2 ;
60+ } else if ( property !== undefined ) {
61+ if ( ( target_type . type === 'string' && typeof property === 'string' ) || ( target_type . type === 'number' && typeof property === 'number' ) || ( target_type . type === 'boolean' && typeof property === 'boolean' ) || ( target_type . type === 'object' && typeof property === 'object' && ! Array . isArray ( property ) ) || ( target_type . type === 'array' && Array . isArray ( property ) ) ) {
62+ score ++ ;
63+ } else score -= 2 ;
64+ } else if ( target_type . required && target_type . default === undefined ) score -= 1 ;
65+ }
5166
52- return typeof property === target_type . type ;
53- } ) ;
67+ if ( score > max_score ) {
68+ max_score = score ;
69+ best_match = schema_record ;
70+ }
71+ }
5472
55- return matched ?? schema_union [ 0 ] ;
73+ return best_match ;
5674} ;
5775
5876export const validate = async < const _Schema extends Schema > ( schema : _Schema , properties : Record < string , unknown > , options : TeyitOptions ) : Promise < InferSchema < _Schema > > => {
@@ -82,7 +100,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
82100 } else throw new ValidationError ( { errors : [ error ] } ) ;
83101 } ;
84102
85- const processProperty = ( equivalent : TypeSingle , property : unknown , path : string ) : unknown => {
103+ const processProperty = async ( equivalent : TypeSingle , property : unknown , path : string ) : Promise < unknown > => {
86104 if ( property === undefined ) {
87105 if ( equivalent . default !== undefined ) {
88106 return equivalent . default ;
@@ -150,7 +168,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
150168
151169 return value ;
152170 } else if ( equivalent . type === 'number' ) {
153- if ( typeof property !== 'number' ) {
171+ if ( typeof property !== 'number' || ! Number . isFinite ( property ) ) {
154172 reportError ( { message : ( options . error_messages ?. number ?. type ?? '' ) . replaceAll ( '{path}' , path ) , parts : { path } } ) ;
155173
156174 return property ;
@@ -166,7 +184,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
166184
167185 if ( equivalent . positive === true && property < 0 ) reportError ( { message : ( options . error_messages ?. number ?. positive ?? '' ) . replaceAll ( '{path}' , path ) , parts : { path } } ) ;
168186
169- if ( equivalent . negative === true && property >= 0 ) reportError ( { message : ( options . error_messages ?. number ?. negative ?? '' ) . replaceAll ( '{path}' , path ) , parts : { path } } ) ;
187+ if ( equivalent . negative === true && property > 0 ) reportError ( { message : ( options . error_messages ?. number ?. negative ?? '' ) . replaceAll ( '{path}' , path ) , parts : { path } } ) ;
170188
171189 return property ;
172190 } else if ( equivalent . type === 'boolean' ) {
@@ -220,7 +238,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
220238 const target_schema = Array . isArray ( schema_property ) ? findMatchedType ( schema_property , property_record [ key ] ) : schema_property ;
221239
222240 const next_path = path === 'root' ? key : `${ path } .${ key } ` ;
223- const property_processed = processProperty ( target_schema , property_record [ key ] , next_path ) ;
241+ const property_processed = await processProperty ( target_schema , property_record [ key ] , next_path ) ;
224242
225243 if ( property_processed !== undefined ) result_record [ key ] = property_processed ;
226244 }
@@ -247,7 +265,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
247265 const base_path = path === 'root' ? '' : path ;
248266 const next_path = `${ base_path } [${ String ( i ) } ]` ;
249267
250- results_array [ i ] = processProperty ( target_schema , property [ i ] , next_path ) ;
268+ results_array [ i ] = await processProperty ( target_schema , property [ i ] , next_path ) ;
251269 }
252270
253271 return results_array ;
@@ -267,7 +285,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
267285 const schema_property = schema_record [ key ] ;
268286 const target_schema = Array . isArray ( schema_property ) ? findMatchedType ( schema_property , properties [ key ] ) : schema_property ;
269287
270- const property_processed = processProperty ( target_schema , properties [ key ] , key ) ;
288+ const property_processed = await processProperty ( target_schema , properties [ key ] , key ) ;
271289
272290 if ( property_processed !== undefined ) result_record [ key ] = property_processed ;
273291 }
0 commit comments