diff options
feat: an implementation of OnceCell
-rw-r--r-- | src/lib/vendor/once-cell/index.ts | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/lib/vendor/once-cell/index.ts b/src/lib/vendor/once-cell/index.ts new file mode 100644 index 0000000..5ae37f0 --- /dev/null +++ b/src/lib/vendor/once-cell/index.ts @@ -0,0 +1,94 @@ +export type Proxy<T> = T; +export type OnceCell<T> = Proxy<T & { + /** + * Do not use. + * @deprecated Implementation Detail. + * @internal @private @ignore + */ + '*internal.oncecelldereference': T +}>; +export type OnceCellConstructor = Proxy<(<T>(create: () => T) => Proxy<T>) & (new <T>(create: () => T) => OnceCell<T>) & { + dereference: <T>(cell: OnceCell<T>) => T +}>; +/** + * @license MIT + * @copyright memdmp <memdmp@estrogen.zone> + */ +export const OnceCell = new Proxy( + // We use the function keyword here to indicate that this *may* be a constructor + function <T>(create: () => T): OnceCell<T> { + if (typeof create !== 'function') throw new Error('Must pass function to OnceCell') + let createOnce = (): T extends object ? T : never => { + const t = create(); + return (createOnce = () => t as T extends object ? T : never)() + } + const onceCellProxyImplementation: ProxyHandler<{ + get value(): T + }> = { + get(_, idx, receiver) { + const target = createOnce(); + if (idx === '*internal.oncecelldereference') return target; + // .valueOf() and similar prototype methods should be proxied properly + if (!Object.hasOwnProperty.call(target, idx) && typeof target[idx as keyof T] === 'function') { + return (...args: unknown[]) => { + // @ts-expect-error we don't know .call's argument types, so we just hope and pray they're good and leave it to the caller to deal with it if it isn't + return target[idx as keyof T].call(target, args); + } + } + // return Reflect.get(obj, idx, receiver) + return target[idx as keyof T]; + }, + set(_, ...args) { + return Reflect.set(createOnce(), ...args) + }, + has(_, idx, ...args) { + if (idx === '*internal.oncecelldereference') return true // to comply with the OnceCell type declaration's meaning + return Reflect.has(createOnce(), idx, ...args) + }, + deleteProperty(_, ...args) { + return Reflect.deleteProperty(createOnce(), ...args) + }, + isExtensible(_, ...args) { + return Reflect.isExtensible(createOnce(), ...args) + }, + ownKeys(_, ...args) { + return Reflect.ownKeys(createOnce(), ...args) + }, + defineProperty(_, ...args) { + return Reflect.defineProperty(createOnce(), ...args) + }, + getOwnPropertyDescriptor(_, ...args) { + return Reflect.getOwnPropertyDescriptor(createOnce(), ...args) + }, + preventExtensions(_, ...args) { + return Reflect.preventExtensions(createOnce(), ...args) + }, + getPrototypeOf(_, ...args) { + return Reflect.getPrototypeOf(createOnce(), ...args) + }, + setPrototypeOf(_, ...args) { + return Reflect.setPrototypeOf(createOnce(), ...args) + }, + apply(_, ...args) { + type F = (this: any, ...args: any[]) => any + return Reflect.apply(createOnce() as unknown as T extends F ? F : never, ...args) + }, + construct(_, ...args) { + type F = (this: any, ...args: any[]) => any + return Reflect.construct(createOnce() as unknown as T extends F ? F : never, ...args) + }, + } + return new Proxy({ + /** For debuggers */ + get value() { + return createOnce() + } + }, onceCellProxyImplementation) as unknown as OnceCell<T> + }, { + construct(onceCellCreationFunction, argArray, newTarget) { + return onceCellCreationFunction(argArray[0]) + }, +}) as OnceCellConstructor +OnceCell.dereference = (t) => Reflect.get(t as object, '*internal.oncecelldereference', t) +Object.freeze(OnceCell) +export default OnceCell |