import { EqualityComparator, InternalEqualityComparator, TypeEqualityComparator, } from '../index.d'; /** * Default equality comparator pass-through, used as the standard `isEqual` creator for * use inside the built comparator. */ export function createDefaultIsNestedEqual( comparator: EqualityComparator, ): InternalEqualityComparator { return function isEqual( a: A, b: B, _indexOrKeyA: any, _indexOrKeyB: any, _parentA: any, _parentB: any, meta: Meta, ) { return comparator(a, b, meta); }; } /** * Wrap the provided `areItemsEqual` method to manage the circular cache, allowing * for circular references to be safely included in the comparison without creating * stack overflows. */ export function createIsCircular< AreItemsEqual extends TypeEqualityComparator, >(areItemsEqual: AreItemsEqual): AreItemsEqual { return function isCircular( a: any, b: any, isEqual: InternalEqualityComparator>, cache: WeakMap, ) { if (!a || !b || typeof a !== 'object' || typeof b !== 'object') { return areItemsEqual(a, b, isEqual, cache); } const cachedA = cache.get(a); const cachedB = cache.get(b); if (cachedA && cachedB) { return cachedA === b && cachedB === a; } cache.set(a, b); cache.set(b, a); const result = areItemsEqual(a, b, isEqual, cache); cache.delete(a); cache.delete(b); return result; } as AreItemsEqual; } /** * Targeted shallow merge of two objects. * * @NOTE * This exists as a tinier compiled version of the `__assign` helper that * `tsc` injects in case of `Object.assign` not being present. */ export function merge(a: A, b: B): A & B { const merged: Record = {}; for (const key in a) { merged[key] = a[key]; } for (const key in b) { merged[key] = b[key]; } return merged as A & B; } /** * Whether the value is a plain object. * * @NOTE * This is a same-realm compariosn only. */ export function isPlainObject(value: any): boolean { return value.constructor === Object || value.constructor == null; } /** * When the value is `Promise`-like, aka "then-able". */ export function isPromiseLike(value: any): boolean { return typeof value.then === 'function'; } /** * Whether the values passed are strictly equal or both NaN. */ export function sameValueZeroEqual(a: any, b: any): boolean { return a === b || (a !== a && b !== b); }