399 lines
13 KiB
JavaScript
399 lines
13 KiB
JavaScript
var toStringFunction = Function.prototype.toString;
|
|
var create = Object.create;
|
|
var toStringObject = Object.prototype.toString;
|
|
/**
|
|
* @classdesc Fallback cache for when WeakMap is not natively supported
|
|
*/
|
|
var LegacyCache = /** @class */ (function () {
|
|
function LegacyCache() {
|
|
this._keys = [];
|
|
this._values = [];
|
|
}
|
|
LegacyCache.prototype.has = function (key) {
|
|
return !!~this._keys.indexOf(key);
|
|
};
|
|
LegacyCache.prototype.get = function (key) {
|
|
return this._values[this._keys.indexOf(key)];
|
|
};
|
|
LegacyCache.prototype.set = function (key, value) {
|
|
this._keys.push(key);
|
|
this._values.push(value);
|
|
};
|
|
return LegacyCache;
|
|
}());
|
|
function createCacheLegacy() {
|
|
return new LegacyCache();
|
|
}
|
|
function createCacheModern() {
|
|
return new WeakMap();
|
|
}
|
|
/**
|
|
* Get a new cache object to prevent circular references.
|
|
*/
|
|
var createCache = typeof WeakMap !== 'undefined' ? createCacheModern : createCacheLegacy;
|
|
/**
|
|
* Get an empty version of the object with the same prototype it has.
|
|
*/
|
|
function getCleanClone(prototype) {
|
|
if (!prototype) {
|
|
return create(null);
|
|
}
|
|
var Constructor = prototype.constructor;
|
|
if (Constructor === Object) {
|
|
return prototype === Object.prototype ? {} : create(prototype);
|
|
}
|
|
if (Constructor &&
|
|
~toStringFunction.call(Constructor).indexOf('[native code]')) {
|
|
try {
|
|
return new Constructor();
|
|
}
|
|
catch (_a) { }
|
|
}
|
|
return create(prototype);
|
|
}
|
|
function getRegExpFlagsLegacy(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 getRegExpFlagsModern(regExp) {
|
|
return regExp.flags;
|
|
}
|
|
/**
|
|
* Get the flags to apply to the copied regexp.
|
|
*/
|
|
var getRegExpFlags = /test/g.flags === 'g' ? getRegExpFlagsModern : getRegExpFlagsLegacy;
|
|
function getTagLegacy(value) {
|
|
var type = toStringObject.call(value);
|
|
return type.substring(8, type.length - 1);
|
|
}
|
|
function getTagModern(value) {
|
|
return value[Symbol.toStringTag] || getTagLegacy(value);
|
|
}
|
|
/**
|
|
* Get the tag of the value passed, so that the correct copier can be used.
|
|
*/
|
|
var getTag = typeof Symbol !== 'undefined' ? getTagModern : getTagLegacy;
|
|
|
|
var defineProperty = Object.defineProperty, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols;
|
|
var _a = Object.prototype, hasOwnProperty = _a.hasOwnProperty, propertyIsEnumerable = _a.propertyIsEnumerable;
|
|
var SUPPORTS_SYMBOL = typeof getOwnPropertySymbols === 'function';
|
|
function getStrictPropertiesModern(object) {
|
|
return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
|
|
}
|
|
/**
|
|
* Get the properites used when copying objects strictly. This includes both keys and symbols.
|
|
*/
|
|
var getStrictProperties = SUPPORTS_SYMBOL
|
|
? getStrictPropertiesModern
|
|
: getOwnPropertyNames;
|
|
/**
|
|
* Striclty copy all properties contained on the object.
|
|
*/
|
|
function copyOwnPropertiesStrict(value, clone, state) {
|
|
var properties = getStrictProperties(value);
|
|
for (var index = 0, length_1 = properties.length, property = void 0, descriptor = void 0; index < length_1; ++index) {
|
|
property = properties[index];
|
|
if (property === 'callee' || property === 'caller') {
|
|
continue;
|
|
}
|
|
descriptor = getOwnPropertyDescriptor(value, property);
|
|
if (!descriptor) {
|
|
// In extra edge cases where the property descriptor cannot be retrived, fall back to
|
|
// the loose assignment.
|
|
clone[property] = state.copier(value[property], state);
|
|
continue;
|
|
}
|
|
// Only clone the value if actually a value, not a getter / setter.
|
|
if (!descriptor.get && !descriptor.set) {
|
|
descriptor.value = state.copier(descriptor.value, state);
|
|
}
|
|
try {
|
|
defineProperty(clone, property, descriptor);
|
|
}
|
|
catch (error) {
|
|
// Tee above can fail on node in edge cases, so fall back to the loose assignment.
|
|
clone[property] = descriptor.value;
|
|
}
|
|
}
|
|
return clone;
|
|
}
|
|
/**
|
|
* Deeply copy the indexed values in the array.
|
|
*/
|
|
function copyArrayLoose(array, state) {
|
|
var clone = new state.Constructor();
|
|
// set in the cache immediately to be able to reuse the object recursively
|
|
state.cache.set(array, clone);
|
|
for (var index = 0, length_2 = array.length; index < length_2; ++index) {
|
|
clone[index] = state.copier(array[index], state);
|
|
}
|
|
return clone;
|
|
}
|
|
/**
|
|
* Deeply copy the indexed values in the array, as well as any custom properties.
|
|
*/
|
|
function copyArrayStrict(array, state) {
|
|
var clone = new state.Constructor();
|
|
// set in the cache immediately to be able to reuse the object recursively
|
|
state.cache.set(array, clone);
|
|
return copyOwnPropertiesStrict(array, clone, state);
|
|
}
|
|
/**
|
|
* Copy the contents of the ArrayBuffer.
|
|
*/
|
|
function copyArrayBuffer(arrayBuffer, _state) {
|
|
return arrayBuffer.slice(0);
|
|
}
|
|
/**
|
|
* Create a new Blob with the contents of the original.
|
|
*/
|
|
function copyBlob(blob, _state) {
|
|
return blob.slice(0, blob.size, blob.type);
|
|
}
|
|
/**
|
|
* Create a new DataView with the contents of the original.
|
|
*/
|
|
function copyDataView(dataView, state) {
|
|
return new state.Constructor(copyArrayBuffer(dataView.buffer));
|
|
}
|
|
/**
|
|
* Create a new Date based on the time of the original.
|
|
*/
|
|
function copyDate(date, state) {
|
|
return new state.Constructor(date.getTime());
|
|
}
|
|
/**
|
|
* Deeply copy the keys and values of the original.
|
|
*/
|
|
function copyMapLoose(map, state) {
|
|
var clone = new state.Constructor();
|
|
// set in the cache immediately to be able to reuse the object recursively
|
|
state.cache.set(map, clone);
|
|
map.forEach(function (value, key) {
|
|
clone.set(key, state.copier(value, state));
|
|
});
|
|
return clone;
|
|
}
|
|
/**
|
|
* Deeply copy the keys and values of the original, as well as any custom properties.
|
|
*/
|
|
function copyMapStrict(map, state) {
|
|
return copyOwnPropertiesStrict(map, copyMapLoose(map, state), state);
|
|
}
|
|
function copyObjectLooseLegacy(object, state) {
|
|
var clone = getCleanClone(state.prototype);
|
|
// set in the cache immediately to be able to reuse the object recursively
|
|
state.cache.set(object, clone);
|
|
for (var key in object) {
|
|
if (hasOwnProperty.call(object, key)) {
|
|
clone[key] = state.copier(object[key], state);
|
|
}
|
|
}
|
|
return clone;
|
|
}
|
|
function copyObjectLooseModern(object, state) {
|
|
var clone = getCleanClone(state.prototype);
|
|
// set in the cache immediately to be able to reuse the object recursively
|
|
state.cache.set(object, clone);
|
|
for (var key in object) {
|
|
if (hasOwnProperty.call(object, key)) {
|
|
clone[key] = state.copier(object[key], state);
|
|
}
|
|
}
|
|
var symbols = getOwnPropertySymbols(object);
|
|
for (var index = 0, length_3 = symbols.length, symbol = void 0; index < length_3; ++index) {
|
|
symbol = symbols[index];
|
|
if (propertyIsEnumerable.call(object, symbol)) {
|
|
clone[symbol] = state.copier(object[symbol], state);
|
|
}
|
|
}
|
|
return clone;
|
|
}
|
|
/**
|
|
* Deeply copy the properties (keys and symbols) and values of the original.
|
|
*/
|
|
var copyObjectLoose = SUPPORTS_SYMBOL
|
|
? copyObjectLooseModern
|
|
: copyObjectLooseLegacy;
|
|
/**
|
|
* Deeply copy the properties (keys and symbols) and values of the original, as well
|
|
* as any hidden or non-enumerable properties.
|
|
*/
|
|
function copyObjectStrict(object, state) {
|
|
var clone = getCleanClone(state.prototype);
|
|
// set in the cache immediately to be able to reuse the object recursively
|
|
state.cache.set(object, clone);
|
|
return copyOwnPropertiesStrict(object, clone, state);
|
|
}
|
|
/**
|
|
* Create a new primitive wrapper from the value of the original.
|
|
*/
|
|
function copyPrimitiveWrapper(primitiveObject, state) {
|
|
return new state.Constructor(primitiveObject.valueOf());
|
|
}
|
|
/**
|
|
* Create a new RegExp based on the value and flags of the original.
|
|
*/
|
|
function copyRegExp(regExp, state) {
|
|
var clone = new state.Constructor(regExp.source, getRegExpFlags(regExp));
|
|
clone.lastIndex = regExp.lastIndex;
|
|
return clone;
|
|
}
|
|
/**
|
|
* Return the original value (an identity function).
|
|
*
|
|
* @note
|
|
* THis is used for objects that cannot be copied, such as WeakMap.
|
|
*/
|
|
function copySelf(value, _state) {
|
|
return value;
|
|
}
|
|
/**
|
|
* Deeply copy the values of the original.
|
|
*/
|
|
function copySetLoose(set, state) {
|
|
var clone = new state.Constructor();
|
|
// set in the cache immediately to be able to reuse the object recursively
|
|
state.cache.set(set, clone);
|
|
set.forEach(function (value) {
|
|
clone.add(state.copier(value, state));
|
|
});
|
|
return clone;
|
|
}
|
|
/**
|
|
* Deeply copy the values of the original, as well as any custom properties.
|
|
*/
|
|
function copySetStrict(set, state) {
|
|
return copyOwnPropertiesStrict(set, copySetLoose(set, state), state);
|
|
}
|
|
|
|
var isArray = Array.isArray;
|
|
var assign = Object.assign;
|
|
var getPrototypeOf = Object.getPrototypeOf || (function (obj) { return obj.__proto__; });
|
|
var DEFAULT_LOOSE_OPTIONS = {
|
|
array: copyArrayLoose,
|
|
arrayBuffer: copyArrayBuffer,
|
|
blob: copyBlob,
|
|
dataView: copyDataView,
|
|
date: copyDate,
|
|
error: copySelf,
|
|
map: copyMapLoose,
|
|
object: copyObjectLoose,
|
|
regExp: copyRegExp,
|
|
set: copySetLoose,
|
|
};
|
|
var DEFAULT_STRICT_OPTIONS = assign({}, DEFAULT_LOOSE_OPTIONS, {
|
|
array: copyArrayStrict,
|
|
map: copyMapStrict,
|
|
object: copyObjectStrict,
|
|
set: copySetStrict,
|
|
});
|
|
/**
|
|
* Get the copiers used for each specific object tag.
|
|
*/
|
|
function getTagSpecificCopiers(options) {
|
|
return {
|
|
Arguments: options.object,
|
|
Array: options.array,
|
|
ArrayBuffer: options.arrayBuffer,
|
|
Blob: options.blob,
|
|
Boolean: copyPrimitiveWrapper,
|
|
DataView: options.dataView,
|
|
Date: options.date,
|
|
Error: options.error,
|
|
Float32Array: options.arrayBuffer,
|
|
Float64Array: options.arrayBuffer,
|
|
Int8Array: options.arrayBuffer,
|
|
Int16Array: options.arrayBuffer,
|
|
Int32Array: options.arrayBuffer,
|
|
Map: options.map,
|
|
Number: copyPrimitiveWrapper,
|
|
Object: options.object,
|
|
Promise: copySelf,
|
|
RegExp: options.regExp,
|
|
Set: options.set,
|
|
String: copyPrimitiveWrapper,
|
|
WeakMap: copySelf,
|
|
WeakSet: copySelf,
|
|
Uint8Array: options.arrayBuffer,
|
|
Uint8ClampedArray: options.arrayBuffer,
|
|
Uint16Array: options.arrayBuffer,
|
|
Uint32Array: options.arrayBuffer,
|
|
Uint64Array: options.arrayBuffer,
|
|
};
|
|
}
|
|
/**
|
|
* Create a custom copier based on the object-specific copy methods passed.
|
|
*/
|
|
function createCopier(options) {
|
|
var normalizedOptions = assign({}, DEFAULT_LOOSE_OPTIONS, options);
|
|
var tagSpecificCopiers = getTagSpecificCopiers(normalizedOptions);
|
|
var array = tagSpecificCopiers.Array, object = tagSpecificCopiers.Object;
|
|
function copier(value, state) {
|
|
state.prototype = state.Constructor = undefined;
|
|
if (!value || typeof value !== 'object') {
|
|
return value;
|
|
}
|
|
if (state.cache.has(value)) {
|
|
return state.cache.get(value);
|
|
}
|
|
state.prototype = getPrototypeOf(value);
|
|
state.Constructor = state.prototype && state.prototype.constructor;
|
|
// plain objects
|
|
if (!state.Constructor || state.Constructor === Object) {
|
|
return object(value, state);
|
|
}
|
|
// arrays
|
|
if (isArray(value)) {
|
|
return array(value, state);
|
|
}
|
|
var tagSpecificCopier = tagSpecificCopiers[getTag(value)];
|
|
if (tagSpecificCopier) {
|
|
return tagSpecificCopier(value, state);
|
|
}
|
|
return typeof value.then === 'function' ? value : object(value, state);
|
|
}
|
|
return function copy(value) {
|
|
return copier(value, {
|
|
Constructor: undefined,
|
|
cache: createCache(),
|
|
copier: copier,
|
|
prototype: undefined,
|
|
});
|
|
};
|
|
}
|
|
/**
|
|
* Create a custom copier based on the object-specific copy methods passed, defaulting to the
|
|
* same internals as `copyStrict`.
|
|
*/
|
|
function createStrictCopier(options) {
|
|
return createCopier(assign({}, DEFAULT_STRICT_OPTIONS, options));
|
|
}
|
|
/**
|
|
* Copy an value deeply as much as possible, where strict recreation of object properties
|
|
* are maintained. All properties (including non-enumerable ones) are copied with their
|
|
* original property descriptors on both objects and arrays.
|
|
*/
|
|
var copyStrict = createStrictCopier({});
|
|
/**
|
|
* Copy an value deeply as much as possible.
|
|
*/
|
|
var index = createCopier({});
|
|
|
|
export { copyStrict, createCopier, createStrictCopier, index as default };
|
|
//# sourceMappingURL=index.mjs.map
|