faasjs/faasjs

View on GitHub
packages/deep_merge/src/index.ts

Summary

Maintainability
A
45 mins
Test Coverage
A
100%
/**
 * A helper function to deep merge objects and array.
 *
 * [![License: MIT](https://img.shields.io/npm/l/@faasjs/deep_merge.svg)](https://github.com/faasjs/faasjs/blob/main/packages/faasjs/deep_merge/LICENSE)
 * [![NPM Version](https://img.shields.io/npm/v/@faasjs/deep_merge.svg)](https://www.npmjs.com/package/@faasjs/deep_merge)
 *
 * ## Install
 *
 * ```sh
 * npm install @faasjs/deep_merge
 * ```
 * @packageDocumentation
 */

const shouldMerge = (item: any) => {
  const type = Object.prototype.toString.call(item)
  return type === '[object Object]' || type === '[object Array]'
}

/**
 * Deep merge two objects or arrays.
 *
 * Features:
 * * All objects will be cloned before merging.
 * * Merging order is from right to left.
 * * If an array include same objects, it will be unique to one.
 *
 * ```ts
 * deepMerge({ a: 1 }, { a: 2 }) // { a: 2 }
 * deepMerge([1, 2], [2, 3]) // [1, 2, 3]
 * ```
 */
export function deepMerge(...sources: any[]): any {
  let acc = Object.create(null)
  for (const source of sources)
    if (Array.isArray(source)) {
      if (!Array.isArray(acc)) acc = []
      acc = [...new Set(source.concat(...(acc as any[])))]
    } else if (shouldMerge(source))
      for (const [key, value] of Object.entries(source)) {
        let val: any
        if (shouldMerge(value)) val = deepMerge(acc[key], value)
        else val = value
        acc = {
          ...acc,
          [key]: val,
        }
      }

  return acc
}