json-object-merge
Version:
Merge JSON Object using rules
123 lines (122 loc) • 5.14 kB
JavaScript
import { __spreadArray } from "tslib";
/* eslint-disable import/no-named-as-default-member */
import jp from "jsonpath";
import { cloneDeep, isArray, isPlainObject } from "lodash";
export var JSONObjectMerge = function (target, source, rules, report) {
if (rules === void 0) { rules = {}; }
if (report === void 0) { report = false; }
var pathToOperationMap = {};
for (var jsonPathExpression in rules) {
var _paths = jp.paths(target, jsonPathExpression);
for (var _i = 0, _paths_1 = _paths; _i < _paths_1.length; _i++) {
var pathComponents = _paths_1[_i];
pathComponents.shift();
pathComponents.unshift("$", "data");
pathToOperationMap[jp.stringify(pathComponents)] =
rules[jsonPathExpression];
}
}
var result = { data: cloneDeep(target) };
var sourceObj = { data: cloneDeep(source) };
var updatedPaths = [];
var pathQueue = [["$", "data"]];
while (pathQueue.length > 0) {
var currentPath = pathQueue.shift();
var currentPathStr = jp.stringify(currentPath);
var currentValue = jp.value(result, currentPathStr);
var currentValueFromSource = jp.value(sourceObj, currentPathStr);
var replace = false;
if (isArray(currentValue)) {
var operation = isArray(currentValueFromSource)
? pathToOperationMap[currentPathStr] || "COMBINE"
: "REPLACE";
switch (operation) {
case "REPLACE":
replace = true;
break;
case "APPEND":
if (report) {
updatedPaths.push({
path: currentPath,
operation: "APPEND",
count: currentValueFromSource.length
});
}
currentValue.push.apply(currentValue, currentValueFromSource);
break;
case "PREPEND":
if (report) {
updatedPaths.push({
path: currentPath,
operation: "PREPEND",
count: currentValueFromSource.length
});
}
currentValue.unshift.apply(currentValue, currentValueFromSource);
break;
default:
for (var i = 0; i < currentValue.length; i++) {
pathQueue.push(__spreadArray(__spreadArray([], currentPath, true), [i], false));
}
for (var i = currentValue.length; i < currentValueFromSource.length; i++) {
currentValue.push(currentValueFromSource[i]);
if (report) {
updatedPaths.push({
path: __spreadArray(__spreadArray([], currentPath, true), [i], false),
operation: "COMBINE"
});
}
}
}
}
else if (isPlainObject(currentValue)) {
var operation = isPlainObject(currentValueFromSource)
? pathToOperationMap[currentPathStr] || "COMBINE"
: "REPLACE";
switch (operation) {
case "REPLACE":
replace = true;
break;
default:
for (var property in currentValue) {
pathQueue.push(__spreadArray(__spreadArray([], currentPath, true), [property], false));
}
for (var property in currentValueFromSource) {
if (currentValue[property] === undefined) {
currentValue[property] = currentValueFromSource[property];
if (report) {
updatedPaths.push({
path: __spreadArray(__spreadArray([], currentPath, true), [property], false),
operation: "COMBINE"
});
}
}
}
}
}
else {
replace = true;
}
if (replace && currentValueFromSource !== undefined) {
jp.value(result, currentPathStr, currentValueFromSource);
if (report) {
updatedPaths.push({
path: __spreadArray([], currentPath, true),
operation: "REPLACE"
});
}
}
}
if (report) {
return {
merged: result.data,
report: {
updatedPaths: updatedPaths.map(function (updatedPath) {
updatedPath.path = __spreadArray(["$"], updatedPath.path.slice(2), true);
return updatedPath;
})
}
};
}
return result.data;
};