Spaces:
Runtime error
Runtime error
File size: 5,299 Bytes
9756872 | 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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | 'use strict';
const Decimal = require('../types/decimal128');
const ObjectId = require('../types/objectid');
const specialProperties = require('./specialProperties');
const isMongooseObject = require('./isMongooseObject');
const getFunctionName = require('./getFunctionName');
const isBsonType = require('./isBsonType');
const isMongooseArray = require('../types/array/isMongooseArray').isMongooseArray;
const isObject = require('./isObject');
const isPOJO = require('./isPOJO');
const symbols = require('./symbols');
const trustedSymbol = require('./query/trusted').trustedSymbol;
/**
* Object clone with Mongoose natives support.
*
* If options.minimize is true, creates a minimal data object. Empty objects and undefined values will not be cloned. This makes the data payload sent to MongoDB as small as possible.
*
* Functions are never cloned.
*
* @param {Object} obj the object to clone
* @param {Object} options
* @param {Boolean} isArrayChild true if cloning immediately underneath an array. Special case for minimize.
* @return {Object} the cloned object
* @api private
*/
function clone(obj, options, isArrayChild) {
if (obj == null) {
return obj;
}
if (Array.isArray(obj)) {
return cloneArray(isMongooseArray(obj) ? obj.__array : obj, options);
}
if (isMongooseObject(obj)) {
if (options) {
// Single nested subdocs should apply getters later in `applyGetters()`
// when calling `toObject()`. See gh-7442, gh-8295
if (options._skipSingleNestedGetters && obj.$isSingleNested) {
options._calledWithOptions = Object.assign({}, options._calledWithOptions || {}, { getters: false });
}
if (options.retainDocuments && obj.$__ != null) {
const clonedDoc = obj.$clone();
if (obj.__index != null) {
clonedDoc.__index = obj.__index;
}
if (obj.__parentArray != null) {
clonedDoc.__parentArray = obj.__parentArray;
}
clonedDoc.$__parent = obj.$__parent;
return clonedDoc;
}
}
const isSingleNested = obj.$isSingleNested;
if (isPOJO(obj) && obj.$__ != null && obj._doc != null) {
return obj._doc;
}
let ret;
if (options && options.json && typeof obj.toJSON === 'function') {
ret = obj.toJSON(options);
} else {
ret = obj.toObject(options);
}
if (options && options.minimize && !obj.constructor.$__required && isSingleNested && Object.keys(ret).length === 0) {
return undefined;
}
return ret;
}
const objConstructor = obj.constructor;
if (objConstructor) {
switch (getFunctionName(objConstructor)) {
case 'Object':
return cloneObject(obj, options, isArrayChild);
case 'Date':
return new objConstructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
if (isBsonType(obj, 'ObjectId')) {
if (options && options.flattenObjectIds) {
return obj.toJSON();
}
return new ObjectId(obj.id);
}
if (isBsonType(obj, 'Decimal128')) {
if (options && options.flattenDecimals) {
return obj.toJSON();
}
return Decimal.fromString(obj.toString());
}
// object created with Object.create(null)
if (!objConstructor && isObject(obj)) {
return cloneObject(obj, options, isArrayChild);
}
if (typeof obj === 'object' && obj[symbols.schemaTypeSymbol]) {
return obj.clone();
}
// If we're cloning this object to go into a MongoDB command,
// and there's a `toBSON()` function, assume this object will be
// stored as a primitive in MongoDB and doesn't need to be cloned.
if (options && options.bson && typeof obj.toBSON === 'function') {
return obj;
}
if (typeof obj.valueOf === 'function') {
return obj.valueOf();
}
return cloneObject(obj, options, isArrayChild);
}
module.exports = clone;
/*!
* ignore
*/
function cloneObject(obj, options, isArrayChild) {
const minimize = options && options.minimize;
const omitUndefined = options && options.omitUndefined;
const seen = options && options._seen;
const ret = {};
let hasKeys;
if (seen && seen.has(obj)) {
return seen.get(obj);
} else if (seen) {
seen.set(obj, ret);
}
if (trustedSymbol in obj) {
ret[trustedSymbol] = obj[trustedSymbol];
}
let i = 0;
let key = '';
const keys = Object.keys(obj);
const len = keys.length;
for (i = 0; i < len; ++i) {
if (specialProperties.has(key = keys[i])) {
continue;
}
// Don't pass `isArrayChild` down
const val = clone(obj[key], options, false);
if ((minimize === false || omitUndefined) && typeof val === 'undefined') {
delete ret[key];
} else if (minimize !== true || (typeof val !== 'undefined')) {
hasKeys || (hasKeys = true);
ret[key] = val;
}
}
return minimize && !isArrayChild ? hasKeys && ret : ret;
}
function cloneArray(arr, options) {
let i = 0;
const len = arr.length;
const ret = new Array(len);
for (i = 0; i < len; ++i) {
ret[i] = clone(arr[i], options, true);
}
return ret;
}
function cloneRegExp(regexp) {
const ret = new RegExp(regexp.source, regexp.flags);
if (ret.lastIndex !== regexp.lastIndex) {
ret.lastIndex = regexp.lastIndex;
}
return ret;
}
|