import { _patcherDelaySymbol } from "@lib/api/patcher"; import { proxyLazy } from "@lib/utils/lazy"; import { findExports } from "./finders"; import { getMetroCache } from "./internals/caches"; import { metroModules, subscribeModule } from "./internals/modules"; import type { FilterFn, LazyModuleContext } from "./types"; /** @internal */ export const _lazyContextSymbol = Symbol.for("bunny.metro.lazyContext"); const _lazyContexts = new WeakMap(); function getIndexedFind(filter: FilterFn) { const modulesMap = getMetroCache().findIndex[filter.uniq]; if (!modulesMap) return undefined; for (const k in modulesMap) if (k[0] !== "_") return Number(k); } function subscribeLazyModule(proxy: any, callback: (exports: any) => void) { const info = getLazyContext(proxy); if (!info) throw new Error("Subscribing a module for non-proxy-find"); if (!info.indexed) throw new Error("Attempting to subscribe to a non-indexed find"); return subscribeModule(info.moduleId!, () => { callback(findExports(info.filter)); }); } export function getLazyContext(proxy: any): LazyModuleContext | void { return _lazyContexts.get(proxy) as unknown as LazyModuleContext; } export function createLazyModule(filter: FilterFn) { let cache: any = undefined; const moduleId = getIndexedFind(filter); const context: LazyModuleContext = { filter, indexed: !!moduleId, moduleId, getExports(cb: (exports: any) => void) { if (!moduleId || metroModules[moduleId]?.isInitialized) { cb(this.forceLoad()); return () => void 0; } return this.subscribe(cb); }, subscribe(cb: (exports: any) => void) { return subscribeLazyModule(proxy, cb); }, get cache() { return cache; }, forceLoad() { cache ??= findExports(filter); if (!cache) throw new Error(`${filter.uniq} is ${typeof cache}! (id ${context.moduleId ?? "unknown"})`); return cache; } }; const proxy = proxyLazy(() => context.forceLoad(), { exemptedEntries: { [_lazyContextSymbol]: context, [_patcherDelaySymbol]: (cb: (exports: any) => void) => context.getExports(cb) } }); _lazyContexts.set(proxy, context as LazyModuleContext); return proxy; }