You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cvm/src/packages/dlayer-old/deep-merge.js

38 lines
1.2 KiB
JavaScript

"use strict";
// A strict deep-merging implementation that *only* merges regular objects, and prevents prototype pollution
function isObject(value) {
// TODO: Disallow special object types, for statically defined values (or just disallow specifying static values in the root schema in dlayer?)
return (value != null && typeof value === "object" && !Array.isArray(value));
}
module.exports = function deepMerge(a, b) {
let merged = Object.create(null);
let keys = new Set([ ... Object.keys(a), ... Object.keys(b) ]);
for (let key of keys) {
// Technically over-blocks *any* 'constructor' key
if (key === "__proto__" || key === "constructor") {
continue;
}
let valueA = a[key];
let valueB = b[key];
if (isObject(valueA) && valueB === undefined) {
merged[key] = valueA;
} else if (isObject(valueB) && valueA === undefined) {
merged[key] = valueB;
} else if (isObject(valueA) && isObject(valueB)) {
merged[key] = deepMerge(valueA, valueB);
} else if (!isObject(valueA) && !isObject(valueB)) {
merged[key] = valueB ?? valueA;
} else {
// FIXME: Identifiable error type, and include the error path as well
throw new Error("Cannot merge non-object into object");
}
}
return merged;
};