HTMLify
clone.js
Views: 6 | Author: cody
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 | 'use strict'; const cloneRegExp = require('regexp-clone'); 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 isObject = require('./isObject'); const symbols = require('./symbols'); /*! * 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(obj, options); } if (isMongooseObject(obj)) { // Single nested subdocs should apply getters later in `applyGetters()` // when calling `toObject()`. See gh-7442, gh-8295 if (options && options._skipSingleNestedGetters && obj.$isSingleNested) { options = Object.assign({}, options, { getters: false }); } if (options && options.json && typeof obj.toJSON === 'function') { return obj.toJSON(options); } return obj.toObject(options); } if (obj.constructor) { switch (getFunctionName(obj.constructor)) { case 'Object': return cloneObject(obj, options, isArrayChild); case 'Date': return new obj.constructor(+obj); case 'RegExp': return cloneRegExp(obj); default: // ignore break; } } if (obj instanceof ObjectId) { return new ObjectId(obj.id); } if (isBsonType(obj, 'Decimal128')) { if (options && options.flattenDecimals) { return obj.toJSON(); } return Decimal.fromString(obj.toString()); } if (!obj.constructor && isObject(obj)) { // object created with Object.create(null) return cloneObject(obj, options, isArrayChild); } if (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 (obj.valueOf != null) { return obj.valueOf(); } return cloneObject(obj, options, isArrayChild); } module.exports = clone; /*! * ignore */ function cloneObject(obj, options, isArrayChild) { const minimize = options && options.minimize; const ret = {}; let hasKeys; for (const k in obj) { if (specialProperties.has(k)) { continue; } // Don't pass `isArrayChild` down const val = clone(obj[k], options); if (!minimize || (typeof val !== 'undefined')) { if (minimize === false && typeof val === 'undefined') { delete ret[k]; } else { hasKeys || (hasKeys = true); ret[k] = val; } } } return minimize && !isArrayChild ? hasKeys && ret : ret; } function cloneArray(arr, options) { const ret = []; for (const item of arr) { ret.push(clone(item, options, true)); } return ret; } |