UNPKG

@storm-stack/utilities

Version:

This package includes various base utility class and various functions to assist in the development process.

71 lines (70 loc) 2.54 kB
import { isFunction, isMergeableObject, propertyUnsafe } from "@storm-stack/types"; const emptyTarget = (val) => { return Array.isArray(val) ? [] : {}; }; const cloneUnlessOtherwiseSpecified = (value, options) => { return options.clone !== false && options.isMergeableObject(value) ? deepMerge(emptyTarget(value), value, options) : value; }; const defaultArrayMerge = (target, source, options) => { return [...target, ...source].map((element) => { return cloneUnlessOtherwiseSpecified(element, options); }); }; const getMergeFunction = (key, options) => { if (!options.customMerge) { return deepMerge; } const customMerge = options.customMerge(key); return isFunction(customMerge) ? customMerge : deepMerge; }; const getKeys = (target) => { return [ ...Object.keys(target), ...Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter((symbol) => { return Object.propertyIsEnumerable.call(target, symbol); }) : [] ]; }; const mergeObject = (target, source, options) => { const destination = {}; if (options.isMergeableObject(target)) { for (const key of getKeys(target)) { destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); } } for (const key of getKeys(source)) { destination[key] = propertyUnsafe(target, key) && options.isMergeableObject(source[key]) ? getMergeFunction(key, options)(target[key], source[key], options) : cloneUnlessOtherwiseSpecified(source[key], options); } return destination; }; export const deepMerge = (target, source, options = {}) => { if (!target || !source) { return target || source; } const _options = options || {}; _options.arrayMerge = options.arrayMerge || defaultArrayMerge; _options.isMergeableObject = _options.isMergeableObject || isMergeableObject; _options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified; const sourceIsArray = Array.isArray(source); const targetIsArray = Array.isArray(target); const sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; if (!sourceAndTargetTypesMatch) { return cloneUnlessOtherwiseSpecified(source, _options); } if (sourceIsArray) { return _options.arrayMerge(target, source, _options); } return mergeObject(target, source, _options); }; deepMerge.all = function deepMergeAll(array, options) { if (!Array.isArray(array)) { throw new TypeError("first argument should be an array"); } return array.reduce((prev, next) => { return deepMerge(prev, next, options); }, {}); };