deepmerge
Advanced tools
Comparing version 2.0.1 to 2.1.0
@@ -0,1 +1,6 @@ | ||
# [2.1.0](https://github.com/KyleAMathews/deepmerge/releases/tag/v2.1.0) | ||
- feature: Support a custom `isMergeableObject` function [#96](https://github.com/KyleAMathews/deepmerge/pull/96) | ||
- documentation: note a Webpack bug that some users might need to work around [#100](https://github.com/KyleAMathews/deepmerge/pull/100) | ||
# [2.0.1](https://github.com/KyleAMathews/deepmerge/releases/tag/v2.0.1) | ||
@@ -2,0 +7,0 @@ |
@@ -30,28 +30,26 @@ var isMergeableObject = function isMergeableObject(value) { | ||
function cloneUnlessOtherwiseSpecified(value, optionsArgument) { | ||
var clone = !optionsArgument || optionsArgument.clone !== false; | ||
return (clone && isMergeableObject(value)) | ||
? deepmerge(emptyTarget(value), value, optionsArgument) | ||
function cloneUnlessOtherwiseSpecified(value, options) { | ||
return (options.clone !== false && options.isMergeableObject(value)) | ||
? deepmerge(emptyTarget(value), value, options) | ||
: value | ||
} | ||
function defaultArrayMerge(target, source, optionsArgument) { | ||
function defaultArrayMerge(target, source, options) { | ||
return target.concat(source).map(function(element) { | ||
return cloneUnlessOtherwiseSpecified(element, optionsArgument) | ||
return cloneUnlessOtherwiseSpecified(element, options) | ||
}) | ||
} | ||
function mergeObject(target, source, optionsArgument) { | ||
function mergeObject(target, source, options) { | ||
var destination = {}; | ||
if (isMergeableObject(target)) { | ||
if (options.isMergeableObject(target)) { | ||
Object.keys(target).forEach(function(key) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(target[key], optionsArgument); | ||
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); | ||
}); | ||
} | ||
Object.keys(source).forEach(function(key) { | ||
if (!isMergeableObject(source[key]) || !target[key]) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(source[key], optionsArgument); | ||
if (!options.isMergeableObject(source[key]) || !target[key]) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options); | ||
} else { | ||
destination[key] = deepmerge(target[key], source[key], optionsArgument); | ||
destination[key] = deepmerge(target[key], source[key], options); | ||
} | ||
@@ -62,19 +60,21 @@ }); | ||
function deepmerge(target, source, optionsArgument) { | ||
function deepmerge(target, source, options) { | ||
options = options || {}; | ||
options.arrayMerge = options.arrayMerge || defaultArrayMerge; | ||
options.isMergeableObject = options.isMergeableObject || isMergeableObject; | ||
var sourceIsArray = Array.isArray(source); | ||
var targetIsArray = Array.isArray(target); | ||
var options = optionsArgument || { arrayMerge: defaultArrayMerge }; | ||
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; | ||
if (!sourceAndTargetTypesMatch) { | ||
return cloneUnlessOtherwiseSpecified(source, optionsArgument) | ||
return cloneUnlessOtherwiseSpecified(source, options) | ||
} else if (sourceIsArray) { | ||
var arrayMerge = options.arrayMerge || defaultArrayMerge; | ||
return arrayMerge(target, source, optionsArgument) | ||
return options.arrayMerge(target, source, options) | ||
} else { | ||
return mergeObject(target, source, optionsArgument) | ||
return mergeObject(target, source, options) | ||
} | ||
} | ||
deepmerge.all = function deepmergeAll(array, optionsArgument) { | ||
deepmerge.all = function deepmergeAll(array, options) { | ||
if (!Array.isArray(array)) { | ||
@@ -85,3 +85,3 @@ throw new Error('first argument should be an array') | ||
return array.reduce(function(prev, next) { | ||
return deepmerge(prev, next, optionsArgument) | ||
return deepmerge(prev, next, options) | ||
}, {}) | ||
@@ -88,0 +88,0 @@ }; |
@@ -36,28 +36,26 @@ (function (global, factory) { | ||
function cloneUnlessOtherwiseSpecified(value, optionsArgument) { | ||
var clone = !optionsArgument || optionsArgument.clone !== false; | ||
return (clone && isMergeableObject(value)) | ||
? deepmerge(emptyTarget(value), value, optionsArgument) | ||
function cloneUnlessOtherwiseSpecified(value, options) { | ||
return (options.clone !== false && options.isMergeableObject(value)) | ||
? deepmerge(emptyTarget(value), value, options) | ||
: value | ||
} | ||
function defaultArrayMerge(target, source, optionsArgument) { | ||
function defaultArrayMerge(target, source, options) { | ||
return target.concat(source).map(function(element) { | ||
return cloneUnlessOtherwiseSpecified(element, optionsArgument) | ||
return cloneUnlessOtherwiseSpecified(element, options) | ||
}) | ||
} | ||
function mergeObject(target, source, optionsArgument) { | ||
function mergeObject(target, source, options) { | ||
var destination = {}; | ||
if (isMergeableObject(target)) { | ||
if (options.isMergeableObject(target)) { | ||
Object.keys(target).forEach(function(key) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(target[key], optionsArgument); | ||
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); | ||
}); | ||
} | ||
Object.keys(source).forEach(function(key) { | ||
if (!isMergeableObject(source[key]) || !target[key]) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(source[key], optionsArgument); | ||
if (!options.isMergeableObject(source[key]) || !target[key]) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options); | ||
} else { | ||
destination[key] = deepmerge(target[key], source[key], optionsArgument); | ||
destination[key] = deepmerge(target[key], source[key], options); | ||
} | ||
@@ -68,19 +66,21 @@ }); | ||
function deepmerge(target, source, optionsArgument) { | ||
function deepmerge(target, source, options) { | ||
options = options || {}; | ||
options.arrayMerge = options.arrayMerge || defaultArrayMerge; | ||
options.isMergeableObject = options.isMergeableObject || isMergeableObject; | ||
var sourceIsArray = Array.isArray(source); | ||
var targetIsArray = Array.isArray(target); | ||
var options = optionsArgument || { arrayMerge: defaultArrayMerge }; | ||
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; | ||
if (!sourceAndTargetTypesMatch) { | ||
return cloneUnlessOtherwiseSpecified(source, optionsArgument) | ||
return cloneUnlessOtherwiseSpecified(source, options) | ||
} else if (sourceIsArray) { | ||
var arrayMerge = options.arrayMerge || defaultArrayMerge; | ||
return arrayMerge(target, source, optionsArgument) | ||
return options.arrayMerge(target, source, options) | ||
} else { | ||
return mergeObject(target, source, optionsArgument) | ||
return mergeObject(target, source, options) | ||
} | ||
} | ||
deepmerge.all = function deepmergeAll(array, optionsArgument) { | ||
deepmerge.all = function deepmergeAll(array, options) { | ||
if (!Array.isArray(array)) { | ||
@@ -91,3 +91,3 @@ throw new Error('first argument should be an array') | ||
return array.reduce(function(prev, next) { | ||
return deepmerge(prev, next, optionsArgument) | ||
return deepmerge(prev, next, options) | ||
}, {}) | ||
@@ -94,0 +94,0 @@ }; |
44
index.js
@@ -1,2 +0,2 @@ | ||
var isMergeableObject = require('is-mergeable-object') | ||
var defaultIsMergeableObject = require('is-mergeable-object') | ||
@@ -7,28 +7,26 @@ function emptyTarget(val) { | ||
function cloneUnlessOtherwiseSpecified(value, optionsArgument) { | ||
var clone = !optionsArgument || optionsArgument.clone !== false | ||
return (clone && isMergeableObject(value)) | ||
? deepmerge(emptyTarget(value), value, optionsArgument) | ||
function cloneUnlessOtherwiseSpecified(value, options) { | ||
return (options.clone !== false && options.isMergeableObject(value)) | ||
? deepmerge(emptyTarget(value), value, options) | ||
: value | ||
} | ||
function defaultArrayMerge(target, source, optionsArgument) { | ||
function defaultArrayMerge(target, source, options) { | ||
return target.concat(source).map(function(element) { | ||
return cloneUnlessOtherwiseSpecified(element, optionsArgument) | ||
return cloneUnlessOtherwiseSpecified(element, options) | ||
}) | ||
} | ||
function mergeObject(target, source, optionsArgument) { | ||
function mergeObject(target, source, options) { | ||
var destination = {} | ||
if (isMergeableObject(target)) { | ||
if (options.isMergeableObject(target)) { | ||
Object.keys(target).forEach(function(key) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(target[key], optionsArgument) | ||
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options) | ||
}) | ||
} | ||
Object.keys(source).forEach(function(key) { | ||
if (!isMergeableObject(source[key]) || !target[key]) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(source[key], optionsArgument) | ||
if (!options.isMergeableObject(source[key]) || !target[key]) { | ||
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options) | ||
} else { | ||
destination[key] = deepmerge(target[key], source[key], optionsArgument) | ||
destination[key] = deepmerge(target[key], source[key], options) | ||
} | ||
@@ -39,19 +37,21 @@ }) | ||
function deepmerge(target, source, optionsArgument) { | ||
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 options = optionsArgument || { arrayMerge: defaultArrayMerge } | ||
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray | ||
if (!sourceAndTargetTypesMatch) { | ||
return cloneUnlessOtherwiseSpecified(source, optionsArgument) | ||
return cloneUnlessOtherwiseSpecified(source, options) | ||
} else if (sourceIsArray) { | ||
var arrayMerge = options.arrayMerge || defaultArrayMerge | ||
return arrayMerge(target, source, optionsArgument) | ||
return options.arrayMerge(target, source, options) | ||
} else { | ||
return mergeObject(target, source, optionsArgument) | ||
return mergeObject(target, source, options) | ||
} | ||
} | ||
deepmerge.all = function deepmergeAll(array, optionsArgument) { | ||
deepmerge.all = function deepmergeAll(array, options) { | ||
if (!Array.isArray(array)) { | ||
@@ -62,3 +62,3 @@ throw new Error('first argument should be an array') | ||
return array.reduce(function(prev, next) { | ||
return deepmerge(prev, next, optionsArgument) | ||
return deepmerge(prev, next, options) | ||
}, {}) | ||
@@ -65,0 +65,0 @@ } |
@@ -13,3 +13,3 @@ { | ||
], | ||
"version": "2.0.1", | ||
"version": "2.1.0", | ||
"homepage": "https://github.com/KyleAMathews/deepmerge", | ||
@@ -27,6 +27,8 @@ "repository": { | ||
"build": "rollup -c", | ||
"test": "npm run build && tap test/*.js && jsmd readme.md" | ||
"test": "npm run build && tap test/*.js && jsmd readme.md", | ||
"size": "npm run build && uglifyjs --compress --mangle -- ./dist/umd.js | gzip -c | wc -c" | ||
}, | ||
"devDependencies": { | ||
"is-mergeable-object": "1.1.0", | ||
"is-plain-object": "^2.0.4", | ||
"jsmd": "0.3.1", | ||
@@ -36,5 +38,6 @@ "rollup": "0.49.3", | ||
"rollup-plugin-node-resolve": "3.0.0", | ||
"tap": "~7.1.2" | ||
"tap": "~7.1.2", | ||
"uglify-js": "^3.3.12" | ||
}, | ||
"license": "MIT" | ||
} |
deepmerge | ||
========= | ||
> ~554B gzipped, ~1.10KiB minified | ||
> UMD bundle is 567B minified+gzipped | ||
@@ -12,2 +12,14 @@ Merge the enumerable attributes of two objects deeply. | ||
## Webpack bug | ||
If you have `require('deepmerge')` (as opposed to `import merge from 'deepmerge'`) anywhere in your codebase, Webpack 3 and 4 have a bug that [breaks bundling](https://github.com/webpack/webpack/issues/6584). | ||
If you see `Error: merge is not a function`, add this alias to your Webpack config: | ||
``` | ||
alias: { | ||
deepmerge$: path.resolve(__dirname, 'node_modules/deepmerge/dist/umd.js'), | ||
} | ||
``` | ||
example | ||
@@ -101,2 +113,4 @@ ======= | ||
The options object will include the default `isMergeableObject` implementation if the top-level consumer didn't pass a custom function in. | ||
```js | ||
@@ -124,7 +138,6 @@ function overwriteMerge(destinationArray, sourceArray, options) { | ||
```js | ||
const isMergeableObject = require('is-mergeable-object') | ||
const emptyTarget = value => Array.isArray(value) ? [] : {} | ||
const clone = (value, options) => merge(emptyTarget(value), value, options) | ||
function oldArrayMerge(target, source, optionsArgument) { | ||
function oldArrayMerge(target, source, options) { | ||
const destination = target.slice() | ||
@@ -134,7 +147,7 @@ | ||
if (typeof destination[i] === 'undefined') { | ||
const cloneRequested = !optionsArgument || optionsArgument.clone !== false | ||
const shouldClone = cloneRequested && isMergeableObject(e) | ||
destination[i] = shouldClone ? clone(e, optionsArgument) : e | ||
} else if (isMergeableObject(e)) { | ||
destination[i] = merge(target[i], e, optionsArgument) | ||
const cloneRequested = options.clone !== false | ||
const shouldClone = cloneRequested && options.isMergeableObject(e) | ||
destination[i] = shouldClone ? clone(e, options) : e | ||
} else if (options.isMergeableObject(e)) { | ||
destination[i] = merge(target[i], e, options) | ||
} else if (target.indexOf(e) === -1) { | ||
@@ -154,2 +167,46 @@ destination.push(e) | ||
#### isMergeableObject | ||
By default, deepmerge clones every property from almost every kind of object. | ||
You may not want this, if your objects are of special types, and you want to copy the whole object instead of just copying its properties. | ||
You can accomplish this by passing in a function for the `isMergeableObject` option. | ||
If you only want to clone properties of plain objects, and ignore all "special" kinds of instantiated objects, you probably want to drop in [`is-plain-object`](https://github.com/jonschlinkert/is-plain-object). | ||
```js | ||
const isPlainObject = require('is-plain-object') | ||
function SuperSpecial() { | ||
this.special = 'oh yeah man totally' | ||
} | ||
const instantiatedSpecialObject = new SuperSpecial() | ||
const target = { | ||
someProperty: { | ||
cool: 'oh for sure' | ||
} | ||
} | ||
const source = { | ||
someProperty: instantiatedSpecialObject | ||
} | ||
const defaultOutput = merge(target, source) | ||
defaultOutput.someProperty.cool // => 'oh for sure' | ||
defaultOutput.someProperty.special // => 'oh yeah man totally' | ||
defaultOutput.someProperty instanceof SuperSpecial // => false | ||
const customMergeOutput = merge(target, source, { | ||
isMergeableObject: isPlainObject | ||
}) | ||
customMergeOutput.someProperty.cool // => undefined | ||
customMergeOutput.someProperty.special // => 'oh yeah man totally' | ||
customMergeOutput.someProperty instanceof SuperSpecial // => true | ||
``` | ||
#### clone | ||
@@ -156,0 +213,0 @@ |
239
21333
8
8
221