Add webpack find testing (#2016)

Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
This commit is contained in:
V 2023-11-25 01:32:21 +01:00 committed by GitHub
parent 3e8e106be7
commit 534565db25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 289 additions and 97 deletions

View file

@ -19,9 +19,11 @@
import { LazyComponent } from "@utils/react";
// eslint-disable-next-line path-alias/no-relative
import { FilterFn, filters, waitFor } from "../webpack";
import { FilterFn, filters, lazyWebpackSearchHistory, waitFor } from "../webpack";
export function waitForComponent<T extends React.ComponentType<any> = React.ComponentType<any> & Record<string, any>>(name: string, filter: FilterFn | string | string[]): T {
if (IS_DEV) lazyWebpackSearchHistory.push(["waitForComponent", Array.isArray(filter) ? filter : [filter]]);
let myValue: T = function () {
throw new Error(`Vencord could not find the ${name} Component`);
} as any;
@ -30,11 +32,13 @@ export function waitForComponent<T extends React.ComponentType<any> = React.Comp
waitFor(filter, (v: any) => {
myValue = v;
Object.assign(lazyComponent, v);
});
}, { isIndirect: true });
return lazyComponent;
}
export function waitForStore(name: string, cb: (v: any) => void) {
waitFor(filters.byStoreName(name), cb);
if (IS_DEV) lazyWebpackSearchHistory.push(["waitForStore", [name]]);
waitFor(filters.byStoreName(name), cb, { isIndirect: true });
}

View file

@ -16,14 +16,23 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { proxyLazy } from "@utils/lazy";
import type { Channel, User } from "discord-types/general";
// eslint-disable-next-line path-alias/no-relative
import { _resolveReady, find, findByPropsLazy, findLazy, waitFor } from "../webpack";
import { _resolveReady, findByPropsLazy, findLazy, waitFor } from "../webpack";
import type * as t from "./types/utils";
export let FluxDispatcher: t.FluxDispatcher;
waitFor(["dispatch", "subscribe"], m => {
FluxDispatcher = m;
const cb = () => {
m.unsubscribe("CONNECTION_OPEN", cb);
_resolveReady();
};
m.subscribe("CONNECTION_OPEN", cb);
});
export let ComponentDispatch;
waitFor(["ComponentDispatch", "ComponentDispatcher"], m => ComponentDispatch = m.ComponentDispatch);
@ -41,7 +50,9 @@ export let SnowflakeUtils: t.SnowflakeUtils;
waitFor(["fromTimestamp", "extractTimestamp"], m => SnowflakeUtils = m);
export let Parser: t.Parser;
waitFor("parseTopic", m => Parser = m);
export let Alerts: t.Alerts;
waitFor(["show", "close"], m => Alerts = m);
const ToastType = {
MESSAGE: 0,
@ -82,6 +93,13 @@ export const Toasts = {
}
};
// This is the same module but this is easier
waitFor("showToast", m => {
Toasts.show = m.showToast;
Toasts.pop = m.popToast;
});
/**
* Show a simple toast. If you need more options, use Toasts.show manually
*/
@ -106,26 +124,8 @@ export const Clipboard: t.Clipboard = findByPropsLazy("SUPPORTS_COPY", "copy");
export const NavigationRouter: t.NavigationRouter = findByPropsLazy("transitionTo", "replaceWith", "transitionToGuild");
waitFor(["dispatch", "subscribe"], m => {
FluxDispatcher = m;
const cb = () => {
m.unsubscribe("CONNECTION_OPEN", cb);
_resolveReady();
};
m.subscribe("CONNECTION_OPEN", cb);
});
// This is the same module but this is easier
waitFor("showToast", m => {
Toasts.show = m.showToast;
Toasts.pop = m.popToast;
});
waitFor(["show", "close"], m => Alerts = m);
waitFor("parseTopic", m => Parser = m);
export let SettingsRouter: any;
waitFor(["open", "saveAccountChanges"], m => SettingsRouter = m);
export const PermissionsBits: t.PermissionsBits = proxyLazy(() => find(m => typeof m.Permissions?.ADMINISTRATOR === "bigint").Permissions);
const { Permissions } = findLazy(m => typeof m.Permissions?.ADMINISTRATOR === "bigint") as { Permissions: t.PermissionsBits; };
export { Permissions as PermissionsBits };

View file

