Comparing version 1.2.4 to 2.0.0
# fast-copy CHANGELOG | ||
## 2.0.0 | ||
- Rewrite in TypeScript | ||
- Add strict mode (for more accurate and thorough copying, at the expense of less performance) | ||
#### BREAKING CHANGES | ||
- Second parameter is now an object of [options](README.md#options) | ||
## 1.2.4 | ||
@@ -4,0 +13,0 @@ |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var create = Object.create, | ||
getSymbols = Object.getOwnPropertySymbols, | ||
getPrototypeOf = Object.getPrototypeOf; | ||
var _Object$prototype = Object.prototype, | ||
hasOwnProperty = _Object$prototype.hasOwnProperty, | ||
propertyIsEnumerable = _Object$prototype.propertyIsEnumerable; | ||
var toStringFunction = Function.prototype.toString; | ||
var create = Object.create, defineProperty = Object.defineProperty, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols, getPrototypeOf = Object.getPrototypeOf; | ||
var _a = Object.prototype, hasOwnProperty = _a.hasOwnProperty, propertyIsEnumerable = _a.propertyIsEnumerable; | ||
/** | ||
* @constant {Object} SUPPORTS cache of values supported | ||
* @enum | ||
* | ||
* @const {Object} SUPPORTS | ||
* | ||
* @property {boolean} SYMBOL_PROPERTIES are symbol properties supported | ||
* @property {boolean} WEAKSET is WeakSet supported | ||
*/ | ||
var SUPPORTS = { | ||
FLAGS: typeof /foo/g.flags === 'string', | ||
SYMBOL_PROPERTIES: typeof global.Object.getOwnPropertySymbols === 'function', | ||
WEAKSET: typeof global.WeakSet === 'function' | ||
SYMBOL_PROPERTIES: typeof getOwnPropertySymbols === 'function', | ||
WEAKSET: typeof WeakSet === 'function', | ||
}; | ||
/** | ||
* @function getNewCache | ||
* @function createCache | ||
* | ||
@@ -26,343 +24,286 @@ * @description | ||
* | ||
* @returns {Object|Weakset} the new cache object | ||
* @returns the new cache object | ||
*/ | ||
var getNewCache = function getNewCache() { | ||
return SUPPORTS.WEAKSET ? new WeakSet() : create({ | ||
_values: [], | ||
add: function add(value) { | ||
this._values.push(value); | ||
}, | ||
has: function has(value) { | ||
return !!~this._values.indexOf(value); | ||
var createCache = function () { | ||
if (SUPPORTS.WEAKSET) { | ||
return new WeakSet(); | ||
} | ||
}); | ||
var object = create({ | ||
add: function (value) { return object._values.push(value); }, | ||
has: function (value) { return !!~object._values.indexOf(value); }, | ||
}); | ||
object._values = []; | ||
return object; | ||
}; | ||
/** | ||
* @function getObjectToCopy | ||
* @function getCleanClone | ||
* | ||
* @description | ||
* get the object to copy, including appropriate prototype | ||
* get an empty version of the object with the same prototype it has | ||
* | ||
* @param {Object} object the object to copy | ||
* @param {function} RealmObject the realm-specific Object constructor | ||
* @param {boolean} isPlainObject is the object a plain object | ||
* @returns {Object} an empty version of the object to copy | ||
* @param object the object to build a clean clone from | ||
* @param realm the realm the object resides in | ||
* @returns the empty cloned object | ||
*/ | ||
var getObjectToCopy = function getObjectToCopy(object, RealmObject, isPlainObject) { | ||
if (isPlainObject) { | ||
var getCleanClone = function (object, realm) { | ||
if (!object.constructor) { | ||
return create(null); | ||
} | ||
var prototype = object.__proto__ || getPrototypeOf(object); | ||
return prototype === RealmObject.prototype ? {} : create(prototype); | ||
} | ||
return object.constructor ? new object.constructor() : create(null); | ||
if (object.constructor === realm.Object) { | ||
return prototype === realm.Object.prototype ? {} : create(prototype); | ||
} | ||
if (~toStringFunction.call(object.constructor).indexOf('[native code]')) { | ||
return new object.constructor(); | ||
} | ||
return create(prototype); | ||
}; | ||
/** | ||
* @function getRegExpFlags | ||
* @function getObjectCloneLoose | ||
* | ||
* @description | ||
* get the flags to apply to the copied regexp | ||
* get a copy of the object based on loose rules, meaning all enumerable keys | ||
* and symbols are copied, but property descriptors are not considered | ||
* | ||
* @param {RegExp} regExp the regexp to get the flags of | ||
* @returns {string} the flags for the regexp | ||
* @param object the object to clone | ||
* @param realm the realm the object resides in | ||
* @param handleCopy the function that handles copying the object | ||
* @returns the copied object | ||
*/ | ||
var getRegExpFlags = function getRegExpFlags(regExp) { | ||
var flags = ''; | ||
if (regExp.global) { | ||
flags += 'g'; | ||
} | ||
if (regExp.ignoreCase) { | ||
flags += 'i'; | ||
} | ||
if (regExp.multiline) { | ||
flags += 'm'; | ||
} | ||
if (regExp.unicode) { | ||
flags += 'u'; | ||
} | ||
if (regExp.sticky) { | ||
flags += 'y'; | ||
} | ||
return flags; | ||
var getObjectCloneLoose = function (object, realm, handleCopy, cache) { | ||
var clone = getCleanClone(object, realm); | ||
for (var key in object) { | ||
if (hasOwnProperty.call(object, key)) { | ||
clone[key] = handleCopy(object[key], cache); | ||
} | ||
} | ||
if (SUPPORTS.SYMBOL_PROPERTIES) { | ||
var symbols = getOwnPropertySymbols(object); | ||
if (symbols.length) { | ||
for (var index = 0, symbol = void 0; index < symbols.length; index++) { | ||
symbol = symbols[index]; | ||
if (propertyIsEnumerable.call(object, symbol)) { | ||
clone[symbol] = handleCopy(object[symbol], cache); | ||
} | ||
} | ||
} | ||
} | ||
return clone; | ||
}; | ||
/** | ||
* @function isObjectCopyable | ||
* @function getObjectCloneStrict | ||
* | ||
* @description | ||
* is the object able to be copied | ||
* get a copy of the object based on strict rules, meaning all keys and symbols | ||
* are copied based on the original property descriptors | ||
* | ||
* @param {any} object the object to test | ||
* @param {Object|Weakset} cache the cache of copied values | ||
* @returns {boolean} can the object be copied | ||
* @param object the object to clone | ||
* @param realm the realm the object resides in | ||
* @param handleCopy the function that handles copying the object | ||
* @returns the copied object | ||
*/ | ||
var isObjectCopyable = function isObjectCopyable(object, cache) { | ||
return typeof object === 'object' && object !== null && !cache.has(object); | ||
var getObjectCloneStrict = function (object, realm, handleCopy, cache) { | ||
var clone = getCleanClone(object, realm); | ||
var properties = SUPPORTS.SYMBOL_PROPERTIES | ||
? [].concat(getOwnPropertyNames(object), getOwnPropertySymbols(object)) | ||
: getOwnPropertyNames(object); | ||
if (properties.length) { | ||
for (var index = 0, property = void 0, descriptor = void 0; index < properties.length; index++) { | ||
property = properties[index]; | ||
if (property !== 'callee' && property !== 'caller') { | ||
descriptor = getOwnPropertyDescriptor(object, property); | ||
descriptor.value = handleCopy(object[property], cache); | ||
defineProperty(clone, property, descriptor); | ||
} | ||
} | ||
} | ||
return clone; | ||
}; | ||
/** | ||
* @function shouldObjectBeCopied | ||
* @function getRegExpFlags | ||
* | ||
* @description | ||
* should the object be copied | ||
* get the flags to apply to the copied regexp | ||
* | ||
* @param {any} object the object to test | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {boolean} should the object be copied | ||
* @param regExp the regexp to get the flags of | ||
* @returns the flags for the regexp | ||
*/ | ||
var shouldObjectBeCopied = function shouldObjectBeCopied(object, realm) { | ||
return typeof object.then !== 'function' && !(object instanceof realm.Error) && !(realm.WeakMap && object instanceof realm.WeakMap) && !(realm.WeakSet && object instanceof realm.WeakSet); | ||
var getRegExpFlags = function (regExp) { | ||
var flags = ''; | ||
if (regExp.global) { | ||
flags += 'g'; | ||
} | ||
if (regExp.ignoreCase) { | ||
flags += 'i'; | ||
} | ||
if (regExp.multiline) { | ||
flags += 'm'; | ||
} | ||
if (regExp.unicode) { | ||
flags += 'u'; | ||
} | ||
if (regExp.sticky) { | ||
flags += 'y'; | ||
} | ||
return flags; | ||
}; | ||
/** | ||
* @function copyArray | ||
* | ||
* @description | ||
* copy the array, deeply copying the values | ||
* | ||
* @param {Array<any>} array the array to copy | ||
* @param {function} copy the function to copy values | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {Array<any>} the copied array | ||
*/ | ||
var copyArray = function copyArray(array, copy, realm) { | ||
var newArray = new array.constructor(); | ||
for (var index = 0; index < array.length; index++) { | ||
newArray[index] = copy(array[index], realm); | ||
} | ||
return newArray; | ||
}; | ||
// utils | ||
var isArray = Array.isArray; | ||
var GLOBAL_THIS = (function () { | ||
if (typeof self !== 'undefined') { | ||
return self; | ||
} | ||
if (typeof window !== 'undefined') { | ||
return window; | ||
} | ||
if (typeof global !== 'undefined') { | ||
return global; | ||
} | ||
if (console && console.error) { | ||
console.error('Unable to locate global object, returning "this".'); | ||
} | ||
})(); | ||
/** | ||
* @function copyArrayBuffer | ||
* @function copy | ||
* | ||
* @description | ||
* copy the arrayBuffer, deeply copying the values | ||
* copy an object deeply as much as possible | ||
* | ||
* @param {ArrayBuffer} arrayBuffer the arrayBuffer to copy | ||
* @returns {ArrayBuffer} the copied bufarrayBufferfer | ||
*/ | ||
var copyArrayBuffer = function copyArrayBuffer(arrayBuffer) { | ||
return arrayBuffer.slice(0); | ||
}; | ||
/** | ||
* @function copyBuffer | ||
* If `strict` is applied, then all properties (including non-enumerable ones) | ||
* are copied with their original property descriptors on both objects and arrays. | ||
* | ||
* @description | ||
* copy the buffer, deeply copying the values | ||
* The object is compared to the global constructors in the `realm` provided, | ||
* and the native constructor is always used to ensure that extensions of native | ||
* objects (allows in ES2015+) are maintained. | ||
* | ||
* @param {Buffer} buffer the buffer to copy | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {Buffer} the copied buffer | ||
* @param object the object to copy | ||
* @param [options] the options for copying with | ||
* @param [options.isStrict] should the copy be strict | ||
* @param [options.realm] the realm (this) object the object is copied from | ||
* @returns the copied object | ||
*/ | ||
var copyBuffer = function copyBuffer(buffer, realm) { | ||
var RealmBuffer = realm.Buffer; | ||
var newBuffer = RealmBuffer.allocUnsafe ? RealmBuffer.allocUnsafe(buffer.length) : new RealmBuffer(buffer.length); | ||
buffer.copy(newBuffer); | ||
return newBuffer; | ||
}; | ||
/** | ||
* @function copyMap | ||
* | ||
* @description | ||
* copy the map values into a new map | ||
* | ||
* @param {Map} map the map to copy | ||
* @param {function} copy the copy object method | ||
* @param {Object} realm the realm the constructor resides in | ||
* @returns {Map} the copied map | ||
*/ | ||
var copyMap = function copyMap(map, copy, realm) { | ||
var newMap = new map.constructor(); | ||
map.forEach(function (value, key) { | ||
return newMap.set(key, copy(value, realm)); | ||
}); | ||
return newMap; | ||
}; | ||
/** | ||
* @function copySet | ||
* | ||
* @description | ||
* copy the set values into a new set | ||
* | ||
* @param {Set} set the set to copy | ||
* @param {function} copy the copy object method | ||
* @param {Object} realm the realm the constructor resides in | ||
* @returns {Set} the copied set | ||
*/ | ||
var copySet = function copySet(set, copy, realm) { | ||
var newSet = new set.constructor(); | ||
set.forEach(function (value) { | ||
return newSet.add(copy(value, realm)); | ||
}); | ||
return newSet; | ||
}; | ||
/** | ||
* @function copyObject | ||
* | ||
* @description | ||
* copy the object values into a new object of the same type | ||
* | ||
* @param {Object} object the object to copy | ||
* @param {function} copy the copy method | ||
* @param {any} realm the realm to check instanceof in | ||
* @param {boolean} isPlainObject is the object to copy a plain object | ||
* @returns {Object} the copied object | ||
*/ | ||
var copyObject = function copyObject(object, copy, realm, isPlainObject) { | ||
var newObject = getObjectToCopy(object, realm.Object, isPlainObject); | ||
for (var key in object) { | ||
if (hasOwnProperty.call(object, key)) { | ||
newObject[key] = copy(object[key], realm); | ||
} | ||
} | ||
if (SUPPORTS.SYMBOL_PROPERTIES) { | ||
var symbols = getSymbols(object); | ||
if (symbols.length) { | ||
for (var index = 0, symbol; index < symbols.length; index++) { | ||
symbol = symbols[index]; | ||
if (propertyIsEnumerable.call(object, symbol)) { | ||
newObject[symbol] = copy(object[symbol], realm); | ||
function copy(object, _a) { | ||
var _b = _a === void 0 ? {} : _a, _c = _b.isStrict, isStrict = _c === void 0 ? false : _c, _d = _b.realm, realm = _d === void 0 ? GLOBAL_THIS : _d; | ||
var RealmArrayBuffer = realm.ArrayBuffer, RealmBuffer = realm.Buffer, RealmMap = realm.Map, RealmSet = realm.Set, RealmWeakMap = realm.WeakMap, RealmWeakSet = realm.WeakSet; | ||
var getObjectClone = isStrict | ||
? getObjectCloneStrict | ||
: getObjectCloneLoose; | ||
/** | ||
* @function handleCopy | ||
* | ||
* @description | ||
* copy the object recursively based on its type | ||
* | ||
* @param object the object to copy | ||
* @returns the copied object | ||
*/ | ||
var handleCopy = function (object, cache) { | ||
if (!object || typeof object !== 'object' || cache.has(object)) { | ||
return object; | ||
} | ||
} | ||
} | ||
} | ||
return newObject; | ||
}; | ||
var Constructor = object.constructor; | ||
// plain objects | ||
if (Constructor === realm.Object) { | ||
cache.add(object); | ||
return getObjectClone(object, realm, handleCopy, cache); | ||
} | ||
var clone; | ||
// arrays | ||
if (isArray(object)) { | ||
cache.add(object); | ||
// if strict, include non-standard properties | ||
if (isStrict) { | ||
return getObjectCloneStrict(object, realm, handleCopy, cache); | ||
} | ||
clone = new Constructor(); | ||
for (var index = 0; index < object.length; index++) { | ||
clone[index] = handleCopy(object[index], cache); | ||
} | ||
return clone; | ||
} | ||
// dates | ||
if (object instanceof realm.Date) { | ||
return new Constructor(object.getTime()); | ||
} | ||
// regexps | ||
if (object instanceof realm.RegExp) { | ||
clone = new Constructor(object.source, object.flags || getRegExpFlags(object)); | ||
clone.lastIndex = object.lastIndex; | ||
return clone; | ||
} | ||
// maps | ||
if (RealmMap && object instanceof RealmMap) { | ||
cache.add(object); | ||
clone = new Constructor(); | ||
object.forEach(function (value, key) { | ||
clone.set(key, handleCopy(value, cache)); | ||
}); | ||
return clone; | ||
} | ||
// sets | ||
if (RealmSet && object instanceof RealmSet) { | ||
cache.add(object); | ||
clone = new Constructor(); | ||
object.forEach(function (value) { | ||
clone.add(handleCopy(value, cache)); | ||
}); | ||
return clone; | ||
} | ||
// buffers (node-only) | ||
if (RealmBuffer && RealmBuffer.isBuffer(object)) { | ||
clone = RealmBuffer.allocUnsafe | ||
? RealmBuffer.allocUnsafe(object.length) | ||
: new Constructor(object.length); | ||
object.copy(clone); | ||
return clone; | ||
} | ||
// arraybuffers / dataviews | ||
if (RealmArrayBuffer) { | ||
// dataviews | ||
if (RealmArrayBuffer.isView(object)) { | ||
return new Constructor(object.buffer.slice(0)); | ||
} | ||
// arraybuffers | ||
if (object instanceof RealmArrayBuffer) { | ||
return object.slice(0); | ||
} | ||
} | ||
// if the object cannot / should not be cloned, don't | ||
if ( | ||
// promise-like | ||
typeof object.then === 'function' || | ||
// errors | ||
object instanceof Error || | ||
// weakmaps | ||
(RealmWeakMap && object instanceof RealmWeakMap) || | ||
// weaksets | ||
(RealmWeakSet && object instanceof RealmWeakSet)) { | ||
return object; | ||
} | ||
cache.add(object); | ||
// assume anything left is a custom constructor | ||
return getObjectClone(object, realm, handleCopy, cache); | ||
}; | ||
return handleCopy(object, createCache()); | ||
} | ||
/** | ||
* @function copyRegExp | ||
* @function strictCopy | ||
* | ||
* @description | ||
* copy the RegExp to a new RegExp with the same properties | ||
* copy the object with `strict` option pre-applied | ||
* | ||
* @param {RegExp} regExp the RegExp to copy | ||
* @param {function} RealmRegExp the realm-specific RegExp constructor | ||
* @returns {RegExp} the copied RegExp | ||
* @param object the object to copy | ||
* @param [options] the options for copying with | ||
* @param [options.realm] the realm (this) object the object is copied from | ||
* @returns the copied object | ||
*/ | ||
var copyRegExp = function copyRegExp(regExp, RealmRegExp) { | ||
var newRegExp = new RealmRegExp(regExp.source, SUPPORTS.FLAGS ? regExp.flags : getRegExpFlags(regExp)); | ||
newRegExp.lastIndex = regExp.lastIndex; | ||
return newRegExp; | ||
copy.strict = function strictCopy(object, options) { | ||
return copy(object, { | ||
isStrict: true, | ||
realm: options ? options.realm : void 0, | ||
}); | ||
}; | ||
/** | ||
* @function copyTypedArray | ||
* | ||
* @description | ||
* copy the typedArray, deeply copying the values | ||
* | ||
* @param {TypedArray} typedArray the typedArray to copy | ||
* @returns {TypedArray} the copied typedArray | ||
*/ | ||
var copyTypedArray = function copyTypedArray(typedArray) { | ||
return new typedArray.constructor(copyArrayBuffer(typedArray.buffer)); | ||
}; | ||
// utils | ||
var isArray = Array.isArray; | ||
/** | ||
* @function copy | ||
* | ||
* @description | ||
* deeply copy the object to a new object of the same type | ||
* | ||
* @param {any} object the object to copy | ||
* @param {any} [realm=global] the realm to check instanceof in | ||
* @returns {any} the copied object | ||
*/ | ||
function copy(object, realm) { | ||
if (realm === void 0) { | ||
realm = global; | ||
} | ||
var _realm = realm, | ||
RealmArrayBuffer = _realm.ArrayBuffer, | ||
RealmBuffer = _realm.Buffer, | ||
RealmDate = _realm.Date, | ||
RealmMap = _realm.Map, | ||
RealmObject = _realm.Object, | ||
RealmRegExp = _realm.RegExp, | ||
RealmSet = _realm.Set; | ||
var cache = getNewCache(); | ||
var handleCopy = function handleCopy(object) { | ||
if (!isObjectCopyable(object, cache)) { | ||
return object; | ||
} | ||
if (isArray(object)) { | ||
cache.add(object); | ||
return copyArray(object, handleCopy, realm); | ||
} | ||
if (object.constructor === RealmObject) { | ||
cache.add(object); | ||
return copyObject(object, handleCopy, realm, true); | ||
} | ||
if (object instanceof RealmDate) { | ||
return new RealmDate(object.getTime()); | ||
} | ||
if (object instanceof RealmRegExp) { | ||
return copyRegExp(object, RealmRegExp); | ||
} | ||
if (RealmMap && object instanceof RealmMap) { | ||
cache.add(object); | ||
return copyMap(object, handleCopy, realm); | ||
} | ||
if (RealmSet && object instanceof RealmSet) { | ||
cache.add(object); | ||
return copySet(object, handleCopy, realm); | ||
} | ||
if (RealmBuffer && RealmBuffer.isBuffer(object)) { | ||
return copyBuffer(object, realm); | ||
} | ||
if (RealmArrayBuffer) { | ||
if (RealmArrayBuffer.isView(object)) { | ||
return copyTypedArray(object); | ||
} | ||
if (object instanceof RealmArrayBuffer) { | ||
return copyArrayBuffer(object); | ||
} | ||
} | ||
if (shouldObjectBeCopied(object, realm)) { | ||
cache.add(object); | ||
return copyObject(object, handleCopy, realm); | ||
} | ||
return object; | ||
}; | ||
return handleCopy(object); | ||
} | ||
exports.default = copy; | ||
module.exports = copy; | ||
//# sourceMappingURL=fast-copy.cjs.js.map |
@@ -1,18 +0,18 @@ | ||
var create = Object.create, | ||
getSymbols = Object.getOwnPropertySymbols, | ||
getPrototypeOf = Object.getPrototypeOf; | ||
var _Object$prototype = Object.prototype, | ||
hasOwnProperty = _Object$prototype.hasOwnProperty, | ||
propertyIsEnumerable = _Object$prototype.propertyIsEnumerable; | ||
var toStringFunction = Function.prototype.toString; | ||
var create = Object.create, defineProperty = Object.defineProperty, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols, getPrototypeOf = Object.getPrototypeOf; | ||
var _a = Object.prototype, hasOwnProperty = _a.hasOwnProperty, propertyIsEnumerable = _a.propertyIsEnumerable; | ||
/** | ||
* @constant {Object} SUPPORTS cache of values supported | ||
* @enum | ||
* | ||
* @const {Object} SUPPORTS | ||
* | ||
* @property {boolean} SYMBOL_PROPERTIES are symbol properties supported | ||
* @property {boolean} WEAKSET is WeakSet supported | ||
*/ | ||
var SUPPORTS = { | ||
FLAGS: typeof /foo/g.flags === 'string', | ||
SYMBOL_PROPERTIES: typeof global.Object.getOwnPropertySymbols === 'function', | ||
WEAKSET: typeof global.WeakSet === 'function' | ||
SYMBOL_PROPERTIES: typeof getOwnPropertySymbols === 'function', | ||
WEAKSET: typeof WeakSet === 'function', | ||
}; | ||
/** | ||
* @function getNewCache | ||
* @function createCache | ||
* | ||
@@ -22,343 +22,286 @@ * @description | ||
* | ||
* @returns {Object|Weakset} the new cache object | ||
* @returns the new cache object | ||
*/ | ||
var getNewCache = function getNewCache() { | ||
return SUPPORTS.WEAKSET ? new WeakSet() : create({ | ||
_values: [], | ||
add: function add(value) { | ||
this._values.push(value); | ||
}, | ||
has: function has(value) { | ||
return !!~this._values.indexOf(value); | ||
var createCache = function () { | ||
if (SUPPORTS.WEAKSET) { | ||
return new WeakSet(); | ||
} | ||
}); | ||
var object = create({ | ||
add: function (value) { return object._values.push(value); }, | ||
has: function (value) { return !!~object._values.indexOf(value); }, | ||
}); | ||
object._values = []; | ||
return object; | ||
}; | ||
/** | ||
* @function getObjectToCopy | ||
* @function getCleanClone | ||
* | ||
* @description | ||
* get the object to copy, including appropriate prototype | ||
* get an empty version of the object with the same prototype it has | ||
* | ||
* @param {Object} object the object to copy | ||
* @param {function} RealmObject the realm-specific Object constructor | ||
* @param {boolean} isPlainObject is the object a plain object | ||
* @returns {Object} an empty version of the object to copy | ||
* @param object the object to build a clean clone from | ||
* @param realm the realm the object resides in | ||
* @returns the empty cloned object | ||
*/ | ||
var getObjectToCopy = function getObjectToCopy(object, RealmObject, isPlainObject) { | ||
if (isPlainObject) { | ||
var getCleanClone = function (object, realm) { | ||
if (!object.constructor) { | ||
return create(null); | ||
} | ||
var prototype = object.__proto__ || getPrototypeOf(object); | ||
return prototype === RealmObject.prototype ? {} : create(prototype); | ||
} | ||
return object.constructor ? new object.constructor() : create(null); | ||
if (object.constructor === realm.Object) { | ||
return prototype === realm.Object.prototype ? {} : create(prototype); | ||
} | ||
if (~toStringFunction.call(object.constructor).indexOf('[native code]')) { | ||
return new object.constructor(); | ||
} | ||
return create(prototype); | ||
}; | ||
/** | ||
* @function getRegExpFlags | ||
* @function getObjectCloneLoose | ||
* | ||
* @description | ||
* get the flags to apply to the copied regexp | ||
* get a copy of the object based on loose rules, meaning all enumerable keys | ||
* and symbols are copied, but property descriptors are not considered | ||
* | ||
* @param {RegExp} regExp the regexp to get the flags of | ||
* @returns {string} the flags for the regexp | ||
* @param object the object to clone | ||
* @param realm the realm the object resides in | ||
* @param handleCopy the function that handles copying the object | ||
* @returns the copied object | ||
*/ | ||
var getRegExpFlags = function getRegExpFlags(regExp) { | ||
var flags = ''; | ||
if (regExp.global) { | ||
flags += 'g'; | ||
} | ||
if (regExp.ignoreCase) { | ||
flags += 'i'; | ||
} | ||
if (regExp.multiline) { | ||
flags += 'm'; | ||
} | ||
if (regExp.unicode) { | ||
flags += 'u'; | ||
} | ||
if (regExp.sticky) { | ||
flags += 'y'; | ||
} | ||
return flags; | ||
var getObjectCloneLoose = function (object, realm, handleCopy, cache) { | ||
var clone = getCleanClone(object, realm); | ||
for (var key in object) { | ||
if (hasOwnProperty.call(object, key)) { | ||
clone[key] = handleCopy(object[key], cache); | ||
} | ||
} | ||
if (SUPPORTS.SYMBOL_PROPERTIES) { | ||
var symbols = getOwnPropertySymbols(object); | ||
if (symbols.length) { | ||
for (var index = 0, symbol = void 0; index < symbols.length; index++) { | ||
symbol = symbols[index]; | ||
if (propertyIsEnumerable.call(object, symbol)) { | ||
clone[symbol] = handleCopy(object[symbol], cache); | ||
} | ||
} | ||
} | ||
} | ||
return clone; | ||
}; | ||
/** | ||
* @function isObjectCopyable | ||
* @function getObjectCloneStrict | ||
* | ||
* @description | ||
* is the object able to be copied | ||
* get a copy of the object based on strict rules, meaning all keys and symbols | ||
* are copied based on the original property descriptors | ||
* | ||
* @param {any} object the object to test | ||
* @param {Object|Weakset} cache the cache of copied values | ||
* @returns {boolean} can the object be copied | ||
* @param object the object to clone | ||
* @param realm the realm the object resides in | ||
* @param handleCopy the function that handles copying the object | ||
* @returns the copied object | ||
*/ | ||
var isObjectCopyable = function isObjectCopyable(object, cache) { | ||
return typeof object === 'object' && object !== null && !cache.has(object); | ||
var getObjectCloneStrict = function (object, realm, handleCopy, cache) { | ||
var clone = getCleanClone(object, realm); | ||
var properties = SUPPORTS.SYMBOL_PROPERTIES | ||
? [].concat(getOwnPropertyNames(object), getOwnPropertySymbols(object)) | ||
: getOwnPropertyNames(object); | ||
if (properties.length) { | ||
for (var index = 0, property = void 0, descriptor = void 0; index < properties.length; index++) { | ||
property = properties[index]; | ||
if (property !== 'callee' && property !== 'caller') { | ||
descriptor = getOwnPropertyDescriptor(object, property); | ||
descriptor.value = handleCopy(object[property], cache); | ||
defineProperty(clone, property, descriptor); | ||
} | ||
} | ||
} | ||
return clone; | ||
}; | ||
/** | ||
* @function shouldObjectBeCopied | ||
* @function getRegExpFlags | ||
* | ||
* @description | ||
* should the object be copied | ||
* get the flags to apply to the copied regexp | ||
* | ||
* @param {any} object the object to test | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {boolean} should the object be copied | ||
* @param regExp the regexp to get the flags of | ||
* @returns the flags for the regexp | ||
*/ | ||
var shouldObjectBeCopied = function shouldObjectBeCopied(object, realm) { | ||
return typeof object.then !== 'function' && !(object instanceof realm.Error) && !(realm.WeakMap && object instanceof realm.WeakMap) && !(realm.WeakSet && object instanceof realm.WeakSet); | ||
var getRegExpFlags = function (regExp) { | ||
var flags = ''; | ||
if (regExp.global) { | ||
flags += 'g'; | ||
} | ||
if (regExp.ignoreCase) { | ||
flags += 'i'; | ||
} | ||
if (regExp.multiline) { | ||
flags += 'm'; | ||
} | ||
if (regExp.unicode) { | ||
flags += 'u'; | ||
} | ||
if (regExp.sticky) { | ||
flags += 'y'; | ||
} | ||
return flags; | ||
}; | ||
/** | ||
* @function copyArray | ||
* | ||
* @description | ||
* copy the array, deeply copying the values | ||
* | ||
* @param {Array<any>} array the array to copy | ||
* @param {function} copy the function to copy values | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {Array<any>} the copied array | ||
*/ | ||
var copyArray = function copyArray(array, copy, realm) { | ||
var newArray = new array.constructor(); | ||
for (var index = 0; index < array.length; index++) { | ||
newArray[index] = copy(array[index], realm); | ||
} | ||
return newArray; | ||
}; | ||
// utils | ||
var isArray = Array.isArray; | ||
var GLOBAL_THIS = (function () { | ||
if (typeof self !== 'undefined') { | ||
return self; | ||
} | ||
if (typeof window !== 'undefined') { | ||
return window; | ||
} | ||
if (typeof global !== 'undefined') { | ||
return global; | ||
} | ||
if (console && console.error) { | ||
console.error('Unable to locate global object, returning "this".'); | ||
} | ||
})(); | ||
/** | ||
* @function copyArrayBuffer | ||
* @function copy | ||
* | ||
* @description | ||
* copy the arrayBuffer, deeply copying the values | ||
* copy an object deeply as much as possible | ||
* | ||
* @param {ArrayBuffer} arrayBuffer the arrayBuffer to copy | ||
* @returns {ArrayBuffer} the copied bufarrayBufferfer | ||
*/ | ||
var copyArrayBuffer = function copyArrayBuffer(arrayBuffer) { | ||
return arrayBuffer.slice(0); | ||
}; | ||
/** | ||
* @function copyBuffer | ||
* If `strict` is applied, then all properties (including non-enumerable ones) | ||
* are copied with their original property descriptors on both objects and arrays. | ||
* | ||
* @description | ||
* copy the buffer, deeply copying the values | ||
* The object is compared to the global constructors in the `realm` provided, | ||
* and the native constructor is always used to ensure that extensions of native | ||
* objects (allows in ES2015+) are maintained. | ||
* | ||
* @param {Buffer} buffer the buffer to copy | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {Buffer} the copied buffer | ||
* @param object the object to copy | ||
* @param [options] the options for copying with | ||
* @param [options.isStrict] should the copy be strict | ||
* @param [options.realm] the realm (this) object the object is copied from | ||
* @returns the copied object | ||
*/ | ||
var copyBuffer = function copyBuffer(buffer, realm) { | ||
var RealmBuffer = realm.Buffer; | ||
var newBuffer = RealmBuffer.allocUnsafe ? RealmBuffer.allocUnsafe(buffer.length) : new RealmBuffer(buffer.length); | ||
buffer.copy(newBuffer); | ||
return newBuffer; | ||
}; | ||
/** | ||
* @function copyMap | ||
* | ||
* @description | ||
* copy the map values into a new map | ||
* | ||
* @param {Map} map the map to copy | ||
* @param {function} copy the copy object method | ||
* @param {Object} realm the realm the constructor resides in | ||
* @returns {Map} the copied map | ||
*/ | ||
var copyMap = function copyMap(map, copy, realm) { | ||
var newMap = new map.constructor(); | ||
map.forEach(function (value, key) { | ||
return newMap.set(key, copy(value, realm)); | ||
}); | ||
return newMap; | ||
}; | ||
/** | ||
* @function copySet | ||
* | ||
* @description | ||
* copy the set values into a new set | ||
* | ||
* @param {Set} set the set to copy | ||
* @param {function} copy the copy object method | ||
* @param {Object} realm the realm the constructor resides in | ||
* @returns {Set} the copied set | ||
*/ | ||
var copySet = function copySet(set, copy, realm) { | ||
var newSet = new set.constructor(); | ||
set.forEach(function (value) { | ||
return newSet.add(copy(value, realm)); | ||
}); | ||
return newSet; | ||
}; | ||
/** | ||
* @function copyObject | ||
* | ||
* @description | ||
* copy the object values into a new object of the same type | ||
* | ||
* @param {Object} object the object to copy | ||
* @param {function} copy the copy method | ||
* @param {any} realm the realm to check instanceof in | ||
* @param {boolean} isPlainObject is the object to copy a plain object | ||
* @returns {Object} the copied object | ||
*/ | ||
var copyObject = function copyObject(object, copy, realm, isPlainObject) { | ||
var newObject = getObjectToCopy(object, realm.Object, isPlainObject); | ||
for (var key in object) { | ||
if (hasOwnProperty.call(object, key)) { | ||
newObject[key] = copy(object[key], realm); | ||
} | ||
} | ||
if (SUPPORTS.SYMBOL_PROPERTIES) { | ||
var symbols = getSymbols(object); | ||
if (symbols.length) { | ||
for (var index = 0, symbol; index < symbols.length; index++) { | ||
symbol = symbols[index]; | ||
if (propertyIsEnumerable.call(object, symbol)) { | ||
newObject[symbol] = copy(object[symbol], realm); | ||
function copy(object, _a) { | ||
var _b = _a === void 0 ? {} : _a, _c = _b.isStrict, isStrict = _c === void 0 ? false : _c, _d = _b.realm, realm = _d === void 0 ? GLOBAL_THIS : _d; | ||
var RealmArrayBuffer = realm.ArrayBuffer, RealmBuffer = realm.Buffer, RealmMap = realm.Map, RealmSet = realm.Set, RealmWeakMap = realm.WeakMap, RealmWeakSet = realm.WeakSet; | ||
var getObjectClone = isStrict | ||
? getObjectCloneStrict | ||
: getObjectCloneLoose; | ||
/** | ||
* @function handleCopy | ||
* | ||
* @description | ||
* copy the object recursively based on its type | ||
* | ||
* @param object the object to copy | ||
* @returns the copied object | ||
*/ | ||
var handleCopy = function (object, cache) { | ||
if (!object || typeof object !== 'object' || cache.has(object)) { | ||
return object; | ||
} | ||
} | ||
} | ||
} | ||
return newObject; | ||
}; | ||
var Constructor = object.constructor; | ||
// plain objects | ||
if (Constructor === realm.Object) { | ||
cache.add(object); | ||
return getObjectClone(object, realm, handleCopy, cache); | ||
} | ||
var clone; | ||
// arrays | ||
if (isArray(object)) { | ||
cache.add(object); | ||
// if strict, include non-standard properties | ||
if (isStrict) { | ||
return getObjectCloneStrict(object, realm, handleCopy, cache); | ||
} | ||
clone = new Constructor(); | ||
for (var index = 0; index < object.length; index++) { | ||
clone[index] = handleCopy(object[index], cache); | ||
} | ||
return clone; | ||
} | ||
// dates | ||
if (object instanceof realm.Date) { | ||
return new Constructor(object.getTime()); | ||
} | ||
// regexps | ||
if (object instanceof realm.RegExp) { | ||
clone = new Constructor(object.source, object.flags || getRegExpFlags(object)); | ||
clone.lastIndex = object.lastIndex; | ||
return clone; | ||
} | ||
// maps | ||
if (RealmMap && object instanceof RealmMap) { | ||
cache.add(object); | ||
clone = new Constructor(); | ||
object.forEach(function (value, key) { | ||
clone.set(key, handleCopy(value, cache)); | ||
}); | ||
return clone; | ||
} | ||
// sets | ||
if (RealmSet && object instanceof RealmSet) { | ||
cache.add(object); | ||
clone = new Constructor(); | ||
object.forEach(function (value) { | ||
clone.add(handleCopy(value, cache)); | ||
}); | ||
return clone; | ||
} | ||
// buffers (node-only) | ||
if (RealmBuffer && RealmBuffer.isBuffer(object)) { | ||
clone = RealmBuffer.allocUnsafe | ||
? RealmBuffer.allocUnsafe(object.length) | ||
: new Constructor(object.length); | ||
object.copy(clone); | ||
return clone; | ||
} | ||
// arraybuffers / dataviews | ||
if (RealmArrayBuffer) { | ||
// dataviews | ||
if (RealmArrayBuffer.isView(object)) { | ||
return new Constructor(object.buffer.slice(0)); | ||
} | ||
// arraybuffers | ||
if (object instanceof RealmArrayBuffer) { | ||
return object.slice(0); | ||
} | ||
} | ||
// if the object cannot / should not be cloned, don't | ||
if ( | ||
// promise-like | ||
typeof object.then === 'function' || | ||
// errors | ||
object instanceof Error || | ||
// weakmaps | ||
(RealmWeakMap && object instanceof RealmWeakMap) || | ||
// weaksets | ||
(RealmWeakSet && object instanceof RealmWeakSet)) { | ||
return object; | ||
} | ||
cache.add(object); | ||
// assume anything left is a custom constructor | ||
return getObjectClone(object, realm, handleCopy, cache); | ||
}; | ||
return handleCopy(object, createCache()); | ||
} | ||
/** | ||
* @function copyRegExp | ||
* @function strictCopy | ||
* | ||
* @description | ||
* copy the RegExp to a new RegExp with the same properties | ||
* copy the object with `strict` option pre-applied | ||
* | ||
* @param {RegExp} regExp the RegExp to copy | ||
* @param {function} RealmRegExp the realm-specific RegExp constructor | ||
* @returns {RegExp} the copied RegExp | ||
* @param object the object to copy | ||
* @param [options] the options for copying with | ||
* @param [options.realm] the realm (this) object the object is copied from | ||
* @returns the copied object | ||
*/ | ||
var copyRegExp = function copyRegExp(regExp, RealmRegExp) { | ||
var newRegExp = new RealmRegExp(regExp.source, SUPPORTS.FLAGS ? regExp.flags : getRegExpFlags(regExp)); | ||
newRegExp.lastIndex = regExp.lastIndex; | ||
return newRegExp; | ||
copy.strict = function strictCopy(object, options) { | ||
return copy(object, { | ||
isStrict: true, | ||
realm: options ? options.realm : void 0, | ||
}); | ||
}; | ||
/** | ||
* @function copyTypedArray | ||
* | ||
* @description | ||
* copy the typedArray, deeply copying the values | ||
* | ||
* @param {TypedArray} typedArray the typedArray to copy | ||
* @returns {TypedArray} the copied typedArray | ||
*/ | ||
var copyTypedArray = function copyTypedArray(typedArray) { | ||
return new typedArray.constructor(copyArrayBuffer(typedArray.buffer)); | ||
}; | ||
// utils | ||
var isArray = Array.isArray; | ||
/** | ||
* @function copy | ||
* | ||
* @description | ||
* deeply copy the object to a new object of the same type | ||
* | ||
* @param {any} object the object to copy | ||
* @param {any} [realm=global] the realm to check instanceof in | ||
* @returns {any} the copied object | ||
*/ | ||
function copy(object, realm) { | ||
if (realm === void 0) { | ||
realm = global; | ||
} | ||
var _realm = realm, | ||
RealmArrayBuffer = _realm.ArrayBuffer, | ||
RealmBuffer = _realm.Buffer, | ||
RealmDate = _realm.Date, | ||
RealmMap = _realm.Map, | ||
RealmObject = _realm.Object, | ||
RealmRegExp = _realm.RegExp, | ||
RealmSet = _realm.Set; | ||
var cache = getNewCache(); | ||
var handleCopy = function handleCopy(object) { | ||
if (!isObjectCopyable(object, cache)) { | ||
return object; | ||
} | ||
if (isArray(object)) { | ||
cache.add(object); | ||
return copyArray(object, handleCopy, realm); | ||
} | ||
if (object.constructor === RealmObject) { | ||
cache.add(object); | ||
return copyObject(object, handleCopy, realm, true); | ||
} | ||
if (object instanceof RealmDate) { | ||
return new RealmDate(object.getTime()); | ||
} | ||
if (object instanceof RealmRegExp) { | ||
return copyRegExp(object, RealmRegExp); | ||
} | ||
if (RealmMap && object instanceof RealmMap) { | ||
cache.add(object); | ||
return copyMap(object, handleCopy, realm); | ||
} | ||
if (RealmSet && object instanceof RealmSet) { | ||
cache.add(object); | ||
return copySet(object, handleCopy, realm); | ||
} | ||
if (RealmBuffer && RealmBuffer.isBuffer(object)) { | ||
return copyBuffer(object, realm); | ||
} | ||
if (RealmArrayBuffer) { | ||
if (RealmArrayBuffer.isView(object)) { | ||
return copyTypedArray(object); | ||
} | ||
if (object instanceof RealmArrayBuffer) { | ||
return copyArrayBuffer(object); | ||
} | ||
} | ||
if (shouldObjectBeCopied(object, realm)) { | ||
cache.add(object); | ||
return copyObject(object, handleCopy, realm); | ||
} | ||
return object; | ||
}; | ||
return handleCopy(object); | ||
} | ||
export default copy; | ||
//# sourceMappingURL=fast-copy.esm.js.map |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
(global = global || self, factory(global['fast-copy'] = {})); | ||
}(this, function (exports) { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = global || self, global['fast-copy'] = factory()); | ||
}(this, function () { 'use strict'; | ||
var create = Object.create, | ||
getSymbols = Object.getOwnPropertySymbols, | ||
getPrototypeOf = Object.getPrototypeOf; | ||
var _Object$prototype = Object.prototype, | ||
hasOwnProperty = _Object$prototype.hasOwnProperty, | ||
propertyIsEnumerable = _Object$prototype.propertyIsEnumerable; | ||
var toStringFunction = Function.prototype.toString; | ||
var create = Object.create, defineProperty = Object.defineProperty, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols, getPrototypeOf = Object.getPrototypeOf; | ||
var _a = Object.prototype, hasOwnProperty = _a.hasOwnProperty, propertyIsEnumerable = _a.propertyIsEnumerable; | ||
/** | ||
* @constant {Object} SUPPORTS cache of values supported | ||
* @enum | ||
* | ||
* @const {Object} SUPPORTS | ||
* | ||
* @property {boolean} SYMBOL_PROPERTIES are symbol properties supported | ||
* @property {boolean} WEAKSET is WeakSet supported | ||
*/ | ||
var SUPPORTS = { | ||
FLAGS: typeof /foo/g.flags === 'string', | ||
SYMBOL_PROPERTIES: typeof global.Object.getOwnPropertySymbols === 'function', | ||
WEAKSET: typeof global.WeakSet === 'function' | ||
SYMBOL_PROPERTIES: typeof getOwnPropertySymbols === 'function', | ||
WEAKSET: typeof WeakSet === 'function', | ||
}; | ||
/** | ||
* @function getNewCache | ||
* @function createCache | ||
* | ||
@@ -28,347 +28,288 @@ * @description | ||
* | ||
* @returns {Object|Weakset} the new cache object | ||
* @returns the new cache object | ||
*/ | ||
var getNewCache = function getNewCache() { | ||
return SUPPORTS.WEAKSET ? new WeakSet() : create({ | ||
_values: [], | ||
add: function add(value) { | ||
this._values.push(value); | ||
}, | ||
has: function has(value) { | ||
return !!~this._values.indexOf(value); | ||
var createCache = function () { | ||
if (SUPPORTS.WEAKSET) { | ||
return new WeakSet(); | ||
} | ||
}); | ||
var object = create({ | ||
add: function (value) { return object._values.push(value); }, | ||
has: function (value) { return !!~object._values.indexOf(value); }, | ||
}); | ||
object._values = []; | ||
return object; | ||
}; | ||
/** | ||
* @function getObjectToCopy | ||
* @function getCleanClone | ||
* | ||
* @description | ||
* get the object to copy, including appropriate prototype | ||
* get an empty version of the object with the same prototype it has | ||
* | ||
* @param {Object} object the object to copy | ||
* @param {function} RealmObject the realm-specific Object constructor | ||
* @param {boolean} isPlainObject is the object a plain object | ||
* @returns {Object} an empty version of the object to copy | ||
* @param object the object to build a clean clone from | ||
* @param realm the realm the object resides in | ||
* @returns the empty cloned object | ||
*/ | ||
var getObjectToCopy = function getObjectToCopy(object, RealmObject, isPlainObject) { | ||
if (isPlainObject) { | ||
var getCleanClone = function (object, realm) { | ||
if (!object.constructor) { | ||
return create(null); | ||
} | ||
var prototype = object.__proto__ || getPrototypeOf(object); | ||
return prototype === RealmObject.prototype ? {} : create(prototype); | ||
} | ||
return object.constructor ? new object.constructor() : create(null); | ||
if (object.constructor === realm.Object) { | ||
return prototype === realm.Object.prototype ? {} : create(prototype); | ||
} | ||
if (~toStringFunction.call(object.constructor).indexOf('[native code]')) { | ||
return new object.constructor(); | ||
} | ||
return create(prototype); | ||
}; | ||
/** | ||
* @function getRegExpFlags | ||
* @function getObjectCloneLoose | ||
* | ||
* @description | ||
* get the flags to apply to the copied regexp | ||
* get a copy of the object based on loose rules, meaning all enumerable keys | ||
* and symbols are copied, but property descriptors are not considered | ||
* | ||
* @param {RegExp} regExp the regexp to get the flags of | ||
* @returns {string} the flags for the regexp | ||
* @param object the object to clone | ||
* @param realm the realm the object resides in | ||
* @param handleCopy the function that handles copying the object | ||
* @returns the copied object | ||
*/ | ||
var getRegExpFlags = function getRegExpFlags(regExp) { | ||
var flags = ''; | ||
if (regExp.global) { | ||
flags += 'g'; | ||
} | ||
if (regExp.ignoreCase) { | ||
flags += 'i'; | ||
} | ||
if (regExp.multiline) { | ||
flags += 'm'; | ||
} | ||
if (regExp.unicode) { | ||
flags += 'u'; | ||
} | ||
if (regExp.sticky) { | ||
flags += 'y'; | ||
} | ||
return flags; | ||
var getObjectCloneLoose = function (object, realm, handleCopy, cache) { | ||
var clone = getCleanClone(object, realm); | ||
for (var key in object) { | ||
if (hasOwnProperty.call(object, key)) { | ||
clone[key] = handleCopy(object[key], cache); | ||
} | ||
} | ||
if (SUPPORTS.SYMBOL_PROPERTIES) { | ||
var symbols = getOwnPropertySymbols(object); | ||
if (symbols.length) { | ||
for (var index = 0, symbol = void 0; index < symbols.length; index++) { | ||
symbol = symbols[index]; | ||
if (propertyIsEnumerable.call(object, symbol)) { | ||
clone[symbol] = handleCopy(object[symbol], cache); | ||
} | ||
} | ||
} | ||
} | ||
return clone; | ||
}; | ||
/** | ||
* @function isObjectCopyable | ||
* @function getObjectCloneStrict | ||
* | ||
* @description | ||
* is the object able to be copied | ||
* get a copy of the object based on strict rules, meaning all keys and symbols | ||
* are copied based on the original property descriptors | ||
* | ||
* @param {any} object the object to test | ||
* @param {Object|Weakset} cache the cache of copied values | ||
* @returns {boolean} can the object be copied | ||
* @param object the object to clone | ||
* @param realm the realm the object resides in | ||
* @param handleCopy the function that handles copying the object | ||
* @returns the copied object | ||
*/ | ||
var isObjectCopyable = function isObjectCopyable(object, cache) { | ||
return typeof object === 'object' && object !== null && !cache.has(object); | ||
var getObjectCloneStrict = function (object, realm, handleCopy, cache) { | ||
var clone = getCleanClone(object, realm); | ||
var properties = SUPPORTS.SYMBOL_PROPERTIES | ||
? [].concat(getOwnPropertyNames(object), getOwnPropertySymbols(object)) | ||
: getOwnPropertyNames(object); | ||
if (properties.length) { | ||
for (var index = 0, property = void 0, descriptor = void 0; index < properties.length; index++) { | ||
property = properties[index]; | ||
if (property !== 'callee' && property !== 'caller') { | ||
descriptor = getOwnPropertyDescriptor(object, property); | ||
descriptor.value = handleCopy(object[property], cache); | ||
defineProperty(clone, property, descriptor); | ||
} | ||
} | ||
} | ||
return clone; | ||
}; | ||
/** | ||
* @function shouldObjectBeCopied | ||
* @function getRegExpFlags | ||
* | ||
* @description | ||
* should the object be copied | ||
* get the flags to apply to the copied regexp | ||
* | ||
* @param {any} object the object to test | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {boolean} should the object be copied | ||
* @param regExp the regexp to get the flags of | ||
* @returns the flags for the regexp | ||
*/ | ||
var shouldObjectBeCopied = function shouldObjectBeCopied(object, realm) { | ||
return typeof object.then !== 'function' && !(object instanceof realm.Error) && !(realm.WeakMap && object instanceof realm.WeakMap) && !(realm.WeakSet && object instanceof realm.WeakSet); | ||
var getRegExpFlags = function (regExp) { | ||
var flags = ''; | ||
if (regExp.global) { | ||
flags += 'g'; | ||
} | ||
if (regExp.ignoreCase) { | ||
flags += 'i'; | ||
} | ||
if (regExp.multiline) { | ||
flags += 'm'; | ||
} | ||
if (regExp.unicode) { | ||
flags += 'u'; | ||
} | ||
if (regExp.sticky) { | ||
flags += 'y'; | ||
} | ||
return flags; | ||
}; | ||
/** | ||
* @function copyArray | ||
* | ||
* @description | ||
* copy the array, deeply copying the values | ||
* | ||
* @param {Array<any>} array the array to copy | ||
* @param {function} copy the function to copy values | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {Array<any>} the copied array | ||
*/ | ||
var copyArray = function copyArray(array, copy, realm) { | ||
var newArray = new array.constructor(); | ||
for (var index = 0; index < array.length; index++) { | ||
newArray[index] = copy(array[index], realm); | ||
} | ||
return newArray; | ||
}; | ||
// utils | ||
var isArray = Array.isArray; | ||
var GLOBAL_THIS = (function () { | ||
if (typeof self !== 'undefined') { | ||
return self; | ||
} | ||
if (typeof window !== 'undefined') { | ||
return window; | ||
} | ||
if (typeof global !== 'undefined') { | ||
return global; | ||
} | ||
if (console && console.error) { | ||
console.error('Unable to locate global object, returning "this".'); | ||
} | ||
})(); | ||
/** | ||
* @function copyArrayBuffer | ||
* @function copy | ||
* | ||
* @description | ||
* copy the arrayBuffer, deeply copying the values | ||
* copy an object deeply as much as possible | ||
* | ||
* @param {ArrayBuffer} arrayBuffer the arrayBuffer to copy | ||
* @returns {ArrayBuffer} the copied bufarrayBufferfer | ||
*/ | ||
var copyArrayBuffer = function copyArrayBuffer(arrayBuffer) { | ||
return arrayBuffer.slice(0); | ||
}; | ||
/** | ||
* @function copyBuffer | ||
* If `strict` is applied, then all properties (including non-enumerable ones) | ||
* are copied with their original property descriptors on both objects and arrays. | ||
* | ||
* @description | ||
* copy the buffer, deeply copying the values | ||
* The object is compared to the global constructors in the `realm` provided, | ||
* and the native constructor is always used to ensure that extensions of native | ||
* objects (allows in ES2015+) are maintained. | ||
* | ||
* @param {Buffer} buffer the buffer to copy | ||
* @param {any} realm the realm to check instanceof in | ||
* @returns {Buffer} the copied buffer | ||
* @param object the object to copy | ||
* @param [options] the options for copying with | ||
* @param [options.isStrict] should the copy be strict | ||
* @param [options.realm] the realm (this) object the object is copied from | ||
* @returns the copied object | ||
*/ | ||
var copyBuffer = function copyBuffer(buffer, realm) { | ||
var RealmBuffer = realm.Buffer; | ||
var newBuffer = RealmBuffer.allocUnsafe ? RealmBuffer.allocUnsafe(buffer.length) : new RealmBuffer(buffer.length); | ||
buffer.copy(newBuffer); | ||
return newBuffer; | ||
}; | ||
/** | ||
* @function copyMap | ||
* | ||
* @description | ||
* copy the map values into a new map | ||
* | ||
* @param {Map} map the map to copy | ||
* @param {function} copy the copy object method | ||
* @param {Object} realm the realm the constructor resides in | ||
* @returns {Map} the copied map | ||
*/ | ||
var copyMap = function copyMap(map, copy, realm) { | ||
var newMap = new map.constructor(); | ||
map.forEach(function (value, key) { | ||
return newMap.set(key, copy(value, realm)); | ||
}); | ||
return newMap; | ||
}; | ||
/** | ||
* @function copySet | ||
* | ||
* @description | ||
* copy the set values into a new set | ||
* | ||
* @param {Set} set the set to copy | ||
* @param {function} copy the copy object method | ||
* @param {Object} realm the realm the constructor resides in | ||
* @returns {Set} the copied set | ||
*/ | ||
var copySet = function copySet(set, copy, realm) { | ||
var newSet = new set.constructor(); | ||
set.forEach(function (value) { | ||
return newSet.add(copy(value, realm)); | ||
}); | ||
return newSet; | ||
}; | ||
/** | ||
* @function copyObject | ||
* | ||
* @description | ||
* copy the object values into a new object of the same type | ||
* | ||
* @param {Object} object the object to copy | ||
* @param {function} copy the copy method | ||
* @param {any} realm the realm to check instanceof in | ||
* @param {boolean} isPlainObject is the object to copy a plain object | ||
* @returns {Object} the copied object | ||
*/ | ||
var copyObject = function copyObject(object, copy, realm, isPlainObject) { | ||
var newObject = getObjectToCopy(object, realm.Object, isPlainObject); | ||
for (var key in object) { | ||
if (hasOwnProperty.call(object, key)) { | ||
newObject[key] = copy(object[key], realm); | ||
} | ||
} | ||
if (SUPPORTS.SYMBOL_PROPERTIES) { | ||
var symbols = getSymbols(object); | ||
if (symbols.length) { | ||
for (var index = 0, symbol; index < symbols.length; index++) { | ||
symbol = symbols[index]; | ||
if (propertyIsEnumerable.call(object, symbol)) { | ||
newObject[symbol] = copy(object[symbol], realm); | ||
function copy(object, _a) { | ||
var _b = _a === void 0 ? {} : _a, _c = _b.isStrict, isStrict = _c === void 0 ? false : _c, _d = _b.realm, realm = _d === void 0 ? GLOBAL_THIS : _d; | ||
var RealmArrayBuffer = realm.ArrayBuffer, RealmBuffer = realm.Buffer, RealmMap = realm.Map, RealmSet = realm.Set, RealmWeakMap = realm.WeakMap, RealmWeakSet = realm.WeakSet; | ||
var getObjectClone = isStrict | ||
? getObjectCloneStrict | ||
: getObjectCloneLoose; | ||
/** | ||
* @function handleCopy | ||
* | ||
* @description | ||
* copy the object recursively based on its type | ||
* | ||
* @param object the object to copy | ||
* @returns the copied object | ||
*/ | ||
var handleCopy = function (object, cache) { | ||
if (!object || typeof object !== 'object' || cache.has(object)) { | ||
return object; | ||
} | ||
} | ||
} | ||
} | ||
return newObject; | ||
}; | ||
var Constructor = object.constructor; | ||
// plain objects | ||
if (Constructor === realm.Object) { | ||
cache.add(object); | ||
return getObjectClone(object, realm, handleCopy, cache); | ||
} | ||
var clone; | ||
// arrays | ||
if (isArray(object)) { | ||
cache.add(object); | ||
// if strict, include non-standard properties | ||
if (isStrict) { | ||
return getObjectCloneStrict(object, realm, handleCopy, cache); | ||
} | ||
clone = new Constructor(); | ||
for (var index = 0; index < object.length; index++) { | ||
clone[index] = handleCopy(object[index], cache); | ||
} | ||
return clone; | ||
} | ||
// dates | ||
if (object instanceof realm.Date) { | ||
return new Constructor(object.getTime()); | ||
} | ||
// regexps | ||
if (object instanceof realm.RegExp) { | ||
clone = new Constructor(object.source, object.flags || getRegExpFlags(object)); | ||
clone.lastIndex = object.lastIndex; | ||
return clone; | ||
} | ||
// maps | ||
if (RealmMap && object instanceof RealmMap) { | ||
cache.add(object); | ||
clone = new Constructor(); | ||
object.forEach(function (value, key) { | ||
clone.set(key, handleCopy(value, cache)); | ||
}); | ||
return clone; | ||
} | ||
// sets | ||
if (RealmSet && object instanceof RealmSet) { | ||
cache.add(object); | ||
clone = new Constructor(); | ||
object.forEach(function (value) { | ||
clone.add(handleCopy(value, cache)); | ||
}); | ||
return clone; | ||
} | ||
// buffers (node-only) | ||
if (RealmBuffer && RealmBuffer.isBuffer(object)) { | ||
clone = RealmBuffer.allocUnsafe | ||
? RealmBuffer.allocUnsafe(object.length) | ||
: new Constructor(object.length); | ||
object.copy(clone); | ||
return clone; | ||
} | ||
// arraybuffers / dataviews | ||
if (RealmArrayBuffer) { | ||
// dataviews | ||
if (RealmArrayBuffer.isView(object)) { | ||
return new Constructor(object.buffer.slice(0)); | ||
} | ||
// arraybuffers | ||
if (object instanceof RealmArrayBuffer) { | ||
return object.slice(0); | ||
} | ||
} | ||
// if the object cannot / should not be cloned, don't | ||
if ( | ||
// promise-like | ||
typeof object.then === 'function' || | ||
// errors | ||
object instanceof Error || | ||
// weakmaps | ||
(RealmWeakMap && object instanceof RealmWeakMap) || | ||
// weaksets | ||
(RealmWeakSet && object instanceof RealmWeakSet)) { | ||
return object; | ||
} | ||
cache.add(object); | ||
// assume anything left is a custom constructor | ||
return getObjectClone(object, realm, handleCopy, cache); | ||
}; | ||
return handleCopy(object, createCache()); | ||
} | ||
/** | ||
* @function copyRegExp | ||
* @function strictCopy | ||
* | ||
* @description | ||
* copy the RegExp to a new RegExp with the same properties | ||
* copy the object with `strict` option pre-applied | ||
* | ||
* @param {RegExp} regExp the RegExp to copy | ||
* @param {function} RealmRegExp the realm-specific RegExp constructor | ||
* @returns {RegExp} the copied RegExp | ||
* @param object the object to copy | ||
* @param [options] the options for copying with | ||
* @param [options.realm] the realm (this) object the object is copied from | ||
* @returns the copied object | ||
*/ | ||
var copyRegExp = function copyRegExp(regExp, RealmRegExp) { | ||
var newRegExp = new RealmRegExp(regExp.source, SUPPORTS.FLAGS ? regExp.flags : getRegExpFlags(regExp)); | ||
newRegExp.lastIndex = regExp.lastIndex; | ||
return newRegExp; | ||
copy.strict = function strictCopy(object, options) { | ||
return copy(object, { | ||
isStrict: true, | ||
realm: options ? options.realm : void 0, | ||
}); | ||
}; | ||
/** | ||
* @function copyTypedArray | ||
* | ||
* @description | ||
* copy the typedArray, deeply copying the values | ||
* | ||
* @param {TypedArray} typedArray the typedArray to copy | ||
* @returns {TypedArray} the copied typedArray | ||
*/ | ||
var copyTypedArray = function copyTypedArray(typedArray) { | ||
return new typedArray.constructor(copyArrayBuffer(typedArray.buffer)); | ||
}; | ||
return copy; | ||
// utils | ||
var isArray = Array.isArray; | ||
/** | ||
* @function copy | ||
* | ||
* @description | ||
* deeply copy the object to a new object of the same type | ||
* | ||
* @param {any} object the object to copy | ||
* @param {any} [realm=global] the realm to check instanceof in | ||
* @returns {any} the copied object | ||
*/ | ||
function copy(object, realm) { | ||
if (realm === void 0) { | ||
realm = global; | ||
} | ||
var _realm = realm, | ||
RealmArrayBuffer = _realm.ArrayBuffer, | ||
RealmBuffer = _realm.Buffer, | ||
RealmDate = _realm.Date, | ||
RealmMap = _realm.Map, | ||
RealmObject = _realm.Object, | ||
RealmRegExp = _realm.RegExp, | ||
RealmSet = _realm.Set; | ||
var cache = getNewCache(); | ||
var handleCopy = function handleCopy(object) { | ||
if (!isObjectCopyable(object, cache)) { | ||
return object; | ||
} | ||
if (isArray(object)) { | ||
cache.add(object); | ||
return copyArray(object, handleCopy, realm); | ||
} | ||
if (object.constructor === RealmObject) { | ||
cache.add(object); | ||
return copyObject(object, handleCopy, realm, true); | ||
} | ||
if (object instanceof RealmDate) { | ||
return new RealmDate(object.getTime()); | ||
} | ||
if (object instanceof RealmRegExp) { | ||
return copyRegExp(object, RealmRegExp); | ||
} | ||
if (RealmMap && object instanceof RealmMap) { | ||
cache.add(object); | ||
return copyMap(object, handleCopy, realm); | ||
} | ||
if (RealmSet && object instanceof RealmSet) { | ||
cache.add(object); | ||
return copySet(object, handleCopy, realm); | ||
} | ||
if (RealmBuffer && RealmBuffer.isBuffer(object)) { | ||
return copyBuffer(object, realm); | ||
} | ||
if (RealmArrayBuffer) { | ||
if (RealmArrayBuffer.isView(object)) { | ||
return copyTypedArray(object); | ||
} | ||
if (object instanceof RealmArrayBuffer) { | ||
return copyArrayBuffer(object); | ||
} | ||
} | ||
if (shouldObjectBeCopied(object, realm)) { | ||
cache.add(object); | ||
return copyObject(object, handleCopy, realm); | ||
} | ||
return object; | ||
}; | ||
return handleCopy(object); | ||
} | ||
exports.default = copy; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
})); | ||
//# sourceMappingURL=fast-copy.js.map |
@@ -1,1 +0,1 @@ | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e=e||self)["fast-copy"]={})}(this,function(e){"use strict";var n=Object.create,t=Object.getOwnPropertySymbols,r=Object.getPrototypeOf,o=Object.prototype,f=o.hasOwnProperty,u=o.propertyIsEnumerable,i="string"==typeof/foo/g.flags,c="function"==typeof global.Object.getOwnPropertySymbols,a="function"==typeof global.WeakSet,s=function(){return a?new WeakSet:n({_values:[],add:function(e){this._values.push(e)},has:function(e){return!!~this._values.indexOf(e)}})},l=function(e,n){return"object"==typeof e&&null!==e&&!n.has(e)},p=function(e,n){return!("function"==typeof e.then||e instanceof n.Error||n.WeakMap&&e instanceof n.WeakMap||n.WeakSet&&e instanceof n.WeakSet)},d=function(e,n,t){for(var r=new e.constructor,o=0;o<e.length;o++)r[o]=n(e[o],t);return r},y=function(e){return e.slice(0)},g=function(e,n){var t=n.Buffer,r=t.allocUnsafe?t.allocUnsafe(e.length):new t(e.length);return e.copy(r),r},b=function(e,n,t){var r=new e.constructor;return e.forEach(function(e,o){return r.set(o,n(e,t))}),r},v=function(e,n,t){var r=new e.constructor;return e.forEach(function(e){return r.add(n(e,t))}),r},h=function(e,o,i,a){var s=function(e,t,o){if(o){var f=e.__proto__||r(e);return f===t.prototype?{}:n(f)}return e.constructor?new e.constructor:n(null)}(e,i.Object,a);for(var l in e)f.call(e,l)&&(s[l]=o(e[l],i));if(c){var p=t(e);if(p.length)for(var d,y=0;y<p.length;y++)d=p[y],u.call(e,d)&&(s[d]=o(e[d],i))}return s},w=function(e,n){var t=new n(e.source,i?e.flags:function(e){var n="";return e.global&&(n+="g"),e.ignoreCase&&(n+="i"),e.multiline&&(n+="m"),e.unicode&&(n+="u"),e.sticky&&(n+="y"),n}(e));return t.lastIndex=e.lastIndex,t},O=function(e){return new e.constructor(y(e.buffer))},j=Array.isArray;e.default=function(e,n){void 0===n&&(n=global);var t=n,r=t.ArrayBuffer,o=t.Buffer,f=t.Date,u=t.Map,i=t.Object,c=t.RegExp,a=t.Set,_=s();return function e(t){if(!l(t,_))return t;if(j(t))return _.add(t),d(t,e,n);if(t.constructor===i)return _.add(t),h(t,e,n,!0);if(t instanceof f)return new f(t.getTime());if(t instanceof c)return w(t,c);if(u&&t instanceof u)return _.add(t),b(t,e,n);if(a&&t instanceof a)return _.add(t),v(t,e,n);if(o&&o.isBuffer(t))return g(t,n);if(r){if(r.isView(t))return O(t);if(t instanceof r)return y(t)}return p(t,n)?(_.add(t),h(t,e,n)):t}(e)},Object.defineProperty(e,"__esModule",{value:!0})}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self)["fast-copy"]=t()}(this,function(){"use strict";var e=Function.prototype.toString,t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,i=Object.getOwnPropertySymbols,f=Object.getPrototypeOf,c=Object.prototype,a=c.hasOwnProperty,u=c.propertyIsEnumerable,l="function"==typeof i,s="function"==typeof WeakSet,d=function(){if(s)return new WeakSet;var e=t({add:function(t){return e._values.push(t)},has:function(t){return!!~e._values.indexOf(t)}});return e._values=[],e},p=function(n,r){if(!n.constructor)return t(null);var o=n.__proto__||f(n);return n.constructor===r.Object?o===r.Object.prototype?{}:t(o):~e.call(n.constructor).indexOf("[native code]")?new n.constructor:t(o)},y=function(e,t,n,r){var o=p(e,t);for(var f in e)a.call(e,f)&&(o[f]=n(e[f],r));if(l){var c=i(e);if(c.length)for(var s=0,d=void 0;s<c.length;s++)d=c[s],u.call(e,d)&&(o[d]=n(e[d],r))}return o},v=function(e,t,f,c){var a=p(e,t),u=l?[].concat(o(e),i(e)):o(e);if(u.length)for(var s=0,d=void 0,y=void 0;s<u.length;s++)"callee"!==(d=u[s])&&"caller"!==d&&((y=r(e,d)).value=f(e[d],c),n(a,d,y));return a},g=function(e){var t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t},b=Array.isArray,w="undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:void(console&&console.error&&console.error('Unable to locate global object, returning "this".'));function O(e,t){var n=void 0===t?{}:t,r=n.isStrict,o=void 0!==r&&r,i=n.realm,f=void 0===i?w:i,c=f.ArrayBuffer,a=f.Buffer,u=f.Map,l=f.Set,s=f.WeakMap,p=f.WeakSet,O=o?v:y,h=function(e,t){if(!e||"object"!=typeof e||t.has(e))return e;var n,r=e.constructor;if(r===f.Object)return t.add(e),O(e,f,h,t);if(b(e)){if(t.add(e),o)return v(e,f,h,t);n=new r;for(var i=0;i<e.length;i++)n[i]=h(e[i],t);return n}if(e instanceof f.Date)return new r(e.getTime());if(e instanceof f.RegExp)return(n=new r(e.source,e.flags||g(e))).lastIndex=e.lastIndex,n;if(u&&e instanceof u)return t.add(e),n=new r,e.forEach(function(e,r){n.set(r,h(e,t))}),n;if(l&&e instanceof l)return t.add(e),n=new r,e.forEach(function(e){n.add(h(e,t))}),n;if(a&&a.isBuffer(e))return n=a.allocUnsafe?a.allocUnsafe(e.length):new r(e.length),e.copy(n),n;if(c){if(c.isView(e))return new r(e.buffer.slice(0));if(e instanceof c)return e.slice(0)}return"function"==typeof e.then||e instanceof Error||s&&e instanceof s||p&&e instanceof p?e:(t.add(e),O(e,f,h,t))};return h(e,d())}return O.strict=function(e,t){return O(e,{isStrict:!0,realm:t?t.realm:void 0})},O}); |
@@ -1,3 +0,7 @@ | ||
declare module 'fast-copy' { | ||
declare export default function copy(object: T): T; | ||
declare module "fast-copy" { | ||
declare export default { | ||
(object: T, options?: O): T, | ||
strict<T>(object: T, options?: O): T | ||
}; | ||
} |
@@ -1,1 +0,36 @@ | ||
export default function copy<T>(object: T): T; | ||
declare namespace FastCopy { | ||
export interface Constructor extends Function { | ||
new (...args: any[]): any; | ||
} | ||
// @ts-ignore | ||
export type Realm = Window | Global; | ||
export interface Cache { | ||
_values?: any[]; | ||
add: (value: any) => void; | ||
has: (value: any) => boolean; | ||
} | ||
export type Copier = (object: any, cache: Cache) => any; | ||
export type ObjectCloner = ( | ||
object: any, | ||
realm: Realm, | ||
handleCopy: Copier, | ||
cache: Cache, | ||
) => any; | ||
export type Options = { | ||
isStrict?: boolean; | ||
realm?: Realm; | ||
}; | ||
} | ||
declare function copy<T>(object: any, options?: FastCopy.Options): T; | ||
declare namespace copy { | ||
function strictCopy<T>(object: any, options?: FastCopy.Options): T; | ||
} | ||
export default copy; |
{ | ||
"author": "tony_quetano@planttheidea.com", | ||
"ava": { | ||
"failFast": true, | ||
"files": [ | ||
"test/*.js" | ||
], | ||
"require": [ | ||
"@babel/register" | ||
], | ||
"sources": [ | ||
"src/*.js" | ||
], | ||
"verbose": true | ||
}, | ||
"browser": "dist/fast-copy.js", | ||
@@ -22,44 +9,34 @@ "bugs": { | ||
"devDependencies": { | ||
"@babel/cli": "^7.0.0", | ||
"@babel/core": "^7.0.0", | ||
"@babel/preset-env": "^7.0.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"@babel/register": "^7.0.0", | ||
"ava": "^1.0.0-beta.8", | ||
"babel-eslint": "^10.0.1", | ||
"babel-loader": "^8.0.0", | ||
"benchmark": "^2.1.4", | ||
"@types/jest": "^23.3.13", | ||
"@types/lodash": "^4.14.120", | ||
"@types/node": "^10.12.19", | ||
"@types/ramda": "^0.25.47", | ||
"@types/react": "^16.7.22", | ||
"benchee": "^1.0.3", | ||
"cli-table2": "^0.2.0", | ||
"clone": "^2.1.2", | ||
"decircularize": "^1.0.0", | ||
"deep-clone": "^3.0.3", | ||
"deep-eql": "^4.0.0", | ||
"deep-equal": "^1.0.1", | ||
"deepclone": "^1.0.2", | ||
"eslint": "^5.7.0", | ||
"eslint-config-rapid7": "^3.1.0", | ||
"eslint-friendly-formatter": "^4.0.1", | ||
"eslint-loader": "^2.1.1", | ||
"fast-clone": "^1.5.3", | ||
"fast-deep-equal": "^2.0.1", | ||
"fast-deepclone": "^1.0.0", | ||
"fast-equals": "^1.6.1", | ||
"fast-deepclone": "^1.0.1", | ||
"html-webpack-plugin": "^3.2.0", | ||
"in-publish": "^2.0.0", | ||
"jest": "^24.0.0", | ||
"lodash": "^4.17.11", | ||
"nano-equal": "^2.0.2", | ||
"nyc": "^13.1.0", | ||
"optimize-js-plugin": "^0.0.4", | ||
"react": "^16.5.2", | ||
"react-dom": "^16.5.2", | ||
"react-fast-compare": "^2.0.2", | ||
"rollup": "^1.1.2", | ||
"rollup-plugin-babel": "^4.0.1", | ||
"nyc": "^13.0.1", | ||
"ramda": "^0.26.1", | ||
"react": "^16.7.0", | ||
"react-dom": "^16.7.0", | ||
"rollup": "^1.1.0", | ||
"rollup-plugin-node-resolve": "^4.0.0", | ||
"rollup-plugin-terser": "^4.0.3", | ||
"shallow-equal-fuzzy": "^0.0.2", | ||
"sinon": "^7.0.0", | ||
"underscore": "^1.9.1", | ||
"webpack": "^4.20.2", | ||
"webpack-cli": "^3.1.2", | ||
"webpack-dev-server": "^3.1.9" | ||
"rollup-plugin-typescript2": "^0.19.2", | ||
"ts-jest": "^23.10.4", | ||
"ts-loader": "^5.3.3", | ||
"tslint": "^5.11.0", | ||
"tslint-config-airbnb": "^5.11.0", | ||
"tslint-loader": "^3.5.4", | ||
"typescript": "^3.2.4", | ||
"webpack": "^4.29.0", | ||
"webpack-cli": "^3.2.0", | ||
"webpack-dev-server": "^3.1.5" | ||
}, | ||
@@ -85,15 +62,15 @@ "homepage": "https://github.com/planttheidea/fast-copy#readme", | ||
"clean": "rimraf dist", | ||
"dev": "NODE_ENV=development webpack-dev-server --colors --progress --config=webpack/webpack.config.dev.js", | ||
"dev": "NODE_ENV=development webpack-dev-server --colors --progress --config=webpack/webpack.config.js", | ||
"dist": "npm run clean && npm run build", | ||
"lint": "NODE_ENV=test eslint src --max-warnings 0", | ||
"lint:fix": "NODE_ENV=test eslint src --fix", | ||
"lint": "NODE_ENV=test tslint 'src/*.ts'", | ||
"lint:fix": "npm run lint -- --fix", | ||
"prepublish": "if in-publish; then npm run prepublish:compile; fi", | ||
"prepublish:compile": "npm run lint && npm run test:coverage && npm run dist", | ||
"start": "npm run dev", | ||
"test": "NODE_PATH=. BABEL_ENV=test ava", | ||
"test:coverage": "nyc npm test", | ||
"test:watch": "npm test -- --watch" | ||
"test": "NODE_PATH=. jest", | ||
"test:coverage": "npm run test -- --coverage", | ||
"test:watch": "npm run test -- --watch" | ||
}, | ||
"types": "index.d.ts", | ||
"version": "1.2.4" | ||
"version": "2.0.0" | ||
} |
109
README.md
@@ -12,3 +12,5 @@ # fast-copy | ||
- [Usage](#usage) | ||
- [Multiple realms](#multiple-realms) | ||
- [Options](#options) | ||
- [isStrict](#isstrict) | ||
- [realm](#realm) | ||
- [Types supported](#types-supported) | ||
@@ -39,6 +41,20 @@ - [Benchmarks](#benchmarks) | ||
#### Multiple realms | ||
## Options | ||
Under the hood, `fast-copy` uses `instanceof` to determine object types, which can cause false negatives when used in combination with `iframe`-based objects. To handle this edge case, you can pass the optional second parameter of `realm` to the `copy` method, which identifies which realm the object comes from and will use that realm to drive both comparisons and constructors for the copies. | ||
#### isStrict | ||
Starting in `2.0.0`, you can use the `isStrict` option to copy the object based on strict standards, meaning: | ||
- Properties retain their original property descriptor | ||
- Non-enumerable properties are copied | ||
- Non-standard properties (e.g., keys on an `Array` object) are copied | ||
This is significantly slower, so you should only use this if you believe it necessary. | ||
**NOTE**: This option is also aliased as `copy.strict`. | ||
#### realm | ||
Under the hood, `fast-copy` uses `instanceof` to determine object types, which can cause false negatives when used in combination with `iframe`-based objects. To handle this edge case, you can pass the `realm` in options, which identifies which realm the object comes from and will use that realm to drive both comparisons and constructors for the copies. | ||
```html | ||
@@ -104,10 +120,12 @@ <iframe srcdoc="<script>var arr = ['foo', 'bar'];</script>"></iframe> | ||
| | Operations / second | Relative margin of error | | ||
| ---------------- | ------------------- | ------------------------ | | ||
| **fast-copy** | **1,725,552** | **0.89%** | | ||
| clone | 1,114,295 | 0.82% | | ||
| lodash.cloneDeep | 904,031 | 0.51% | | ||
| fast-deepclone | 716,908 | 0.87% | | ||
| fast-clone | 497,748 | 0.88% | | ||
| deepclone | 420,962 | 0.59% | | ||
| | Operations / second | | ||
| ------------------ | ------------------- | | ||
| **fast-copy** | **2,692,822** | | ||
| clone | 1,420,277 | | ||
| lodash.cloneDeep | 1,277,213 | | ||
| fast-deepclone | 768,982 | | ||
| ramda | 719,948 | | ||
| fast-clone | 567,342 | | ||
| deepclone | 509,547 | | ||
| fast-copy (strict) | 420,804 | | ||
@@ -118,11 +136,28 @@ #### Complex objects | ||
| | Operations / second | Relative margin of error | | ||
| ---------------- | ------------------- | ------------------------ | | ||
| **fast-copy** | **113,553** | **0.76%** | | ||
| fast-deepclone | 101,356 | 0.76% | | ||
| deepclone | 54,401 | 0.80% | | ||
| clone | 51,183 | 0.79% | | ||
| fast-clone | 46,165 | 0.66% | | ||
| lodash.cloneDeep | 39,395 | 0.78% | | ||
| | Operations / second | | ||
| ------------------ | ------------------- | | ||
| **fast-copy** | **109,352** | | ||
| fast-deepclone | 101,808 | | ||
| ramda | 93,103 | | ||
| deepclone | 74,270 | | ||
| fast-clone | 49,911 | | ||
| clone | 46,355 | | ||
| lodash.cloneDeep | 43,900 | | ||
| fast-copy (strict) | 33,440 | | ||
#### Big data | ||
_Very large number of properties with high amount of nesting, mainly objects and arrays_ | ||
| | Operations / second | | ||
| ------------------ | ------------------- | | ||
| **fast-copy** | 123 | | ||
| fast-deepclone | 101 | | ||
| fast-clone | 93 | | ||
| lodash.cloneDeep | 92 | | ||
| deepclone | 66 | | ||
| clone | 50 | | ||
| fast-copy (strict) | 42 | | ||
| ramda | 5 | | ||
#### Circular objects | ||
@@ -132,10 +167,12 @@ | ||
| | Operations / second | Relative margin of error | | ||
| -------------------------- | ------------------- | ------------------------ | | ||
| **fast-copy** | **1,011,337** | **0.80%** | | ||
| clone | 644,481 | 0.67% | | ||
| lodash.cloneDeep | 577,534 | 0.48% | | ||
| fast-deepclone | 359,288 | 0.79% | | ||
| deepclone | 371,971 | 0.55% | | ||
| fast-clone (not supported) | 0 | 0.00% | | ||
| | Operations / second | | ||
| -------------------------- | ------------------- | | ||
| **fast-copy** | **1,143,074** | | ||
| ramda | 750,430 | | ||
| clone | 722,632 | | ||
| lodash.cloneDeep | 580,005 | | ||
| deepclone | 490,824 | | ||
| fast-deepclone | 446,585 | | ||
| fast-copy (strict) | 321,678 | | ||
| fast-clone (not supported) | 0 | | ||
@@ -146,10 +183,12 @@ #### Special objects | ||
| | Operations / second | Relative margin of error | | ||
| ---------------- | ------------------- | ------------------------ | | ||
| **fast-copy** | **56,013** | **0.97%** | | ||
| clone | 42,107 | 0.87% | | ||
| lodash.cloneDeep | 36,113 | 0.74% | | ||
| fast-deepclone | 25,278 | 1.45% | | ||
| fast-clone | 21,450 | 0.86% | | ||
| deepclone | 12,768 | 0.77% | | ||
| | Operations / second | | ||
| ------------------ | ------------------- | | ||
| **fast-copy** | **78,422** | | ||
| clone | 52,165 | | ||
| lodash.cloneDeep | 39,648 | | ||
| ramda | 32,372 | | ||
| fast-deepclone | 27,518 | | ||
| fast-clone | 27,495 | | ||
| deepclone | 16,552 | | ||
| fast-copy (strict) | 12,509 | | ||
@@ -156,0 +195,0 @@ ## Development |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
32
205
97276
13
964