cross-domain-safe-weakmap
Version:
Cross domain safe WeakMap.
240 lines (192 loc) • 4.77 kB
JavaScript
import { isWindow, isWindowClosed } from 'cross-domain-utils/src';
import { hasNativeWeakMap } from './native';
import { noop, safeIndexOf } from './util';
export var CrossDomainSafeWeakMap = /*#__PURE__*/function () {
// eslint-disable-next-line flowtype/no-mutable-array
// eslint-disable-next-line flowtype/no-mutable-array
function CrossDomainSafeWeakMap() {
this.name = void 0;
this.weakmap = void 0;
this.keys = void 0;
this.values = void 0;
// eslint-disable-next-line no-bitwise
this.name = "__weakmap_" + (Math.random() * 1e9 >>> 0) + "__";
if (hasNativeWeakMap()) {
try {
this.weakmap = new WeakMap();
} catch (err) {// pass
}
}
this.keys = [];
this.values = [];
}
var _proto = CrossDomainSafeWeakMap.prototype;
_proto._cleanupClosedWindows = function _cleanupClosedWindows() {
var weakmap = this.weakmap;
var keys = this.keys;
for (var i = 0; i < keys.length; i++) {
var value = keys[i];
if (isWindow(value) && isWindowClosed(value)) {
if (weakmap) {
try {
weakmap.delete(value);
} catch (err) {// pass
}
}
keys.splice(i, 1);
this.values.splice(i, 1);
i -= 1;
}
}
};
_proto.isSafeToReadWrite = function isSafeToReadWrite(key) {
if (isWindow(key)) {
return false;
}
try {
noop(key && key.self);
noop(key && key[this.name]);
} catch (err) {
return false;
}
return true;
};
_proto.set = function set(key, value) {
if (!key) {
throw new Error("WeakMap expected key");
}
var weakmap = this.weakmap;
if (weakmap) {
try {
weakmap.set(key, value);
} catch (err) {
delete this.weakmap;
}
}
if (this.isSafeToReadWrite(key)) {
try {
var name = this.name;
var entry = key[name];
if (entry && entry[0] === key) {
entry[1] = value;
} else {
Object.defineProperty(key, name, {
value: [key, value],
writable: true
});
}
return;
} catch (err) {// pass
}
}
this._cleanupClosedWindows();
var keys = this.keys;
var values = this.values;
var index = safeIndexOf(keys, key);
if (index === -1) {
keys.push(key);
values.push(value);
} else {
values[index] = value;
}
};
_proto.get = function get(key) {
if (!key) {
throw new Error("WeakMap expected key");
}
var weakmap = this.weakmap;
if (weakmap) {
try {
if (weakmap.has(key)) {
return weakmap.get(key);
}
} catch (err) {
delete this.weakmap;
}
}
if (this.isSafeToReadWrite(key)) {
try {
var entry = key[this.name];
if (entry && entry[0] === key) {
return entry[1];
}
return;
} catch (err) {// pass
}
}
this._cleanupClosedWindows();
var keys = this.keys;
var index = safeIndexOf(keys, key);
if (index === -1) {
return;
}
return this.values[index];
};
_proto.delete = function _delete(key) {
if (!key) {
throw new Error("WeakMap expected key");
}
var weakmap = this.weakmap;
if (weakmap) {
try {
weakmap.delete(key);
} catch (err) {
delete this.weakmap;
}
}
if (this.isSafeToReadWrite(key)) {
try {
var entry = key[this.name];
if (entry && entry[0] === key) {
entry[0] = entry[1] = undefined;
}
} catch (err) {// pass
}
}
this._cleanupClosedWindows();
var keys = this.keys;
var index = safeIndexOf(keys, key);
if (index !== -1) {
keys.splice(index, 1);
this.values.splice(index, 1);
}
};
_proto.has = function has(key) {
if (!key) {
throw new Error("WeakMap expected key");
}
var weakmap = this.weakmap;
if (weakmap) {
try {
if (weakmap.has(key)) {
return true;
}
} catch (err) {
delete this.weakmap;
}
}
if (this.isSafeToReadWrite(key)) {
try {
var entry = key[this.name];
if (entry && entry[0] === key) {
return true;
}
return false;
} catch (err) {// pass
}
}
this._cleanupClosedWindows();
var index = safeIndexOf(this.keys, key);
return index !== -1;
};
_proto.getOrSet = function getOrSet(key, getter) {
if (this.has(key)) {
// $FlowFixMe
return this.get(key);
}
var value = getter();
this.set(key, value);
return value;
};
return CrossDomainSafeWeakMap;
}();