Source: core/src/util/deepCopy.js

/**
 * Duplicate objects to prevent Cite changing values outside of own scope
 *
 * @access protected
 * @method deepCopy
 * @memberof module:@citation-js/core.util
 *
 * @param {Object} obj - Input object
 * @param {Set} [seen]
 *
 * @return {Object} Duplicated object
 * @throws {TypeError}
 */
export function deepCopy (value, seen = new Set()) {
  if (typeof value !== 'object' || value === null || (value.constructor !== Object && value.constructor !== Array)) {
    return value
  }

  if (seen.has(value)) {
    throw new TypeError('Recursively copying circular structure')
  }

  seen.add(value)
  let copy

  if (value.constructor === Array) {
    copy = value.map(value => deepCopy(value, seen))
  } else {
    const object = {}
    for (const key in value) {
      object[key] = deepCopy(value[key], seen)
    }
    copy = object
  }

  seen.delete(value)
  return copy
}

// // Unfortunately too costly performance-wise, but the
// // proper way to clone any object (apart from arrays perhaps):
// const object = Object.create(Object.getPrototypeOf(value))
// const descriptors = Object.getOwnPropertyDescriptors(value)
// for (let key in descriptors) {
//   const descriptor = descriptors[key]
//   if (descriptor.value) { descriptor.value = deepCopy(descriptor.value) }
//   Object.defineProperty(object, key, descriptor)
// }

export default deepCopy