Path: blob/master/node_modules/@hapi/hoek/lib/clone.js
1126 views
'use strict';12const Reach = require('./reach');3const Types = require('./types');4const Utils = require('./utils');567const internals = {8needsProtoHack: new Set([Types.set, Types.map, Types.weakSet, Types.weakMap])9};101112module.exports = internals.clone = function (obj, options = {}, _seen = null) {1314if (typeof obj !== 'object' ||15obj === null) {1617return obj;18}1920let clone = internals.clone;21let seen = _seen;2223if (options.shallow) {24if (options.shallow !== true) {25return internals.cloneWithShallow(obj, options);26}2728clone = (value) => value;29}30else if (seen) {31const lookup = seen.get(obj);32if (lookup) {33return lookup;34}35}36else {37seen = new Map();38}3940// Built-in object types4142const baseProto = Types.getInternalProto(obj);43if (baseProto === Types.buffer) {44return Buffer && Buffer.from(obj); // $lab:coverage:ignore$45}4647if (baseProto === Types.date) {48return new Date(obj.getTime());49}5051if (baseProto === Types.regex) {52return new RegExp(obj);53}5455// Generic objects5657const newObj = internals.base(obj, baseProto, options);58if (newObj === obj) {59return obj;60}6162if (seen) {63seen.set(obj, newObj); // Set seen, since obj could recurse64}6566if (baseProto === Types.set) {67for (const value of obj) {68newObj.add(clone(value, options, seen));69}70}71else if (baseProto === Types.map) {72for (const [key, value] of obj) {73newObj.set(key, clone(value, options, seen));74}75}7677const keys = Utils.keys(obj, options);78for (const key of keys) {79if (key === '__proto__') {80continue;81}8283if (baseProto === Types.array &&84key === 'length') {8586newObj.length = obj.length;87continue;88}8990const descriptor = Object.getOwnPropertyDescriptor(obj, key);91if (descriptor) {92if (descriptor.get ||93descriptor.set) {9495Object.defineProperty(newObj, key, descriptor);96}97else if (descriptor.enumerable) {98newObj[key] = clone(obj[key], options, seen);99}100else {101Object.defineProperty(newObj, key, { enumerable: false, writable: true, configurable: true, value: clone(obj[key], options, seen) });102}103}104else {105Object.defineProperty(newObj, key, {106enumerable: true,107writable: true,108configurable: true,109value: clone(obj[key], options, seen)110});111}112}113114return newObj;115};116117118internals.cloneWithShallow = function (source, options) {119120const keys = options.shallow;121options = Object.assign({}, options);122options.shallow = false;123124const seen = new Map();125126for (const key of keys) {127const ref = Reach(source, key);128if (typeof ref === 'object' ||129typeof ref === 'function') {130131seen.set(ref, ref);132}133}134135return internals.clone(source, options, seen);136};137138139internals.base = function (obj, baseProto, options) {140141if (options.prototype === false) { // Defaults to true142if (internals.needsProtoHack.has(baseProto)) {143return new baseProto.constructor();144}145146return baseProto === Types.array ? [] : {};147}148149const proto = Object.getPrototypeOf(obj);150if (proto &&151proto.isImmutable) {152153return obj;154}155156if (baseProto === Types.array) {157const newObj = [];158if (proto !== baseProto) {159Object.setPrototypeOf(newObj, proto);160}161162return newObj;163}164165if (internals.needsProtoHack.has(baseProto)) {166const newObj = new proto.constructor();167if (proto !== baseProto) {168Object.setPrototypeOf(newObj, proto);169}170171return newObj;172}173174return Object.create(proto);175};176177178