You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
298 lines
6.0 KiB
JavaScript
298 lines
6.0 KiB
JavaScript
12 months ago
|
'use strict';
|
||
|
|
||
|
/*!
|
||
|
* Module dependencies.
|
||
|
*/
|
||
|
|
||
|
const specialProperties = ['__proto__', 'constructor', 'prototype'];
|
||
|
|
||
|
/**
|
||
|
* Clones objects
|
||
|
*
|
||
|
* @param {Object} obj the object to clone
|
||
|
* @param {Object} options
|
||
|
* @return {Object} the cloned object
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
const clone = exports.clone = function clone(obj, options) {
|
||
|
if (obj === undefined || obj === null)
|
||
|
return obj;
|
||
|
|
||
|
if (Array.isArray(obj))
|
||
|
return exports.cloneArray(obj, options);
|
||
|
|
||
|
if (obj.constructor) {
|
||
|
if (/ObjectI[dD]$/.test(obj.constructor.name)) {
|
||
|
return 'function' == typeof obj.clone
|
||
|
? obj.clone()
|
||
|
: new obj.constructor(obj.id);
|
||
|
}
|
||
|
|
||
|
if (obj.constructor.name === 'ReadPreference') {
|
||
|
return new obj.constructor(obj.mode, clone(obj.tags, options));
|
||
|
}
|
||
|
|
||
|
if ('Binary' == obj._bsontype && obj.buffer && obj.value) {
|
||
|
return 'function' == typeof obj.clone
|
||
|
? obj.clone()
|
||
|
: new obj.constructor(obj.value(true), obj.sub_type);
|
||
|
}
|
||
|
|
||
|
if ('Date' === obj.constructor.name || 'Function' === obj.constructor.name)
|
||
|
return new obj.constructor(+obj);
|
||
|
|
||
|
if ('RegExp' === obj.constructor.name)
|
||
|
return new RegExp(obj);
|
||
|
|
||
|
if ('Buffer' === obj.constructor.name)
|
||
|
return Buffer.from(obj);
|
||
|
}
|
||
|
|
||
|
if (isObject(obj))
|
||
|
return exports.cloneObject(obj, options);
|
||
|
|
||
|
if (obj.valueOf)
|
||
|
return obj.valueOf();
|
||
|
};
|
||
|
|
||
|
/*!
|
||
|
* ignore
|
||
|
*/
|
||
|
|
||
|
exports.cloneObject = function cloneObject(obj, options) {
|
||
|
const minimize = options && options.minimize,
|
||
|
ret = {},
|
||
|
keys = Object.keys(obj),
|
||
|
len = keys.length;
|
||
|
let hasKeys = false,
|
||
|
val,
|
||
|
k = '',
|
||
|
i = 0;
|
||
|
|
||
|
for (i = 0; i < len; ++i) {
|
||
|
k = keys[i];
|
||
|
// Not technically prototype pollution because this wouldn't merge properties
|
||
|
// onto `Object.prototype`, but avoid properties like __proto__ as a precaution.
|
||
|
if (specialProperties.indexOf(k) !== -1) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
val = clone(obj[k], options);
|
||
|
|
||
|
if (!minimize || ('undefined' !== typeof val)) {
|
||
|
hasKeys || (hasKeys = true);
|
||
|
ret[k] = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return minimize
|
||
|
? hasKeys && ret
|
||
|
: ret;
|
||
|
};
|
||
|
|
||
|
exports.cloneArray = function cloneArray(arr, options) {
|
||
|
const ret = [],
|
||
|
l = arr.length;
|
||
|
let i = 0;
|
||
|
for (; i < l; i++)
|
||
|
ret.push(clone(arr[i], options));
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Merges `from` into `to` without overwriting existing properties.
|
||
|
*
|
||
|
* @param {Object} to
|
||
|
* @param {Object} from
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
exports.merge = function merge(to, from) {
|
||
|
const keys = Object.keys(from);
|
||
|
|
||
|
for (const key of keys) {
|
||
|
if (specialProperties.indexOf(key) !== -1) {
|
||
|
continue;
|
||
|
}
|
||
|
if ('undefined' === typeof to[key]) {
|
||
|
to[key] = from[key];
|
||
|
} else {
|
||
|
if (exports.isObject(from[key])) {
|
||
|
merge(to[key], from[key]);
|
||
|
} else {
|
||
|
to[key] = from[key];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Same as merge but clones the assigned values.
|
||
|
*
|
||
|
* @param {Object} to
|
||
|
* @param {Object} from
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
exports.mergeClone = function mergeClone(to, from) {
|
||
|
const keys = Object.keys(from);
|
||
|
|
||
|
for (const key of keys) {
|
||
|
if (specialProperties.indexOf(key) !== -1) {
|
||
|
continue;
|
||
|
}
|
||
|
if ('undefined' === typeof to[key]) {
|
||
|
to[key] = clone(from[key]);
|
||
|
} else {
|
||
|
if (exports.isObject(from[key])) {
|
||
|
mergeClone(to[key], from[key]);
|
||
|
} else {
|
||
|
to[key] = clone(from[key]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Read pref helper (mongo 2.2 drivers support this)
|
||
|
*
|
||
|
* Allows using aliases instead of full preference names:
|
||
|
*
|
||
|
* p primary
|
||
|
* pp primaryPreferred
|
||
|
* s secondary
|
||
|
* sp secondaryPreferred
|
||
|
* n nearest
|
||
|
*
|
||
|
* @param {String} pref
|
||
|
*/
|
||
|
|
||
|
exports.readPref = function readPref(pref) {
|
||
|
switch (pref) {
|
||
|
case 'p':
|
||
|
pref = 'primary';
|
||
|
break;
|
||
|
case 'pp':
|
||
|
pref = 'primaryPreferred';
|
||
|
break;
|
||
|
case 's':
|
||
|
pref = 'secondary';
|
||
|
break;
|
||
|
case 'sp':
|
||
|
pref = 'secondaryPreferred';
|
||
|
break;
|
||
|
case 'n':
|
||
|
pref = 'nearest';
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return pref;
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Read Concern helper (mongo 3.2 drivers support this)
|
||
|
*
|
||
|
* Allows using string to specify read concern level:
|
||
|
*
|
||
|
* local 3.2+
|
||
|
* available 3.6+
|
||
|
* majority 3.2+
|
||
|
* linearizable 3.4+
|
||
|
* snapshot 4.0+
|
||
|
*
|
||
|
* @param {String|Object} concern
|
||
|
*/
|
||
|
|
||
|
exports.readConcern = function readConcern(concern) {
|
||
|
if ('string' === typeof concern) {
|
||
|
switch (concern) {
|
||
|
case 'l':
|
||
|
concern = 'local';
|
||
|
break;
|
||
|
case 'a':
|
||
|
concern = 'available';
|
||
|
break;
|
||
|
case 'm':
|
||
|
concern = 'majority';
|
||
|
break;
|
||
|
case 'lz':
|
||
|
concern = 'linearizable';
|
||
|
break;
|
||
|
case 's':
|
||
|
concern = 'snapshot';
|
||
|
break;
|
||
|
}
|
||
|
concern = { level: concern };
|
||
|
}
|
||
|
return concern;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Object.prototype.toString.call helper
|
||
|
*/
|
||
|
|
||
|
const _toString = Object.prototype.toString;
|
||
|
exports.toString = function(arg) {
|
||
|
return _toString.call(arg);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Determines if `arg` is an object.
|
||
|
*
|
||
|
* @param {Object|Array|String|Function|RegExp|any} arg
|
||
|
* @return {Boolean}
|
||
|
*/
|
||
|
|
||
|
const isObject = exports.isObject = function(arg) {
|
||
|
return '[object Object]' == exports.toString(arg);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Object.keys helper
|
||
|
*/
|
||
|
|
||
|
exports.keys = Object.keys;
|
||
|
|
||
|
/**
|
||
|
* Basic Object.create polyfill.
|
||
|
* Only one argument is supported.
|
||
|
*
|
||
|
* Based on https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
|
||
|
*/
|
||
|
|
||
|
exports.create = 'function' == typeof Object.create
|
||
|
? Object.create
|
||
|
: create;
|
||
|
|
||
|
function create(proto) {
|
||
|
if (arguments.length > 1) {
|
||
|
throw new Error('Adding properties is not supported');
|
||
|
}
|
||
|
|
||
|
function F() { }
|
||
|
F.prototype = proto;
|
||
|
return new F;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* inheritance
|
||
|
*/
|
||
|
|
||
|
exports.inherits = function(ctor, superCtor) {
|
||
|
ctor.prototype = exports.create(superCtor.prototype);
|
||
|
ctor.prototype.constructor = ctor;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Check if this object is an arguments object
|
||
|
*
|
||
|
* @param {Any} v
|
||
|
* @return {Boolean}
|
||
|
*/
|
||
|
|
||
|
exports.isArgumentsObject = function(v) {
|
||
|
return Object.prototype.toString.call(v) === '[object Arguments]';
|
||
|
};
|