var defaultIsMergeableObject = require('is-mergeable-object') function emptyTarget(val) { return Array.isArray(val) ? [] : {} } function cloneUnlessOtherwiseSpecified(value, options) { return (options.clone !== false && options.isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, options) : value } function defaultArrayMerge(target, source, options) { return target.concat(source).map(function(element) { return cloneUnlessOtherwiseSpecified(element, options) }) } function mergeObject(target, source, options) { var destination = {} if (options.isMergeableObject(target)) { Object.keys(target).forEach(function(key) { destination[key] = cloneUnlessOtherwiseSpecified(target[key], options) }) } Object.keys(source).forEach(function(key) { if (!options.isMergeableObject(source[key]) || !target[key]) { destination[key] = cloneUnlessOtherwiseSpecified(source[key], options) } else { destination[key] = deepmerge(target[key], source[key], options) } }) return destination } function deepmerge(target, source, options) { options = options || {} options.arrayMerge = options.arrayMerge || defaultArrayMerge options.isMergeableObject = options.isMergeableObject || defaultIsMergeableObject var sourceIsArray = Array.isArray(source) var targetIsArray = Array.isArray(target) var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray if (!sourceAndTargetTypesMatch) { return cloneUnlessOtherwiseSpecified(source, options) } else if (sourceIsArray) { return options.arrayMerge(target, source, options) } else { return mergeObject(target, source, options) } } deepmerge.all = function deepmergeAll(array, options) { if (!Array.isArray(array)) { throw new Error('first argument should be an array') } return array.reduce(function(prev, next) { return deepmerge(prev, next, options) }, {}) } module.exports = deepmerge