UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

56 lines (55 loc) 1.98 kB
import { isArray } from "./array.js"; import { isArrayEqual, isDeepEqual } from "./equal.js"; import { isObject } from "./object.js"; /** The `SAME` symbol indicates sameness. */ export const SAME = Symbol("shelving/SAME"); export function deepDiff(left, right) { if (left === right) return SAME; if (isArray(right)) return isArray(left) ? deepDiffArray(left, right) : right; if (isObject(right)) return isObject(left) && !isArray(left) ? deepDiffObject(left, right) : right; return right; } /** * Diff two arrays to produce the transformation needed to transform `left` into `right` * DH: Currently arrays don't diff at an item level, they return the entire new array if not deeply equal. * * @returns The `right` array if it is different to `left`, or the exact `SAME` constant otherwise. * - If the two values are deeply equal the `SAME` constant is returned. */ export function deepDiffArray(left, right) { if (left === right) return SAME; if (isArrayEqual(left, right, isDeepEqual)) return SAME; // Left is exactly equal to right so return `SAME` return right; // Right must be different to left so return right. } export function deepDiffObject(left, right) { if (left === right) return SAME; const rightKeys = Object.keys(right); const leftKeys = Object.keys(left); // If left is empty, entire right is returned. if (!leftKeys.length) return rightKeys.length ? right : SAME; const diff = {}; let changed = false; for (const k of rightKeys) { const d = deepDiff(left[k], right[k]); if (d !== SAME) { diff[k] = d; changed = true; } } // Loop through left to find any deleted docs. for (const k of leftKeys) { if (!rightKeys.includes(k)) { diff[k] = undefined; changed = true; } } // If any properties changed. return changed ? diff : SAME; }