deepMerge, deepDiff: Fixes for arrays, null-s, undefined-s and __delete* for non-objects
This commit is contained in:
parent
aac2ee85df
commit
9807dfb5d5
@ -1,28 +1,26 @@
|
||||
import { unique } from './iteratees';
|
||||
import { isLiteralObject, unique } from './iteratees';
|
||||
|
||||
const EQUAL = Symbol('EQUAL');
|
||||
const DELETE = { __delete: true };
|
||||
const DELETE_ALL_CHILDREN = { __deleteAllChildren: true };
|
||||
|
||||
export function deepDiff<T extends any>(value1: T, value2: T): Partial<T> | typeof EQUAL | typeof DELETE_ALL_CHILDREN {
|
||||
const type1 = typeof value1;
|
||||
const type2 = typeof value2;
|
||||
|
||||
if (value1 === value2) {
|
||||
return EQUAL;
|
||||
}
|
||||
|
||||
const type1 = typeof value1;
|
||||
const type2 = typeof value2;
|
||||
|
||||
if (type1 !== type2) {
|
||||
return value2;
|
||||
}
|
||||
|
||||
if (type2 !== 'object') {
|
||||
return value2;
|
||||
if (Array.isArray(value1) && Array.isArray(value2) && areSortedArraysDeepEqual(value1, value2)) {
|
||||
return EQUAL;
|
||||
}
|
||||
|
||||
if (Array.isArray(value1) && Array.isArray(value2)) {
|
||||
if (areSortedArraysDeepEqual(value1, value2)) return EQUAL;
|
||||
|
||||
if (!isLiteralObject(value1) || !isLiteralObject(value2)) {
|
||||
return value2;
|
||||
}
|
||||
|
||||
@ -38,22 +36,20 @@ export function deepDiff<T extends any>(value1: T, value2: T): Partial<T> | type
|
||||
const allKeys = unique(keys1.concat(keys2));
|
||||
|
||||
const diff = allKeys.reduce((acc: any, key) => {
|
||||
if (object1[key] === object2[key]) {
|
||||
return acc;
|
||||
}
|
||||
const subValue1 = object1[key];
|
||||
const subValue2 = object2[key];
|
||||
|
||||
const o1has = object1.hasOwnProperty(key);
|
||||
const o2has = object2.hasOwnProperty(key);
|
||||
if (!o2has) {
|
||||
if (!object2.hasOwnProperty(key)) {
|
||||
acc[key] = DELETE;
|
||||
return acc;
|
||||
}
|
||||
if (!o1has && o2has) {
|
||||
acc[key] = object2[key];
|
||||
|
||||
if (!object1!.hasOwnProperty(key)) {
|
||||
acc[key] = subValue2;
|
||||
return acc;
|
||||
}
|
||||
|
||||
const subDiff = deepDiff(object1[key], object2[key]);
|
||||
const subDiff = deepDiff(subValue1, subValue2);
|
||||
if (subDiff !== EQUAL) {
|
||||
acc[key] = subDiff;
|
||||
}
|
||||
|
||||
@ -1,41 +1,32 @@
|
||||
import { unique } from './iteratees';
|
||||
|
||||
export function deepMerge<T extends any>(value1: T, value2: Record<keyof T, any>): T {
|
||||
const type1 = typeof value1;
|
||||
const type2 = typeof value2;
|
||||
if (type1 !== 'object') {
|
||||
return value2 as T;
|
||||
}
|
||||
|
||||
if (Array.isArray(value2)) {
|
||||
return value2 as T;
|
||||
}
|
||||
|
||||
if (type1 !== type2) {
|
||||
return value2 as T;
|
||||
}
|
||||
import { isLiteralObject, unique } from './iteratees';
|
||||
|
||||
export function deepMerge<T extends any>(value1: T, value2: T): T {
|
||||
if (value1 === value2) {
|
||||
return value2 as T;
|
||||
return value2;
|
||||
}
|
||||
|
||||
const object1 = value1 as AnyLiteral;
|
||||
const object2 = value2 as AnyLiteral;
|
||||
if (!isLiteralObject(value2)) {
|
||||
return value2;
|
||||
}
|
||||
|
||||
if (!isLiteralObject(value1)) {
|
||||
return reduceDiff(value2) as T;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (object2.__deleteAllChildren) {
|
||||
if (value2.__deleteAllChildren) {
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
const allKeys = unique(Object.keys(object1).concat(Object.keys(object2)));
|
||||
const allKeys = unique(Object.keys(value1).concat(Object.keys(value2)));
|
||||
|
||||
return allKeys.reduce((acc: AnyLiteral, key) => {
|
||||
const oldValue = object1[key];
|
||||
const oldValue = value1[key];
|
||||
|
||||
if (!(key in object2)) {
|
||||
if (!value2.hasOwnProperty(key)) {
|
||||
acc[key] = oldValue;
|
||||
} else {
|
||||
const newValue = object2[key];
|
||||
const newValue = value2[key];
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (!newValue?.__delete) {
|
||||
acc[key] = deepMerge(oldValue, newValue);
|
||||
@ -45,3 +36,20 @@ export function deepMerge<T extends any>(value1: T, value2: Record<keyof T, any>
|
||||
return acc;
|
||||
}, {}) as T;
|
||||
}
|
||||
|
||||
function reduceDiff(diff: AnyLiteral) {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (diff.__deleteAllChildren) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return Object.entries(diff).reduce((acc: AnyLiteral, [key, value]) => {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (!value?.__delete) {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
acc[key] = isLiteralObject(value) ? reduceDiff(value) : value;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
@ -188,6 +188,10 @@ export function cloneDeep<T>(value: T): T {
|
||||
}, {} as T);
|
||||
}
|
||||
|
||||
export function isLiteralObject(value: any): value is AnyLiteral {
|
||||
return isObject(value) && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function isObject(value: any): value is object {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
return typeof value === 'object' && value !== null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user