UNPKG

@ts-fluentvalidation/core

Version:

Core library of @ts-fluentvalidation providing validations in a fluent syntax.

239 lines 12.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createValidator = createValidator; const tslib_1 = require("tslib"); const errors_1 = require("./errors"); const validate_async_1 = require("./functions/validate-async"); const validate_sync_1 = require("./functions/validate-sync"); const result_1 = require("./result"); const ts_helpers_1 = require("./types/ts-helpers"); const validation_context_1 = require("./validation-context"); /** * Creates a new validator with the given configuration. * * @param config - The configuration for the validator. */ function createValidator(config) { const _validations = {}; const keyValidations = []; const _defaultConfig = { cascadeMode: 'Continue' }; const validatorConfig = Object.assign(Object.assign({}, _defaultConfig), (config !== null && config !== void 0 ? config : {})); let preValidation = () => true; /** * Updates the validators validations dictionary. Called after validations for a given key were added. * * @param validator - The validator to update. */ function updateValidations(validator) { validator.validations = keyValidations.reduce((acc, { key, validations: keyValidations }) => { if (!acc[key]) { acc[key] = []; } acc[key].push(...keyValidations); return acc; }, {}); } return { validations: _validations, ruleFor(key, ...cascadeModeAndValidations) { var _a; const cascadeMode = typeof cascadeModeAndValidations[0] === 'string' ? cascadeModeAndValidations.shift() : undefined; const validations = cascadeModeAndValidations; overridePropertyNames(validations); applyConditions(...validations); keyValidations.push({ key, validations: validations, cascadeMode: (_a = cascadeMode !== null && cascadeMode !== void 0 ? cascadeMode : validatorConfig.propertyCascadeMode) !== null && _a !== void 0 ? _a : 'Continue' }); updateValidations(this); return this; }, ruleForEach(key, ...cascadeModeAndValidations) { var _a; const cascadeMode = typeof cascadeModeAndValidations[0] === 'string' ? cascadeModeAndValidations.shift() : undefined; const validations = cascadeModeAndValidations; overridePropertyNames(validations); applyConditions(...validations); validations.forEach(v => { v.metadata.isEach = true; }); keyValidations.push({ key, validations: validations, cascadeMode: (_a = cascadeMode !== null && cascadeMode !== void 0 ? cascadeMode : validatorConfig.propertyCascadeMode) !== null && _a !== void 0 ? _a : 'Continue' }); updateValidations(this); return this; }, include(validator) { Object.entries(validator.validations).forEach(([key, validations]) => { var _a; keyValidations.push({ key: key, validations: validations, cascadeMode: (_a = validatorConfig.propertyCascadeMode) !== null && _a !== void 0 ? _a : 'Continue' }); updateValidations(this); }); return this; }, preValidate(preValidationFunc) { preValidation = preValidationFunc; return this; }, when(predicate, callback) { const validator = Object.assign({}, this); const conditionalValidator = callback(createValidator()); const conditionalValidations = conditionalValidator.validations; Object.entries(conditionalValidations).forEach(([key, validations]) => { var _a; keyValidations.push({ key: key, validations: validations.map(v => v.when(predicate)), cascadeMode: (_a = validatorConfig.propertyCascadeMode) !== null && _a !== void 0 ? _a : 'Continue' }); }); updateValidations(validator); return Object.assign(Object.assign({}, validator), { otherwise(callback) { const otherwiseValidator = callback(createValidator()); const otherwiseValidations = otherwiseValidator.validations; Object.entries(otherwiseValidations).forEach(([key, validations]) => { var _a; keyValidations.push({ key: key, validations: validations.map(v => v.when((m, c) => !predicate(m, c))), cascadeMode: (_a = validatorConfig.propertyCascadeMode) !== null && _a !== void 0 ? _a : 'Continue' }); }); updateValidations(validator); return Object.assign({}, validator); } }); }, whenAsync(predicate, callback) { const validator = Object.assign({}, this); const conditionalValidator = callback(createValidator()); const conditionalValidations = conditionalValidator.validations; Object.entries(conditionalValidations).forEach(([key, validations]) => { var _a; keyValidations.push({ key: key, validations: validations.map(v => v.whenAsync(predicate)), cascadeMode: (_a = validatorConfig.propertyCascadeMode) !== null && _a !== void 0 ? _a : 'Continue' }); }); updateValidations(validator); return Object.assign(Object.assign({}, validator), { otherwise(callback) { const otherwiseValidator = callback(createValidator()); const otherwiseValidations = otherwiseValidator.validations; Object.entries(otherwiseValidations).forEach(([key, validations]) => { var _a; keyValidations.push({ key: key, validations: validations.map(v => v.whenAsync((m, c) => tslib_1.__awaiter(this, void 0, void 0, function* () { return !(yield predicate(m, c)); }))), cascadeMode: (_a = validatorConfig.propertyCascadeMode) !== null && _a !== void 0 ? _a : 'Continue' }); }); updateValidations(validator); return Object.assign({}, validator); } }); }, unless(predicate, callback) { return this.when((model, validationContext) => !predicate(model, validationContext), callback); }, unlessAsync(predicate, callback) { return this.whenAsync((model, validationContext) => tslib_1.__awaiter(this, void 0, void 0, function* () { return !(yield predicate(model, validationContext)); }), callback); }, validate(modelOrContext, config) { config === null || config === void 0 ? void 0 : config(validatorConfig); const context = getValidationContext(modelOrContext); const preValidationResult = (0, result_1.createValidationResult)(context.failures); const shouldContinue = preValidation(context, preValidationResult); if (!shouldContinue) { if (preValidationResult.isValid === false && validatorConfig.throwOnFailures) { throwValidationError(preValidationResult); } return (0, result_1.createValidationResult)(preValidationResult.failures); } (0, validate_sync_1.validateSync)(context, keyValidations, validatorConfig); return (0, result_1.createValidationResult)(context.failures); }, validateAsync(modelOrContext, config) { return tslib_1.__awaiter(this, void 0, void 0, function* () { config === null || config === void 0 ? void 0 : config(validatorConfig); const context = getValidationContext(modelOrContext); const preValidationResult = (0, result_1.createValidationResult)(context.failures); const shouldContinue = preValidation(context, preValidationResult); if (!shouldContinue) { if (preValidationResult.isValid === false && validatorConfig.throwOnFailures) { throwValidationError(preValidationResult); } return (0, result_1.createValidationResult)(preValidationResult.failures); } yield (0, validate_async_1.validateAsync)(context, keyValidations, validatorConfig); return (0, result_1.createValidationResult)(context.failures); }); }, validateAndThrow(model) { return this.validate(model, c => (c.throwOnFailures = true)); }, validateAndThrowAsync(model) { return tslib_1.__awaiter(this, void 0, void 0, function* () { return yield this.validateAsync(model, c => (c.throwOnFailures = true)); }); } }; } /** * Applies conditions if neccesary. * * @template TModel - The type of the model being validated. * @template TValue - The type of the value being validated. * @param validations - The validations to apply the conditions to. * @returns The updated validator. */ function applyConditions(...validations) { // the latest validation to add which contains `ApplyConditionTo === 'AllValidators'` or none which will default to 'AllValidators' // will aplly its condition to all preceding validators from the same `ruleFor` call const lastConditionValidation = (0, ts_helpers_1.getLastElement)(validations, v => v.metadata.condition !== undefined && v.metadata.applyConditionTo !== 'CurrentValidator'); if (lastConditionValidation) { const index = validations.indexOf(lastConditionValidation); const condition = lastConditionValidation.metadata.condition; if (condition) { for (let i = 0; i < index; i++) { validations[i].metadata.condition = condition; } } } const lastAsyncConditionValidation = (0, ts_helpers_1.getLastElement)(validations, v => v.metadata.asyncCondition !== undefined && v.metadata.applyAsyncConditionTo !== 'CurrentValidator'); if (lastAsyncConditionValidation) { const index = validations.indexOf(lastAsyncConditionValidation); const asyncCondition = lastAsyncConditionValidation.metadata.asyncCondition; if (asyncCondition) { for (let i = 0; i < index; i++) { validations[i].metadata.asyncCondition = asyncCondition; } } } } function overridePropertyNames(keyValidations) { var _a; const lastPropertyNameOverride = (0, ts_helpers_1.getLastElement)(keyValidations, v => v.metadata.propertyNameOverride !== undefined); if ((_a = lastPropertyNameOverride === null || lastPropertyNameOverride === void 0 ? void 0 : lastPropertyNameOverride.metadata) === null || _a === void 0 ? void 0 : _a.propertyNameOverride) { const propertyNameOverride = lastPropertyNameOverride.metadata.propertyNameOverride; keyValidations.forEach(v => { if (v.metadata.propertyNameOverride === undefined) { v.metadata.propertyNameOverride = propertyNameOverride; } }); } } function getValidationContext(modelOrContext) { return (0, validation_context_1.isValidationContext)(modelOrContext) ? modelOrContext : (0, validation_context_1.createValidationContext)(modelOrContext); } function throwValidationError(validationResult) { throw new errors_1.ValidationError(validationResult.failures); } //# sourceMappingURL=create-validator.js.map