datum-merge
Version:
Simplified diff and merging for deeply nested objects
144 lines (143 loc) • 4.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateCode = void 0;
exports.mergeScalarField = mergeScalarField;
exports.mergeVectorField = mergeVectorField;
const lodash_es_1 = require("lodash-es");
const type_utils_1 = require("./type-utils");
const datum_utils_1 = require("./datum-utils");
exports.UpdateCode = {
T: "T",
C: "C",
N: "N",
Y: "Y",
B: "B",
U: "U",
H: "H",
I: "I",
D: "D",
XR: "XR",
XM: "XM",
XD: "XD",
XI: "XI",
XS: "XS",
XF: "XF",
};
function mergeScalarField(target, source, label, mergeCode) {
const sourceHas = !(0, type_utils_1.isNullish)(source[label]);
const targetKey = target.hasOwnProperty(label);
const targetHas = targetKey && !(0, type_utils_1.isNullish)(target[label]);
if (!targetHas && !sourceHas) {
return false;
}
if (targetHas && sourceHas) {
if ((0, type_utils_1.typeOfValue)(target[label]) !== (0, type_utils_1.typeOfValue)(source[label])) {
throw new TypeError("scalar type mismatch for " + label);
}
if (target[label] === source[label]) {
return false;
}
}
let migrateVal = false;
switch (mergeCode) {
case exports.UpdateCode.N:
return false;
case exports.UpdateCode.Y:
target[label] = (0, datum_utils_1.deepClone)(source[label]);
return true;
case exports.UpdateCode.B:
if (sourceHas)
migrateVal = true;
break;
case exports.UpdateCode.U:
if (targetHas)
migrateVal = true;
break;
case exports.UpdateCode.I:
if (!targetHas)
migrateVal = true;
break;
case exports.UpdateCode.H:
if (targetHas && sourceHas)
migrateVal = true;
break;
case exports.UpdateCode.D:
if (targetHas && !sourceHas)
migrateVal = true;
break;
case exports.UpdateCode.XR:
case exports.UpdateCode.XS:
case exports.UpdateCode.XF:
case exports.UpdateCode.XM:
case exports.UpdateCode.XD:
case exports.UpdateCode.XI:
return mergeVectorField(target, source, label, mergeCode);
}
if (!migrateVal) {
return false;
}
target[label] = !sourceHas || (0, type_utils_1.isPrimitive)(source[label])
? source[label]
: (0, datum_utils_1.deepClone)(source[label]);
if ((0, type_utils_1.emptyValue)(target[label])) {
delete target[label];
return targetKey;
}
return true;
}
;
function mergeVectorField(target, source, label, mergeCode) {
var _a, _b;
let sourceVals = source[label];
if ((0, type_utils_1.isNullish)(sourceVals)) {
return false;
}
let sourceVec = (0, type_utils_1.isArrayOfAny)(sourceVals);
const targetKey = target.hasOwnProperty(label);
const targetHas = targetKey && !(0, type_utils_1.isNullish)(target[label]);
const targetVec = (0, type_utils_1.isArrayOfAny)(target[label]);
if (targetHas && !targetVec) {
throw new TypeError("type change to vector for " + label);
}
if (!sourceVec) {
sourceVals = [sourceVals];
sourceVec = true;
}
let targetVals;
switch (mergeCode) {
case exports.UpdateCode.N:
return false;
case exports.UpdateCode.Y:
target[label] = (0, datum_utils_1.deepClone)(sourceVals);
return true;
case exports.UpdateCode.XR:
targetVals = sourceVals;
break;
case exports.UpdateCode.XS:
targetVals = (0, lodash_es_1.concat)((_a = target[label]) !== null && _a !== void 0 ? _a : [], sourceVals);
break;
case exports.UpdateCode.XF:
targetVals = (0, lodash_es_1.concat)(sourceVals, (_b = target[label]) !== null && _b !== void 0 ? _b : []);
break;
case exports.UpdateCode.B:
case exports.UpdateCode.XM:
targetVals = (0, lodash_es_1.unionWith)(target[label], sourceVals, datum_utils_1.deepEquals);
break;
case exports.UpdateCode.XD:
targetVals = (0, lodash_es_1.differenceWith)(target[label], sourceVals, datum_utils_1.deepEquals);
break;
case exports.UpdateCode.XI:
targetVals = (0, lodash_es_1.intersectionWith)(target[label], sourceVals, datum_utils_1.deepEquals);
break;
default:
return false;
}
if (!(targetVals === null || targetVals === void 0 ? void 0 : targetVals.length)) {
delete target[label];
return targetKey;
}
const changed = !(0, datum_utils_1.areArraysEqual)(targetVals, target[label]);
target[label] = !changed ? targetVals : (0, datum_utils_1.deepClone)(targetVals);
return changed;
}
;