object-deep-compare
Version:
A type-safe collection of comparison methods for objects and arrays in TypeScript/JavaScript
156 lines (155 loc) • 7.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeSafeCompareValuesWithDetailedDifferences = exports.TypeSafeCompareObjects = exports.MapObjectProperties = exports.TypeSafeCompareArrays = void 0;
const compare_arrays_1 = require("../comparison/compare-arrays");
const object_comparison_1 = require("../comparison/object-comparison");
const detailed_comparison_1 = require("../comparison/detailed-comparison");
const schema_validation_1 = require("../core/schema-validation");
const utils_1 = require("../core/utils");
/**
* Type-safe comparison of arrays that includes type information
*
* @param firstArray - First array to compare
* @param secondArray - Second array to compare
* @param options - Optional comparison options (strict, circularReferences)
* @returns Object with isEqual flag and type information
*/
const TypeSafeCompareArrays = (firstArray, secondArray, options = {}) => {
// Perform schema validation if specified
if (options.schemaValidation) {
// Convert arrays to objects for schema validation if schemas are provided
if (options.schemaValidation.firstObjectSchema || options.schemaValidation.secondObjectSchema) {
const firstObject = { items: firstArray };
const secondObject = { items: secondArray };
// Wrap the array schemas inside an object with 'items' property
const wrappedFirstSchema = options.schemaValidation.firstObjectSchema
? { items: [options.schemaValidation.firstObjectSchema] }
: undefined;
const wrappedSecondSchema = options.schemaValidation.secondObjectSchema
? { items: [options.schemaValidation.secondObjectSchema] }
: undefined;
const wrappedSchemaValidation = {
firstObjectSchema: wrappedFirstSchema,
secondObjectSchema: wrappedSecondSchema,
throwOnValidationFailure: options.schemaValidation.throwOnValidationFailure
};
// Run the schema validation
(0, schema_validation_1.ValidateObjectsAgainstSchemas)(firstObject, secondObject, wrappedSchemaValidation);
}
}
const isEqual = (0, compare_arrays_1.CompareArrays)(firstArray, secondArray, options);
return {
isEqual,
firstType: (0, utils_1.getTypeName)(firstArray),
secondType: (0, utils_1.getTypeName)(secondArray)
};
};
exports.TypeSafeCompareArrays = TypeSafeCompareArrays;
/**
* Maps properties between objects with different structures
*
* @param sourceObject - Source object
* @param propertyMapping - Mapping from source properties to target properties
* @returns A new object with mapped properties
*/
const MapObjectProperties = (sourceObject, propertyMapping) => {
const result = {};
Object.entries(propertyMapping).forEach(([sourceKey, targetKey]) => {
if (sourceKey in sourceObject && targetKey) {
// @ts-ignore - We know these keys exist based on the check
result[targetKey] = sourceObject[sourceKey];
}
});
return result;
};
exports.MapObjectProperties = MapObjectProperties;
/**
* Type-safe version of object comparison that supports objects with different structures
*
* @param firstObject - First object to compare
* @param secondObject - Second object to compare
* @param options - Type-safe comparison options
* @returns Object with isEqual flag and type information
*/
const TypeSafeCompareObjects = (firstObject, secondObject, options = {}) => {
// Handle null and undefined cases
if (!firstObject || !secondObject) {
return {
isEqual: firstObject === secondObject,
firstType: (firstObject === null ? 'null' : firstObject === undefined ? 'undefined' : 'object'),
secondType: (secondObject === null ? 'null' : secondObject === undefined ? 'undefined' : 'object')
};
}
// Create a new object for comparison if property mapping is provided
if (options.propertyMapping && Object.keys(options.propertyMapping).length > 0) {
// Create a clean object with only mapped properties
const mappedFirstObject = {};
// Apply property mapping
for (const [sourceKey, targetKey] of Object.entries(options.propertyMapping)) {
if (sourceKey in firstObject && targetKey) {
// Map the source property to the target property name
// @ts-ignore - We know these keys exist based on the check
mappedFirstObject[targetKey] = firstObject[sourceKey];
}
}
// Use existing CompareValuesWithConflicts function for comparison
const conflicts = (0, object_comparison_1.CompareValuesWithConflicts)(mappedFirstObject, secondObject, '', {
strict: options.strict,
circularReferences: options.circularReferences,
pathFilter: options.pathFilter
});
return {
isEqual: conflicts.length === 0,
firstType: 'object',
secondType: 'object'
};
}
else {
// Without property mapping, do a regular comparison
const conflicts = (0, object_comparison_1.CompareValuesWithConflicts)(firstObject, secondObject, '', {
strict: options.strict,
circularReferences: options.circularReferences,
pathFilter: options.pathFilter
});
return {
isEqual: conflicts.length === 0,
firstType: 'object',
secondType: 'object'
};
}
};
exports.TypeSafeCompareObjects = TypeSafeCompareObjects;
/**
* Type-safe version of detailed comparison that supports objects with different structures
* and provides type information
*
* @param firstObject - First object to compare
* @param secondObject - Second object to compare
* @param options - Type-safe comparison options
* @returns Array of typed detailed differences with type information
*/
const TypeSafeCompareValuesWithDetailedDifferences = (firstObject, secondObject, options = {}) => {
if (!firstObject || !secondObject) {
return [];
}
// Perform schema validation if specified
if (options.schemaValidation) {
(0, schema_validation_1.ValidateObjectsAgainstSchemas)(firstObject, secondObject, options.schemaValidation);
}
// Get standard detailed differences
const differences = (0, detailed_comparison_1.CompareValuesWithDetailedDifferences)(firstObject, secondObject, '', options);
// If we don't need type info, just return the standard differences
if (!options.includeTypeInfo) {
return differences;
}
// Add type information to each difference
return differences.map((diff) => {
const typedDiff = {
...diff,
oldValueType: diff.oldValue !== undefined ? (0, utils_1.getTypeName)(diff.oldValue) : undefined,
newValueType: diff.newValue !== undefined ? (0, utils_1.getTypeName)(diff.newValue) : undefined
};
return typedDiff;
});
};
exports.TypeSafeCompareValuesWithDetailedDifferences = TypeSafeCompareValuesWithDetailedDifferences;