| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 | 
							- 'use strict';
 
- const Types = require('./types');
 
- const Utils = require('./utils');
 
- const internals = {
 
-     needsProtoHack: new Set([Types.set, Types.map, Types.weakSet, Types.weakMap])
 
- };
 
- module.exports = internals.clone = function (obj, options = {}, _seen = null) {
 
-     if (typeof obj !== 'object' ||
 
-         obj === null) {
 
-         return obj;
 
-     }
 
-     let clone = internals.clone;
 
-     let seen = _seen;
 
-     if (options.shallow) {
 
-         if (options.shallow !== true) {
 
-             return internals.cloneWithShallow(obj, options);
 
-         }
 
-         clone = (value) => value;
 
-     }
 
-     else {
 
-         seen = seen || new Map();
 
-         const lookup = seen.get(obj);
 
-         if (lookup) {
 
-             return lookup;
 
-         }
 
-     }
 
-     // Built-in object types
 
-     const baseProto = Types.getInternalProto(obj);
 
-     if (baseProto === Types.buffer) {
 
-         return Buffer && Buffer.from(obj);              // $lab:coverage:ignore$
 
-     }
 
-     if (baseProto === Types.date) {
 
-         return new Date(obj.getTime());
 
-     }
 
-     if (baseProto === Types.regex) {
 
-         return new RegExp(obj);
 
-     }
 
-     // Generic objects
 
-     const newObj = internals.base(obj, baseProto, options);
 
-     if (newObj === obj) {
 
-         return obj;
 
-     }
 
-     if (seen) {
 
-         seen.set(obj, newObj);                              // Set seen, since obj could recurse
 
-     }
 
-     if (baseProto === Types.set) {
 
-         for (const value of obj) {
 
-             newObj.add(clone(value, options, seen));
 
-         }
 
-     }
 
-     else if (baseProto === Types.map) {
 
-         for (const [key, value] of obj) {
 
-             newObj.set(key, clone(value, options, seen));
 
-         }
 
-     }
 
-     const keys = Utils.keys(obj, options);
 
-     for (const key of keys) {
 
-         if (key === '__proto__') {
 
-             continue;
 
-         }
 
-         if (baseProto === Types.array &&
 
-             key === 'length') {
 
-             newObj.length = obj.length;
 
-             continue;
 
-         }
 
-         const descriptor = Object.getOwnPropertyDescriptor(obj, key);
 
-         if (descriptor) {
 
-             if (descriptor.get ||
 
-                 descriptor.set) {
 
-                 Object.defineProperty(newObj, key, descriptor);
 
-             }
 
-             else if (descriptor.enumerable) {
 
-                 newObj[key] = clone(obj[key], options, seen);
 
-             }
 
-             else {
 
-                 Object.defineProperty(newObj, key, { enumerable: false, writable: true, configurable: true, value: clone(obj[key], options, seen) });
 
-             }
 
-         }
 
-         else {
 
-             Object.defineProperty(newObj, key, {
 
-                 enumerable: true,
 
-                 writable: true,
 
-                 configurable: true,
 
-                 value: clone(obj[key], options, seen)
 
-             });
 
-         }
 
-     }
 
-     return newObj;
 
- };
 
- internals.cloneWithShallow = function (source, options) {
 
-     const keys = options.shallow;
 
-     options = Object.assign({}, options);
 
-     options.shallow = false;
 
-     const storage = Utils.store(source, keys);    // Move shallow copy items to storage
 
-     const copy = internals.clone(source, options);      // Deep copy the rest
 
-     Utils.restore(copy, source, storage);         // Shallow copy the stored items and restore
 
-     return copy;
 
- };
 
- internals.base = function (obj, baseProto, options) {
 
-     if (baseProto === Types.array) {
 
-         return [];
 
-     }
 
-     if (options.prototype === false) {                  // Defaults to true
 
-         if (internals.needsProtoHack.has(baseProto)) {
 
-             return new baseProto.constructor();
 
-         }
 
-         return {};
 
-     }
 
-     const proto = Object.getPrototypeOf(obj);
 
-     if (proto &&
 
-         proto.isImmutable) {
 
-         return obj;
 
-     }
 
-     if (internals.needsProtoHack.has(baseProto)) {
 
-         const newObj = new proto.constructor();
 
-         if (proto !== baseProto) {
 
-             Object.setPrototypeOf(newObj, proto);
 
-         }
 
-         return newObj;
 
-     }
 
-     return Object.create(proto);
 
- };
 
 
  |