Skip to content

Commit 00f878d

Browse files
committed
Merge branch 'release/0.7.3'
2 parents 328578d + 2f91ab4 commit 00f878d

File tree

5 files changed

+57
-21
lines changed

5 files changed

+57
-21
lines changed

lib/index.ts

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { keysOf, tryCatch } from './utils';
1+
import { keysOf, tryCatch, increaseIndent } from './utils';
22
import {
33
ArrayIndexPathNode,
44
error,
@@ -87,10 +87,17 @@ export function conformsTo<T>(validator: Validator<T>, optionsOrNext?: IValidati
8787
return errors;
8888
}, [] as ValidationError[]);
8989

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+
}
94101
}
95102

96103
if (errors.length > 0) return new ErrorResult(errors);
@@ -102,18 +109,22 @@ export function conformsTo<T>(validator: Validator<T>, optionsOrNext?: IValidati
102109
}
103110

104111

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> {
106115
return (arg: any) => {
107116
if (arg === undefined) return success(undefined);
108-
return next(arg);
117+
return next ? next(arg) : success(arg);
109118
};
110119
}
111120

112121

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> {
114125
return (arg: any) => {
115126
if (arg === null) return success(null);
116-
return next(arg);
127+
return next ? next(arg) : success(arg);
117128
};
118129
}
119130

@@ -130,12 +141,15 @@ export function defaultsTo(def: any, next?: (arg: any) => ValidationResult<any>)
130141

131142
export function onErrorDefaultsTo<T,U>(def: U, next: (arg: T) => ValidationResult<U>): (arg: T) => ValidationResult<U> {
132143
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);
139153
};
140154
}
141155

@@ -246,7 +260,7 @@ export function eachItem<T>(assertion: (arg: any) => ValidationResult<T>, next?:
246260
return (arg: any[]) => {
247261
const results = arg.map((item, index) => tryCatch(
248262
() => assertion(item),
249-
(err) => error('UNHANDLED_ERROR', `Unhandled error: ${typeof err === 'object' && err.message || 'Unknown error'}`)
263+
(err) => errorFromException(err)
250264
));
251265

252266
if (results.some(ErrorResult.isErrorResult)) {
@@ -310,7 +324,7 @@ export function eachValue<T>(assertion: (arg: any) => ValidationResult<T>): (arg
310324
export function eachValue<T,U>(assertion: (arg: any) => ValidationResult<T>, next: (arg: {[key: string]: T}) => ValidationResult<U>): (arg: {[key: string]: any}) => ValidationResult<U>;
311325
export function eachValue<T>(assertion: (arg: any) => ValidationResult<T>, next?: (arg: {[key: string]: T}) => ValidationResult<any>): (arg: {[key: string]: any}) => ValidationResult<any> {
312326
return (arg: {[key: string]: any}) => {
313-
return conformsTo(
327+
const result = conformsTo(
314328
Object.keys(arg).reduce(
315329
(validator, key) => {
316330
validator[key] = assertion;
@@ -319,6 +333,10 @@ export function eachValue<T>(assertion: (arg: any) => ValidationResult<T>, next?
319333
{} as Validator<{[key: string]: T}>
320334
)
321335
)(arg);
336+
337+
if (result.success && next) return next(result.value);
338+
339+
return result;
322340
};
323341
}
324342

@@ -346,6 +364,6 @@ export function either(...assertions: Array<(arg: any) => any>): (arg: any) => a
346364
errors = errors.concat(result.errors);
347365
}
348366

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'));
350368
};
351369
}

lib/utils.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,18 @@ export function keysOf<T>(arg: T): Array<keyof T> {
2020
}
2121

2222

23+
export function repeat(text: string, count: number): string {
24+
let result = '';
25+
26+
for (let i = 0; i < count; i++) {
27+
result += text;
28+
}
29+
30+
return result;
31+
}
32+
33+
34+
export function increaseIndent(text: string, indent: number): string {
35+
const indentPadding = repeat(' ', indent);
36+
return indentPadding + text.split('\n').join('\n' + indentPadding);
37+
}

lib/validation-result.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { increaseIndent } from './utils';
2+
3+
14
export type ValidationResult<T> = SuccessResult<T> | ErrorResult;
25

36

@@ -75,7 +78,7 @@ export class ErrorResult {
7578
}
7679

7780
public toString(root: string = '$'): string {
78-
return `${this.errors.length} validation error${this.errors.length === 1 ? '' : 's'}:\n ${this.errors.map(error => error.toString(root)).join('\n ')}`;
81+
return `${this.errors.length} validation error${this.errors.length === 1 ? '' : 's'}:\n${this.errors.map(error => increaseIndent(error.toString(root), 2)).join('\n')}`;
7982
}
8083

8184
public static isErrorResult(arg: any): arg is ErrorResult {

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typed-validation",
3-
"version": "0.7.2",
3+
"version": "0.7.3",
44
"description": "Validate Objects Against TypeScript Interfaces",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

0 commit comments

Comments
 (0)