UNPKG

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.

128 lines (106 loc) 5.34 kB
import { Equals } from "../helpers/equals"; import { Finite } from "../helpers/finite"; import { Integer } from "../helpers/integer"; import { Max } from "../helpers/max"; import { Min } from "../helpers/min"; import { MultipleOf } from "../helpers/multipleOf"; import { Negative } from "../helpers/negative"; import { NotEquals } from "../helpers/notEquals"; import { Positive } from "../helpers/positive"; import { SafeInteger } from "../helpers/safeInteger"; import { ValNumberOptions } from "../types/dv/dv-number"; import { ValidationError } from "./error/validation.error"; import { registerValidation } from "./register.validation"; export function DvNumber(options: ValNumberOptions = {}) { const { min, max, positive, negative, multipleOf, equals, notEquals, finite, safe, integer, optional = false, empty = false, null: allowNull = false, } = options; // Valores padrão e mensagens const minValue = typeof min === "object" ? min.value : min; const minMessage = typeof min === "object" ? min.message : `Number must be greater than or equal to ${minValue}`; const maxValue = typeof max === "object" ? max.value : max; const maxMessage = typeof max === "object" ? max.message : `Number must be less than or equal to ${maxValue}`; const positiveValue = typeof positive === "object" ? positive.value : positive; const positiveMessage = typeof positive === "object" ? positive.message : `The number must be positive`; const negativeValue = typeof negative === "object" ? negative.value : negative; const negativeMessage = typeof negative === "object" ? negative.message : `The number must be negative`; const multipleOfValue = typeof multipleOf === "object" ? multipleOf.value : multipleOf; const multipleOfMessage = typeof multipleOf === "object" ? multipleOf.message : `Number must be a multiple of ${multipleOfValue}`; const equalsValue = typeof equals === "object" ? equals.value : equals; const equalsMessage = typeof equals === "object" ? equals.message : `Number must be equal to ${equalsValue}`; const notEqualsValue = typeof notEquals === "object" ? notEquals.value : notEquals; const notEqualsMessage = typeof notEquals === "object" ? notEquals.message : `Number cannot be equal to ${notEqualsValue}`; if (optional && empty) { throw new Error("The 'optional' and 'empty' options cannot be used together."); } if (optional && allowNull) { throw new Error("The 'optional' and 'null' options cannot be used together."); } if (empty && allowNull) { throw new Error("The 'empty' and 'null' options cannot be used together."); } if (positive && negative) { throw new Error("The options 'positive' and 'negative' cannot be used together."); } if (equals !== undefined && notEquals !== undefined) { throw new Error("The 'equals' and 'notEquals' options cannot be used together."); } if (minValue !== undefined && maxValue !== undefined && minValue > maxValue) { throw new Error("The minimum value cannot be greater than the maximum value."); } if ( multipleOfValue && minValue !== undefined && minValue % multipleOfValue !== 0 && maxValue !== undefined && maxValue % multipleOfValue !== 0 ) { throw new Error(`Number must be a multiple of ${multipleOfValue}, but the minimum or maximum value conflicts.`); } return function (target: any, propertyKey: string) { const alreadyApplied = Reflect.getMetadata("valnumber:applied", target, propertyKey); if (alreadyApplied) { throw new Error(`The @ValNumber decorator has already been applied to the field "${propertyKey}"`); } Reflect.defineMetadata("valnumber:applied", true, target, propertyKey); registerValidation(target, propertyKey, (value: any) => { const isNull = value === null; const isUndefined = value === undefined; const isEmptyString = value === ""; if ((optional && (isUndefined || isEmptyString || isNull)) || (empty && isEmptyString) || (allowNull && isNull)) { return; } if (typeof value !== "number" || isNaN(value)) { throw new ValidationError(`The "${propertyKey}" field must be a number`); } }); if (integer) { const message = typeof integer === "string" ? integer : `The "${propertyKey}" field must be an integer`; Integer(message)(target, propertyKey); } // Validações adicionais if (min !== undefined) Min(minValue!, minMessage)(target, propertyKey); if (max !== undefined) Max(maxValue!, maxMessage)(target, propertyKey); if (positiveValue) Positive(positiveMessage)(target, propertyKey); if (negativeValue) Negative(negativeMessage)(target, propertyKey); if (multipleOfValue) MultipleOf(multipleOfValue, multipleOfMessage)(target, propertyKey); if (equalsValue !== undefined) Equals(equalsValue, equalsMessage)(target, propertyKey); if (notEqualsValue !== undefined) NotEquals(notEqualsValue, notEqualsMessage)(target, propertyKey); if (finite) Finite("The number must be finite")(target, propertyKey); if (safe) SafeInteger("The number must be safe integer")(target, propertyKey); }; }