From d2341a33231717d2ca2d6d27679266c7fa424e8d Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Mon, 20 May 2024 20:42:57 +0800 Subject: [PATCH] refactor(metro): last one I promise --- src/lib/api/assets.ts | 2 +- src/metro/caches.ts | 41 +++++++++++++++++++-------------------- src/metro/common/index.ts | 8 ++------ src/metro/filters.ts | 2 +- src/metro/finders.ts | 21 +++++++++++--------- src/metro/modules.ts | 2 +- src/metro/types.ts | 23 ++++++++++++++++++++++ src/metro/utils.ts | 33 ++++++++++--------------------- 8 files changed, 70 insertions(+), 62 deletions(-) diff --git a/src/lib/api/assets.ts b/src/lib/api/assets.ts index 993c50c..eef5745 100644 --- a/src/lib/api/assets.ts +++ b/src/lib/api/assets.ts @@ -53,4 +53,4 @@ export function patchAssets(module: AssetModule) { export const find = (filter: (a: any) => void): Asset | null | undefined => Object.values(all).find(filter); export const getAssetByName = (name: string): Asset => all[name]; export const getAssetByID = (id: number): Asset => assetsModule.getAssetByID(id); -export const getAssetIDByName = (name: string) => all[name]?.id ?? requireModule(getMetroCache().assetsCache[name]); +export const getAssetIDByName = (name: string) => all[name]?.id ?? requireModule(getMetroCache().assetsIndex[name]); diff --git a/src/metro/caches.ts b/src/metro/caches.ts index 0e08279..62d69cb 100644 --- a/src/metro/caches.ts +++ b/src/metro/caches.ts @@ -3,38 +3,37 @@ import { throttle } from "@lib/utils/throttle"; import { getCachedPolyfillModules } from "./modules"; -const BUNNY_METRO_CACHE_KEY = "__bunny_metro_cache_key_v5__"; - type ModulesMap = { _?: 1; [id: number]: 1 | void; }; interface MetroCacheStore { - v: 5; - buildNumber: number; + _v: 6; + _buildNumber: number; findIndex: Record; - polyfillCache: Record; - assetsCache: Record; + polyfillIndex: Record; + assetsIndex: Record; } -let metroCache = null as unknown as MetroCacheStore; +const BUNNY_METRO_CACHE_KEY = "__bunny_metro_cache_key_v5__"; +let _metroCache = null as unknown as MetroCacheStore; export function getMetroCache() { - return metroCache; + return _metroCache; } function buildInitCache() { - metroCache = { - v: 5, - buildNumber: ClientInfoManager.Build, + _metroCache = { + _v: 6, + _buildNumber: ClientInfoManager.Build, findIndex: {}, - polyfillCache: {}, - assetsCache: {} + polyfillIndex: {}, + assetsIndex: {} } as const; // Make sure all assets are cached. Delay by a second - // because force loading all will results in an unexpected crash. + // because force loading it all will results in an unexpected crash. setTimeout(() => { for (const id in window.modules) { require("@metro/modules").requireModule(id); @@ -47,9 +46,9 @@ export async function initMetroCache() { if (rawCache == null) return void buildInitCache(); try { - metroCache = JSON.parse(rawCache); - if (metroCache.buildNumber !== ClientInfoManager.Build) { - metroCache = null!; + _metroCache = JSON.parse(rawCache); + if (_metroCache._buildNumber !== ClientInfoManager.Build) { + _metroCache = null!; throw "cache invalidated; version mismatch"; } } catch { @@ -57,10 +56,10 @@ export async function initMetroCache() { } } -const saveCache = throttle(() => MMKVManager.setItem(BUNNY_METRO_CACHE_KEY, JSON.stringify(metroCache))); +const saveCache = throttle(() => MMKVManager.setItem(BUNNY_METRO_CACHE_KEY, JSON.stringify(_metroCache))); export function getCacherForUniq(uniq: string, allFind: boolean) { - const indexObject = metroCache.findIndex[uniq] ??= {}; + const indexObject = _metroCache.findIndex[uniq] ??= {}; return { cacheId(moduleId: number) { @@ -75,7 +74,7 @@ export function getCacherForUniq(uniq: string, allFind: boolean) { } export function getPolyfillModuleCacher(name: string) { - const indexObject = metroCache.polyfillCache[name] ??= {}; + const indexObject = _metroCache.polyfillIndex[name] ??= {}; return { getModules() { @@ -90,7 +89,7 @@ export function getPolyfillModuleCacher(name: string) { export function registerAssetCacheId(name: string, moduleId: number) { if (!isNaN(moduleId)) { - metroCache.assetsCache[name] = moduleId; + _metroCache.assetsIndex[name] = moduleId; saveCache(); } } diff --git a/src/metro/common/index.ts b/src/metro/common/index.ts index f05357b..521e3eb 100644 --- a/src/metro/common/index.ts +++ b/src/metro/common/index.ts @@ -1,6 +1,5 @@ -import { findExports } from "@metro/finders"; import { Dispatcher } from "@metro/types"; -import { createSimpleFilter, findByProps } from "@metro/utils"; +import { findByFilePath, findByProps } from "@metro/utils"; // Discord export const constants = findByProps("Fonts", "Permissions"); @@ -12,10 +11,7 @@ export const assets = findByProps("registerAsset"); export const invites = findByProps("acceptInviteAndTransitionToInviteChannel"); export const commands = findByProps("getBuiltInCommands"); export const navigation = findByProps("pushLazy"); -export const toasts = findExports(createSimpleFilter( - m => m.open && m.close && !m.startDrag && !m.init && !m.openReplay && !m.setAlwaysOnTop && !m.setAccountFlag, - "bunny.metro.common.toasts" -)); +export const toasts = findByFilePath("modules/toast/native/ToastActionCreators.tsx").default; export const messageUtil = findByProps("sendBotMessage"); export const navigationStack = findByProps("createStackNavigator"); export const NavigationNative = findByProps("NavigationContainer"); diff --git a/src/metro/filters.ts b/src/metro/filters.ts index 7b46e36..0a450f2 100644 --- a/src/metro/filters.ts +++ b/src/metro/filters.ts @@ -27,7 +27,7 @@ export const byStoreName = createFilterDefinition<[string]>( ); export const byFilePath = createFilterDefinition<[string]>( - ([path], _, id) => metroModules[id]?.__filePath === path, + ([path], _, id, defaultCheck) => !defaultCheck && metroModules[id]?.__filePath === path, path => `bunny.metro.byFilePath(${path})` ); diff --git a/src/metro/finders.ts b/src/metro/finders.ts index 97c847c..5db2695 100644 --- a/src/metro/finders.ts +++ b/src/metro/finders.ts @@ -1,18 +1,21 @@ import { getCacherForUniq } from "./caches"; import { getModules, requireModule } from "./modules"; -import { FilterFn } from "./utils"; +import { FilterFn } from "./types"; function testExports(moduleExports: any, moduleId: number, filter: FilterFn) { - if (moduleExports.default && moduleExports.__esModule && filter(moduleExports.default, moduleId)) + if (moduleExports.default && moduleExports.__esModule && filter(moduleExports.default, moduleId, true)) { return [moduleExports.default, true]; - if (filter(moduleExports, moduleId)) + } + + if (!filter.defaultFilter && filter(moduleExports, moduleId, false)) { return [moduleExports, false]; + } return []; } /** - * Returns the [id, defaultExports] of the first module where filter returns truthy, and undefined otherwise. + * Returns the [id, defaultExports] of the first module where filter returns non-undefined, and undefined otherwise. * @param filter find calls filter once for each enumerable module's exports until it finds one where filter returns a thruthy value. */ export function findModule(filter: FilterFn) { @@ -31,7 +34,7 @@ export function findModule(filter: FilterFn) { } /** - * Returns the id of the first module where filter returns truthy, and undefined otherwise. + * Returns the id of the first module where filter returns non-undefined, and undefined otherwise. * @param filter find calls filter once for each enumerable module's exports until it finds one where filter returns a thruthy value. */ export function findModuleId(filter: FilterFn) { @@ -39,7 +42,7 @@ export function findModuleId(filter: FilterFn) { } /** - * Returns the exports of the first module where filter returns truthy, and undefined otherwise. + * Returns the exports of the first module where filter returns non-undefined, and undefined otherwise. * @param filter find calls filter once for each enumerable module's exports until it finds one where filter returns a thruthy value. */ export function findExports(filter: FilterFn) { @@ -49,7 +52,7 @@ export function findExports(filter: FilterFn) { } /** - * Returns the [id, defaultExports] of all modules where filter returns truthy. + * Returns the [id, defaultExports] of all modules where filter returns non-undefined. * @param filter findAll calls filter once for each enumerable module's exports, adding the exports to the returned array when filter returns a thruthy value. */ export function findAllModule(filter: FilterFn) { @@ -69,7 +72,7 @@ export function findAllModule(filter: FilterFn) { } /** - * Returns the ids of all modules where filter returns truthy. + * Returns the ids of all modules where filter returns non-undefined. * @param filter findAll calls filter once for each enumerable module's exports, adding the exports to the returned array when filter returns a thruthy value. */ export function findAllModuleId(filter: FilterFn) { @@ -77,7 +80,7 @@ export function findAllModuleId(filter: FilterFn) { } /** - * Returns the ids of all exports where filter returns truthy. + * Returns the ids of all exports where filter returns non-undefined. * @param filter findAll calls filter once for each enumerable module's exports, adding the exports to the returned array when filter returns a thruthy value. */ export function findAllExports(filter: FilterFn) { diff --git a/src/metro/modules.ts b/src/metro/modules.ts index 50c37ca..3f8508d 100644 --- a/src/metro/modules.ts +++ b/src/metro/modules.ts @@ -172,7 +172,7 @@ export function* getModules(uniq: string, all = false) { } export function* getCachedPolyfillModules(name: string) { - const cache = getMetroCache().polyfillCache[name]; + const cache = getMetroCache().polyfillIndex[name]; for (const id in cache ?? metroModules) { const exports = requireModule(id); if (isBadExports(exports)) continue; diff --git a/src/metro/types.ts b/src/metro/types.ts index c15b618..b343ea1 100644 --- a/src/metro/types.ts +++ b/src/metro/types.ts @@ -126,6 +126,29 @@ export namespace Metro { } } + +export type ModuleExports = any; +export type FilterCheckDef = ( + args: A, + module: any, + modulesId: number, + defaultCheck: boolean +) => boolean; + +export interface FilterFn { + (m: any, id: number, defaultCheck: boolean): boolean; + filter: FilterCheckDef; + args: A; + defaultFilter: boolean; + uniq: string; +} + +export interface FilterDefinition { + (...args: A): FilterFn; + byDefault(...args: A): FilterFn; + uniqMaker(args: A): string; +} + export interface Dispatcher { _actionHandlers: unknown; _interceptors?: ((payload: any) => void | boolean)[]; diff --git a/src/metro/utils.ts b/src/metro/utils.ts index d09c3c6..bf0cfff 100644 --- a/src/metro/utils.ts +++ b/src/metro/utils.ts @@ -1,43 +1,30 @@ import { byDisplayName, byFilePath, byName, byProps, byStoreName, byTypeName } from "./filters"; import { findAllExports, findExports } from "./finders"; - -type ModuleExports = any; -type FilterCheckDef = (args: A, m: any, id: number) => boolean; - -export interface FilterFn { - (m: any, id: number): boolean; - filter: FilterCheckDef; - args: A; - isDefault: boolean; - uniq: string; -} - -export interface FilterDefinition { - (...args: A): FilterFn; - byDefault(...args: A): FilterFn; - uniqMaker(args: A): string; -} +import { FilterCheckDef, FilterDefinition, ModuleExports } from "./types"; export function createFilterDefinition( fn: FilterCheckDef, uniqMaker: (args: A) => string ): FilterDefinition { - function createHolder(func: T, args: A, isDefault: boolean) { + function createHolder(func: T, args: A, defaultFilter: boolean) { return Object.assign(func, { filter: fn, args, - isDefault, + defaultFilter, uniq: [ - isDefault && "default::", + defaultFilter && "default::", uniqMaker(args) ].filter(Boolean).join("") }); } - const curried = (...args: A) => createHolder((m: ModuleExports, id: number) => fn(args, m, id), args, false); + const curried = (...args: A) => createHolder((m: ModuleExports, id: number, defaultCheck: boolean) => { + return fn(args, m, id, defaultCheck); + }, args, false); + const curriedDefault = (...args: A) => { - function filter(m: ModuleExports, id: number) { - return m.__esModule && m.default ? fn(args, m.default, id) : false; + function filter(m: ModuleExports, id: number, defaultCheck: boolean) { + return m.__esModule && m.default ? fn(args, m.default, id, defaultCheck) : false; } return createHolder(filter, args, true); };