@open-kappa/myjson
Version:
A simple JSON management library.
180 lines • 5.96 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeJson = exports.JsonMergePolicy = void 0;
/* eslint-disable no-shadow */
/**
* @brief Enum to list possible behaviors in case of conflicting values
* during JSON merge.
*/
var JsonMergePolicy;
(function (JsonMergePolicy) {
JsonMergePolicy[JsonMergePolicy["KEEP_LEFT"] = 0] = "KEEP_LEFT";
JsonMergePolicy[JsonMergePolicy["KEEP_RIGHT"] = 1] = "KEEP_RIGHT";
JsonMergePolicy[JsonMergePolicy["CONFLICT"] = 2] = "CONFLICT";
})(JsonMergePolicy || (JsonMergePolicy = {}));
exports.JsonMergePolicy = JsonMergePolicy;
/* eslint-enable no-shadow */
/**
* @brief Merge two arrays.
* @private
* @param {Array<any>} a1 The left array.
* @param {Array<any>} a2 The right array.
* @param {JsonMergePolicy} policy The merge policy.
* @param {(j1: any, j2: any) => boolean} arrayComparator The element
* comparator.
* @return {Error | null} null in case of success.
*/
function _mergeTwoArrays(a1, a2, policy, arrayComparator) {
for (let i = 0; i < a2.length; ++i) {
const e2 = a2[i];
let found = false;
let j = 0;
for (; j < a1.length; ++j) {
const e1 = a1[j];
found = arrayComparator(e1, e2);
if (found)
break;
}
if (!found) {
a1.push(e2);
}
else {
const e1 = a1[j];
// eslint-disable-next-line no-use-before-define
const ret = _mergeObjectHelper(a1, j, e1, e2, policy, arrayComparator);
if (ret !== null)
return ret;
}
}
return null;
}
/**
* @brief Merge two objects.
* @private
* @param {any} o1 The left parent object.
* @param {string | number} k The key under merging.
* @param {any} v1 The left value.
* @param {any} v2 The right value.
* @param {JsonMergePolicy} policy The merge policy.
* @param {(j1: any, j2: any) => boolean} arrayComparator The element
* comparator.
* @return {Error | null} null in case of success.
*/
function _mergeObjectHelper(o1, k, v1, v2, policy, arrayComparator) {
const t1 = typeof v1;
const t2 = typeof v2;
if (Array.isArray(v1) && Array.isArray(v2)) {
return _mergeTwoArrays(v1, v2, policy, arrayComparator);
}
else if (t1 !== t2) {
// Keep one:
switch (policy) {
case JsonMergePolicy.KEEP_LEFT:
return null;
case JsonMergePolicy.KEEP_RIGHT:
o1[k] = v2;
return null;
case JsonMergePolicy.CONFLICT:
return new Error("Conflict on key " + k);
default:
}
}
else if (t1 === "object") {
// eslint-disable-next-line no-use-before-define
return _mergeTwoObjects(v1, v2, policy, arrayComparator);
}
else if (t1 === "number"
|| t1 === "string"
|| t1 === "boolean") {
// Keep one:
switch (policy) {
case JsonMergePolicy.KEEP_LEFT:
return null;
case JsonMergePolicy.KEEP_RIGHT:
o1[k] = v2;
return null;
case JsonMergePolicy.CONFLICT:
if (v1 !== v2) {
return new Error("Conflict on key " + k);
}
return null;
default:
}
}
return new Error("Cannot merge type " + t1 + " with type " + t2);
}
/**
* @brief Merge two objects.
* @private
* @param {any} o1 The left value.
* @param {any} o2 The right value.
* @param {JsonMergePolicy} policy The merge policy.
* @param {(j1: any, j2: any) => boolean} arrayComparator The element
* comparator.
* @return {Error | null} null in case of success.
*/
function _mergeTwoObjects(o1, o2, policy, arrayComparator) {
const keys2 = Object.keys(o2);
for (let i = 0; i < keys2.length; ++i) {
const k = keys2[i];
const v1 = o1[k];
const v2 = o2[k];
if (typeof v1 === "undefined") {
o1[k] = v2;
continue;
}
const res = _mergeObjectHelper(o1, k, v1, v2, policy, arrayComparator);
if (res !== null)
return res;
}
return null;
}
/**
* @brief Default comparator.
* @param {any} _j1 The first object.
* @param {any} _j2 The second object.
* @return {boolean} Always false.
*/
function appendArrayComparator(_j1, _j2) {
return false;
}
/**
* @brief Merge all the given JSONs.
* @param {Array<any>} jsons The list of JSONs to merge.
* @param {JsonMergePolicy} policy The merge policy.
* @param {(j1: any, j2: any) => boolean} arrayComparator The comparator to use.
* Default is appendArrayComparator.
* @return {Promise<any>} A new JSON, as result.
*/
function mergeJson(jsons, policy = JsonMergePolicy.KEEP_LEFT, arrayComparator = appendArrayComparator) {
if (jsons.length === 0)
return Promise.resolve({});
const first = jsons[0];
if (Array.isArray(first)) {
const ret = [];
for (let i = 0; i < jsons.length; ++i) {
const res = _mergeTwoArrays(ret, jsons[i], policy, arrayComparator);
if (res !== null)
return Promise.reject(res);
}
return Promise.resolve(ret);
}
else if (typeof first === "object") {
const ret = {};
for (let i = 0; i < jsons.length; ++i) {
const res = _mergeTwoObjects(ret, jsons[i], policy, arrayComparator);
if (res !== null)
return Promise.reject(res);
}
return Promise.resolve(ret);
}
else if (jsons.length === 1
&& (typeof jsons[0] === "number"
|| typeof jsons[0] === "string"
|| typeof jsons[0] === "boolean")) {
return Promise.resolve(jsons[0]);
}
return Promise.reject(new Error("Unable to perform the merge."));
}
exports.mergeJson = mergeJson;
//# sourceMappingURL=mergeJson.js.map