summaryrefslogtreecommitdiff
path: root/src/node_modules/class-validator/esm2015/validation/ValidationExecutor.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/node_modules/class-validator/esm2015/validation/ValidationExecutor.js')
-rw-r--r--src/node_modules/class-validator/esm2015/validation/ValidationExecutor.js316
1 files changed, 316 insertions, 0 deletions
diff --git a/src/node_modules/class-validator/esm2015/validation/ValidationExecutor.js b/src/node_modules/class-validator/esm2015/validation/ValidationExecutor.js
new file mode 100644
index 0000000..c2ff53d
--- /dev/null
+++ b/src/node_modules/class-validator/esm2015/validation/ValidationExecutor.js
@@ -0,0 +1,316 @@
+import { ValidationError } from "./ValidationError";
+import { ValidationTypes } from "./ValidationTypes";
+import { ValidationUtils } from "./ValidationUtils";
+import { isPromise, convertToArray } from "../utils";
+import { getMetadataStorage } from "../metadata/MetadataStorage";
+/**
+ * Executes validation over given object.
+ */
+export class ValidationExecutor {
+ // -------------------------------------------------------------------------
+ // Constructor
+ // -------------------------------------------------------------------------
+ constructor(validator, validatorOptions) {
+ this.validator = validator;
+ this.validatorOptions = validatorOptions;
+ // -------------------------------------------------------------------------
+ // Properties
+ // -------------------------------------------------------------------------
+ this.awaitingPromises = [];
+ this.ignoreAsyncValidations = false;
+ // -------------------------------------------------------------------------
+ // Private Properties
+ // -------------------------------------------------------------------------
+ this.metadataStorage = getMetadataStorage();
+ }
+ // -------------------------------------------------------------------------
+ // Public Methods
+ // -------------------------------------------------------------------------
+ execute(object, targetSchema, validationErrors) {
+ /**
+ * If there is no metadata registered it means possibly the dependencies are not flatterned and
+ * more than one instance is used.
+ *
+ * TODO: This needs proper handling, forcing to use the same container or some other proper solution.
+ */
+ if (!this.metadataStorage.hasValidationMetaData) {
+ console.warn(`No metadata found. There is more than once class-validator version installed probably. You need to flatten your dependencies.`);
+ }
+ const groups = this.validatorOptions ? this.validatorOptions.groups : undefined;
+ const targetMetadatas = this.metadataStorage.getTargetValidationMetadatas(object.constructor, targetSchema, groups);
+ const groupedMetadatas = this.metadataStorage.groupByPropertyName(targetMetadatas);
+ if (this.validatorOptions && this.validatorOptions.forbidUnknownValues && !targetMetadatas.length) {
+ const validationError = new ValidationError();
+ if (!this.validatorOptions ||
+ !this.validatorOptions.validationError ||
+ this.validatorOptions.validationError.target === undefined ||
+ this.validatorOptions.validationError.target === true)
+ validationError.target = object;
+ validationError.value = undefined;
+ validationError.property = undefined;
+ validationError.children = [];
+ validationError.constraints = { unknownValue: "an unknown value was passed to the validate function" };
+ validationErrors.push(validationError);
+ return;
+ }
+ if (this.validatorOptions && this.validatorOptions.whitelist)
+ this.whitelist(object, groupedMetadatas, validationErrors);
+ // General validation
+ Object.keys(groupedMetadatas).forEach(propertyName => {
+ const value = object[propertyName];
+ const definedMetadatas = groupedMetadatas[propertyName].filter(metadata => metadata.type === ValidationTypes.IS_DEFINED);
+ const metadatas = groupedMetadatas[propertyName].filter(metadata => metadata.type !== ValidationTypes.IS_DEFINED && metadata.type !== ValidationTypes.WHITELIST);
+ if (value instanceof Promise && metadatas.find(metadata => metadata.type === ValidationTypes.PROMISE_VALIDATION)) {
+ this.awaitingPromises.push(value.then((resolvedValue) => {
+ this.performValidations(object, resolvedValue, propertyName, definedMetadatas, metadatas, validationErrors);
+ }));
+ }
+ else {
+ this.performValidations(object, value, propertyName, definedMetadatas, metadatas, validationErrors);
+ }
+ });
+ }
+ whitelist(object, groupedMetadatas, validationErrors) {
+ let notAllowedProperties = [];
+ Object.keys(object).forEach(propertyName => {
+ // does this property have no metadata?
+ if (!groupedMetadatas[propertyName] || groupedMetadatas[propertyName].length === 0)
+ notAllowedProperties.push(propertyName);
+ });
+ if (notAllowedProperties.length > 0) {
+ if (this.validatorOptions && this.validatorOptions.forbidNonWhitelisted) {
+ // throw errors
+ notAllowedProperties.forEach(property => {
+ const validationError = this.generateValidationError(object, object[property], property);
+ validationError.constraints = { [ValidationTypes.WHITELIST]: `property ${property} should not exist` };
+ validationError.children = undefined;
+ validationErrors.push(validationError);
+ });
+ }
+ else {
+ // strip non allowed properties
+ notAllowedProperties.forEach(property => delete object[property]);
+ }
+ }
+ }
+ stripEmptyErrors(errors) {
+ return errors.filter(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
+ // -------------------------------------------------------------------------
+ performValidations(object, value, propertyName, definedMetadatas, metadatas, validationErrors) {
+ const customValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CUSTOM_VALIDATION);
+ const nestedValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.NESTED_VALIDATION);
+ const conditionalValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CONDITIONAL_VALIDATION);
+ const validationError = this.generateValidationError(object, value, propertyName);
+ validationErrors.push(validationError);
+ const canValidate = this.conditionalValidations(object, value, conditionalValidationMetadatas);
+ if (!canValidate) {
+ return;
+ }
+ // handle IS_DEFINED validation type the special way - it should work no matter skipUndefinedProperties/skipMissingProperties is set or not
+ this.customValidations(object, value, definedMetadatas, validationError);
+ this.mapContexts(object, value, definedMetadatas, validationError);
+ if (value === undefined && this.validatorOptions && this.validatorOptions.skipUndefinedProperties === true) {
+ return;
+ }
+ if (value === null && this.validatorOptions && this.validatorOptions.skipNullProperties === true) {
+ return;
+ }
+ if ((value === null || value === undefined) && this.validatorOptions && this.validatorOptions.skipMissingProperties === true) {
+ return;
+ }
+ this.customValidations(object, value, customValidationMetadatas, validationError);
+ this.nestedValidations(value, nestedValidationMetadatas, validationError.children);
+ this.mapContexts(object, value, metadatas, validationError);
+ this.mapContexts(object, value, customValidationMetadatas, validationError);
+ }
+ generateValidationError(object, value, propertyName) {
+ const validationError = new 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;
+ }
+ conditionalValidations(object, value, metadatas) {
+ return metadatas
+ .map(metadata => metadata.constraints[0](object, value))
+ .reduce((resultA, resultB) => resultA && resultB, true);
+ }
+ customValidations(object, value, metadatas, error) {
+ metadatas.forEach(metadata => {
+ this.metadataStorage
+ .getTargetValidatorConstraints(metadata.constraintCls)
+ .forEach(customConstraintMetadata => {
+ if (customConstraintMetadata.async && this.ignoreAsyncValidations)
+ return;
+ const validationArguments = {
+ targetName: object.constructor ? object.constructor.name : undefined,
+ property: metadata.propertyName,
+ object: object,
+ value: value,
+ constraints: metadata.constraints
+ };
+ if (!metadata.each || !(value instanceof Array || value instanceof Set || value instanceof Map)) {
+ const validatedValue = customConstraintMetadata.instance.validate(value, validationArguments);
+ if (isPromise(validatedValue)) {
+ const promise = validatedValue.then(isValid => {
+ if (!isValid) {
+ const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+ error.constraints[type] = message;
+ if (metadata.context) {
+ if (!error.contexts) {
+ error.contexts = {};
+ }
+ error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
+ }
+ }
+ });
+ this.awaitingPromises.push(promise);
+ }
+ else {
+ if (!validatedValue) {
+ const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+ error.constraints[type] = message;
+ }
+ }
+ return;
+ }
+ // convert set and map into array
+ const arrayValue = convertToArray(value);
+ // Validation needs to be applied to each array item
+ const validatedSubValues = arrayValue.map((subValue) => customConstraintMetadata.instance.validate(subValue, validationArguments));
+ const validationIsAsync = validatedSubValues
+ .some((validatedSubValue) => isPromise(validatedSubValue));
+ if (validationIsAsync) {
+ // Wrap plain values (if any) in promises, so that all are async
+ const asyncValidatedSubValues = validatedSubValues
+ .map((validatedSubValue) => isPromise(validatedSubValue) ? validatedSubValue : Promise.resolve(validatedSubValue));
+ const asyncValidationIsFinishedPromise = Promise.all(asyncValidatedSubValues)
+ .then((flatValidatedValues) => {
+ const validationResult = flatValidatedValues.every((isValid) => isValid);
+ if (!validationResult) {
+ const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+ error.constraints[type] = message;
+ if (metadata.context) {
+ if (!error.contexts) {
+ error.contexts = {};
+ }
+ error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
+ }
+ }
+ });
+ this.awaitingPromises.push(asyncValidationIsFinishedPromise);
+ return;
+ }
+ const validationResult = validatedSubValues.every((isValid) => isValid);
+ if (!validationResult) {
+ const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+ error.constraints[type] = message;
+ }
+ });
+ });
+ }
+ nestedValidations(value, metadatas, errors) {
+ if (value === void 0) {
+ return;
+ }
+ metadatas.forEach(metadata => {
+ if (metadata.type !== ValidationTypes.NESTED_VALIDATION &&
+ metadata.type !== ValidationTypes.PROMISE_VALIDATION) {
+ return;
+ }
+ if (value instanceof Array || value instanceof Set || value instanceof Map) {
+ // Treats Set as an array - as index of Set value is value itself and it is common case to have Object as value
+ const arrayLikeValue = value instanceof Set ? Array.from(value) : value;
+ arrayLikeValue.forEach((subValue, index) => {
+ this.performValidations(value, subValue, index.toString(), [], metadatas, errors);
+ });
+ }
+ else if (value instanceof Object) {
+ const targetSchema = typeof metadata.target === "string" ? metadata.target : metadata.target.name;
+ this.execute(value, targetSchema, errors);
+ }
+ else {
+ const error = new ValidationError();
+ error.value = value;
+ error.property = metadata.propertyName;
+ error.target = metadata.target;
+ const [type, message] = this.createValidationError(metadata.target, value, metadata);
+ error.constraints = {
+ [type]: message
+ };
+ errors.push(error);
+ }
+ });
+ }
+ mapContexts(object, value, metadatas, error) {
+ return metadatas
+ .forEach(metadata => {
+ if (metadata.context) {
+ let customConstraint;
+ if (metadata.type === ValidationTypes.CUSTOM_VALIDATION) {
+ const customConstraints = this.metadataStorage.getTargetValidatorConstraints(metadata.constraintCls);
+ customConstraint = customConstraints[0];
+ }
+ const type = this.getConstraintType(metadata, customConstraint);
+ if (error.constraints[type]) {
+ if (!error.contexts) {
+ error.contexts = {};
+ }
+ error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
+ }
+ }
+ });
+ }
+ createValidationError(object, value, metadata, customValidatorMetadata) {
+ const targetName = object.constructor ? object.constructor.name : undefined;
+ const type = this.getConstraintType(metadata, customValidatorMetadata);
+ const validationArguments = {
+ targetName: targetName,
+ property: metadata.propertyName,
+ object: object,
+ value: value,
+ constraints: metadata.constraints
+ };
+ let 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);
+ }
+ }
+ const messageString = ValidationUtils.replaceMessageSpecialTokens(message, validationArguments);
+ return [type, messageString];
+ }
+ getConstraintType(metadata, customValidatorMetadata) {
+ const type = customValidatorMetadata && customValidatorMetadata.name ? customValidatorMetadata.name : metadata.type;
+ return type;
+ }
+}
+
+//# sourceMappingURL=ValidationExecutor.js.map