UNPKG

@rxap/utilities

Version:

A collection of utility functions, types and interfaces.

264 lines 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MergeDeepRight = MergeDeepRight; exports.MergeDeepLeft = MergeDeepLeft; exports.MergeArrayDeep = MergeArrayDeep; exports.UseLeftArray = UseLeftArray; exports.UseRightArray = UseRightArray; exports.deepMerge = deepMerge; const helpers_1 = require("./helpers"); /** * Checks if the provided object has a specific property. * * @function _has * @param {string} prop - The property name to check for in the object. * @param {any} obj - The object to check for the property. This can be of any type that can have properties (e.g., objects, arrays, etc.). * @returns {boolean} Returns true if the object has the specified property, false otherwise. * * @example * // returns true * _has('name', { name: 'John', age: 30 }); * * @example * // returns false * _has('height', { name: 'John', age: 30 }); * * @example * // returns true * _has('0', ['apple', 'banana', 'cherry']); * * @example * // returns false * _has('3', ['apple', 'banana', 'cherry']); */ function _has(prop, obj) { return Object.prototype.hasOwnProperty.call(obj, prop); } /** * The `mergeWithKey` function merges two string arrays into a single object, using the array indices as keys. * If a key exists in both arrays, a custom merge function is applied to the values of the key in both arrays. * * @param {function} fn - A function that takes three string parameters: the key (K), the value from the left array (lk), and the value from the right array (rk). * This function is applied when a key exists in both arrays and should return the value to be used in the result object for that key. * @param {string[]} l - The left array to be merged. * @param {string[]} r - The right array to be merged. * * @returns {Record<any, any>} - The resulting object after merging the two input arrays. The keys of the object are the indices of the arrays, * and the values are either the value from the left array, the value from the right array, or the result of the custom merge function. * * @example * // returns {0: 'a', 1: 'b', 2: 'c', 3: 'd'} * mergeWithKey((k, lk, rk) => lk + rk, ['a', 'b'], ['c', 'd']); * * @throws {TypeError} - Throws a TypeError if the first argument is not a function or if the second and third arguments are not arrays of strings. */ function mergeWithKey(fn, l, r) { const result = {}; let k; for (k in l) { if (_has(k, l)) { result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k]; } } for (k in r) { if (_has(k, r) && !_has(k, result)) { result[k] = r[k]; } } return result; } /** * This function merges two objects deeply by applying a custom function to each key-value pair. * The custom function is applied to the values of each key in both objects. * If the value of a key in both objects is another object, the function is applied recursively. * * @param {function} fn - A function that takes three arguments: * 1. K: The key of the current key-value pair. * 2. lk: The value of the current key in the left object. * 3. rk: The value of the current key in the right object. * The function should return a value that will replace the current value in the merged object. * * @param {any} lObj - The left object to be merged. This object will not be modified. * * @param {any} rObj - The right object to be merged. This object will not be modified. * * @returns {any} - Returns a new object that is the result of deeply merging lObj and rObj. * For each key, if the value in both objects is an object, the function is applied recursively. * Otherwise, the custom function is applied to the values of the key in both objects. * * @example * // returns { a: 1, b: { c: 3, d: 4 } } * mergeDeepWithKey((k, l, r) => l + r, { a: 1, b: { c: 2 } }, { a: 0, b: { c: 1, d: 4 } }); */ function mergeDeepWithKey(fn, lObj, rObj) { return mergeWithKey(function (k, lVal, rVal) { if ((0, helpers_1.isObject)(lVal) && (0, helpers_1.isObject)(rVal)) { return mergeDeepWithKey(fn, lVal, rVal); } else { return fn(k, lVal, rVal); } }, lObj, rObj); } /** * Merges two objects deeply, giving priority to the properties of the second object (`rObj`) in case of a conflict. * * @param {any} lObj - The first object to be merged. This object's properties will be overridden by `rObj`'s properties in case of a conflict. * @param {any} rObj - The second object to be merged. This object's properties will override `lObj`'s properties in case of a conflict. * @param {MergeArrayFunction} mergeArrayFunction - The function used to merge arrays * * @returns {any} A new object that is the result of a deep merge of `lObj` and `rObj`. In case of a conflict, the properties of `rObj` will take precedence. * * @example * // returns { a: 1, b: 2, c: 3 } * mergeDeepRight({ a: 1, b: 2 }, { b: 3, c: 3 }); * * @function MergeDeepRight */ function MergeDeepRight(lObj, rObj, mergeArrayFunction) { return mergeDeepWithKey(function (k, lVal, rVal) { if (Array.isArray(rVal)) { if (Array.isArray(lVal)) { return mergeArrayFunction(lVal, rVal, MergeDeepRight); } } return rVal === undefined ? lVal : rVal; }, lObj, rObj); } /** * Merges two objects deeply, giving priority to the properties of the first object (`lObj`) in case of a conflict. * * @param {any} lObj - The first object to be merged. This object's properties will override `rObj`'s properties in case of a conflict. * @param {any} rObj - The second object to be merged. This object's properties will be overridden by `lObj`'s properties in case of a conflict. * @param {MergeArrayFunction} mergeArrayFunction - The function used to merge arrays * * @returns {any} A new object that is the result of a deep merge of `lObj` and `rObj`. In case of a conflict, the properties of `lObj` will take precedence. * * @example * // returns { a: 1, b: 2, c: 3 } * mergeDeepLeft({ a: 1, b: 2 }, { b: 3, c: 3 }); * * @function MergeDeepLeft */ function MergeDeepLeft(lObj, rObj, mergeArrayFunction) { return mergeDeepWithKey(function (k, lVal, rVal) { if (Array.isArray(lVal)) { if (Array.isArray(rVal)) { return mergeArrayFunction(lVal, rVal, MergeDeepLeft); } } return lVal === undefined ? rVal : lVal; }, lObj, rObj); } /** * Merges two arrays deeply by applying a custom merge function to elements at corresponding indices. * * This function creates a new array where each element is the result of a deep merge operation between * elements from two input arrays at the same index. The merging of elements at each index is handled by * a user-provided merge function. If an element exists in the second array but not in the first, the element * from the second array is taken as is. If an element exists in both arrays, the merge function is applied. * * @param {any[]} a - The first array to merge. * @param {any[]} b - The second array to merge. Elements in this array can overwrite or be merged with elements in the first array. * @param {MergeFunction} mergeDeepFunction - A function that defines how two elements should be merged deeply. It should take two values and return the merged result. * @returns {any[]} A new array containing the deeply merged elements of the two input arrays. * * @example * const array1 = [{ name: "Alice" }, { name: "Bob" }]; * const array2 = [{ age: 25 }, { age: 30 }]; * const mergedArray = MergeArrayDeep(array1, array2, (x, y) => ({ ...x, ...y })); * // mergedArray would be [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }] */ function MergeArrayDeep(a, b, mergeDeepFunction) { const clone = a.slice(); for (let i = 0; i < Math.max(a.length, b.length); i++) { if (b[i] !== undefined) { if (a[i] === undefined) { clone[i] = b[i]; } else { clone[i] = deepMerge(clone[i], b[i], mergeDeepFunction); } } } return clone; } /** * Returns a shallow copy of the first array passed to the function. * * This function ignores the second array and the merge function provided as parameters. * It simply returns a new array that is a shallow copy of the first array, meaning that * the elements of the new array are exactly the same as the elements of the input array `a`. * Changes to the elements of the returned array will reflect on the corresponding elements * of the original array if those elements are objects. * * @param a - The array to be copied. * @param b - This parameter is not used in the function. * @param mergeDeepFunction - This parameter is not used in the function. * @returns A new array that is a shallow copy of array `a`. */ function UseLeftArray(a, b, mergeDeepFunction) { return a.slice(); } /** * Returns a shallow copy of the second array provided. * * This function ignores the first array and the merge function provided, and simply returns a new array that is a shallow copy of the second array. This means that the new array will have the same elements as the second array, but will be a different object in memory. * * @param a - The first array, which is not used in this function. * @param b - The second array, from which a shallow copy is created and returned. * @param mergeDeepFunction - A function intended for merging, which is not utilized in this function. * @returns A new array that is a shallow copy of array `b`. */ function UseRightArray(a, b, mergeDeepFunction) { return b.slice(); } /** * Merges two objects or arrays deeply, returning a new object or array that contains the combined contents of both. * If the same key exists in both objects, the value from the second object (`b`) will be used. * If the same index exists in both arrays, the value from the second array (`b`) will be used. * * @template T The type of the objects or arrays to be merged. * * @param {T} a The first object or array to merge. This will not be modified. * @param {Partial<T> | RecursivePartial<T> | T} b The second object or array to merge. This will not be modified. * @param {Function} mergeDeepFunction The function to use to merge nested objects or arrays. * * @returns {T} A new object or array that contains the combined contents of `a` and `b`. * * @throws {TypeError} If `a` or `b` is not an object or array. * * @example * * deepMerge({ a: 1, b: 2 }, { b: 3, c: 4 }); // Returns { a: 1, b: 3, c: 4 } * deepMerge([1, 2], [2, 3]); // Returns [2, 3] * * @note * * - If `a` and `b` are both arrays, the returned array will have a length equal to the longer of the two input arrays. * - If `a` and `b` are both objects, the returned object will contain all keys present in either `a` or `b`. * - If `a` is an array and `b` is an object, or vice versa, a TypeError will be thrown. * - This function uses recursion to merge objects and arrays deeply. Therefore, it may not be suitable for very large or deeply nested objects or arrays due to the risk of a stack overflow. * */ function deepMerge(a, b, mergeDeepFunction = MergeDeepRight, mergeArrayFunction) { if (!mergeArrayFunction) { mergeArrayFunction = mergeDeepFunction === MergeDeepRight ? UseRightArray : UseLeftArray; } if (Array.isArray(a) || Array.isArray(b)) { if (Array.isArray(a) && Array.isArray(b)) { return mergeArrayFunction(a, b, mergeDeepFunction); } } if (!(0, helpers_1.isObject)(a) || !(0, helpers_1.isObject)(b)) { if (mergeDeepFunction === MergeDeepRight) { return b; } else if (mergeDeepFunction === MergeDeepLeft) { return a; } return b; } return mergeDeepFunction(a, b, mergeArrayFunction); } //# sourceMappingURL=deep-merge.js.map