feat(patcher): resolvable proxy patch

This commit is contained in:
amsyarasyiq 2024-05-23 15:17:35 +08:00
parent b0acf895e4
commit dd6742d08d
4 changed files with 38 additions and 12 deletions

View file

@ -5,8 +5,11 @@ import {
instead as _instead
} from "spitroast";
function shim<T extends (...args: any) => any>(fn: T) {
return function shimmed(this: any, ...args: Parameters<T>) {
type ParametersAfterOneArgs<F> = F extends (x: any, y: any, ...args: infer P) => unknown ? P : never;
type ProxyPatchParameters<T, P> = [func: string, parent: [P, (t: P) => any], ...args: ParametersAfterOneArgs<T>];
function shim<T extends (func: string, parent: any, ...args: ParametersAfterOneArgs<T>) => any>(fn: T) {
function shimmed(this: any, ...args: Parameters<T>) {
const proxyInfo = getFindProxyInfo(args[1]);
if (proxyInfo && !proxyInfo.cache && proxyInfo.indexed) {
let cancel = false;
@ -20,7 +23,28 @@ function shim<T extends (...args: any) => any>(fn: T) {
return () => unpatch();
}
return fn.apply(this, args);
}
shimmed.proxy = function proxyPatch<P>(this: any, ...args: ProxyPatchParameters<T, P>) {
const [target, resolve] = args[1];
const proxyInfo = getFindProxyInfo(target);
if (!proxyInfo) {
args[1] = resolve(target);
return shimmed(...args as unknown as Parameters<T>);
}
let cancel = false;
let unpatch = () => cancel = true;
proxyInfo.getExports(exp => {
if (cancel) return;
args[1] = resolve(exp);
unpatch = shimmed(...args as unknown as Parameters<T>);
});
return unpatch;
};
return shimmed;
}
export const after = shim(_after);

View file

@ -68,7 +68,7 @@ const tabs: Tab[] = [
{ id: "componentStack", title: () => Strings.COMPONENT, trimWhitespace: true },
];
export default () => after("render", ErrorBoundary.prototype, function (this: any, _, ret) {
export default () => after.proxy("render", [ErrorBoundary, r => r.prototype], function (this: any, _, ret) {
if (!this.state.error) return;
// Not using setState here as we don't want to cause a re-render, we want this to be set in the initial render

View file

@ -2,7 +2,7 @@ import { getCacherForUniq } from "./caches";
import { getModules, requireModule } from "./modules";
import { FilterFn } from "./types";
export function filterExports<A extends unknown[]>(
function filterExports<A extends unknown[]>(
moduleExports: any,
moduleId: number, filter:
FilterFn<A>

View file

@ -1,8 +1,8 @@
import { proxyLazy } from "@lib/utils/lazy";
import { getMetroCache } from "./caches";
import { filterExports, findExports } from "./finders";
import { requireModule, subscribeModule } from "./modules";
import { findExports } from "./finders";
import { metroModules, subscribeModule } from "./modules";
import type { FilterFn } from "./types";
const proxyInfoMap = new WeakMap<{}, FindProxyInfo<any[]>>();
@ -11,6 +11,7 @@ interface FindProxyInfo<A extends unknown[]> {
filter: FilterFn<A>;
indexed: boolean;
moduleId: number | undefined;
getExports(cb: (exports: any) => void): () => void;
subscribe(cb: (exports: any) => void): () => void;
unproxy(): any;
get cache(): any;
@ -29,12 +30,7 @@ function subscribeModuleForFind(proxy: any, callback: (exports: any) => void) {
if (!info.indexed) throw new Error("Attempting to subscribe to a non-indexed find");
return subscribeModule(info.moduleId!, () => {
const [exp] = filterExports(
requireModule(info.moduleId!),
info.moduleId!,
info.filter
);
callback(exp);
callback(findExports(info.filter));
});
}
@ -50,6 +46,12 @@ export function createFindProxy<A extends unknown[]>(filter: FilterFn<A>) {
filter,
indexed: !!moduleId,
moduleId,
getExports(cb: (exports: any) => void) {
if (moduleId && metroModules[moduleId!]?.isInitialized) {
return cb(findExports(filter)), () => { };
}
return this.subscribe(cb);
},
subscribe(cb: (exports: any) => void) {
return subscribeModuleForFind(proxy, cb);
},