1
- import { keysOf , tryCatch } from './utils' ;
1
+ import { keysOf , tryCatch , increaseIndent } from './utils' ;
2
2
import {
3
3
ArrayIndexPathNode ,
4
4
error ,
@@ -87,10 +87,17 @@ export function conformsTo<T>(validator: Validator<T>, optionsOrNext?: IValidati
87
87
return errors ;
88
88
} , [ ] as ValidationError [ ] ) ;
89
89
90
- if ( ! allowAdditionalProperties && keysOf ( arg ) . some ( key => ! validator . hasOwnProperty ( key ) ) ) {
91
- errors . push (
92
- new ValidationError ( 'UNEXPECTED_ADDITIONAL_PROPERTIES' , `Unexpected additional propertie(s): ${ keysOf ( arg ) . filter ( key => ! validator . hasOwnProperty ( key ) ) . join ( ', ' ) } ` )
93
- ) ;
90
+ if ( ! allowAdditionalProperties ) {
91
+ const additionalProperties = keysOf ( arg ) . filter ( key => ! validator . hasOwnProperty ( key ) ) ;
92
+
93
+ if ( additionalProperties . length > 0 ) {
94
+ errors . push (
95
+ new ValidationError (
96
+ 'UNEXPECTED_ADDITIONAL_PROPERTIES' ,
97
+ `Unexpected additional propert${ additionalProperties . length === 1 ? 'y' : 'ies' } : ${ additionalProperties . join ( ', ' ) } `
98
+ )
99
+ ) ;
100
+ }
94
101
}
95
102
96
103
if ( errors . length > 0 ) return new ErrorResult ( errors ) ;
@@ -102,18 +109,22 @@ export function conformsTo<T>(validator: Validator<T>, optionsOrNext?: IValidati
102
109
}
103
110
104
111
105
- export function optional < T > ( next : ( arg : any ) => ValidationResult < T > ) : ( arg : any ) => ValidationResult < T | undefined > {
112
+ export function optional ( ) : ( arg : any ) => ValidationResult < any | undefined > ;
113
+ export function optional < T > ( next : ( arg : any ) => ValidationResult < T > ) : ( arg : any ) => ValidationResult < T | undefined > ;
114
+ export function optional ( next ?: ( arg : any ) => ValidationResult < any > ) : ( arg : any ) => ValidationResult < any | undefined > {
106
115
return ( arg : any ) => {
107
116
if ( arg === undefined ) return success ( undefined ) ;
108
- return next ( arg ) ;
117
+ return next ? next ( arg ) : success ( arg ) ;
109
118
} ;
110
119
}
111
120
112
121
113
- export function nullable < T > ( next : ( arg : any ) => ValidationResult < T > ) : ( arg : any ) => ValidationResult < T | null > {
122
+ export function nullable ( ) : ( arg : any ) => ValidationResult < any | null > ;
123
+ export function nullable < T > ( next : ( arg : any ) => ValidationResult < T > ) : ( arg : any ) => ValidationResult < T | null > ;
124
+ export function nullable ( next ?: ( arg : any ) => ValidationResult < any > ) : ( arg : any ) => ValidationResult < any | null > {
114
125
return ( arg : any ) => {
115
126
if ( arg === null ) return success ( null ) ;
116
- return next ( arg ) ;
127
+ return next ? next ( arg ) : success ( arg ) ;
117
128
} ;
118
129
}
119
130
@@ -130,12 +141,15 @@ export function defaultsTo(def: any, next?: (arg: any) => ValidationResult<any>)
130
141
131
142
export function onErrorDefaultsTo < T , U > ( def : U , next : ( arg : T ) => ValidationResult < U > ) : ( arg : T ) => ValidationResult < U > {
132
143
return ( arg : T ) => {
133
- try {
134
- return next ( arg ) ;
135
- } catch ( _ ) {
136
- // Ignore error - resort to default
137
- return success ( def ) ;
138
- }
144
+ const result = tryCatch (
145
+ ( ) => next ( arg ) ,
146
+ ( err ) => errorFromException ( err )
147
+ ) ;
148
+
149
+ if ( result . success ) return result ;
150
+
151
+ // Ignore error - resort to default
152
+ return success ( def ) ;
139
153
} ;
140
154
}
141
155
@@ -246,7 +260,7 @@ export function eachItem<T>(assertion: (arg: any) => ValidationResult<T>, next?:
246
260
return ( arg : any [ ] ) => {
247
261
const results = arg . map ( ( item , index ) => tryCatch (
248
262
( ) => assertion ( item ) ,
249
- ( err ) => error ( 'UNHANDLED_ERROR' , `Unhandled error: ${ typeof err === 'object' && err . message || 'Unknown error' } ` )
263
+ ( err ) => errorFromException ( err )
250
264
) ) ;
251
265
252
266
if ( results . some ( ErrorResult . isErrorResult ) ) {
@@ -310,7 +324,7 @@ export function eachValue<T>(assertion: (arg: any) => ValidationResult<T>): (arg
310
324
export function eachValue < T , U > ( assertion : ( arg : any ) => ValidationResult < T > , next : ( arg : { [ key : string ] : T } ) => ValidationResult < U > ) : ( arg : { [ key : string ] : any } ) => ValidationResult < U > ;
311
325
export function eachValue < T > ( assertion : ( arg : any ) => ValidationResult < T > , next ?: ( arg : { [ key : string ] : T } ) => ValidationResult < any > ) : ( arg : { [ key : string ] : any } ) => ValidationResult < any > {
312
326
return ( arg : { [ key : string ] : any } ) => {
313
- return conformsTo (
327
+ const result = conformsTo (
314
328
Object . keys ( arg ) . reduce (
315
329
( validator , key ) => {
316
330
validator [ key ] = assertion ;
@@ -319,6 +333,10 @@ export function eachValue<T>(assertion: (arg: any) => ValidationResult<T>, next?
319
333
{ } as Validator < { [ key : string ] : T } >
320
334
)
321
335
) ( arg ) ;
336
+
337
+ if ( result . success && next ) return next ( result . value ) ;
338
+
339
+ return result ;
322
340
} ;
323
341
}
324
342
@@ -346,6 +364,6 @@ export function either(...assertions: Array<(arg: any) => any>): (arg: any) => a
346
364
errors = errors . concat ( result . errors ) ;
347
365
}
348
366
349
- return error ( 'NO_MATCH' , 'No match found - the following assertions failed:\n ' + errors . map ( error => error . toString ( ) ) . join ( '\n ' ) ) ;
367
+ return error ( 'NO_MATCH' , 'No match found - the following assertions failed:\n' + errors . map ( error => increaseIndent ( error . toString ( ) , 2 ) ) . join ( '\n' ) ) ;
350
368
} ;
351
369
}
0 commit comments