_baseMergeDeep.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. var assignMergeValue = require('./_assignMergeValue'),
  2. cloneBuffer = require('./_cloneBuffer'),
  3. cloneTypedArray = require('./_cloneTypedArray'),
  4. copyArray = require('./_copyArray'),
  5. initCloneObject = require('./_initCloneObject'),
  6. isArguments = require('./isArguments'),
  7. isArray = require('./isArray'),
  8. isArrayLikeObject = require('./isArrayLikeObject'),
  9. isBuffer = require('./isBuffer'),
  10. isFunction = require('./isFunction'),
  11. isObject = require('./isObject'),
  12. isPlainObject = require('./isPlainObject'),
  13. isTypedArray = require('./isTypedArray'),
  14. safeGet = require('./_safeGet'),
  15. toPlainObject = require('./toPlainObject');
  16. /**
  17. * A specialized version of `baseMerge` for arrays and objects which performs
  18. * deep merges and tracks traversed objects enabling objects with circular
  19. * references to be merged.
  20. *
  21. * @private
  22. * @param {Object} object The destination object.
  23. * @param {Object} source The source object.
  24. * @param {string} key The key of the value to merge.
  25. * @param {number} srcIndex The index of `source`.
  26. * @param {Function} mergeFunc The function to merge values.
  27. * @param {Function} [customizer] The function to customize assigned values.
  28. * @param {Object} [stack] Tracks traversed source values and their merged
  29. * counterparts.
  30. */
  31. function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
  32. var objValue = safeGet(object, key),
  33. srcValue = safeGet(source, key),
  34. stacked = stack.get(srcValue);
  35. if (stacked) {
  36. assignMergeValue(object, key, stacked);
  37. return;
  38. }
  39. var newValue = customizer
  40. ? customizer(objValue, srcValue, (key + ''), object, source, stack)
  41. : undefined;
  42. var isCommon = newValue === undefined;
  43. if (isCommon) {
  44. var isArr = isArray(srcValue),
  45. isBuff = !isArr && isBuffer(srcValue),
  46. isTyped = !isArr && !isBuff && isTypedArray(srcValue);
  47. newValue = srcValue;
  48. if (isArr || isBuff || isTyped) {
  49. if (isArray(objValue)) {
  50. newValue = objValue;
  51. }
  52. else if (isArrayLikeObject(objValue)) {
  53. newValue = copyArray(objValue);
  54. }
  55. else if (isBuff) {
  56. isCommon = false;
  57. newValue = cloneBuffer(srcValue, true);
  58. }
  59. else if (isTyped) {
  60. isCommon = false;
  61. newValue = cloneTypedArray(srcValue, true);
  62. }
  63. else {
  64. newValue = [];
  65. }
  66. }
  67. else if (isPlainObject(srcValue) || isArguments(srcValue)) {
  68. newValue = objValue;
  69. if (isArguments(objValue)) {
  70. newValue = toPlainObject(objValue);
  71. }
  72. else if (!isObject(objValue) || isFunction(objValue)) {
  73. newValue = initCloneObject(srcValue);
  74. }
  75. }
  76. else {
  77. isCommon = false;
  78. }
  79. }
  80. if (isCommon) {
  81. // Recursively merge objects and arrays (susceptible to call stack limits).
  82. stack.set(srcValue, newValue);
  83. mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
  84. stack['delete'](srcValue);
  85. }
  86. assignMergeValue(object, key, newValue);
  87. }
  88. module.exports = baseMergeDeep;