UNPKG

deepmerge-plus

Version:

A library for deep (recursive) merging of Javascript objects

199 lines (168 loc) 4.86 kB
import isMergeableObject from 'is-mergeable-object'; function emptyTarget(val) { return Array.isArray(val) ? [] : {} } function cloneUnlessOtherwiseSpecified(value, optionsArgument: IOptions, tmp?: ICache) { const clone = !optionsArgument || optionsArgument.clone !== false; const bool = clone && _isMergeableObject(value, optionsArgument, tmp); let ret = (bool) ? deepmerge(emptyTarget(value), value, optionsArgument) : value; if (optionsArgument?.keyValueOrMode && !bool && tmp && ('key' in tmp)) { if (tmp.destination) { //console.log('destination', tmp.destination[tmp.key], ret, tmp.key); ret = tmp.destination[tmp.key] || ret; } if (tmp.target) { //console.log('target', tmp.target[tmp.key], ret, tmp.key); ret = tmp.target[tmp.key] || ret; } if (tmp.source) { //console.log('source', tmp.source[tmp.key], ret, tmp.key); ret = tmp.source[tmp.key] || ret; } } return ret; } export function _isMergeableObject(value, optionsArgument: IOptions, tmp?: ICache): boolean { let ret = optionsArgument?.isMergeableObject?.(value, isMergeableObject, optionsArgument, tmp) as any; if (ret === null || typeof ret === 'undefined') { if ((typeof value?.[SYMBOL_IS_MERGEABLE] == 'boolean')) { ret = value[SYMBOL_IS_MERGEABLE]; } else { ret = isMergeableObject(value); } } return ret } function defaultArrayMerge(target, source, optionsArgument: IOptions) { return target.concat(source).map(function (element, index, array) { return cloneUnlessOtherwiseSpecified(element, optionsArgument, { key: index, }) }) } function mergeObject(target, source, optionsArgument: IOptions) { let destination = {}; if (_isMergeableObject(target, optionsArgument)) { Object.keys(target).forEach(function (key) { destination[key] = cloneUnlessOtherwiseSpecified(target[key], optionsArgument, { key, source, target, destination, }) }) } Object.keys(source).forEach(function (key) { if (!_isMergeableObject(source[key], optionsArgument, { key, source, target, }) || !target[key]) { destination[key] = cloneUnlessOtherwiseSpecified(source[key], optionsArgument, { key, source, target, }) } else { destination[key] = deepmerge(target[key], source[key], optionsArgument) } }); return destination } export function deepmerge<T1, T2>(x: T1, y: T2, options?: IOptions): Partial<T1 & T2> export function deepmerge<T>(x: Partial<T>, y: Partial<T>, options?: IOptions): Partial<T> export function deepmerge(target, source, optionsArgument) { const sourceIsArray = Array.isArray(source); const targetIsArray = Array.isArray(target); const options = optionsArgument || { arrayMerge: defaultArrayMerge }; const sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; if (!sourceAndTargetTypesMatch) { return cloneUnlessOtherwiseSpecified(source, optionsArgument, { target, source, }); } else if (sourceIsArray) { let arrayMerge = options.arrayMerge || defaultArrayMerge; return arrayMerge(target, source, optionsArgument); } else { return mergeObject(target, source, optionsArgument); } } export interface ICache { key? source? target? destination? } export interface IOptions { clone?: boolean; arrayMerge?(destination: any[], source: any[], options?: IOptions): any[]; isMergeableObject?(value, isMergeableObject: typeof isMergeable, optionsArgument?: IOptions, key?): void; isMergeableObject?(value, isMergeableObject: typeof isMergeable, optionsArgument?: IOptions, key?): boolean; /** * (val = old || new) mode */ keyValueOrMode?: boolean, } export function isMergeable(value: any): boolean { return isMergeableObject(value) } const SYMBOL_IS_MERGEABLE = Symbol.for('SYMBOL_IS_MERGEABLE'); export { SYMBOL_IS_MERGEABLE } export function deepmergeAll<T, T2 = any>(array: Array<Partial<T2 & T>>, optionsArgument?: IOptions): T2 & T { if (!Array.isArray(array)) { throw new Error('first argument should be an array') } // @ts-ignore return array.reduce(function (prev, next) { return deepmerge(prev, next, optionsArgument) }, {}) } export { deepmergeAll as all } export default deepmerge // @ts-ignore if (process.env.TSDX_FORMAT !== 'esm') { Object.defineProperty(deepmerge, "__esModule", { value: true }); Object.defineProperty(deepmerge, 'deepmerge', { value: deepmerge }); Object.defineProperty(deepmerge, 'default', { value: deepmerge }); Object.defineProperty(deepmerge, 'isMergeable', { value: isMergeable }); Object.defineProperty(deepmerge, 'SYMBOL_IS_MERGEABLE', { value: SYMBOL_IS_MERGEABLE }); Object.defineProperty(deepmerge, 'deepmergeAll', { value: deepmergeAll }); Object.defineProperty(deepmerge, 'all', { value: deepmergeAll }); Object.defineProperty(deepmerge, '_isMergeableObject', { value: _isMergeableObject }); }