@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
JavaScript
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);
}, {});
};