Fix modals, add wp.mapMangledModule

This commit is contained in:
Vendicated 2022-10-14 21:34:35 +02:00
parent 563f2fb1dc
commit 296336535f
No known key found for this signature in database
GPG key ID: EC781ADFB93EFFA3
7 changed files with 102 additions and 29 deletions

View file

@ -3,6 +3,7 @@ export * as Webpack from "./webpack";
export * as Api from "./api";
export * as Updater from "./utils/updater";
export * as QuickCss from "./utils/quickCss";
export * as Util from "./utils";
import { popNotice, showNotice } from "./api/Notices";
import { Settings, PlainSettings } from "./api/settings";

View file

@ -1,7 +1,7 @@
import { ApplicationCommandOptionType, findOption, ApplicationCommandInputType, Argument, CommandContext } from "../api/Commands";
import { Devs } from "../utils/constants";
import definePlugin from "../utils/types";
import { lazy, lazyWebpack } from "../utils/misc";
import { makeLazy, lazyWebpack } from "../utils/misc";
import { filters } from "../webpack";
const DRAFT_TYPE = 0;
@ -12,9 +12,9 @@ const FRAMES = 10;
// https://github.com/mattdesl/gifenc
// this lib is way better than gif.js and all other libs, they're all so terrible but this one is nice
// @ts-ignore ts mad
const getGifEncoder = lazy(() => import("https://unpkg.com/gifenc@1.0.3/dist/gifenc.esm.js"));
const getGifEncoder = makeLazy(() => import("https://unpkg.com/gifenc@1.0.3/dist/gifenc.esm.js"));
const getFrames = lazy(() => Promise.all(
const getFrames = makeLazy(() => Promise.all(
Array.from(
{ length: FRAMES },
(_, i) => loadImage(`https://raw.githubusercontent.com/VenPlugs/petpet/main/frames/pet${i}.gif`)

11
src/utils/index.ts Normal file
View file

@ -0,0 +1,11 @@
export * from "./ChangeList";
export * from "./debounce";
export * from "./misc";
export * from "./proxyLazy";
export { default as IpcEvents } from "./IpcEvents";
export { default as Logger } from "./logger";
export * as Constants from "./constants";
export * as Discord from "./discord";
export * as Modals from "./modal";

View file

@ -1,15 +1,17 @@
import { FilterFn, find } from "../webpack";
import { React } from "../webpack/common";
import { proxyLazy } from "./proxyLazy";
/**
* Makes a lazy function. On first call, the value is computed.
* On subsequent calls, the same computed value will be returned
* @param factory Factory function
*/
export function lazy<T>(factory: () => T): () => T {
export function makeLazy<T>(factory: () => T): () => T {
let cache: T;
return () => cache ?? (cache = factory());
}
export const lazy = makeLazy;
/**
* Do a lazy webpack search. Searches the module on first property access
@ -17,18 +19,7 @@ export function lazy<T>(factory: () => T): () => T {
* @returns A proxy to the webpack module. Not all traps are implemented, may produce unexpected results.
*/
export function lazyWebpack<T = any>(filter: FilterFn): T {
const getMod = lazy(() => find(filter));
return new Proxy(() => null, {
get: (_, prop) => getMod()[prop],
set: (_, prop, value) => getMod()[prop] = value,
has: (_, prop) => prop in getMod(),
apply: (_, $this, args) => (getMod() as Function).apply($this, args),
ownKeys: () => Reflect.ownKeys(getMod()),
construct: (_, args, newTarget) => Reflect.construct(getMod(), args, newTarget),
deleteProperty: (_, prop) => delete getMod()[prop],
defineProperty: (_, property, attributes) => !!Object.defineProperty(getMod(), property, attributes)
}) as any as T;
return proxyLazy(() => find(filter));
}
/**

View file

@ -1,13 +1,12 @@
// TODO: fix
import { filters } from "../webpack";
import { lazyWebpack } from "./misc";
import { mapMangledModuleLazy } from "../webpack/webpack";
import Components from "discord-types/components";
import { waitFor } from "../webpack";
export let Modal: Components.Modal;
export let modals: any;
waitFor("openModalLazy", m => modals = m);
waitFor("ModalRoot", m => Modal = m);
const ModalRoot = lazyWebpack(filters.byCode("headerIdIsManaged:"));
const Modals = mapMangledModuleLazy("onCloseRequest:null!=", {
openModal: filters.byCode("onCloseRequest:null!="),
closeModal: filters.byCode("onCloseCallback&&")
});
let modalId = 1337;
@ -18,10 +17,10 @@ let modalId = 1337;
*/
export function openModal(Component: React.ComponentType, modalProps: Record<string, any>) {
let key = `Vencord${modalId++}`;
modals.openModal(props => (
<Modal.ModalRoot {...props} {...modalProps}>
Modals.openModal(props => (
<ModalRoot {...props} {...modalProps}>
<Component />
</Modal.ModalRoot>
</ModalRoot>
), { modalKey: key });
return key;
@ -32,5 +31,5 @@ export function openModal(Component: React.ComponentType, modalProps: Record<str
* @param key The key of the modal to close
*/
export function closeModal(key: string) {
modals.closeModal(key);
Modals.closeModal(key);
}

25
src/utils/proxyLazy.ts Normal file
View file

@ -0,0 +1,25 @@
import { makeLazy } from "./misc";
/**
* Wraps the result of {@see makeLazy} in a Proxy you can consume as if it wasn't lazy.
* On first property access, the lazy is evaluated
* @param factory lazy factory
* @returns Proxy
*
* Note that the example below exists already as an api, see {@link lazyWebpack}
* @example const mod = proxyLazy(makeLazy(() => findByProps("blah"))); console.log(mod.blah);
*/
export function proxyLazy<T>(factory: () => T): T {
const lazy = makeLazy(factory);
return new Proxy(() => null, {
get: (_, prop) => lazy()[prop],
set: (_, prop, value) => lazy()[prop] = value,
has: (_, prop) => prop in lazy(),
apply: (_, $this, args) => (lazy() as Function).apply($this, args),
ownKeys: () => Reflect.ownKeys(lazy() as object),
construct: (_, args, newTarget) => Reflect.construct(lazy() as Function, args, newTarget),
deleteProperty: (_, prop) => delete lazy()[prop],
defineProperty: (_, property, attributes) => !!Object.defineProperty(lazy(), property, attributes)
}) as any as T;
}

View file

@ -1,4 +1,5 @@
import type { WebpackInstance } from "discord-types/other";
import { proxyLazy } from "../utils/proxyLazy";
export let _resolveReady: () => void;
/**
@ -92,6 +93,51 @@ export function findAll(filter: FilterFn, getDefault = true) {
return ret;
}
/**
* Finds a mangled module by the provided code "code" (must be unique and can be anywhere in the module)
* then maps it into an easily usable module via the specified mappers
* @param code Code snippet
* @param mappers Mappers to create the non mangled exports
* @returns Unmangled exports as specified in mappers
*
* @example mapMangledModule("headerIdIsManaged:", {
* openModal: filters.byCode("headerIdIsManaged:"),
* closeModal: filters.byCode("key==")
* })
*/
export function mapMangledModule<S extends string>(code: string, mappers: Record<S, FilterFn>): Record<S, any> {
const exports = {} as Record<S, any>;
// search every factory function
for (const id in wreq.m) {
const src = wreq.m[id].toString() as string;
if (src.includes(code)) {
const mod = wreq(id as any as number);
outer:
for (const key in mod) {
const member = mod[key];
for (const newName in mappers) {
// if the current mapper matches this module
if (mappers[newName](member)) {
exports[newName] = member;
continue outer;
}
}
}
break;
}
}
return exports;
}
/**
* Same as {@link mapMangledModule} but lazy
*/
export function mapMangledModuleLazy<S extends string>(code: string, mappers: Record<S, FilterFn>): Record<S, any> {
return proxyLazy(() => mapMangledModule(code, mappers));
}
export function findByProps(...props: string[]) {
return find(filters.byProps(props));
}