UNPKG

@decaf-ts/decorator-validation

Version:
191 lines 7.4 kB
import { COMPARISON_ERROR_MESSAGES } from "./../../constants/index.js"; import { sf } from "./../../utils/index.js"; // /** // * Safely retrieves a nested property value from an object using a dot-notated path string. // * // * @template T - The expected return type of the property value. // * // * @param {Record<string, any>} obj - The source object to retrieve the value from. // * @param {string} path - A dot-separated string representing the path to the desired property (e.g., "user.address.street"). // * // * @returns {T} - The value found at the specified path // * // * @throws {Error} - Throws an error if the path is not a non-empty string or if any part of the path does not exist in the object. // * @memberOf module:decorator-validation // */ // export function getValueByPath<T>(obj: Record<string, any>, path: string): T { // if (typeof path !== "string" || !path.trim()) { // throw new Error(sf(COMPARISON_ERROR_MESSAGES.INVALID_PATH, path)); // } // // // Process parent directory access (../) // const parentAccessors = path.match(/\.\.\//g) || []; // const parentLevel = parentAccessors.length; // const cleanPath = path.replace(/\.\.\//g, ""); // // // Navigate up the parent chain // let currentContext: any = obj; // for (let i = 0; i < parentLevel; i++) { // if (!currentContext || typeof currentContext !== "object") { // throw new Error( // sf(COMPARISON_ERROR_MESSAGES.CONTEXT_NOT_OBJECT_COMPARISON, i + 1, path) // ); // } // // if (!currentContext[VALIDATION_PARENT_KEY]) { // throw new Error( // sf(COMPARISON_ERROR_MESSAGES.NO_PARENT_COMPARISON, i + 1, path) // ); // } // // currentContext = currentContext[VALIDATION_PARENT_KEY]; // } // // // Process dot notation path // const parts = cleanPath.split("."); // let currentValue: any = currentContext; // // for (const part of parts) { // if ( // currentValue !== null && // typeof currentValue === "object" && // part in currentValue // ) { // currentValue = (currentValue as Record<string, any>)[part]; // } else { // const errorMsgTemplate = // parentLevel === 0 // ? COMPARISON_ERROR_MESSAGES.PROPERTY_NOT_FOUND // : parentLevel === 1 // ? COMPARISON_ERROR_MESSAGES.PROPERTY_NOT_FOUND_ON_PARENT // : COMPARISON_ERROR_MESSAGES.PROPERTY_NOT_FOUND_AFTER_PARENT; // // throw new Error(sf(errorMsgTemplate, path, part, parentLevel)); // } // } // // return currentValue as T; // } const getTypeName = (value) => { if (value === null) return "null"; if (value instanceof Date) return "Date"; if (Number.isNaN(value)) return "NaN"; if (value === Infinity) return "Infinity"; if (value === -Infinity) return "-Infinity"; if (Array.isArray(value)) return "array"; return typeof value; }; const isSupported = (value) => { if (value === undefined || value instanceof Date) return true; if (typeof value === "bigint") return true; // Numbers must be finite (excludes NaN, Infinity, -Infinity) if (typeof value === "number") return Number.isFinite(value); return false; }; /** * Validates whether two values are eligible for comparison using >= or <= operators. * * Supported types: `undefined`, `number`, `bigint`, and `Date`. * * @param a - The first value to compare. * @param b - The second value to compare. * * @returns {boolean} True if both values are of supported types. * * @throws {TypeError} If either value is of an unsupported type. * @memberOf module:decorator-validation */ export function isValidForGteOrLteComparison(a, b) { if (isSupported(a) && isSupported(b)) return true; throw new TypeError(sf(COMPARISON_ERROR_MESSAGES.UNSUPPORTED_TYPES_COMPARISON, getTypeName(a), getTypeName(b))); } /** * @summary Compares two values to determine if the first is less than the second. * @description Supports numbers and dates. Throws an error for unsupported types. * * @param {any} a - The first value to compare. * @param {any} b - The second value to compare against. * * @returns {boolean} True if `a` is less than `b`, false otherwise. * * @throws {Error} If either `a` or `b` is `null` or `undefined`. * @throws {TypeError} If values are of mismatched or unsupported types. * @memberOf module:decorator-validation */ export function isLessThan(a, b) { if ([null, undefined].includes(a) || [null, undefined].includes(b)) throw new Error(COMPARISON_ERROR_MESSAGES.NULL_OR_UNDEFINED_COMPARISON); // Validate type compatibility const aType = typeof a; const bType = typeof b; if (aType !== bType) { // Allow number X bigint if (aType === "bigint" && bType === "number") return Number(a) < b; if (aType === "number" && bType === "bigint") return a < Number(b); throw new TypeError(sf(COMPARISON_ERROR_MESSAGES.TYPE_MISMATCH_COMPARISON, aType, bType)); } if ((aType === "number" && bType === "number") || (aType === "bigint" && bType === "bigint")) { if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(COMPARISON_ERROR_MESSAGES.NAN_COMPARISON); return a < b; } if (a instanceof Date && b instanceof Date) { if (isNaN(a.getTime()) || isNaN(b.getTime())) throw new TypeError(COMPARISON_ERROR_MESSAGES.INVALID_DATE_COMPARISON); return a.getTime() < b.getTime(); } throw new TypeError(sf(COMPARISON_ERROR_MESSAGES.UNSUPPORTED_TYPES_COMPARISON, getTypeName(a), getTypeName(b))); } /** * Checks if `a` is greater than `b`. * Supports comparison for numbers and Date objects. * * @param {any} a - The value to validate. * @param {any} b - The value to compare against. * * @returns {boolean} True if `a` is greater than `b`, otherwise false. * * @throws {Error} If either `a` or `b` is `null` or `undefined`. * @throws {TypeError} If values are of mismatched or unsupported types. * @memberOf module:decorator-validation */ export function isGreaterThan(a, b) { if ([null, undefined].includes(a) || [null, undefined].includes(b)) throw new Error(COMPARISON_ERROR_MESSAGES.NULL_OR_UNDEFINED_COMPARISON); const aType = typeof a; const bType = typeof b; if (aType !== bType) { // Allow number X bigint if (aType === "bigint" && bType === "number") return Number(a) > b; if (aType === "number" && bType === "bigint") return a > Number(b); throw new Error(sf(COMPARISON_ERROR_MESSAGES.TYPE_MISMATCH_COMPARISON, aType, bType)); } if ((aType === "number" && bType === "number") || (aType === "bigint" && bType === "bigint")) { if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(COMPARISON_ERROR_MESSAGES.NAN_COMPARISON); return a > b; } if (a instanceof Date && b instanceof Date) { if (isNaN(a.getTime()) || isNaN(b.getTime())) throw new TypeError(COMPARISON_ERROR_MESSAGES.INVALID_DATE_COMPARISON); return a.getTime() > b.getTime(); } throw new TypeError(sf(COMPARISON_ERROR_MESSAGES.UNSUPPORTED_TYPES_COMPARISON, getTypeName(a), getTypeName(b))); } //# sourceMappingURL=utils.js.map