UNPKG

@nestjs/common

Version:

Nest - modern, fast, powerful node.js web framework (@common)

96 lines (95 loc) 4.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const decorators_1 = require("../decorators"); const core_1 = require("../decorators/core"); const index_1 = require("../index"); const load_package_util_1 = require("../utils/load-package.util"); const shared_utils_1 = require("../utils/shared.utils"); let classValidator = {}; let classTransformer = {}; let ValidationPipe = class ValidationPipe { constructor(options) { options = options || {}; const { transform, disableErrorMessages, transformOptions, validateCustomDecorators } = options, validatorOptions = tslib_1.__rest(options, ["transform", "disableErrorMessages", "transformOptions", "validateCustomDecorators"]); this.isTransformEnabled = !!transform; this.validatorOptions = validatorOptions; this.transformOptions = transformOptions; this.isDetailedOutputDisabled = disableErrorMessages; this.validateCustomDecorators = validateCustomDecorators || false; this.exceptionFactory = options.exceptionFactory || (errors => new index_1.BadRequestException(this.isDetailedOutputDisabled ? undefined : errors)); classValidator = load_package_util_1.loadPackage('class-validator', 'ValidationPipe', () => require('class-validator')); classTransformer = load_package_util_1.loadPackage('class-transformer', 'ValidationPipe', () => require('class-transformer')); } async transform(value, metadata) { const { metatype } = metadata; if (!metatype || !this.toValidate(metadata)) { return value; } const originalValue = value; value = this.toEmptyIfNil(value); const isNil = value !== originalValue; const isPrimitive = this.isPrimitive(value); this.stripProtoKeys(value); let entity = classTransformer.plainToClass(metatype, value, this.transformOptions); const originalEntity = entity; const isCtorNotEqual = entity.constructor !== metatype; if (isCtorNotEqual && !isPrimitive) { entity.constructor = metatype; } else if (isCtorNotEqual) { // when "entity" is a primitive value, we have to temporarily // replace the entity to perform the validation against the original // metatype defined inside the handler entity = { constructor: metatype }; } const errors = await classValidator.validate(entity, this.validatorOptions); if (errors.length > 0) { throw this.exceptionFactory(errors); } if (isPrimitive) { // if the value is a primitive value and the validation process has been successfully completed // we have to revert the original value passed through the pipe entity = originalEntity; } if (this.isTransformEnabled) { return entity; } if (isNil) { // if the value was originally undefined or null, revert it back return originalValue; } return Object.keys(this.validatorOptions).length > 0 ? classTransformer.classToPlain(entity, this.transformOptions) : value; } toValidate(metadata) { const { metatype, type } = metadata; if (type === 'custom' && !this.validateCustomDecorators) { return false; } const types = [String, Boolean, Number, Array, Object]; return !types.some(t => metatype === t) && !shared_utils_1.isNil(metatype); } toEmptyIfNil(value) { return shared_utils_1.isNil(value) ? {} : value; } stripProtoKeys(value) { delete value.__proto__; const keys = Object.keys(value); keys .filter(key => typeof value[key] === 'object' && value[key]) .forEach(key => this.stripProtoKeys(value[key])); } isPrimitive(value) { return ['number', 'boolean', 'string'].includes(typeof value); } }; ValidationPipe = tslib_1.__decorate([ core_1.Injectable(), tslib_1.__param(0, decorators_1.Optional()), tslib_1.__metadata("design:paramtypes", [Object]) ], ValidationPipe); exports.ValidationPipe = ValidationPipe;