index.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. var isMergeableObject = require('is-mergeable-object')
  2. function emptyTarget(val) {
  3. return Array.isArray(val) ? [] : {}
  4. }
  5. function cloneIfNecessary(value, optionsArgument) {
  6. var clone = optionsArgument && optionsArgument.clone === true
  7. return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value
  8. }
  9. function defaultArrayMerge(target, source, optionsArgument) {
  10. var destination = target.slice()
  11. source.forEach(function(e, i) {
  12. if (typeof destination[i] === 'undefined') {
  13. destination[i] = cloneIfNecessary(e, optionsArgument)
  14. } else if (isMergeableObject(e)) {
  15. destination[i] = deepmerge(target[i], e, optionsArgument)
  16. } else if (target.indexOf(e) === -1) {
  17. destination.push(cloneIfNecessary(e, optionsArgument))
  18. }
  19. })
  20. return destination
  21. }
  22. function mergeObject(target, source, optionsArgument) {
  23. var destination = {}
  24. if (isMergeableObject(target)) {
  25. Object.keys(target).forEach(function(key) {
  26. destination[key] = cloneIfNecessary(target[key], optionsArgument)
  27. })
  28. }
  29. Object.keys(source).forEach(function(key) {
  30. if (!isMergeableObject(source[key]) || !target[key]) {
  31. destination[key] = cloneIfNecessary(source[key], optionsArgument)
  32. } else {
  33. destination[key] = deepmerge(target[key], source[key], optionsArgument)
  34. }
  35. })
  36. return destination
  37. }
  38. function deepmerge(target, source, optionsArgument) {
  39. var sourceIsArray = Array.isArray(source)
  40. var targetIsArray = Array.isArray(target)
  41. var options = optionsArgument || { arrayMerge: defaultArrayMerge }
  42. var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray
  43. if (!sourceAndTargetTypesMatch) {
  44. return cloneIfNecessary(source, optionsArgument)
  45. } else if (sourceIsArray) {
  46. var arrayMerge = options.arrayMerge || defaultArrayMerge
  47. return arrayMerge(target, source, optionsArgument)
  48. } else {
  49. return mergeObject(target, source, optionsArgument)
  50. }
  51. }
  52. deepmerge.all = function deepmergeAll(array, optionsArgument) {
  53. if (!Array.isArray(array) || array.length < 2) {
  54. throw new Error('first argument should be an array with at least two elements')
  55. }
  56. // we are sure there are at least 2 values, so it is safe to have no initial value
  57. return array.reduce(function(prev, next) {
  58. return deepmerge(prev, next, optionsArgument)
  59. })
  60. }
  61. module.exports = deepmerge