merge.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. 'use strict';
  2. const Assert = require('./assert');
  3. const Clone = require('./clone');
  4. const Utils = require('./utils');
  5. const internals = {};
  6. module.exports = internals.merge = function (target, source, options) {
  7. Assert(target && typeof target === 'object', 'Invalid target value: must be an object');
  8. Assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
  9. if (!source) {
  10. return target;
  11. }
  12. options = Object.assign({ nullOverride: true, mergeArrays: true }, options);
  13. if (Array.isArray(source)) {
  14. Assert(Array.isArray(target), 'Cannot merge array onto an object');
  15. if (!options.mergeArrays) {
  16. target.length = 0; // Must not change target assignment
  17. }
  18. for (let i = 0; i < source.length; ++i) {
  19. target.push(Clone(source[i], { symbols: options.symbols }));
  20. }
  21. return target;
  22. }
  23. const keys = Utils.keys(source, options);
  24. for (let i = 0; i < keys.length; ++i) {
  25. const key = keys[i];
  26. if (key === '__proto__' ||
  27. !Object.prototype.propertyIsEnumerable.call(source, key)) {
  28. continue;
  29. }
  30. const value = source[key];
  31. if (value &&
  32. typeof value === 'object') {
  33. if (!target[key] ||
  34. typeof target[key] !== 'object' ||
  35. (Array.isArray(target[key]) !== Array.isArray(value)) ||
  36. value instanceof Date ||
  37. (Buffer && Buffer.isBuffer(value)) || // $lab:coverage:ignore$
  38. value instanceof RegExp) {
  39. target[key] = Clone(value, { symbols: options.symbols });
  40. }
  41. else {
  42. internals.merge(target[key], value, options);
  43. }
  44. }
  45. else {
  46. if (value !== null &&
  47. value !== undefined) { // Explicit to preserve empty strings
  48. target[key] = value;
  49. }
  50. else if (options.nullOverride) {
  51. target[key] = value;
  52. }
  53. }
  54. }
  55. return target;
  56. };