/* * Vencord, a modification for Discord's desktop app * Copyright (c) 2022 Vendicated and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ // Proxies demand that these properties be unmodified, so proxyLazy // will always return the function default for them. const unconfigurable = ["arguments", "caller", "prototype"]; const handler: ProxyHandler<any> = {}; const GET_KEY = Symbol.for("vencord.lazy.get"); const CACHED_KEY = Symbol.for("vencord.lazy.cached"); for (const method of [ "apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf" ]) { handler[method] = (target: any, ...args: any[]) => Reflect[method](target[GET_KEY](), ...args); } handler.ownKeys = target => { const v = target[GET_KEY](); const keys = Reflect.ownKeys(v); for (const key of unconfigurable) { if (!keys.includes(key)) keys.push(key); } return keys; }; handler.getOwnPropertyDescriptor = (target, p) => { if (typeof p === "string" && unconfigurable.includes(p)) return Reflect.getOwnPropertyDescriptor(target, p); const descriptor = Reflect.getOwnPropertyDescriptor(target[GET_KEY](), p); if (descriptor) Object.defineProperty(target, p, descriptor); return descriptor; }; /** * Wraps the result of {@see makeLazy} in a Proxy you can consume as if it wasn't lazy. * On first property access, the lazy is evaluated * @param factory lazy factory * @returns Proxy * * Note that the example below exists already as an api, see {@link findByPropsLazy} * @example const mod = proxyLazy(() => findByProps("blah")); console.log(mod.blah); */ export function proxyLazy<T>(factory: () => T): T { const proxyDummy: { (): void; [CACHED_KEY]?: T; [GET_KEY](): T; } = Object.assign(function () { }, { [CACHED_KEY]: void 0, [GET_KEY]: () => proxyDummy[CACHED_KEY] ??= factory(), }); return new Proxy(proxyDummy, handler) as any; }