aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/vendor/once-cell/index.ts
blob: 5ae37f0d6ece00492a0a1b175e8d18e46f266748 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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