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.
63 lines (62 loc) • 2.84 kB
JavaScript
import { Optional } from "../helpers/optional";
import { ID_PATTERNS } from "../types/dv/dv-id";
import { ValidationError } from "./error/validation.error";
import { registerValidation } from "./register.validation";
import { skipValidation } from "./skip/skip.validation";
export function DvId(options = {}) {
const { type, optional = false, empty = false, null: allowNull = false, regex } = options;
if (optional && allowNull) {
throw new Error("The 'optional' and 'null' options cannot be used simultaneously.");
}
if (empty && type) {
throw new Error("The 'empty' option cannot be used with the defined ID type.");
}
if (regex && type) {
throw new Error("It is not recommended to use 'regex' and 'type' at the same time. Choose only one.");
}
return function (target, propertyKey) {
const alreadyApplied = Reflect.getMetadata("dvid:applied", target, propertyKey);
if (alreadyApplied) {
throw new Error(`The @DvId decorator has already been applied to the field "${propertyKey}".`);
}
Reflect.defineMetadata("dvid:applied", true, target, propertyKey);
registerValidation(target, propertyKey, (value) => {
if (skipValidation(value, {
optional: typeof optional === "object" ? optional : optional,
null: typeof allowNull === "object" ? allowNull : allowNull,
empty: typeof empty === "object" ? empty : empty,
}))
return;
if (typeof value !== "string" && typeof value !== "number") {
throw new ValidationError(`The "${propertyKey}" field must be a valid ID (string or number).`);
}
const strValue = String(value);
if (type) {
const pattern = ID_PATTERNS[type];
if (!pattern) {
throw new Error(`ID type "${type}" is not supported.`);
}
if (!pattern.test(strValue)) {
throw new ValidationError(`The field "${propertyKey}" is not a valid ${type}.`);
}
}
if (regex) {
let pattern;
let message = `The field "${propertyKey}" does not match the required pattern.`;
if (typeof regex === "string" || regex instanceof RegExp) {
pattern = new RegExp(regex);
}
else {
pattern = new RegExp(regex.value);
if (regex.message)
message = regex.message;
}
if (!pattern.test(strValue)) {
throw new ValidationError(message);
}
}
});
if (optional)
Optional()(target, propertyKey);
};
}