UNPKG

@empathyco/x-deep-merge

Version:
140 lines 4.39 kB
"use strict"; 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