@nestjs/common
Version:
Decorators, pipes, exceptions and utilities for NestJS applications: @Controller(), @Injectable(), @Body(), ValidationPipe, HttpException and more.
123 lines (122 loc) • 5.08 kB
JavaScript
import { __decorate, __metadata, __param } from "tslib";
import { Injectable } from '../decorators/core/injectable.decorator.js';
import { Optional } from '../decorators/core/optional.decorator.js';
import { HttpStatus } from '../enums/http-status.enum.js';
import { HttpErrorByCode, } from '../utils/http-error-by-code.util.js';
import { isObject } from '../utils/shared.utils.js';
import { stripProtoKeys } from '../utils/strip-proto-keys.util.js';
import { OMITTED_ERRORS_MESSAGE, resolveMaxErrorMessagesLength, } from './validation-errors.constants.js';
/**
* Defines the built-in StandardSchemaValidation Pipe.
*
* Uses a standard schema object (conforming to the Standard Schema spec)
* attached to the parameter metadata to validate incoming values.
*
* @see [Standard Schema](https://github.com/standard-schema/standard-schema)
*
* @publicApi
*/
let StandardSchemaValidationPipe = class StandardSchemaValidationPipe {
options;
isTransformEnabled;
validateCustomDecorators;
validateOptions;
maxErrorMessagesLength;
exceptionFactory;
constructor(options) {
this.options = options;
const { transform = true, validateCustomDecorators = false, validateOptions, exceptionFactory, errorHttpStatusCode = HttpStatus.BAD_REQUEST, maxErrorMessagesLength, } = options || {};
this.isTransformEnabled = transform;
this.validateCustomDecorators = validateCustomDecorators;
this.validateOptions = validateOptions;
this.maxErrorMessagesLength = resolveMaxErrorMessagesLength(maxErrorMessagesLength);
this.exceptionFactory =
exceptionFactory ||
(issues => {
const messages = this.formatIssueMessages(issues);
return new HttpErrorByCode[errorHttpStatusCode](messages);
});
}
/**
* Formats Standard Schema validation issues into a flat list of error messages.
* When an issue includes a path, the path is prefixed to the message.
* The issues that come after the first `maxErrorMessagesLength` characters
* of messages are left out, and a last message says so.
*/
formatIssueMessages(issues) {
const messages = [];
let remainingLength = this.maxErrorMessagesLength;
for (const issue of issues) {
if (remainingLength <= 0) {
// The issues past the limit are not formatted: how many there are is
// up to the validated value, and each of them repeats its whole path.
messages.push(OMITTED_ERRORS_MESSAGE);
break;
}
let message = issue.message;
if (issue.path?.length) {
const stringPath = issue.path
.map(segment => String(isObject(segment) ? segment.key : segment))
.join('.');
message = `${stringPath}: ${issue.message}`;
}
remainingLength -= String(message).length;
messages.push(message);
}
return messages;
}
/**
* Method that validates the incoming value against the standard schema
* provided in the parameter metadata.
*
* @param value currently processed route argument
* @param metadata contains metadata about the currently processed route argument
*/
async transform(value, metadata) {
const schema = metadata.schema;
if (!schema || !this.toValidate(metadata)) {
return value;
}
this.stripProtoKeys(value);
const result = await this.validate(value, schema, this.validateOptions);
if (result.issues) {
throw this.exceptionFactory(result.issues);
}
return this.isTransformEnabled ? result.value : value;
}
/**
* Determines whether validation should be performed for the given metadata.
* Skips validation for custom decorators unless `validateCustomDecorators` is enabled.
*
* @param metadata contains metadata about the currently processed route argument
* @returns `true` if validation should be performed
*/
toValidate(metadata) {
const { type } = metadata;
if (type === 'custom' && !this.validateCustomDecorators) {
return false;
}
return true;
}
/**
* Validates a value against a standard schema.
* Can be overridden to customize validation behavior.
*
* @param value The value to validate
* @param schema The standard schema to validate against
* @param options Optional options forwarded to the schema's validate method
* @returns The validation result
*/
validate(value, schema, options) {
return schema['~standard'].validate(value, options);
}
stripProtoKeys(value) {
stripProtoKeys(value);
}
};
StandardSchemaValidationPipe = __decorate([
Injectable(),
__param(0, Optional()),
__metadata("design:paramtypes", [Object])
], StandardSchemaValidationPipe);
export { StandardSchemaValidationPipe };