object-deep-compare
Version:
A type-safe collection of comparison methods for objects and arrays in TypeScript/JavaScript
130 lines (129 loc) • 4.19 kB
JavaScript
;
/**
* Core utility functions for object comparison
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTypeName = exports.pick = exports.areValuesEqual = exports.isObject = exports.isEmpty = exports.hasOwn = void 0;
/**
* Helper function to check if an object has a property
* @param obj - Object to check
* @param key - Property to check for
* @returns Whether the object has the property
*/
const hasOwn = (obj, key) => {
return Object.prototype.hasOwnProperty.call(obj, key);
};
exports.hasOwn = hasOwn;
/**
* Helper function to check if a value is empty
* @param value - Value to check
* @returns Whether the value is empty
*/
const isEmpty = (value) => {
if (value === null || value === undefined)
return true;
if (typeof value === 'string')
return value.length === 0;
if (Array.isArray(value))
return value.length === 0;
if (typeof value === 'object')
return Object.keys(value).length === 0;
return false;
};
exports.isEmpty = isEmpty;
/**
* Helper function to check if a value is an object
* @param value - Value to check
* @returns Whether the value is an object
*/
const isObject = (value) => {
return typeof value === 'object' && value !== null && !Array.isArray(value);
};
exports.isObject = isObject;
/**
* Helper function to determine if two values are equal
* @param a - First value
* @param b - Second value
* @param strict - Whether to use strict equality
* @returns Whether the values are equal
*/
const areValuesEqual = (a, b, strict = true) => {
// Handle identical values first
if (a === b)
return true;
// If strict mode is enabled and values are not strictly equal, they're not equal
if (strict)
return false;
// For non-strict mode:
// Handle NaN
if (Number.isNaN(a) && Number.isNaN(b))
return true;
// Handle null and undefined
if ((a === null && b === undefined) || (a === undefined && b === null))
return true;
// Handle type coercion for primitives
if (typeof a === 'string' || typeof b === 'string') {
// Only try numeric comparison if one is a string and the other is a number
if ((typeof a === 'string' && typeof b === 'number') ||
(typeof a === 'number' && typeof b === 'string')) {
const numA = Number(a);
const numB = Number(b);
if (!Number.isNaN(numA) && !Number.isNaN(numB) && numA === numB)
return true;
}
}
// Handle boolean values
if (typeof a === 'boolean' || typeof b === 'boolean') {
const boolA = Boolean(a);
const boolB = Boolean(b);
if (boolA === boolB)
return true;
}
// At this point, if one is falsy and the other is not, they're not equal
if (!a || !b)
return false;
// If both are dates
if (a instanceof Date && b instanceof Date)
return a.getTime() === b.getTime();
// If both are RegExp
if (a instanceof RegExp && b instanceof RegExp)
return a.toString() === b.toString();
return false;
};
exports.areValuesEqual = areValuesEqual;
/**
* Creates a filtered copy of an object with only the specified keys
* @param obj - Object to filter
* @param keys - Keys to include in the result
* @returns A new object with only the specified keys
*/
const pick = (obj, keys) => {
return keys.reduce((result, key) => {
if ((0, exports.hasOwn)(obj, key)) {
result[key] = obj[key];
}
return result;
}, {});
};
exports.pick = pick;
/**
* Gets the type name of a value for better type information
* @param value - The value to get the type of
* @returns A string representing the type
*/
const getTypeName = (value) => {
if (value === null)
return 'null';
if (value === undefined)
return 'undefined';
if (Array.isArray(value))
return 'array';
if (value instanceof Date)
return 'date';
if (value instanceof RegExp)
return 'regexp';
if (typeof value === 'object')
return 'object';
return typeof value;
};
exports.getTypeName = getTypeName;