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 993x   993x             1x           1x 1346x   1346x         1x 2x   2x 2x 2x                         2x     1x 318x   318x 318x 823x     318x 675x 521x   154x       318x                   1x 320x 320x 320x   320x 2x         318x        
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;