decoval
Version:
DecoVal is a decorator-driven validation pattern that allows you to add validation rules directly to the properties of TypeScript classes, simplifying data control and increasing code readability and reusability.
44 lines (43 loc) • 2.42 kB
JavaScript
import { ValidationError } from "./error/validation.error";
import { registerValidation } from "./register.validation";
export function DvArray(options = {}) {
const { minLength = { value: 0, message: "The array must contain at least {minLength.value} elements." }, maxLength = { value: Infinity, message: "The array must contain at most {maxLength.value} elements." }, elementsType = { value: "any", message: "The array elements must be of type {elementsType.value}." }, allowedValues = {
value: [],
message: "The array elements must be one of the allowed values: {allowedValues.value.join(', ')}.",
}, message = "The array contains invalid elements.", } = options;
const interpolateMessage = (message, data) => {
return message.replace(/{([^}]+)}/g, (_, key) => data[key] || "");
};
return function (target, propertyKey) {
const alreadyApplied = Reflect.getMetadata("valarray:applied", target, propertyKey);
if (alreadyApplied) {
throw new Error(`The @ValArray decorator has already been applied to the field "${propertyKey}"`);
}
Reflect.defineMetadata("valarray:applied", true, target, propertyKey);
registerValidation(target, propertyKey, (value) => {
if (!Array.isArray(value)) {
throw new ValidationError(interpolateMessage(`The field "${propertyKey}" must be an array.`, {}));
}
if (value.length < minLength.value) {
throw new ValidationError(interpolateMessage(minLength.message, { minLength }));
}
if (value.length > maxLength.value) {
throw new ValidationError(interpolateMessage(maxLength.message, { maxLength }));
}
if (elementsType.value !== "any") {
for (const item of value) {
if (typeof item !== elementsType.value) {
throw new ValidationError(interpolateMessage(elementsType.message, { elementsType }));
}
}
}
if (allowedValues.value.length > 0) {
for (const item of value) {
if (!allowedValues.value.includes(item)) {
throw new ValidationError(interpolateMessage(allowedValues.message || message, { allowedValues }));
}
}
}
});
};
}