@empathyco/x-deep-merge
Version:
Utility for deep cloning objects.
140 lines • 4.39 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.deepMerge = deepMerge;
exports.replaceBehaviour = replaceBehaviour;
exports.deepMergeBehaviour = deepMergeBehaviour;
var tslib_1 = require("tslib");
var x_utils_1 = require("@empathyco/x-utils");
var Behaviour;
(function (Behaviour) {
Behaviour["Replace"] = "replace";
Behaviour["DeepMerge"] = "deep-merge";
})(Behaviour || (Behaviour = {}));
/**
* Clones deeply all of the sources objects values into the target, except the arrays,
* which only generates a new one, but keeping the references of the sources one.
*
* TODO Make it work with circular references.
*
* @param target - The object which will be used as the base to clone all the sources into.
* @param sources - One or more objects to clone to the target.
*
* @returns The target modified.
*/
function deepMerge(target) {
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
return sources.reduce(cloneSourcesProperties, target || {});
}
var behaviourMap = new WeakMap();
/**
* When setting replace behaviour to an object, target properties will not be used,
* only the source ones.
*
* @param obj - The object to set its merge behavior.
* @example
* ```ts
* const target = { children: { a: 1, b: 2, c: 3 } };
* const firstSource = { children: replaceBehaviour({ c: 4, d: 5 }) };
* deepMerge(target, firstSource);
* // `target` is now { children: { c: 4, d: 5 } }
* ```
*
* @returns The same object with the new behaviour.
*/
function replaceBehaviour(obj) {
behaviourMap.set(obj, Behaviour.Replace);
return obj;
}
/**
* When setting deep merge behaviour, target and source properties will be used. This is the default
* behavior.
*
* @param obj - The object to set its merge behavior.
*
* @returns The same object with the new behaviour.
*/
function deepMergeBehaviour(obj) {
behaviourMap.set(obj, Behaviour.DeepMerge);
return obj;
}
/**
* A function which clones the properties of two sources.
*
* @param target - The target object to clone in.
* @param source - The source objet to clone.
*
* @returns The union of the target and source.
*/
function cloneSourcesProperties(target, source) {
if (source) {
return Object.entries(source).reduce(cloneObjectProperties, target);
}
else {
return target || {};
}
}
/**
* A function which clones the properties of two object.
*
* @param target - The target object to clone in.
* @param source - Key-Value to clone into the target object.
* @param source.0 - Key to clone into the target object.
* @param source.1 - Value to clone into the target object.
*
* @returns The target object updated with the entry parameter.
*/
function cloneObjectProperties(target, _a) {
var key = _a[0], value = _a[1];
if (value === undefined) {
delete target[key];
}
else if ((0, x_utils_1.isObject)(value)) {
mergeObject(target, [key, value]);
}
else if (Array.isArray(value)) {
target[key] = tslib_1.__spreadArray([], value, true);
}
else {
target[key] = value;
}
return target;
}
/**
* A function which merges two sources.
*
* @param target - The target object to clone in.
* @param source - Key-Value to clone into the target object.
* @param source.0 - Key to clone into the target object.
* @param source.1 - Value to clone into the target object.
*
*/
function mergeObject(target, _a) {
var key = _a[0], value = _a[1];
var mergeBehaviour = getMergeBehaviour(target[key], value);
if (mergeBehaviour === Behaviour.Replace) {
target[key] = deepMerge({}, value);
replaceBehaviour(target[key]);
}
else if (mergeBehaviour === Behaviour.DeepMerge) {
target[key] = deepMerge(target[key] || {}, value);
deepMergeBehaviour(target[key]);
}
else {
target[key] = deepMerge((0, x_utils_1.isObject)(target[key]) ? target[key] : {}, value);
}
}
/**
* A function which detects the merge behaviour.
*
* @param targetValue - The target object.
* @param sourceValue - The source objet.
*
* @returns The correct behaviour.
*/
function getMergeBehaviour(targetValue, sourceValue) {
return behaviourMap.get(sourceValue) || behaviourMap.get(targetValue);
}
//# sourceMappingURL=deep-merge.js.map