datum-merge
Version:
Simplified diff and merging for deeply nested objects
96 lines (95 loc) • 3.95 kB
JavaScript
import { isArrayOfAny, emptyObject, isObject, isString } from "./type-utils";
import { deepClone, getObjectKeys } from "./datum-utils";
import { deepDiffTyped } from "./diff-high";
import { UpdateCode, mergeScalarField, mergeVectorField } from "./merge-low";
export function updateCodeInfo(mergeCode) {
if (!isString(mergeCode)) {
return { enable: false };
}
const allowUnset = [
UpdateCode.Y, UpdateCode.D, UpdateCode.U,
UpdateCode.XR, UpdateCode.XD, UpdateCode.XI
].includes(mergeCode);
const allowInsert = [
UpdateCode.Y, UpdateCode.I, UpdateCode.B,
UpdateCode.XR, UpdateCode.XM, UpdateCode.XS, UpdateCode.XF
].includes(mergeCode);
const allowUpdate = [
UpdateCode.Y, UpdateCode.H, UpdateCode.U, UpdateCode.B,
UpdateCode.XR, UpdateCode.XS, UpdateCode.XF,
UpdateCode.XM, UpdateCode.XI, UpdateCode.XD
].includes(mergeCode);
return {
insert: allowInsert,
update: allowUpdate,
unset: allowUnset,
enable: allowInsert || allowUpdate || allowUnset,
};
}
export function shallowMerge(target, source, scalarCode, vectorCode, excludeKeys, includeKeys) {
const sourceKeys = getObjectKeys(source, excludeKeys, includeKeys);
if (!(sourceKeys === null || sourceKeys === void 0 ? void 0 : sourceKeys.length)) {
return false;
}
let changed = false;
for (const label of sourceKeys) {
if (isArrayOfAny(target[label]) || isArrayOfAny(source[label])) {
if (mergeVectorField(target, source, label, vectorCode !== null && vectorCode !== void 0 ? vectorCode : scalarCode)) {
changed = true;
}
continue;
}
if (mergeScalarField(target, source, label, scalarCode))
changed = true;
}
return changed;
}
export function immutableMerge(target, source, scalarCode, vectorCode) {
const targetCopy = deepClone(target);
shallowMerge(targetCopy, source, scalarCode, vectorCode);
return targetCopy;
}
;
export function deepMerge(target, source, scalarCode, vectorCode, nestedCode) {
const sourceKeys = getObjectKeys(source);
if (!(sourceKeys === null || sourceKeys === void 0 ? void 0 : sourceKeys.length)) {
return false;
}
let changed = false;
for (const label of sourceKeys) {
if (isArrayOfAny(target[label]) || isArrayOfAny(source[label])) {
if (mergeVectorField(target, source, label, vectorCode)) {
changed = true;
}
continue;
}
if (isObject(target[label]) && isObject(source[label])) {
if (nestedCode === UpdateCode.N)
continue;
if (nestedCode === UpdateCode.Y) {
if (mergeScalarField(target, source, label, scalarCode))
changed = true;
continue;
}
if (deepMerge(target[label], source[label], nestedCode.startsWith("X") ? scalarCode : nestedCode, nestedCode.startsWith("X") ? nestedCode : vectorCode, nestedCode)) {
changed = true;
}
continue;
}
if (mergeScalarField(target, source, label, scalarCode)) {
changed = true;
}
}
return changed;
}
export function immutableDeepMerge(target, source, scalarCode, vectorCode, nestedCode) {
const targetCopy = deepClone(target);
deepMerge(targetCopy, source, scalarCode, vectorCode !== null && vectorCode !== void 0 ? vectorCode : scalarCode, nestedCode !== null && nestedCode !== void 0 ? nestedCode : scalarCode);
return targetCopy;
}
;
export function diffFromMerge(target, source, scalarCode, vectorCode, nestedCode, orderInd = false) {
const targetCopy = immutableDeepMerge(target, source, scalarCode, vectorCode, nestedCode);
const delta = deepDiffTyped(target, targetCopy, orderInd);
return emptyObject(delta) ? false : delta;
}