From 668ab618fc73bad0d532b13fdb6925a3e8bd0ea8 Mon Sep 17 00:00:00 2001 From: AAGaming Date: Sun, 29 May 2022 20:19:10 -0400 Subject: [PATCH] add patcher and react utils --- src/index.ts | 1 + src/utils.ts | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/utils.ts diff --git a/src/index.ts b/src/index.ts index e2d954c..10d707b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,3 +2,4 @@ export * from './deck-components'; export * from './plugin'; export * from './webpack'; +export * from './utils'; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..d47918f --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,87 @@ +import * as React from "react"; + +// this shouldn't need to be redeclared but it does for some reason + +declare global { + interface Window { + SP_REACT: typeof React; + } +} + +export function fakeRenderComponent(fun: Function): any { + const hooks = (window.SP_REACT as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current; + + // TODO: add more hooks + + let oldHooks = { + useContext: hooks.useContext, + useCallback: hooks.useCallback, + useLayoutEffect: hooks.useLayoutEffect, + useEffect: hooks.useEffect, + useMemo: hooks.useMemo, + useRef: hooks.useRef, + useState: hooks.useState, + } + + hooks.useCallback = (cb: Function) => cb; + hooks.useContext = (cb: any) => cb._currentValue; + hooks.useLayoutEffect = (_: Function) => {}//cb(); + hooks.useMemo = (cb: Function, _: any[]) => cb; + hooks.useEffect = (_: Function) => {}//cb(); + hooks.useRef = (val: any) => ({current: val || {}}); + hooks.useState = (v: any) => { + let val = v; + + return [val, (n: any) => val = n]; + }; + + const res = fun(hooks); + + Object.assign(hooks, oldHooks); + + return res; +} + +export function beforePatch(obj: any, name: string, fnc: Function): void { + const orig = obj[name]; + obj[name] = function (...args: any[]) { + fnc.call(this, args); + return orig.call(this, ...args); + } + Object.assign(obj[name], orig); + obj[name].toString = () => orig.toString(); + obj[name].__deckyOrig = orig; +} + +export function afterPatch(obj: any, name: string, fnc: Function): void { + const orig = obj[name]; + obj[name] = function (...args: any[]) { + let ret = orig.call(this, ...args); + ret = fnc.call(this, args, ret); + return ret; + } + Object.assign(obj[name], orig); + obj[name].toString = () => orig.toString(); + obj[name].__deckyOrig = orig; +} + +export function replacePatch(obj: any, name: string, fnc: Function): void { + const orig = obj[name]; + obj[name] = function (...args: any[]) { + const ret = fnc.call(this, args); + if (ret == 'CALL_ORIGINAL') return orig.call(this, ...args); + return ret; + }; + Object.assign(obj[name], orig); + obj[name].toString = () => orig.toString(); + obj[name].__deckyOrig = orig; +} + +// TODO allow one method to be patched and unpatched multiple times independently using IDs in a Map or something +export function unpatch(obj: any, name: any): void { + obj[name] = obj[name].__deckyOrig; +} + +export function getReactInstance(o: HTMLElement | Element | Node) { + return o[Object.keys(o).find(k => k.startsWith('__reactInternalInstance')) as string] +}