_baseMergeDeep.js 3.0 KB

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