qol improvements

This commit is contained in:
Vendicated 2022-11-03 19:12:50 +01:00
parent c20dc269d2
commit 2c3dee4120
No known key found for this signature in database
GPG key ID: EC781ADFB93EFFA3
3 changed files with 159 additions and 50 deletions

View file

@ -80,7 +80,7 @@ function ReplacementComponent({ module, match, replacement, setReplacementError
const fullMatch = matchResult[0] ? makeCodeblock(matchResult[0], "js") : ""; const fullMatch = matchResult[0] ? makeCodeblock(matchResult[0], "js") : "";
const groups = matchResult.length > 1 const groups = matchResult.length > 1
? makeCodeblock(matchResult.slice(1).map((g, i) => `Group ${i}: ${g}`).join("\n"), "yml") ? makeCodeblock(matchResult.slice(1).map((g, i) => `Group ${i + 1}: ${g}`).join("\n"), "yml")
: ""; : "";
return ( return (
@ -172,6 +172,22 @@ function ReplacementInput({ replacement, setReplacement, replacementError }) {
onChange={onChange} onChange={onChange}
error={error ?? replacementError} error={error ?? replacementError}
/> />
{!isFunc && (
<>
<Forms.FormTitle>Cheat Sheet</Forms.FormTitle>
{Object.entries({
"$$": "Insert a $",
"$&": "Insert the entire match",
"$\\`": "Insert the substring before the match",
"$'": "Insert the substring after the match",
"$n": "Insert the nth capturing group ($1, $2...)"
}).map(([placeholder, desc]) => (
<Forms.FormText key={placeholder}>
{Parser.parse("`" + placeholder + "`")}: {desc}
</Forms.FormText>
))}
</>
)}
<Switch <Switch
className={Margins.marginTop8} className={Margins.marginTop8}
@ -202,7 +218,7 @@ function PatchHelper() {
find: ${JSON.stringify(find)}, find: ${JSON.stringify(find)},
replacement: { replacement: {
match: /${match.replace(/(?<!\\)\//g, "\\/")}/, match: /${match.replace(/(?<!\\)\//g, "\\/")}/,
replacement: ${typeof replacement === "function" ? replacement.toString() : JSON.stringify(replacement)} replace: ${typeof replacement === "function" ? replacement.toString() : JSON.stringify(replacement)}
} }
} }
`.trim(); `.trim();

View file

@ -19,9 +19,9 @@
import { Promisable } from "type-fest"; import { Promisable } from "type-fest";
export class Queue { export class Queue {
private promise = Promise.resolve(); private promise: Promise<any> = Promise.resolve();
add(func: () => Promisable<void>) { add<T>(func: (lastValue: unknown) => Promisable<T>): Promise<T> {
this.promise = this.promise.then(func); return (this.promise = this.promise.then(func));
} }
} }

View file

@ -21,6 +21,8 @@ import type { WebpackInstance } from "discord-types/other";
import Logger from "../utils/logger"; import Logger from "../utils/logger";
import { proxyLazy } from "../utils/proxyLazy"; import { proxyLazy } from "../utils/proxyLazy";
const logger = new Logger("Webpack");
export let _resolveReady: () => void; export let _resolveReady: () => void;
/** /**
* Fired once a gateway connection to Discord has been established. * Fired once a gateway connection to Discord has been established.
@ -51,7 +53,6 @@ export const filters = {
}, },
}; };
const logger = new Logger("Webpack");
export const subscriptions = new Map<FilterFn, CallbackFn>(); export const subscriptions = new Map<FilterFn, CallbackFn>();
export const listeners = new Set<CallbackFn>(); export const listeners = new Set<CallbackFn>();
@ -126,51 +127,143 @@ export function findAll(filter: FilterFn, getDefault = true) {
} }
/** /**
* Finds a mangled module by the provided code "code" (must be unique and can be anywhere in the module) * Same as {@link find} but in bulk
* then maps it into an easily usable module via the specified mappers * @param filterFns Arry of filters. Please note that this array will be modified in place, so if you still
* @param code Code snippet * need it afterwards, pass a copy.
* @param mappers Mappers to create the non mangled exports * @returns Array of results in the same order as the passed filters
* @returns Unmangled exports as specified in mappers */
* export function bulk(...filterFns: FilterFn[]) {
* @example mapMangledModule("headerIdIsManaged:", { if (!Array.isArray(filterFns))
* openModal: filters.byCode("headerIdIsManaged:"), throw new Error("Invalid filters. Expected function[] got " + typeof filterFns);
* 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 const { length } = filterFns;
for (const id in wreq.m) {
const src = wreq.m[id].toString() as string; if (length === 0)
if (src.includes(code)) { throw new Error("Expected at least two filters.");
const mod = wreq(id as any as number);
outer: if (length === 1) {
for (const key in mod) { if (IS_DEV) {
const member = mod[key]; throw new Error("bulk called with only one filter. Use find");
for (const newName in mappers) { }
// if the current mapper matches this module return find(filterFns[0]);
if (mappers[newName](member)) { }
exports[newName] = member;
const filters = filterFns as Array<FilterFn | undefined>;
let found = 0;
const results = Array(length);
outer:
for (const key in cache) {
const mod = cache[key];
if (!mod?.exports) continue;
for (let j = 0; j < length; j++) {
const filter = filters[j];
// Already done
if (filter === undefined) continue;
if (filter(mod.exports)) {
results[j] = mod.exports;
filters[j] = undefined;
if (++found === length) break outer;
break;
}
if (typeof mod.exports !== "object")
continue;
if (mod.exports.default && filter(mod.exports.default)) {
results[j] = mod.exports.default;
filters[j] = undefined;
if (++found === length) break outer;
break;
}
for (const nestedMod in mod.exports)
if (nestedMod.length <= 3) {
const nested = mod.exports[nestedMod];
if (nested && filter(nested)) {
results[j] = nested;
filters[j] = undefined;
if (++found === length) break outer;
continue outer; continue outer;
} }
} }
}
return exports;
} }
} }
const err = new Error("Didn't find module matching this code:\n" + code); if (found !== length) {
if (IS_DEV) const err = new Error(`Got ${length} filters, but only found ${found} modules!`);
throw err; if (IS_DEV) {
// Strict behaviour in DevBuilds to fail early and make sure the issue is found
throw err;
}
logger.warn(err);
}
return results;
}
/**
* Find the id of a module by its code
* @param code Code
* @returns number or null
*/
export function findModuleId(code: string) {
for (const id in wreq.m) {
if (wreq.m[id].toString().includes(code)) {
return Number(id);
}
}
const err = new Error("Didn't find module with code:\n" + code);
if (IS_DEV) {
// Strict behaviour in DevBuilds to fail early and make sure the issue is found
throw err;
}
logger.warn(err); logger.warn(err);
return null;
}
/**
* 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>;
const id = findModuleId(code);
if (id === null)
return exports;
const mod = wreq(id);
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;
}
}
}
return exports; return exports;
} }
/** /**
* Same as {@link mapMangledModule} but lazy * Same as {@link mapMangledModule} but lazy
*/ */
export function mapMangledModuleLazy<S extends string>(code: string, mappers: Record<S, FilterFn>): Record<S, any> { export function mapMangledModuleLazy<S extends string>(code: string, mappers: Record<S, FilterFn>): Record<S, any> {
return proxyLazy(() => mapMangledModule(code, mappers)); return proxyLazy(() => mapMangledModule(code, mappers));
} }
@ -210,11 +303,11 @@ export function removeListener(callback: CallbackFn) {
} }
/** /**
* Search modules by keyword. This searches the factory methods, * Search modules by keyword. This searches the factory methods,
* meaning you can search all sorts of things, displayName, methodName, strings somewhere in the code, etc * meaning you can search all sorts of things, displayName, methodName, strings somewhere in the code, etc
* @param filters One or more strings or regexes * @param filters One or more strings or regexes
* @returns Mapping of found modules * @returns Mapping of found modules
*/ */
export function search(...filters: Array<string | RegExp>) { export function search(...filters: Array<string | RegExp>) {
const results = {} as Record<number, Function>; const results = {} as Record<number, Function>;
const factories = wreq.m; const factories = wreq.m;
@ -233,13 +326,13 @@ export function search(...filters: Array<string | RegExp>) {
} }
/** /**
* Extract a specific module by id into its own Source File. This has no effect on * Extract a specific module by id into its own Source File. This has no effect on
* the code, it is only useful to be able to look at a specific module without having * the code, it is only useful to be able to look at a specific module without having
* to view a massive file. extract then returns the extracted module so you can jump to it. * to view a massive file. extract then returns the extracted module so you can jump to it.
* As mentioned above, note that this extracted module is not actually used, * As mentioned above, note that this extracted module is not actually used,
* so putting breakpoints or similar will have no effect. * so putting breakpoints or similar will have no effect.
* @param id The id of the module to extract * @param id The id of the module to extract
*/ */
export function extract(id: number) { export function extract(id: number) {
const mod = wreq.m[id] as Function; const mod = wreq.m[id] as Function;
if (!mod) return null; if (!mod) return null;