UNPKG

datum-merge

Version:

Simplified diff and merging for deeply nested objects

166 lines (165 loc) 7.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fillUpdateCodes = exports.immutableCustomMerge = exports.bypassMerge = exports.customMerge = exports.getDetailKeys = exports.immutableDetailMerge = exports.detailMerge = void 0; const type_utils_1 = require("./type-utils"); const datum_utils_1 = require("./datum-utils"); const diff_high_1 = require("./diff-high"); const merge_low_1 = require("./merge-low"); const merge_high_1 = require("./merge-high"); function detailMerge(target, source, mergeCodes) { if (!(0, type_utils_1.isObject)(mergeCodes) || (0, type_utils_1.emptyObject)(mergeCodes)) { return false; } let changed = false; const mergeKeys = (0, datum_utils_1.getObjectKeys)(mergeCodes); for (const label of mergeKeys) { const mergeCode = mergeCodes[label]; if (!(0, type_utils_1.isString)(mergeCode)) { if ((0, type_utils_1.isObject)(target[label]) && (0, type_utils_1.isObject)(source[label])) { changed = detailMerge(target[label], source[label], mergeCode) || changed; continue; } if (!(0, type_utils_1.isObject)(target[label]) && (0, type_utils_1.isObject)(source[label])) { const targetVal = {}; detailMerge(targetVal, source[label], mergeCode); changed = (0, merge_low_1.mergeScalarField)(target, { [label]: targetVal }, label, merge_low_1.UpdateCode.I) || changed; continue; } changed = (0, merge_low_1.mergeScalarField)(target, source, label, merge_low_1.UpdateCode.I) || changed; continue; } if (mergeCode.toString().startsWith("X") ? (0, merge_low_1.mergeVectorField)(target, source, label, mergeCode) : (0, merge_low_1.mergeScalarField)(target, source, label, mergeCode)) { changed = true; } } return changed; } exports.detailMerge = detailMerge; function immutableDetailMerge(target, source, mergeCodes) { const targetCopy = (0, datum_utils_1.deepClone)(target); detailMerge(targetCopy, source, mergeCodes); return targetCopy; } exports.immutableDetailMerge = immutableDetailMerge; function getDetailKeys(obj, mergeCodes, excludeKeys) { const includeKeys = []; if (!obj || !mergeCodes) { return includeKeys; } for (const label of (0, datum_utils_1.getObjectKeys)(obj, excludeKeys)) { const labelConf = mergeCodes[label]; if ((0, type_utils_1.isString)(labelConf) && (0, merge_high_1.updateCodeInfo)(labelConf).enable) includeKeys.push(label); if ((0, type_utils_1.isObject)(labelConf) && !(0, type_utils_1.emptyObject)(labelConf)) includeKeys.push(label); } return includeKeys; } exports.getDetailKeys = getDetailKeys; function customMerge(target, source, mergeConf, excludeKeys) { switch (mergeConf) { case merge_low_1.UpdateCode.C: return false; case merge_low_1.UpdateCode.T: return {}; case merge_low_1.UpdateCode.N: return false; case merge_low_1.UpdateCode.Y: return bypassMerge(target, source); } const mergeCodes = (0, exports.fillUpdateCodes)(source, mergeConf, false, excludeKeys); if ((0, type_utils_1.emptyObject)(mergeCodes)) { return false; } const targetBkp = (0, datum_utils_1.deepClone)(target); const changed = detailMerge(target, source, mergeCodes); const delta = (0, diff_high_1.deepDiffTyped)(targetBkp, target, true); if (changed || !(0, type_utils_1.emptyObject)(delta)) { return delta; } return false; } exports.customMerge = customMerge; function bypassMerge(target, source) { if ((0, type_utils_1.emptyObject)(source)) { return false; } let delta = (0, diff_high_1.deepDiffTyped)(target, source, true); Object.assign(target, Object.assign({}, source)); delta = (0, datum_utils_1.selectObjKeys)(delta, (0, datum_utils_1.getObjectKeys)(source)); return (0, type_utils_1.emptyObject)(delta) ? false : delta; } exports.bypassMerge = bypassMerge; function immutableCustomMerge(target, source, mergeConf, skipFill = false) { const mergeCodes = !skipFill ? (0, exports.fillUpdateCodes)(source, mergeConf) : mergeConf; const targetCopy = (0, datum_utils_1.deepClone)(target); detailMerge(targetCopy, source, mergeCodes); return targetCopy; } exports.immutableCustomMerge = immutableCustomMerge; const fillUpdateCodes = (source, mergeConf, blockUnset = false, excludeKeys) => { if ((0, type_utils_1.isString)(mergeConf)) { mergeConf = { scalar: mergeConf }; } const deepConf = { scalar: (mergeConf === null || mergeConf === void 0 ? void 0 : mergeConf.scalar) || merge_low_1.UpdateCode.B, vector: (mergeConf === null || mergeConf === void 0 ? void 0 : mergeConf.vector) || merge_low_1.UpdateCode.XS, nested: (mergeConf === null || mergeConf === void 0 ? void 0 : mergeConf.nested) || merge_low_1.UpdateCode.N, }; const globKeys = (0, datum_utils_1.getObjectKeys)(mergeConf) .filter((s) => s.includes("*")) .sort((s1, s2) => s2.length - s1.length); const globPats = globKeys.map((g) => (0, datum_utils_1.createGlobRegex)(g)); const mergeCodes = {}; const sourceKeys = (0, datum_utils_1.getObjectKeys)(source); for (const srcLabel of sourceKeys) { const srcValue = source[srcLabel]; const labelConf = mergeConf === null || mergeConf === void 0 ? void 0 : mergeConf[srcLabel]; if (excludeKeys === null || excludeKeys === void 0 ? void 0 : excludeKeys.includes(srcLabel)) { mergeCodes[srcLabel] = merge_low_1.UpdateCode.N; continue; } if ((0, type_utils_1.isNullish)(srcValue) && blockUnset) { mergeCodes[srcLabel] = merge_low_1.UpdateCode.N; continue; } if ((0, type_utils_1.isString)(labelConf)) { mergeCodes[srcLabel] = labelConf; continue; } if ((0, type_utils_1.isObject)(labelConf) && (0, type_utils_1.isObject)(srcValue)) { mergeCodes[srcLabel] = (0, exports.fillUpdateCodes)(srcValue, Object.assign(Object.assign({}, deepConf), labelConf), blockUnset); continue; } const globIndex = globPats.findIndex((r) => r.test(srcLabel)); if (globIndex >= 0) { const globConf = mergeConf[globKeys[globIndex]]; if ((0, type_utils_1.isString)(globConf)) { mergeCodes[srcLabel] = globConf; continue; } if ((0, type_utils_1.isObject)(globConf) && (0, type_utils_1.isObject)(srcValue)) { mergeCodes[srcLabel] = (0, exports.fillUpdateCodes)(srcValue, Object.assign(Object.assign({}, deepConf), globConf), blockUnset); continue; } } if ((0, type_utils_1.isObject)(srcValue)) { mergeCodes[srcLabel] = deepConf.nested; } else if ((0, type_utils_1.isArrayOfAny)(srcValue)) { mergeCodes[srcLabel] = deepConf.vector; } else { mergeCodes[srcLabel] = deepConf.scalar; } } if ((0, datum_utils_1.getObjectKeys)(mergeCodes).length !== sourceKeys.length) { throw new Error("illegal merge config state"); } return mergeCodes; }; exports.fillUpdateCodes = fillUpdateCodes;