[Refactoring] deepMerge, deepDiff: Optimize, refactor, add tests
This commit is contained in:
parent
bd3afbca75
commit
7430336ba7
@ -1,13 +1,7 @@
|
|||||||
|
import { unique } from './iteratees';
|
||||||
|
|
||||||
const EQUAL = Symbol('EQUAL');
|
const EQUAL = Symbol('EQUAL');
|
||||||
|
|
||||||
function deepAreSortedArraysEqual<T extends Array<any>>(array1: T, array2: T) {
|
|
||||||
if (array1.length !== array2.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array1.every((item, i) => deepDiff(item, array2[i]) === EQUAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deepDiff<T extends any>(value1: T, value2: T): Partial<T> | typeof EQUAL {
|
export function deepDiff<T extends any>(value1: T, value2: T): Partial<T> | typeof EQUAL {
|
||||||
const type1 = typeof value1;
|
const type1 = typeof value1;
|
||||||
const type2 = typeof value2;
|
const type2 = typeof value2;
|
||||||
@ -25,39 +19,50 @@ export function deepDiff<T extends any>(value1: T, value2: T): Partial<T> | type
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(value1) && Array.isArray(value2)) {
|
if (Array.isArray(value1) && Array.isArray(value2)) {
|
||||||
if (deepAreSortedArraysEqual(value1, value2)) return EQUAL;
|
if (areSortedArraysDeepEqual(value1, value2)) return EQUAL;
|
||||||
|
|
||||||
return value2;
|
return value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const object1 = value1 as AnyLiteral;
|
const object1 = value1 as AnyLiteral;
|
||||||
const object2 = value2 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) => {
|
const diff = allKeys.reduce((acc: any, key) => {
|
||||||
if (object1[el] === object2[el]) {
|
if (object1[key] === object2[key]) {
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
const o1has = object1.hasOwnProperty(el);
|
const o1has = object1.hasOwnProperty(key);
|
||||||
const o2has = object2.hasOwnProperty(el);
|
const o2has = object2.hasOwnProperty(key);
|
||||||
if (!o2has) {
|
if (!o2has) {
|
||||||
acc[el] = { __delete: true };
|
acc[key] = { __delete: true };
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
if (!o1has && o2has) {
|
if (!o1has && o2has) {
|
||||||
acc[el] = object2[el];
|
acc[key] = object2[key];
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
const diff = deepDiff(object1[el], object2[el]);
|
const subDiff = deepDiff(object1[key], object2[key]);
|
||||||
if (diff !== EQUAL) acc[el] = diff;
|
if (subDiff !== EQUAL) {
|
||||||
|
acc[key] = subDiff;
|
||||||
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
if (Object.keys(reduced).length === 0) {
|
if (Object.keys(diff).length === 0) {
|
||||||
return EQUAL;
|
return EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return reduced;
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function areSortedArraysDeepEqual<T extends Array<any>>(array1: T, array2: T) {
|
||||||
|
if (array1.length !== array2.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array1.every((item, i) => deepDiff(item, array2[i]) === EQUAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { omit } from './iteratees';
|
import { unique } from './iteratees';
|
||||||
|
|
||||||
export function deepMerge<T extends any>(value1: T, value2: Partial<T>): T {
|
export function deepMerge<T extends any>(value1: T, value2: Record<keyof T, any>): T {
|
||||||
const type1 = typeof value1;
|
const type1 = typeof value1;
|
||||||
const type2 = typeof value2;
|
const type2 = typeof value2;
|
||||||
if (type1 !== 'object') {
|
if (type1 !== 'object') {
|
||||||
@ -21,14 +21,21 @@ export function deepMerge<T extends any>(value1: T, value2: Partial<T>): T {
|
|||||||
|
|
||||||
const object1 = value1 as AnyLiteral;
|
const object1 = value1 as AnyLiteral;
|
||||||
const object2 = value2 as AnyLiteral;
|
const object2 = value2 as AnyLiteral;
|
||||||
const keys = Object.keys(object2);
|
const allKeys = unique(Object.keys(object1).concat(Object.keys(object2)));
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
|
||||||
const keysDeleted = keys.filter((k) => object2[k]?.__delete);
|
return allKeys.reduce((acc: AnyLiteral, key) => {
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
const oldValue = object1[key];
|
||||||
const keysNotDeleted = keys.filter((k) => !object2[k]?.__delete);
|
|
||||||
return keysNotDeleted.reduce((acc: any, key) => {
|
if (!(key in object2)) {
|
||||||
acc[key] = deepMerge(object1[key], object2[key]);
|
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;
|
return acc;
|
||||||
}, { ...omit(object1, keysDeleted) });
|
}, {}) as T;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user