All files / packages/core/src/utilities deepMerge.ts

83.33% Statements 30/36
61.11% Branches 22/36
88.88% Functions 8/9
83.33% Lines 30/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 871x 981x   981x             1x           1x 1330x   1330x         1x 2x   2x 2x 2x                         2x     1x 315x   315x 315x 814x     315x 666x 514x   152x       315x                   1x 317x 317x 317x   317x 2x         315x        
const isMergeableObject = (val) => {
  const nonNullObject = val && typeof val === 'object';
 
  return (
    nonNullObject &&
    Object.prototype.toString.call(val) !== '[object RegExp]' &&
    Object.prototype.toString.call(val) !== '[object Date]'
  );
};
 
const emptyTarget = (val) => {
  const isEmpty = Array.isArray(val) ? [] : {};
 
  return isEmpty;
};
 
const cloneIfNecessary = (value, optionsArgument) => {
  const clone = optionsArgument && optionsArgument.clone === true;
 
  return clone && isMergeableObject(value)
    ? deepMerge(emptyTarget(value), value, optionsArgument)
    : value;
};
 
const defaultArrayMerge = (target, source, optionsArgument) => {
  const destination = target.slice();
 
  source.forEach(function (e, i) {
    if (typeof destination[i] === 'undefined') {
      destination[i] = cloneIfNecessary(e, optionsArgument);
    } else Eif (isMergeableObject(e)) {
      destination[i] = deepMerge(target[i], e, optionsArgument);
    } else if (target.indexOf(e) === -1) {
      // IMPORTANT: WE SHOULD NOT PUSH NEW ELEMENTS TO THE ARRAY
      // INSTEAD WE SHOULD REPLACE THE ELEMENT, this will result
      // in unexpected behaviors if the initial tool parameters
      // are desired to override the default tool parameters that are
      // arrays
      destination[i] = cloneIfNecessary(e, optionsArgument);
    }
  });
 
  return destination;
};
 
const mergeObject = (target, source, optionsArgument) => {
  const destination = {};
 
  Eif (isMergeableObject(target)) {
    Object.keys(target).forEach(function (key) {
      destination[key] = cloneIfNecessary(target[key], optionsArgument);
    });
  }
  Object.keys(source).forEach(function (key) {
    if (!isMergeableObject(source[key]) || !target[key]) {
      destination[key] = cloneIfNecessary(source[key], optionsArgument);
    } else {
      destination[key] = deepMerge(target[key], source[key], optionsArgument);
    }
  });
 
  return destination;
};
 
/**
 * Merge two objects, recursively merging any objects that are arrays
 * @param target - The target object.
 * @param source - The source object to merge into the target object.
 * @param optionsArgument - The options object.
 * @returns The merged object.
 */
const deepMerge = (target = {}, source = {}, optionsArgument = undefined) => {
  const array = Array.isArray(source);
  const options = optionsArgument || { arrayMerge: defaultArrayMerge };
  const arrayMerge = options.arrayMerge || defaultArrayMerge;
 
  if (array) {
    return Array.isArray(target)
      ? arrayMerge(target, source, optionsArgument)
      : cloneIfNecessary(source, optionsArgument);
  }
 
  return mergeObject(target, source, optionsArgument);
};
 
export default deepMerge;