Skip to content

Commit a055bba

Browse files
authored
feat: support ES6 Map and Set for regular validators with each o… (#430)
Close #428
1 parent d6816ac commit a055bba

File tree

4 files changed

+438
-121
lines changed

4 files changed

+438
-121
lines changed

Diff for: src/utils.ts

+10
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,13 @@
33
export function isPromise<T = any>(p: any): p is Promise<T> {
44
return p !== null && typeof p === "object" && typeof p.then === "function";
55
}
6+
7+
/**
8+
* Convert Map, Set to Array
9+
*/
10+
export function convertToArray<T>(val: Array<T> | Set<T> | Map<any, T>): Array<T> {
11+
if (val instanceof Map) {
12+
return Array.from(val.values());
13+
}
14+
return Array.isArray(val) ? val : Array.from(val);
15+
}

Diff for: src/validation/ValidationExecutor.ts

+12-26
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {ValidationTypes} from "./ValidationTypes";
88
import {ConstraintMetadata} from "../metadata/ConstraintMetadata";
99
import {ValidationArguments} from "./ValidationArguments";
1010
import {ValidationUtils} from "./ValidationUtils";
11-
import {isPromise} from "../utils";
11+
import {isPromise, convertToArray} from "../utils";
1212

1313
/**
1414
* Executes validation over given object.
@@ -225,8 +225,9 @@ export class ValidationExecutor {
225225
return metadatas
226226
.filter(metadata => {
227227
if (metadata.each) {
228-
if (value instanceof Array) {
229-
return !value.every((subValue: any) => this.validator.validateValueByMetadata(subValue, metadata));
228+
if (value instanceof Array || value instanceof Set || value instanceof Map) {
229+
const arrayValue = convertToArray(value);
230+
return !arrayValue.every((subValue: any) => this.validator.validateValueByMetadata(subValue, metadata));
230231
}
231232

232233
} else {
@@ -259,7 +260,7 @@ export class ValidationExecutor {
259260
constraints: metadata.constraints
260261
};
261262

262-
if (!metadata.each || !(value instanceof Array)) {
263+
if (!metadata.each || !(value instanceof Array || value instanceof Set || value instanceof Map)) {
263264
const validatedValue = customConstraintMetadata.instance.validate(value, validationArguments);
264265
if (isPromise(validatedValue)) {
265266
const promise = validatedValue.then(isValid => {
@@ -279,8 +280,10 @@ export class ValidationExecutor {
279280
return;
280281
}
281282

283+
// convert set and map into array
284+
const arrayValue = convertToArray(value);
282285
// Validation needs to be applied to each array item
283-
const validatedSubValues = value.map((subValue: any) => customConstraintMetadata.instance.validate(subValue, validationArguments));
286+
const validatedSubValues = arrayValue.map((subValue: any) => customConstraintMetadata.instance.validate(subValue, validationArguments));
284287
const validationIsAsync = validatedSubValues
285288
.some((validatedSubValue: boolean | Promise<boolean>) => isPromise(validatedSubValue));
286289

@@ -338,33 +341,16 @@ export class ValidationExecutor {
338341

339342
const targetSchema = typeof metadata.target === "string" ? metadata.target as string : undefined;
340343

341-
if (value instanceof Array) {
342-
value.forEach((subValue: any, index: number) => {
344+
if (value instanceof Array || value instanceof Set || value instanceof Map) {
345+
// Treats Set as an array - as index of Set value is value itself and it is common case to have Object as value
346+
const arrayLikeValue = value instanceof Set ? Array.from(value) : value;
347+
arrayLikeValue.forEach((subValue: any, index: any) => {
343348
const validationError = this.generateValidationError(value, subValue, index.toString());
344349
errors.push(validationError);
345350

346351
this.execute(subValue, targetSchema, validationError.children);
347352
});
348353

349-
} else if (value instanceof Set) {
350-
let index = 0;
351-
value.forEach((subValue: any) => {
352-
const validationError = this.generateValidationError(value, subValue, index.toString());
353-
errors.push(validationError);
354-
355-
this.execute(subValue, targetSchema, validationError.children);
356-
357-
++index;
358-
});
359-
360-
} else if (value instanceof Map) {
361-
value.forEach((subValue: any, key: any) => {
362-
const validationError = this.generateValidationError(value, subValue, key.toString());
363-
errors.push(validationError);
364-
365-
this.execute(subValue, targetSchema, validationError.children);
366-
});
367-
368354
} else if (value instanceof Object) {
369355
this.execute(value, targetSchema, errors);
370356

0 commit comments

Comments
 (0)