froebel
Version:
TypeScript utility library
85 lines (68 loc) • 2.49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clone = _interopRequireDefault(require("./clone"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const merge_ = (a, b) => {
const visited = new Map();
return mergeItems(a, b, visited);
};
const mergeItems = (a, b, visited) => {
if (isPrimitive(a) || isPrimitive(b)) return (0, _clone.default)(b);
if (!visited.has(a)) visited.set(a, new Map());
if (visited.get(a).has(b)) return visited.get(a).get(b);
let result;
if (Array.isArray(b)) {
const clonedA = Array.isArray(a) ? (0, _clone.default)(a) : [];
const clonedB = (0, _clone.default)(b);
result = [...clonedA, ...clonedB];
for (let i = 0; i < result.length; i++) {
if (result[i] === clonedA || result[i] === clonedB) result[i] = result;
}
} else if (b instanceof Set) {
result = new Set([...(a instanceof Set ? a : []), ...b]);
if (result.has(a) || result.has(b)) {
result.delete(a);
result.delete(b);
result.add(result);
}
} else if (b instanceof Map) {
result = new Map([...(a instanceof Map ? a : []), ...b]);
const keys = [...result.keys()];
if (keys.includes(a)) {
result.set(result, result.get(a));
result.delete(a);
}
if (keys.includes(b)) {
result.set(result, result.get(b));
result.delete(b);
}
for (const [k, v] of result) {
if (v === a || v === b) result.set(k, result);
}
} else {
const keys = [...new Set([...Object.keys(a), ...Object.keys(b)])];
result = {};
visited.get(a).set(b, result);
for (const key of keys) {
result[key] = !(key in b) ? (0, _clone.default)(a[key]) : !(key in a) ? (0, _clone.default)(b[key]) : mergeItems(a[key], b[key], visited);
}
}
visited.get(a).set(b, result);
return result;
};
/**
* Recursively merges `A` and `B`. If a property in `A` and `B` is of a
* different type (i.e. it's not an array, Set, Map, or plain object in both,
* the value from `B` will be used in the result).
*
* If there are self-references in the cloned values, array / Set items, or Map
* keys or values, they will also be self-referencing in the result.
*/
const merge = merge_;
var _default = merge;
exports.default = _default;
const isPrimitive = value => typeof value !== "object" || value === null;
module.exports = Object.assign(exports.default || {}, exports);