UNPKG

@tanstack/persister

Version:

Utilities for persisting state to local storage, session storage, indexedDB, and more.

106 lines (88 loc) 2.58 kB
/** * This function returns `a` if `b` is deeply equal. * If not, it will replace any deeply equal children of `b` with those of `a`. * This can be used for structural sharing between JSON values for example. */ export function replaceEqualDeep<T>(a: unknown, b: T): T export function replaceEqualDeep(a: any, b: any): any { if (a === b) { return a } const array = isPlainArray(a) && isPlainArray(b) if (array || (isPlainObject(a) && isPlainObject(b))) { const aItems = array ? a : Object.keys(a) const aSize = aItems.length const bItems = array ? b : Object.keys(b) const bSize = bItems.length const copy: any = array ? [] : {} let equalItems = 0 for (let i = 0; i < bSize; i++) { const key = array ? i : bItems[i] if ( ((!array && aItems.includes(key)) || array) && a[key] === undefined && b[key] === undefined ) { copy[key] = undefined equalItems++ } else { copy[key] = replaceEqualDeep(a[key], b[key]) if (copy[key] === a[key] && a[key] !== undefined) { equalItems++ } } } return aSize === bSize && equalItems === aSize ? a : copy } return b } /** * Shallow compare objects. */ export function shallowEqualObjects<T extends Record<string, any>>( a: T, b: T | undefined, ): boolean { if (!b || Object.keys(a).length !== Object.keys(b).length) { return false } for (const key in a) { if (a[key] !== b[key]) { return false } } return true } export function isPlainArray(value: unknown) { return Array.isArray(value) && value.length === Object.keys(value).length } // Copied from: https://github.com/jonschlinkert/is-plain-object // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types export function isPlainObject(o: any): o is Object { if (!hasObjectPrototype(o)) { return false } // If has no constructor const ctor = o.constructor if (ctor === undefined) { return true } // If has modified prototype const prot = ctor.prototype if (!hasObjectPrototype(prot)) { return false } // If constructor does not have an Object-specific method if (!prot.hasOwnProperty('isPrototypeOf')) { return false } // Handles Objects created by Object.create(<arbitrary prototype>) if (Object.getPrototypeOf(o) !== Object.prototype) { return false } // Most likely a plain Object return true } function hasObjectPrototype(o: any): boolean { return Object.prototype.toString.call(o) === '[object Object]' }