diff --git a/src/webpack/api.tsx b/src/webpack/api.tsx index 8f3dc0965..7a27f7ff9 100644 --- a/src/webpack/api.tsx +++ b/src/webpack/api.tsx @@ -129,7 +129,7 @@ export const filters = { } }; -export const webpackSearchHistory = [] as Array<["waitFor" | "find" | "findComponent" | "findExportedComponent" | "findComponentByCode" | "findByProps" | "findByCode" | "findStore" | "findByFactoryCode" | "mapMangledModule" | "extractAndLoadChunks" | "webpackDependantLazy" | "webpackDependantLazyComponent", any[]]>; +export const webpackSearchHistory = [] as Array<["waitFor" | "find" | "findComponent" | "findExportedComponent" | "findComponentByCode" | "findByProps" | "findByPropsAndExtract" | "findByCode" | "findStore" | "findByFactoryCode" | "mapMangledModule" | "extractAndLoadChunks" | "webpackDependantLazy" | "webpackDependantLazyComponent", any[]]>; function printFilter(filter: FilterFn) { if (filter.$$vencordProps != null) { @@ -182,26 +182,26 @@ export function waitFor(filter: FilterFn, callback: ModCallbackFn, { isIndirect * * The way this works internally is: * Wait for the first export or module exports that matches the provided filter to be required, - * then call the callback with the export or module exports as the first argument. + * then call the parse function with the export or module exports as the first argument. * - * If the module containing the export(s) is already required, the callback will be called immediately. + * If the module containing the export(s) is already required, the parse function will be called immediately. * - * The callback must return a value that will be used as the proxy inner value. + * The parse function must return a value that will be used as the proxy inner value. * - * If no callback is specified, the default callback will assign the proxy inner value to the plain find result + * If no parse function is specified, the default parse will assign the proxy inner value to the plain find result. * * @param filter A function that takes an export or module exports and returns a boolean - * @param callback A function that takes the find result as its first argument and returns something to use as the proxy inner value. Useful if you want to use a value from the find result, instead of all of it. Defaults to the find result itself - * @returns A proxy that has the callback return value as its true value, or the callback return value if the callback was called when the function was called + * @param parse A function that takes the find result as its first argument and returns something to use as the proxy inner value. Useful if you want to use a value from the find result, instead of all of it. Defaults to the find result itself + * @returns A proxy that has the parse function return value as its true value, or the plain parse function return value if it was called immediately. */ -export function find(filter: FilterFn, callback: (mod: any) => any = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) { +export function find(filter: FilterFn, parse: (mod: any) => any = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) { if (typeof filter !== "function") throw new Error("Invalid filter. Expected a function got " + typeof filter); - if (typeof callback !== "function") - throw new Error("Invalid callback. Expected a function got " + typeof callback); + if (typeof parse !== "function") + throw new Error("Invalid find parse. Expected a function got " + typeof parse); const [proxy, setInnerValue] = proxyInner(`Webpack find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find."); - waitFor(filter, m => setInnerValue(callback(m)), { isIndirect: true }); + waitFor(filter, m => setInnerValue(parse(m)), { isIndirect: true }); if (IS_REPORTER && !isIndirect) { webpackSearchHistory.push(["find", [proxy, filter]]); @@ -326,12 +326,37 @@ export function findComponentByCode(...code: string[] | * Find the first module exports or export that includes all the given props. * * @param props A list of props to search the module or exports for + * @param parse A function that takes the find result as its first argument and returns something. Useful if you want to use a value from the find result, instead of all of it. Defaults to the find result itself */ -export function findByProps(...props: string[]) { - const result = find(filters.byProps(...props), m => m, { isIndirect: true }); +export function findByProps(...props: string[] | [...string[], (mod: any) => T]) { + const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (mod: any) => T; + const newProps = props as string[]; + + const result = find(filters.byProps(...newProps), parse, { isIndirect: true }); if (IS_REPORTER) { - webpackSearchHistory.push(["findByProps", [result, ...props]]); + webpackSearchHistory.push(["findByProps", [result, ...newProps]]); + } + + return result; +} + +/** + * Find the first prop value defined by the first prop name, which is in a module exports or export including all the given props. + * + * @example const getUser = findByPropsAndExtract("getUser", "fetchUser") + * + * @param props A list of props to search the module or exports for + * @param parse A function that takes the find result as its first argument and returns something. Useful if you want to use a value from the find result, instead of all of it. Defaults to the find result itself + */ +export function findByPropsAndExtract(...props: string[] | [...string[], (mod: any) => T]) { + const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (mod: any) => T; + const newProps = props as string[]; + + const result = find(filters.byProps(...newProps), m => parse(m[newProps[0]]), { isIndirect: true }); + + if (IS_REPORTER) { + webpackSearchHistory.push(["findByPropsAndExtract", [result, ...newProps]]); } return result; @@ -341,12 +366,16 @@ export function findByProps(...props: string[]) { * Find the first export that includes all the given code. * * @param code A list of code to search each export for + * @param parse A function that takes the find result as its first argument and returns something. Useful if you want to use a value from the find result, instead of all of it. Defaults to the find result itself */ -export function findByCode(...code: string[]) { - const result = find(filters.byCode(...code), m => m, { isIndirect: true }); +export function findByCode(...code: string[] | [...string[], (mod: any) => T]) { + const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (mod: any) => T; + const newCode = code as string[]; + + const result = find(filters.byCode(...newCode), parse, { isIndirect: true }); if (IS_REPORTER) { - webpackSearchHistory.push(["findByCode", [result, ...code]]); + webpackSearchHistory.push(["findByCode", [result, ...newCode]]); } return result; @@ -371,12 +400,16 @@ export function findStore(name: string) { * Find the module exports of the first module which the factory includes all the given code. * * @param code A list of code to search each factory for + * @param parse A function that takes the find result as its first argument and returns something. Useful if you want to use a value from the find result, instead of all of it. Defaults to the find result itself */ -export function findByFactoryCode(...code: string[]) { - const result = find(filters.byFactoryCode(...code), m => m, { isIndirect: true }); +export function findByFactoryCode(...code: string[] | [...string[], (mod: any) => T]) { + const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (mod: any) => T; + const newCode = code as string[]; + + const result = find(filters.byFactoryCode(...newCode), parse, { isIndirect: true }); if (IS_REPORTER) { - webpackSearchHistory.push(["findByFactoryCode", [result, ...code]]); + webpackSearchHistory.push(["findByFactoryCode", [result, ...newCode]]); } return result;