UNPKG

@instantdb/core

Version:

Instant's core local abstraction

177 lines (149 loc) 3.78 kB
export function areObjectKeysEqual(a, b) { const ak = Object.keys(a); const bk = Object.keys(b); return ( ak.length === bk.length && Object.keys(a).every((k) => b.hasOwnProperty(k)) ); } export function areObjectsShallowEqual(obj1, obj2) { return ( Object.keys(obj1).length === Object.keys(obj2).length && Object.keys(obj1).every( (key) => obj2.hasOwnProperty(key) && obj1[key] === obj2[key], ) ); } export function areObjectsDeepEqual(obj1, obj2) { if ( typeof obj1 !== 'object' || typeof obj2 !== 'object' || obj1 === null || obj2 === null ) { return obj1 === obj2; } if (!areObjectKeysEqual(obj1, obj2)) { return false; } return Object.keys(obj1).every((key) => areObjectsDeepEqual(obj1[key], obj2[key]), ); } export function immutableRemoveUndefined(obj) { if (!isObject(obj)) { return obj; } const result = {}; for (const [key, value] of Object.entries(obj)) { if (value === undefined) continue; result[key] = value; } return result; } export function immutableDeepMerge(target, source) { if (!isObject(target) || !isObject(source)) { return source; } const result = { ...target }; for (const key of Object.keys(source)) { if (source[key] === undefined) continue; if (source[key] === null) { delete result[key]; continue; } const areBothObjects = isObject(target[key]) && isObject(source[key]); result[key] = areBothObjects ? immutableDeepMerge(target[key], source[key]) : source[key]; } return result; } export function immutableDeepReplace(target, replaceValue, replacementValue) { if (!isObject(target)) { return target; } const result = {}; for (const [key, value] of Object.entries(target)) { result[key] = isObject(value) ? immutableDeepReplace(value, replaceValue, replacementValue) : value === replaceValue ? replacementValue : value; } return result; } export function isObject(val) { return typeof val === 'object' && val !== null && !Array.isArray(val); } export function immutableOmitValue(obj, v) {} /** * Like `assocInMutative`, but * * - for arrays: inserts the value at the specified index, instead of replacing it */ export function insertInMutative(obj, path, value) { if (!obj) { return; } if (path.length === 0) { return; } let current = obj || {}; for (let i = 0; i < path.length - 1; i++) { const key = path[i]; if (!(key in current) || typeof current[key] !== 'object') { current[key] = typeof path[i + 1] === 'number' ? [] : {}; } current = current[key]; } const key = path[path.length - 1]; if (Array.isArray(current) && typeof key === 'number') { current.splice(key, 0, value); } else { current[key] = value; } } export function assocInMutative(obj, path, value) { if (!obj) { return; } if (path.length === 0) { return; } let current = obj || {}; for (let i = 0; i < path.length - 1; i++) { const key = path[i]; if (!(key in current) || typeof current[key] !== 'object') { current[key] = typeof path[i + 1] === 'number' ? [] : {}; } current = current[key]; } current[path[path.length - 1]] = value; } export function dissocInMutative(obj, path) { if (!obj) { return; } if (path.length === 0) { return; } const [key, ...restPath] = path; if (!(key in obj)) { return; } if (restPath.length === 0) { if (Array.isArray(obj)) { obj.splice(key, 1); } else { delete obj[key]; } return; } dissocInMutative(obj[key], restPath); if (isEmpty(obj[key])) { delete obj[key]; } } function isEmpty(obj) { return obj && Object.keys(obj).length === 0; }