datum-merge
Version:
Simplified diff and merging for deeply nested objects
81 lines (80 loc) • 2.83 kB
JavaScript
import { emptyObject, isString } from "./type-utils";
import { createValueKeys, deepClone, getObjectKeys } from "./datum-utils";
import { asLodashPath, deepPatchLog } from "./patch-low";
import { UpdateCode } from "./merge-low";
import { detailMerge, fillUpdateCodes } from "./merge-conf";
export function customMergePatch(target, source, mergeConf, excludeKeys) {
switch (mergeConf) {
case UpdateCode.C:
return false;
case UpdateCode.T:
return [];
case UpdateCode.N:
return false;
case UpdateCode.Y:
return bypassMergePatch(target, source);
}
const mergeCodes = fillUpdateCodes(source, mergeConf, false, excludeKeys);
if (emptyObject(mergeCodes)) {
return false;
}
const targetBkp = deepClone(target);
const changed = detailMerge(target, source, mergeCodes);
const patch = deepMergeLog(targetBkp, target, mergeCodes);
if (changed || (patch === null || patch === void 0 ? void 0 : patch.length) > 0) {
return patch;
}
return false;
}
export function bypassMergePatch(target, source) {
const sourceKeys = getObjectKeys(source !== null && source !== void 0 ? source : {});
if (!source || !sourceKeys.length) {
return false;
}
const mergeCodes = createValueKeys(sourceKeys, UpdateCode.Y);
const targetBkp = deepClone(target);
Object.assign(target, Object.assign({}, source));
const patch = deepMergeLog(targetBkp, target, mergeCodes);
return !(patch === null || patch === void 0 ? void 0 : patch.length) ? false : patch;
}
export function deepMergeLog(lhsObj, rhsObj, mergeCodes) {
const mergeLog = deepPatchLog(lhsObj, rhsObj, false, true);
if (!(mergeLog === null || mergeLog === void 0 ? void 0 : mergeLog.length)) {
return [];
}
const opCodeMap = {
"add": UpdateCode.I,
"replace": UpdateCode.H,
"remove": UpdateCode.D,
"test": UpdateCode.N,
};
for (const patchItem of mergeLog) {
const pathParts = asLodashPath(patchItem.path);
patchItem.code = !mergeCodes
? opCodeMap[patchItem.op]
: selectPathCode(mergeCodes, pathParts);
}
return mergeLog;
}
;
export function selectPathCode(mergeCodes, pathParts) {
if (!mergeCodes || emptyObject(mergeCodes)) {
return UpdateCode.N;
}
let currConf = mergeCodes;
for (let itr = 0; itr < pathParts.length; itr++) {
const part = pathParts[itr];
const partConf = currConf[part];
if (!partConf) {
return UpdateCode.N;
}
if (isString(partConf)) {
return partConf;
}
if (itr === pathParts.length - 1) {
return UpdateCode.I;
}
currConf = partConf;
}
return UpdateCode.N;
}