130 lines
3.7 KiB
TypeScript
130 lines
3.7 KiB
TypeScript
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-nocheck
|
|
/* eslint-disable no-new,no-useless-call */
|
|
// mutableProxyFactory from https://stackoverflow.com/a/54460544
|
|
// (C) Alex Hall https://stackoverflow.com/users/2482744/alex-hall
|
|
// License CC BY-SA 3.0
|
|
/* eslint-disable @typescript-eslint/ban-types */
|
|
|
|
export class PProxyHandler<T extends object> implements ProxyHandler<T> {
|
|
getPrototypeOf?(target: T): object | null {
|
|
return Reflect.getPrototypeOf(target);
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
setPrototypeOf?(target: T, v: any): boolean {
|
|
return Reflect.setPrototypeOf(target, v);
|
|
}
|
|
|
|
isExtensible?(target: T): boolean {
|
|
return Reflect.isExtensible(target);
|
|
}
|
|
|
|
preventExtensions?(target: T): boolean {
|
|
return Reflect.preventExtensions(target);
|
|
}
|
|
|
|
getOwnPropertyDescriptor?(
|
|
target: T,
|
|
p: PropertyKey
|
|
): PropertyDescriptor | undefined {
|
|
return Reflect.getOwnPropertyDescriptor(target, p);
|
|
}
|
|
|
|
has?(target: T, p: PropertyKey): boolean {
|
|
return Reflect.has(target, p);
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
get?(target: T, p: PropertyKey, receiver: any): any {
|
|
return Reflect.get(target, p, receiver);
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
set?(target: T, p: PropertyKey, value: any, receiver: any): boolean {
|
|
return Reflect.set(target, p, value, receiver);
|
|
}
|
|
|
|
deleteProperty?(target: T, p: PropertyKey): boolean {
|
|
return Reflect.deleteProperty(target, p);
|
|
}
|
|
|
|
defineProperty?(
|
|
target: T,
|
|
p: PropertyKey,
|
|
attributes: PropertyDescriptor
|
|
): boolean {
|
|
return Reflect.defineProperty(target, p, attributes);
|
|
}
|
|
|
|
enumerate?(target: T): PropertyKey[] {
|
|
return Reflect.ownKeys(target);
|
|
}
|
|
|
|
ownKeys?(target: T): PropertyKey[] {
|
|
return Reflect.ownKeys(target);
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
apply?(target: T, thisArg: any, argArray?: any): any {
|
|
return Reflect.apply(target as Function, thisArg, argArray);
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
construct?(target: T, argArray: any, newTarget?: any): object {
|
|
return Reflect.construct(target as Function, argArray, newTarget);
|
|
}
|
|
}
|
|
|
|
interface MutableProxy<T extends object> {
|
|
setTarget(target: T): void;
|
|
setHandler(handler: PProxyHandler<T>): void;
|
|
getTarget(): T;
|
|
getHandler(): ProxyHandler<T>;
|
|
proxy: T;
|
|
}
|
|
|
|
export function mutableProxyFactory<T extends object>(
|
|
mutableTarget: T,
|
|
mutableHandler?: ProxyHandler<T>
|
|
): MutableProxy<T> {
|
|
if (!mutableHandler) mutableHandler = new PProxyHandler();
|
|
return {
|
|
setTarget(target: T): void {
|
|
new Proxy(target, {}); // test target validity
|
|
mutableTarget = target;
|
|
},
|
|
setHandler(handler: PProxyHandler<T>): void {
|
|
new Proxy({}, handler); // test handler validity
|
|
Object.keys(handler).forEach((key) => {
|
|
const value = handler[key];
|
|
if (Reflect[key] && typeof value !== "function") {
|
|
throw new Error(`Trap "${key}: ${value}" is not a function`);
|
|
}
|
|
});
|
|
mutableHandler = handler;
|
|
},
|
|
getTarget(): T {
|
|
return mutableTarget;
|
|
},
|
|
getHandler(): PProxyHandler<T> {
|
|
return mutableHandler;
|
|
},
|
|
proxy: new Proxy(
|
|
mutableTarget,
|
|
new Proxy(
|
|
{},
|
|
{
|
|
// Dynamically forward all the traps to the associated methods on the mutable handler
|
|
get(target, property) {
|
|
return (_target, ...args) =>
|
|
mutableHandler[property].apply(mutableHandler, [
|
|
mutableTarget,
|
|
...args,
|
|
]);
|
|
},
|
|
}
|
|
)
|
|
),
|
|
};
|
|
}
|