UNPKG

object-deep-compare

Version:

A type-safe collection of comparison methods for objects and arrays in TypeScript/JavaScript

137 lines (136 loc) 6.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidateObjectsAgainstSchemas = exports.validateObjectAgainstSchema = void 0; const errors_1 = require("./errors"); const utils_1 = require("./utils"); /** * Validates an object against a schema * @param obj - Object to validate * @param schema - Schema to validate against * @param path - Current path (used for error messages) * @returns Array of validation error messages */ const validateObjectAgainstSchema = (obj, schema, path = '') => { const errors = []; // Check all schema properties against the object for (const key in schema) { const currentPath = path ? `${path}.${key}` : key; // Check if property exists if (!(0, utils_1.hasOwn)(obj, key)) { errors.push(`Missing required property: ${currentPath}`); continue; } const schemaValue = schema[key]; const objValue = obj[key]; // Check property type if (typeof schemaValue === 'string') { // String values in schema represent type constraints const expectedType = schemaValue; if (expectedType === 'any') { // Skip type checking for 'any' continue; } // Handle special array type notation: 'array<string>', 'array<number>', etc. if (expectedType.startsWith('array<') && expectedType.endsWith('>')) { if (!Array.isArray(objValue)) { errors.push(`Property ${currentPath} should be an array but got ${typeof objValue}`); continue; } // Extract the array item type const itemType = expectedType.substring(6, expectedType.length - 1); // Validate array items if needed for (let i = 0; i < objValue.length; i++) { const item = objValue[i]; if (typeof item !== itemType && itemType !== 'any') { errors.push(`Array item ${currentPath}[${i}] should be of type ${itemType} but got ${typeof item}`); } } continue; } // Check primitive types if (typeof objValue !== expectedType && expectedType !== 'any') { errors.push(`Property ${currentPath} should be of type ${expectedType} but got ${typeof objValue}`); } } else if ((0, utils_1.isObject)(schemaValue) && !(0, utils_1.isEmpty)(schemaValue)) { // For nested objects, recursively validate if ((0, utils_1.isObject)(objValue)) { const nestedErrors = (0, exports.validateObjectAgainstSchema)(objValue, schemaValue, currentPath); errors.push(...nestedErrors); } else { errors.push(`Property ${currentPath} should be an object but got ${typeof objValue}`); } } else if (Array.isArray(schemaValue)) { // Array schema - check that the value is an array if (!Array.isArray(objValue)) { errors.push(`Property ${currentPath} should be an array but got ${typeof objValue}`); continue; } // If the schema array has a single item, it's a schema for all items if (schemaValue.length === 1 && (0, utils_1.isObject)(schemaValue[0])) { const itemSchema = schemaValue[0]; // Check each array item against the item schema for (let i = 0; i < objValue.length; i++) { const item = objValue[i]; if ((0, utils_1.isObject)(item)) { const nestedErrors = (0, exports.validateObjectAgainstSchema)(item, itemSchema, `${currentPath}[${i}]`); errors.push(...nestedErrors); } else { errors.push(`Array item ${currentPath}[${i}] should be an object but got ${typeof item}`); } } } } } return errors; }; exports.validateObjectAgainstSchema = validateObjectAgainstSchema; /** * Validates objects against schemas based on schema validation options * @param firstObject - First object to validate * @param secondObject - Second object to validate * @param schemaValidation - Schema validation options * @returns Validation result with any errors */ const ValidateObjectsAgainstSchemas = (firstObject, secondObject, schemaValidation) => { // Handle null or undefined inputs if (!firstObject || !secondObject) { return { firstObjectValid: !firstObject ? false : true, secondObjectValid: !secondObject ? false : true, firstObjectErrors: !firstObject ? ['First object is null or undefined'] : undefined, secondObjectErrors: !secondObject ? ['Second object is null or undefined'] : undefined }; } const result = { firstObjectValid: true, secondObjectValid: true }; // Validate first object if schema is provided if (schemaValidation.firstObjectSchema) { const firstObjectErrors = (0, exports.validateObjectAgainstSchema)(firstObject, schemaValidation.firstObjectSchema); if (firstObjectErrors.length > 0) { result.firstObjectValid = false; result.firstObjectErrors = firstObjectErrors; } } // Validate second object if schema is provided if (schemaValidation.secondObjectSchema) { const secondObjectErrors = (0, exports.validateObjectAgainstSchema)(secondObject, schemaValidation.secondObjectSchema); if (secondObjectErrors.length > 0) { result.secondObjectValid = false; result.secondObjectErrors = secondObjectErrors; } } // If throwOnValidationFailure is true and any validation failed, throw an error if (schemaValidation.throwOnValidationFailure && (!result.firstObjectValid || !result.secondObjectValid)) { const errorMsg = `Schema validation failed: ${!result.firstObjectValid ? 'First object has validation errors. ' : ''}${!result.secondObjectValid ? 'Second object has validation errors.' : ''}`; throw new errors_1.SchemaValidationError(errorMsg, result); } return result; }; exports.ValidateObjectsAgainstSchemas = ValidateObjectsAgainstSchemas;