refactor(metro): last one I promise

This commit is contained in:
amsyarasyiq 2024-05-20 20:42:57 +08:00
parent da76c66702
commit d2341a3323
8 changed files with 70 additions and 62 deletions

View file

@ -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]);

View file

@ -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<string, ModulesMap | undefined>;
polyfillCache: Record<string, ModulesMap | undefined>;
assetsCache: Record<string, number>;
polyfillIndex: Record<string, ModulesMap | undefined>;
assetsIndex: Record<string, number>;
}
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();
}
}

View file

@ -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");

View file

@ -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})`
);

View file

@ -1,18 +1,21 @@
import { getCacherForUniq } from "./caches";
import { getModules, requireModule } from "./modules";
import { FilterFn } from "./utils";
import { FilterFn } from "./types";
function testExports<A extends unknown[]>(moduleExports: any, moduleId: number, filter: FilterFn<A>) {
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<A extends unknown[]>(filter: FilterFn<A>) {
@ -31,7 +34,7 @@ export function findModule<A extends unknown[]>(filter: FilterFn<A>) {
}
/**
* 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<A extends unknown[]>(filter: FilterFn<A>) {
@ -39,7 +42,7 @@ export function findModuleId<A extends unknown[]>(filter: FilterFn<A>) {
}
/**
* 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<A extends unknown[]>(filter: FilterFn<A>) {
@ -49,7 +52,7 @@ export function findExports<A extends unknown[]>(filter: FilterFn<A>) {
}
/**
* 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<A extends unknown[]>(filter: FilterFn<A>) {
@ -69,7 +72,7 @@ export function findAllModule<A extends unknown[]>(filter: FilterFn<A>) {
}
/**
* 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<A extends unknown[]>(filter: FilterFn<A>) {
@ -77,7 +80,7 @@ export function findAllModuleId<A extends unknown[]>(filter: FilterFn<A>) {
}
/**
* 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<A extends unknown[]>(filter: FilterFn<A>) {

View file

@ -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;

View file

@ -126,6 +126,29 @@ export namespace Metro {
}
}
export type ModuleExports = any;
export type FilterCheckDef<A extends unknown[]> = (
args: A,
module: any,
modulesId: number,
defaultCheck: boolean
) => boolean;
export interface FilterFn<A extends unknown[]> {
(m: any, id: number, defaultCheck: boolean): boolean;
filter: FilterCheckDef<A>;
args: A;
defaultFilter: boolean;
uniq: string;
}
export interface FilterDefinition<A extends unknown[]> {
(...args: A): FilterFn<A>;
byDefault(...args: A): FilterFn<A>;
uniqMaker(args: A): string;
}
export interface Dispatcher {
_actionHandlers: unknown;
_interceptors?: ((payload: any) => void | boolean)[];

View file

@ -1,43 +1,30 @@
import { byDisplayName, byFilePath, byName, byProps, byStoreName, byTypeName } from "./filters";
import { findAllExports, findExports } from "./finders";
type ModuleExports = any;
type FilterCheckDef<A extends unknown[]> = (args: A, m: any, id: number) => boolean;
export interface FilterFn<A extends unknown[]> {
(m: any, id: number): boolean;
filter: FilterCheckDef<A>;
args: A;
isDefault: boolean;
uniq: string;
}
export interface FilterDefinition<A extends unknown[]> {
(...args: A): FilterFn<A>;
byDefault(...args: A): FilterFn<A>;
uniqMaker(args: A): string;
}
import { FilterCheckDef, FilterDefinition, ModuleExports } from "./types";
export function createFilterDefinition<A extends unknown[]>(
fn: FilterCheckDef<A>,
uniqMaker: (args: A) => string
): FilterDefinition<A> {
function createHolder<T extends Function>(func: T, args: A, isDefault: boolean) {
function createHolder<T extends Function>(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);
};