153 lines
3.4 KiB
JavaScript
153 lines
3.4 KiB
JavaScript
import path from './path.js';
|
|
|
|
/**
|
|
@class Cache
|
|
@private
|
|
*/
|
|
export default class Cache {
|
|
constructor(equals) {
|
|
this._equals = equals;
|
|
this._proxyCache = new WeakMap();
|
|
this._pathCache = new WeakMap();
|
|
this.isUnsubscribed = false;
|
|
}
|
|
|
|
_getDescriptorCache() {
|
|
if (this._descriptorCache === undefined) {
|
|
this._descriptorCache = new WeakMap();
|
|
}
|
|
|
|
return this._descriptorCache;
|
|
}
|
|
|
|
_getProperties(target) {
|
|
const descriptorCache = this._getDescriptorCache();
|
|
let properties = descriptorCache.get(target);
|
|
|
|
if (properties === undefined) {
|
|
properties = {};
|
|
descriptorCache.set(target, properties);
|
|
}
|
|
|
|
return properties;
|
|
}
|
|
|
|
_getOwnPropertyDescriptor(target, property) {
|
|
if (this.isUnsubscribed) {
|
|
return Reflect.getOwnPropertyDescriptor(target, property);
|
|
}
|
|
|
|
const properties = this._getProperties(target);
|
|
let descriptor = properties[property];
|
|
|
|
if (descriptor === undefined) {
|
|
descriptor = Reflect.getOwnPropertyDescriptor(target, property);
|
|
properties[property] = descriptor;
|
|
}
|
|
|
|
return descriptor;
|
|
}
|
|
|
|
getProxy(target, path, handler, proxyTarget) {
|
|
if (this.isUnsubscribed) {
|
|
return target;
|
|
}
|
|
|
|
const reflectTarget = target[proxyTarget];
|
|
const source = reflectTarget ?? target;
|
|
|
|
this._pathCache.set(source, path);
|
|
|
|
let proxy = this._proxyCache.get(source);
|
|
|
|
if (proxy === undefined) {
|
|
proxy = reflectTarget === undefined
|
|
? new Proxy(target, handler)
|
|
: target;
|
|
|
|
this._proxyCache.set(source, proxy);
|
|
}
|
|
|
|
return proxy;
|
|
}
|
|
|
|
getPath(target) {
|
|
return this.isUnsubscribed ? undefined : this._pathCache.get(target);
|
|
}
|
|
|
|
isDetached(target, object) {
|
|
return !Object.is(target, path.get(object, this.getPath(target)));
|
|
}
|
|
|
|
defineProperty(target, property, descriptor) {
|
|
if (!Reflect.defineProperty(target, property, descriptor)) {
|
|
return false;
|
|
}
|
|
|
|
if (!this.isUnsubscribed) {
|
|
this._getProperties(target)[property] = descriptor;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
setProperty(target, property, value, receiver, previous) { // eslint-disable-line max-params
|
|
if (!this._equals(previous, value) || !(property in target)) {
|
|
const descriptor = this._getOwnPropertyDescriptor(target, property);
|
|
|
|
if (descriptor !== undefined && 'set' in descriptor) {
|
|
return Reflect.set(target, property, value, receiver);
|
|
}
|
|
|
|
return Reflect.set(target, property, value);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
deleteProperty(target, property, previous) {
|
|
if (Reflect.deleteProperty(target, property)) {
|
|
if (!this.isUnsubscribed) {
|
|
const properties = this._getDescriptorCache().get(target);
|
|
|
|
if (properties) {
|
|
delete properties[property];
|
|
this._pathCache.delete(previous);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
isSameDescriptor(a, target, property) {
|
|
const b = this._getOwnPropertyDescriptor(target, property);
|
|
|
|
return a !== undefined
|
|
&& b !== undefined
|
|
&& Object.is(a.value, b.value)
|
|
&& (a.writable || false) === (b.writable || false)
|
|
&& (a.enumerable || false) === (b.enumerable || false)
|
|
&& (a.configurable || false) === (b.configurable || false)
|
|
&& a.get === b.get
|
|
&& a.set === b.set;
|
|
}
|
|
|
|
isGetInvariant(target, property) {
|
|
const descriptor = this._getOwnPropertyDescriptor(target, property);
|
|
|
|
return descriptor !== undefined
|
|
&& descriptor.configurable !== true
|
|
&& descriptor.writable !== true;
|
|
}
|
|
|
|
unsubscribe() {
|
|
this._descriptorCache = null;
|
|
this._pathCache = null;
|
|
this._proxyCache = null;
|
|
this.isUnsubscribed = true;
|
|
}
|
|
}
|