UNPKG

joiful

Version:

TypeScript Declarative Validation. Decorate your class properties to validate them using Joi.

179 lines 7.23 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createValidatePropertyDecorator = exports.Validator = exports.InvalidValidationTarget = exports.isValidationFail = exports.isValidationPass = exports.MultipleValidationError = exports.NoValidationSchemaForClassError = void 0; const core_1 = require("./core"); const Joi = require("joi"); require("reflect-metadata"); class NoValidationSchemaForClassError extends Error { constructor(Class) { const className = Class && Class.name || ''; const classNameText = className ? ` ${className}` : ''; const message = `No validation schema was found for class${classNameText}. Did you forget to decorate the class?`; super(message); } } exports.NoValidationSchemaForClassError = NoValidationSchemaForClassError; class MultipleValidationError extends Error { constructor(errors) { super(); this.errors = errors; Object.setPrototypeOf(this, MultipleValidationError.prototype); } } exports.MultipleValidationError = MultipleValidationError; /** * Returns true if validation result passed validation. * @param validationResult The validation result to test. */ function isValidationPass(validationResult) { return !validationResult.error; } exports.isValidationPass = isValidationPass; /** * Returns true if validation result failed validation. * @param validationResult The validation result to test. */ function isValidationFail(validationResult) { return !!validationResult.error; } exports.isValidationFail = isValidationFail; class InvalidValidationTarget extends Error { constructor() { super('Cannot validate null or undefined'); } } exports.InvalidValidationTarget = InvalidValidationTarget; class Validator { constructor(defaultOptions) { this.defaultOptions = defaultOptions; /** * Validates an instance of a decorated class. * @param target Instance of decorated class to validate. * @param options Optional validation options to use. These override any default options. */ this.validate = (target, options) => { if (target === null || target === undefined) { throw new InvalidValidationTarget(); } return this.validateAsClass(target, target.constructor, options); }; /** * Validates a plain old javascript object against a decorated class. * @param target Object to validate. * @param clz Decorated class to validate against. * @param options Optional validation options to use. These override any default options. */ this.validateAsClass = (target, Class, options = this.defaultOptions) => { if (target === null || target === undefined) { throw new InvalidValidationTarget(); } const { joi, joiOptions } = this.extractOptions(options); const classSchema = core_1.getJoiSchema(Class, joi); if (!classSchema) { throw new NoValidationSchemaForClassError(Class); } const result = joiOptions ? classSchema.validate(target, joiOptions) : classSchema.validate(target); return { error: (result.error ? result.error : null), errors: null, warning: null, value: result.value, }; }; /** * Validates an array of plain old javascript objects against a decorated class. * @param target Objects to validate. * @param clz Decorated class to validate against. * @param options Optional validation options to use. These override any default options. */ this.validateArrayAsClass = (target, Class, options = this.defaultOptions) => { if (target === null || target === undefined) { throw new InvalidValidationTarget(); } const { joi, joiOptions } = this.extractOptions(options); const classSchema = core_1.getJoiSchema(Class, joi); if (!classSchema) { throw new NoValidationSchemaForClassError(Class); } const arraySchema = joi.array().items(classSchema); const result = joiOptions ? arraySchema.validate(target, joiOptions) : arraySchema.validate(target); return { error: (result.error ? result.error : null), errors: null, warning: null, value: result.value, }; }; } /** * Issue #117: Joi's `validate()` method dies when we pass it our own validation options, so we need to strip it * out. * @url https://github.com/joiful-ts/joiful/issues/117 */ extractOptions(options) { if (!options) { return { joi: Joi, }; } else { const { joi } = options, rest = __rest(options, ["joi"]); return { joi: joi || Joi, joiOptions: rest, }; } } } exports.Validator = Validator; const createValidatePropertyDecorator = (options) => { const validator = (options || { validator: undefined }).validator || new Validator(); return (target, propertyKey, descriptor) => { const original = descriptor.value; descriptor.value = function (...args) { const types = Reflect.getMetadata('design:paramtypes', target, propertyKey); const failures = []; const newArgs = []; for (let i = 0; i < args.length; i++) { const arg = args[i]; const argType = types[i]; // TODO: Use `getWorkingSchema`? const workingSchema = Reflect.getMetadata(core_1.WORKING_SCHEMA_KEY, argType.prototype); if (workingSchema) { let result = validator.validateAsClass(arg, argType); if (result.error != null) { failures.push(result.error); } newArgs.push(result.value); } else { newArgs.push(arg); } } if (failures.length > 0) { throw new MultipleValidationError(failures); } else { return original.apply(this, newArgs); } }; return descriptor; }; }; exports.createValidatePropertyDecorator = createValidatePropertyDecorator; //# sourceMappingURL=validation.js.map