diff --git a/src/util/deepDiff.ts b/src/util/deepDiff.ts index 5d0ec2b3f..5ae1e5f8d 100644 --- a/src/util/deepDiff.ts +++ b/src/util/deepDiff.ts @@ -1,13 +1,7 @@ +import { unique } from './iteratees'; + const EQUAL = Symbol('EQUAL'); -function deepAreSortedArraysEqual>(array1: T, array2: T) { - if (array1.length !== array2.length) { - return false; - } - - return array1.every((item, i) => deepDiff(item, array2[i]) === EQUAL); -} - export function deepDiff(value1: T, value2: T): Partial | typeof EQUAL { const type1 = typeof value1; const type2 = typeof value2; @@ -25,39 +19,50 @@ export function deepDiff(value1: T, value2: T): Partial | type } if (Array.isArray(value1) && Array.isArray(value2)) { - if (deepAreSortedArraysEqual(value1, value2)) return EQUAL; + if (areSortedArraysDeepEqual(value1, value2)) return EQUAL; return value2; } const object1 = value1 as AnyLiteral; const object2 = value2 as AnyLiteral; - const keys1 = Array.from(new Set([...Object.keys(object1), ...Object.keys(object2)])); + const allKeys = unique(Object.keys(object1).concat(Object.keys(object2))); - const reduced = keys1.reduce((acc: any, el) => { - if (object1[el] === object2[el]) { + const diff = allKeys.reduce((acc: any, key) => { + if (object1[key] === object2[key]) { return acc; } - const o1has = object1.hasOwnProperty(el); - const o2has = object2.hasOwnProperty(el); + const o1has = object1.hasOwnProperty(key); + const o2has = object2.hasOwnProperty(key); if (!o2has) { - acc[el] = { __delete: true }; + acc[key] = { __delete: true }; return acc; } if (!o1has && o2has) { - acc[el] = object2[el]; + acc[key] = object2[key]; return acc; } - const diff = deepDiff(object1[el], object2[el]); - if (diff !== EQUAL) acc[el] = diff; + const subDiff = deepDiff(object1[key], object2[key]); + if (subDiff !== EQUAL) { + acc[key] = subDiff; + } + return acc; }, {}); - if (Object.keys(reduced).length === 0) { + if (Object.keys(diff).length === 0) { return EQUAL; } - return reduced; + return diff; +} + +function areSortedArraysDeepEqual>(array1: T, array2: T) { + if (array1.length !== array2.length) { + return false; + } + + return array1.every((item, i) => deepDiff(item, array2[i]) === EQUAL); } diff --git a/src/util/deepMerge.ts b/src/util/deepMerge.ts index 50fccd970..3aa4a4cc4 100644 --- a/src/util/deepMerge.ts +++ b/src/util/deepMerge.ts @@ -1,6 +1,6 @@ -import { omit } from './iteratees'; +import { unique } from './iteratees'; -export function deepMerge(value1: T, value2: Partial): T { +export function deepMerge(value1: T, value2: Record): T { const type1 = typeof value1; const type2 = typeof value2; if (type1 !== 'object') { @@ -21,14 +21,21 @@ export function deepMerge(value1: T, value2: Partial): T { const object1 = value1 as AnyLiteral; const object2 = value2 as AnyLiteral; - const keys = Object.keys(object2); - // eslint-disable-next-line no-underscore-dangle - const keysDeleted = keys.filter((k) => object2[k]?.__delete); - // eslint-disable-next-line no-underscore-dangle - const keysNotDeleted = keys.filter((k) => !object2[k]?.__delete); - return keysNotDeleted.reduce((acc: any, key) => { - acc[key] = deepMerge(object1[key], object2[key]); + const allKeys = unique(Object.keys(object1).concat(Object.keys(object2))); + + return allKeys.reduce((acc: AnyLiteral, key) => { + const oldValue = object1[key]; + + if (!(key in object2)) { + acc[key] = oldValue; + } else { + const newValue = object2[key]; + // eslint-disable-next-line no-underscore-dangle + if (!newValue?.__delete) { + acc[key] = deepMerge(oldValue, newValue); + } + } return acc; - }, { ...omit(object1, keysDeleted) }); + }, {}) as T; }