joiful
Version:
TypeScript Declarative Validation. Decorate your class properties to validate them using Joi.
179 lines • 7.23 kB
JavaScript
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
;