UNPKG

class-validator

Version:

Class-based validation with Typescript / ES6 / ES5 using decorators or validation schemas. Supports both node.js and browser

200 lines (198 loc) 10.8 kB
"use strict"; var ValidationError_1 = require("./ValidationError"); var MetadataStorage_1 = require("../metadata/MetadataStorage"); var index_1 = require("../index"); var ValidationTypes_1 = require("./ValidationTypes"); var ValidationUtils_1 = require("./ValidationUtils"); /** * Executes validation over given object. */ var ValidationExecutor = (function () { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- function ValidationExecutor(validator, validatorOptions) { this.validator = validator; this.validatorOptions = validatorOptions; // ------------------------------------------------------------------------- // Properties // ------------------------------------------------------------------------- this.awaitingPromises = []; this.ignoreAsyncValidations = false; // ------------------------------------------------------------------------- // Private Properties // ------------------------------------------------------------------------- this.metadataStorage = index_1.getFromContainer(MetadataStorage_1.MetadataStorage); } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- ValidationExecutor.prototype.execute = function (object, targetSchema, validationErrors) { var _this = this; var groups = this.validatorOptions ? this.validatorOptions.groups : undefined; var targetMetadatas = this.metadataStorage.getTargetValidationMetadatas(object.constructor, targetSchema, groups); var groupedMetadatas = this.metadataStorage.groupByPropertyName(targetMetadatas); Object.keys(groupedMetadatas).forEach(function (propertyName) { var value = object[propertyName]; var definedMetadatas = groupedMetadatas[propertyName].filter(function (metadata) { return metadata.type === ValidationTypes_1.ValidationTypes.IS_DEFINED; }); var metadatas = groupedMetadatas[propertyName].filter(function (metadata) { return metadata.type !== ValidationTypes_1.ValidationTypes.IS_DEFINED; }); var customValidationMetadatas = metadatas.filter(function (metadata) { return metadata.type === ValidationTypes_1.ValidationTypes.CUSTOM_VALIDATION; }); var nestedValidationMetadatas = metadatas.filter(function (metadata) { return metadata.type === ValidationTypes_1.ValidationTypes.NESTED_VALIDATION; }); var conditionalValidationMetadatas = metadatas.filter(function (metadata) { return metadata.type === ValidationTypes_1.ValidationTypes.CONDITIONAL_VALIDATION; }); var validationError = _this.generateValidationError(object, value, propertyName); validationErrors.push(validationError); var canValidate = _this.conditionalValidations(object, value, conditionalValidationMetadatas); if (!canValidate) { return; } // handle IS_DEFINED validation type the special way - it should work no matter skipMissingProperties is set or not _this.defaultValidations(object, value, definedMetadatas, validationError.constraints); if ((value === null || value === undefined) && _this.validatorOptions && _this.validatorOptions.skipMissingProperties === true) { return; } _this.defaultValidations(object, value, metadatas, validationError.constraints); _this.customValidations(object, value, customValidationMetadatas, validationError.constraints); _this.nestedValidations(value, nestedValidationMetadatas, validationError.children); }); }; ValidationExecutor.prototype.stripEmptyErrors = function (errors) { var _this = this; return errors.filter(function (error) { if (error.children) { error.children = _this.stripEmptyErrors(error.children); } if (Object.keys(error.constraints).length === 0) { if (error.children.length === 0) { return false; } else { delete error.constraints; } } return true; }); }; // ------------------------------------------------------------------------- // Private Methods // ------------------------------------------------------------------------- ValidationExecutor.prototype.generateValidationError = function (object, value, propertyName) { var validationError = new ValidationError_1.ValidationError(); if (!this.validatorOptions || !this.validatorOptions.validationError || this.validatorOptions.validationError.target === undefined || this.validatorOptions.validationError.target === true) validationError.target = object; if (!this.validatorOptions || !this.validatorOptions.validationError || this.validatorOptions.validationError.value === undefined || this.validatorOptions.validationError.value === true) validationError.value = value; validationError.property = propertyName; validationError.children = []; validationError.constraints = {}; return validationError; }; ValidationExecutor.prototype.conditionalValidations = function (object, value, metadatas) { return metadatas .map(function (metadata) { return metadata.constraints[0](object, value); }) .reduce(function (resultA, resultB) { return resultA && resultB; }, true); }; ValidationExecutor.prototype.defaultValidations = function (object, value, metadatas, errorMap) { var _this = this; return metadatas .filter(function (metadata) { if (metadata.each) { if (value instanceof Array) { return !value.every(function (subValue) { return _this.validator.validateValueByMetadata(subValue, metadata); }); } } else { return !_this.validator.validateValueByMetadata(value, metadata); } }) .forEach(function (metadata) { var _a = _this.createValidationError(object, value, metadata), key = _a[0], message = _a[1]; errorMap[key] = message; }); }; ValidationExecutor.prototype.customValidations = function (object, value, metadatas, errorMap) { var _this = this; metadatas.forEach(function (metadata) { index_1.getFromContainer(MetadataStorage_1.MetadataStorage) .getTargetValidatorConstraints(metadata.constraintCls) .forEach(function (customConstraintMetadata) { if (customConstraintMetadata.async && _this.ignoreAsyncValidations) return; var validationArguments = { targetName: object.constructor ? object.constructor.name : undefined, property: metadata.propertyName, object: object, value: value, constraints: metadata.constraints }; var validatedValue = customConstraintMetadata.instance.validate(value, validationArguments); if (validatedValue instanceof Promise) { var promise = validatedValue.then(function (isValid) { if (!isValid) { var _a = _this.createValidationError(object, value, metadata, customConstraintMetadata), type = _a[0], message = _a[1]; errorMap[type] = message; } }); _this.awaitingPromises.push(promise); } else { if (!validatedValue) { var _a = _this.createValidationError(object, value, metadata, customConstraintMetadata), type = _a[0], message = _a[1]; errorMap[type] = message; } } }); }); }; ValidationExecutor.prototype.nestedValidations = function (value, metadatas, errors) { var _this = this; metadatas.forEach(function (metadata) { if (metadata.type !== ValidationTypes_1.ValidationTypes.NESTED_VALIDATION) return; var targetSchema = typeof metadata.target === "string" ? metadata.target : undefined; if (value instanceof Array) { value.forEach(function (subValue, index) { var validationError = _this.generateValidationError(value, subValue, index.toString()); errors.push(validationError); _this.execute(subValue, targetSchema, validationError.children); }); } else if (value instanceof Object) { _this.execute(value, targetSchema, errors); } else { throw new Error("Only objects and arrays are supported to nested validation"); } }); }; ValidationExecutor.prototype.createValidationError = function (object, value, metadata, customValidatorMetadata) { var targetName = object.constructor ? object.constructor.name : undefined; var type = customValidatorMetadata && customValidatorMetadata.name ? customValidatorMetadata.name : metadata.type; var validationArguments = { targetName: targetName, property: metadata.propertyName, object: object, value: value, constraints: metadata.constraints }; var message = metadata.message; if (!metadata.message && (!this.validatorOptions || (this.validatorOptions && !this.validatorOptions.dismissDefaultMessages))) { if (customValidatorMetadata && customValidatorMetadata.instance.defaultMessage instanceof Function) { message = customValidatorMetadata.instance.defaultMessage(validationArguments); } if (!message) message = ValidationTypes_1.ValidationTypes.getMessage(type, metadata.each); } var messageString = ValidationUtils_1.ValidationUtils.replaceMessageSpecialTokens(message, validationArguments); return [type, messageString]; }; return ValidationExecutor; }()); exports.ValidationExecutor = ValidationExecutor; //# sourceMappingURL=ValidationExecutor.js.map