UNPKG

@decaf-ts/decorator-validation

Version:
262 lines 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isValidForGteOrLteComparison = isValidForGteOrLteComparison; exports.isLessThan = isLessThan; exports.isGreaterThan = isGreaterThan; exports.checkType = checkType; exports.checkTypes = checkTypes; exports.evaluateDesignTypes = evaluateDesignTypes; exports.valueLength = valueLength; const constants_1 = require("./../../constants/index.cjs"); const strings_1 = require("./../../utils/strings.cjs"); // /** // * 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 */ function isValidForGteOrLteComparison(a, b) { if (isSupported(a) && isSupported(b)) return true; throw new TypeError((0, strings_1.sf)(constants_1.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 */ function isLessThan(a, b) { if ([null, undefined].includes(a) || [null, undefined].includes(b)) throw new Error(constants_1.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((0, strings_1.sf)(constants_1.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(constants_1.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(constants_1.COMPARISON_ERROR_MESSAGES.INVALID_DATE_COMPARISON); return a.getTime() < b.getTime(); } throw new TypeError((0, strings_1.sf)(constants_1.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 */ function isGreaterThan(a, b) { if ([null, undefined].includes(a) || [null, undefined].includes(b)) throw new Error(constants_1.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((0, strings_1.sf)(constants_1.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(constants_1.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(constants_1.COMPARISON_ERROR_MESSAGES.INVALID_DATE_COMPARISON); return a.getTime() > b.getTime(); } throw new TypeError((0, strings_1.sf)(constants_1.COMPARISON_ERROR_MESSAGES.UNSUPPORTED_TYPES_COMPARISON, getTypeName(a), getTypeName(b))); } /** * @description Checks if a value matches a specified type name * @summary Utility function to verify if a value's type matches the provided type name * @param {unknown} value - The value to check the type of * @param {string} acceptedType - The type name to check against * @return {boolean} Returns true if the value matches the accepted type, false otherwise */ function checkType(value, acceptedType) { if (typeof value === acceptedType.toLowerCase()) return true; if (typeof value === "undefined") return false; if (typeof value !== "object") return false; return (value.constructor && value.constructor.name.toLowerCase() === acceptedType.toLowerCase()); } /** * @description Checks if a value matches any of the specified type names * @summary Utility function to verify if a value's type matches any of the provided type names * @param {unknown} value - The value to check the type of * @param {string[]} acceptedTypes - Array of type names to check against * @return {boolean} Returns true if the value matches any of the accepted types, false otherwise */ function checkTypes(value, acceptedTypes) { return !acceptedTypes.every((t) => !checkType(value, t)); } /** * @description Evaluates if a value matches the specified type metadata * @summary Compares a value against type metadata to determine if they match * @param {unknown} value - The value to evaluate * @param {string | string[] | {name: string}} types - Type metadata to check against, can be a string, array of strings, or an object with a name property * @return {boolean} Returns true if the value matches the type metadata, false otherwise */ function evaluateDesignTypes(value, types) { switch (typeof types) { case "string": return checkType(value, types); case "object": if (Array.isArray(types)) return checkTypes(value, types); return true; case "function": if (types.name && types.name !== "Object") return checkType(value, types.name); return true; default: return true; } } /** * @description Returns the length of a value * @summary Returns the length of a value * @param {string | Set<any> | any[] | Map<any, any>} value - The value to evaluate * @return {number} Returns the length of a value */ function valueLength(value) { return value instanceof Set || value instanceof Map ? value.size : value.length; } //# sourceMappingURL=utils.js.map