UNPKG

data-transfer-object

Version:

Data Transfer Object class built on `class-validator`.

112 lines (111 loc) 4.5 kB
var _a, _b; import { validate, validateSync } from 'class-validator'; import { ValidationException } from './validation-exception'; import { onValidationError } from './validation-error-handler'; // Strict options by default const defaultOpts = { whitelist: true, forbidNonWhitelisted: true, forbidUnknownValues: true, }; // Must use symbols for private properties so that they are not included in validation /** Cached validation errors from previous validation. */ const validationErrors = Symbol.for('validationErrors'); /** Whether this object has already been validated. */ const validated = Symbol.for('validated'); /** Pending validation promise, if any. */ const ongoingValidation = Symbol.for('ongoingValidation'); /** * Checks the input error list, and if non-empty, throws an error. * @param errors The error list to check against. */ function assertEmptyErrorList(errors) { if (errors.length) { if (!onValidationError) throw new ValidationException(errors); onValidationError(errors); throw new ValidationException(errors); } } /** * Creates a new data transfer object which will validate and reshape its input * data based on the validators of its own properties. Must be extended, should * not be instantiated on its own. */ export class DataTransferObject { /** * Constructs a new instance of a data transfer object with the given input. * @param data The input data to assign to this data transfer object. */ constructor(data) { /** Cached validation errors from previous validation. */ this[_a] = []; /** Whether this object has already been validated. */ this[_b] = false; Object.assign(this, data); } /** * Runs all synchronous validators on this object. * To run asynchronous validators as well, use `.getValidationErrorsAsync()`. * @param opts Options to pass to the validator system. */ getValidationErrors(opts) { if (this[validated]) return this[validationErrors]; this[validationErrors] = validateSync(this, { ...defaultOpts, ...opts }); this[validated] = true; return this[validationErrors]; } /** * Runs all synchronous and asynchronous validators on this object. * Always returns a promise. To validate synchronously, use `.getValidationErrors()`. * @param opts Options to pass to the validator system. */ async getValidationErrorsAsync(opts) { if (this[validated]) return this[validationErrors]; const ongoing = this[ongoingValidation]; if (ongoing) return ongoing; const newPromise = validate(this, { ...defaultOpts, ...opts }).then(errs => { this[validationErrors] = errs; this[validated] = true; this[ongoingValidation] = undefined; return errs; }); this[ongoingValidation] = newPromise; return newPromise; } /** * Validates this object (sync validators only), and returns its plain data if validations pass. * Otherwise, throws an error or runs the appropriate handler set with `setValidationErrorHandler()`. * * To run both sync and async validators, use `.validateAsync()`. * @param opts Options to pass to the validator system. */ validate(opts) { const errors = this.getValidationErrors(opts); assertEmptyErrorList(errors); return this.toJSON(); } /** * Validates this object asynchronously, and resolves to its plain data if validations pass. * Otherwise, rejects with an error or runs the appropriate handler set with `setValidationErrorHandler()`. * * To validate synchronously, use `.validate()`. * @param opts Options to pass to the validator system. */ async validateAsync(opts) { const errors = await this.getValidationErrorsAsync(opts); assertEmptyErrorList(errors); return this.toJSON(); } /** * Returns a JSON friendly object containing only data properties of this object (ie, no validation functions). * Automatically used by `JSON.stringify()`. */ toJSON() { return Object.fromEntries(Object.entries(this).filter(([_key, val]) => typeof val !== 'function')); } } _a = validationErrors, _b = validated;