@ -127,13 +127,6 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn
return isWaitFor ? [null, null] : null;
});
/**
* find but lazy
*/
export function findLazy(filter: FilterFn) {
return proxyLazy(() => find(filter));
}
export function findAll(filter: FilterFn) {
if (typeof filter !== "function")
throw new Error("Invalid filter. Expected a function got " + typeof filter);
@ -244,6 +237,49 @@ export const findModuleId = traceFunction("findModuleId", function findModuleId(
return null;
});
export const lazyWebpackSearchHistory = [] as Array<["find" | "findByProps" | "findByCode" | "findStore" | "findComponent" | "findComponentByCode" | "findExportedComponent" | "waitFor" | "waitForComponent" | "waitForStore" | "proxyLazyWebpack" | "LazyComponentWebpack", any[]]>;
/**
* This is just a wrapper around {@link proxyLazy} to make our reporter test for your webpack finds.
*
* Wraps the result of {@link 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
* @param attempts how many times to try to evaluate the lazy before giving up
* @returns Proxy
*
* Note that the example below exists already as an api, see {@link findByPropsLazy}
* @example const mod = proxyLazy(() => findByProps("blah")); console.log(mod.blah);
*/
export function proxyLazyWebpack<T = any>(factory: () => any, attempts?: number) {
if (IS_DEV) lazyWebpackSearchHistory.push(["proxyLazyWebpack", [factory]]);
return proxyLazy<T>(factory, attempts);
}
/**
* This is just a wrapper around {@link LazyComponent} to make our reporter test for your webpack finds.
*
* A lazy component. The factory method is called on first render.
* @param factory Function returning a Component
* @param attempts How many times to try to get the component before giving up
* @returns Result of factory function
*/
export function LazyComponentWebpack<T extends object = any>(factory: () => any, attempts?: number) {
if (IS_DEV) lazyWebpackSearchHistory.push(["LazyComponentWebpack", [factory]]);
return LazyComponent<T>(factory, attempts);
}
/**
* find but lazy
*/
export function findLazy(filter: FilterFn) {
if (IS_DEV) lazyWebpackSearchHistory.push(["find", [filter]]);
return proxyLazy(() => find(filter));
}
/**
* Find the first module that has the specified properties
*/
@ -258,6 +294,8 @@ export function findByProps(...props: string[]) {
* findByProps but lazy
*/
export function findByPropsLazy(...props: string[]) {
if (IS_DEV) lazyWebpackSearchHistory.push(["findByProps", props]);
return proxyLazy(() => findByProps(...props));
}
@ -275,6 +313,8 @@ export function findByCode(...code: string[]) {
* findByCode but lazy
*/
export function findByCodeLazy(...code: string[]) {
if (IS_DEV) lazyWebpackSearchHistory.push(["findByCode", code]);
return proxyLazy(() => findByCode(...code));
}
@ -292,6 +332,8 @@ export function findStore(name: string) {
* findStore but lazy
*/
export function findStoreLazy(name: string) {
if (IS_DEV) lazyWebpackSearchHistory.push(["findStore", [name]]);
return proxyLazy(() => findStore(name));
}
@ -309,6 +351,8 @@ export function findComponentByCode(...code: string[]) {
* Finds the first component that matches the filter, lazily.
*/
export function findComponentLazy<T extends object = any>(filter: FilterFn) {
if (IS_DEV) lazyWebpackSearchHistory.push(["findComponent", [filter]]);
return LazyComponent<T>(() => find(filter));
}
@ -316,6 +360,8 @@ export function findComponentLazy<T extends object = any>(filter: FilterFn) {
* Finds the first component that includes all the given code, lazily
*/
export function findComponentByCodeLazy<T extends object = any>(...code: string[]) {
if (IS_DEV) lazyWebpackSearchHistory.push(["findComponentByCode", code]);
return LazyComponent<T>(() => findComponentByCode(...code));
}
@ -323,6 +369,8 @@ export function findComponentByCodeLazy<T extends object = any>(...code: string[
* Finds the first component that is exported by the first prop name, lazily
*/
export function findExportedComponentLazy<T extends object = any>(...props: string[]) {
if (IS_DEV) lazyWebpackSearchHistory.push(["findExportedComponent", props]);
return LazyComponent<T>(() => findByProps(...props)?.[props[0]]);
}
@ -330,7 +378,9 @@ export function findExportedComponentLazy<T extends object = any>(...props: stri
* Wait for a module that matches the provided filter to be registered,
* then call the callback with the module as the first argument
*/
export function waitFor(filter: string | string[] | FilterFn, callback: CallbackFn) {
export function waitFor(filter: string | string[] | FilterFn, callback: CallbackFn, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
if (IS_DEV && !isIndirect) lazyWebpackSearchHistory.push(["waitFor", Array.isArray(filter) ? filter : [filter]]);
if (typeof filter === "string")
filter = filters.byProps(filter);
else if (Array.isArray(filter))