|
|
@ -4,7 +4,7 @@
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import { makeLazy, proxyLazy } from "@utils/lazy";
|
|
|
|
import { proxyLazy } from "@utils/lazy";
|
|
|
|
import { LazyComponent, LazyComponentType, SYM_LAZY_COMPONENT_INNER } from "@utils/lazyReact";
|
|
|
|
import { LazyComponent, LazyComponentType, SYM_LAZY_COMPONENT_INNER } from "@utils/lazyReact";
|
|
|
|
import { Logger } from "@utils/Logger";
|
|
|
|
import { Logger } from "@utils/Logger";
|
|
|
|
import { canonicalizeMatch } from "@utils/patches";
|
|
|
|
import { canonicalizeMatch } from "@utils/patches";
|
|
|
@ -27,8 +27,9 @@ export const onceDiscordLoaded = new Promise<void>(r => _resolveDiscordLoaded =
|
|
|
|
export let wreq: WebpackInstance;
|
|
|
|
export let wreq: WebpackInstance;
|
|
|
|
export let cache: WebpackInstance["c"];
|
|
|
|
export let cache: WebpackInstance["c"];
|
|
|
|
|
|
|
|
|
|
|
|
export type FilterFn = ((mod: any) => boolean) & {
|
|
|
|
export type FilterFn = ((module: any) => boolean) & {
|
|
|
|
$$vencordProps?: string[];
|
|
|
|
$$vencordProps?: string[];
|
|
|
|
|
|
|
|
$$vencordIsFactoryFilter?: boolean;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const filters = {
|
|
|
|
export const filters = {
|
|
|
@ -44,7 +45,7 @@ export const filters = {
|
|
|
|
byCode: (...code: string[]): FilterFn => {
|
|
|
|
byCode: (...code: string[]): FilterFn => {
|
|
|
|
const filter: FilterFn = m => {
|
|
|
|
const filter: FilterFn = m => {
|
|
|
|
if (typeof m !== "function") return false;
|
|
|
|
if (typeof m !== "function") return false;
|
|
|
|
const s = Function.prototype.toString.call(m);
|
|
|
|
const s = String(m);
|
|
|
|
for (const c of code) {
|
|
|
|
for (const c of code) {
|
|
|
|
if (!s.includes(c)) return false;
|
|
|
|
if (!s.includes(c)) return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -62,7 +63,7 @@ export const filters = {
|
|
|
|
return filter;
|
|
|
|
return filter;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
componentByCode: (...code: string[]): FilterFn => {
|
|
|
|
byComponentCode: (...code: string[]): FilterFn => {
|
|
|
|
const byCodeFilter = filters.byCode(...code);
|
|
|
|
const byCodeFilter = filters.byCode(...code);
|
|
|
|
const filter: FilterFn = m => {
|
|
|
|
const filter: FilterFn = m => {
|
|
|
|
let inner = m;
|
|
|
|
let inner = m;
|
|
|
@ -80,17 +81,39 @@ export const filters = {
|
|
|
|
|
|
|
|
|
|
|
|
filter.$$vencordProps = ["componentByCode", ...code];
|
|
|
|
filter.$$vencordProps = ["componentByCode", ...code];
|
|
|
|
return filter;
|
|
|
|
return filter;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
byFactoryCode: (...code: string[]): FilterFn => {
|
|
|
|
|
|
|
|
const byCodeFilter = filters.byCode(...code);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
byCodeFilter.$$vencordProps = ["byFactoryCode", ...code];
|
|
|
|
|
|
|
|
byCodeFilter.$$vencordIsFactoryFilter = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return byCodeFilter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export type ModCallbackFn = ((mod: any) => void) & {
|
|
|
|
type ModuleFactory = (module: any, exports: any, require: WebpackInstance) => void;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export type ModListenerInfo = {
|
|
|
|
|
|
|
|
id: PropertyKey;
|
|
|
|
|
|
|
|
factory: ModuleFactory;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export type ModCallbackInfo = {
|
|
|
|
|
|
|
|
id: PropertyKey;
|
|
|
|
|
|
|
|
exportKey: PropertyKey | null;
|
|
|
|
|
|
|
|
factory: ModuleFactory;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export type ModListenerFn = (module: any, info: ModListenerInfo) => void;
|
|
|
|
|
|
|
|
export type ModCallbackFn = ((module: any, info: ModCallbackInfo) => void) & {
|
|
|
|
$$vencordCallbackCalled?: () => boolean;
|
|
|
|
$$vencordCallbackCalled?: () => boolean;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
export type ModCallbackFnWithId = (mod: any, id: string) => void;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const factoryListeners = new Set<(factory: ModuleFactory) => void>();
|
|
|
|
|
|
|
|
export const moduleListeners = new Set<ModListenerFn>();
|
|
|
|
export const waitForSubscriptions = new Map<FilterFn, ModCallbackFn>();
|
|
|
|
export const waitForSubscriptions = new Map<FilterFn, ModCallbackFn>();
|
|
|
|
export const moduleListeners = new Set<ModCallbackFnWithId>();
|
|
|
|
|
|
|
|
export const factoryListeners = new Set<(factory: (module: any, exports: any, require: WebpackInstance) => void) => void>();
|
|
|
|
|
|
|
|
export const beforeInitListeners = new Set<(wreq: WebpackInstance) => void>();
|
|
|
|
export const beforeInitListeners = new Set<(wreq: WebpackInstance) => void>();
|
|
|
|
|
|
|
|
|
|
|
|
export function _initWebpack(webpackRequire: WebpackInstance) {
|
|
|
|
export function _initWebpack(webpackRequire: WebpackInstance) {
|
|
|
@ -106,25 +129,25 @@ if (IS_DEV && IS_DISCORD_DESKTOP) {
|
|
|
|
}, 0);
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export const webpackSearchHistory = [] as Array<["waitFor" | "find" | "findComponent" | "findExportedComponent" | "findComponentByCode" | "findByProps" | "findByCode" | "findStore" | "extractAndLoadChunks" | "webpackDependantLazy" | "webpackDependantLazyComponent", any[]]>;
|
|
|
|
export const webpackSearchHistory = [] as Array<["waitFor" | "find" | "findComponent" | "findExportedComponent" | "findComponentByCode" | "findByProps" | "findByCode" | "findStore" | "findByFactoryCode" | "mapMangledModule" | "extractAndLoadChunks" | "webpackDependantLazy" | "webpackDependantLazyComponent", any[]]>;
|
|
|
|
|
|
|
|
|
|
|
|
function printFilter(filter: FilterFn) {
|
|
|
|
function printFilter(filter: FilterFn) {
|
|
|
|
if (filter.$$vencordProps != null) {
|
|
|
|
if (filter.$$vencordProps != null) {
|
|
|
|
const props = filter.$$vencordProps;
|
|
|
|
const props = filter.$$vencordProps;
|
|
|
|
return `${props[0]}(${props.slice(1).map(arg => `"${arg}"`).join(", ")})`;
|
|
|
|
return `${props[0]}(${props.slice(1).map(arg => JSON.stringify(arg)).join(", ")})`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return filter.toString();
|
|
|
|
return filter.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Wait for the first module that matches the provided filter to be required,
|
|
|
|
* Wait for the first export or module exports that matches the provided filter to be required,
|
|
|
|
* then call the callback with the module as the first argument.
|
|
|
|
* then call the callback with the export or module exports as the first argument.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* If the module is already required, the callback will be called immediately.
|
|
|
|
* If the module containing the export(s) is already required, the callback will be called immediately.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param filter A function that takes a module and returns a boolean
|
|
|
|
* @param filter A function that takes an export or module exports and returns a boolean
|
|
|
|
* @param callback A function that takes the found module as its first argument
|
|
|
|
* @param callback A function that takes the find result as its first argument
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function waitFor(filter: FilterFn, callback: ModCallbackFn, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
|
|
|
|
export function waitFor(filter: FilterFn, callback: ModCallbackFn, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
|
|
|
|
if (typeof filter !== "function")
|
|
|
|
if (typeof filter !== "function")
|
|
|
@ -147,28 +170,28 @@ export function waitFor(filter: FilterFn, callback: ModCallbackFn, { isIndirect
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (cache != null) {
|
|
|
|
if (cache != null) {
|
|
|
|
const existing = cacheFind(filter);
|
|
|
|
const { result, id, exportKey, factory } = _cacheFind(filter);
|
|
|
|
if (existing) return callback(existing);
|
|
|
|
if (result != null) return callback(result, { id: id!, exportKey: exportKey as PropertyKey | null, factory: factory! });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
waitForSubscriptions.set(filter, callback);
|
|
|
|
waitForSubscriptions.set(filter, callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the first module that matches the filter.
|
|
|
|
* Find the first export or module exports that matches the filter.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The way this works internally is:
|
|
|
|
* The way this works internally is:
|
|
|
|
* Wait for the first module that matches the provided filter to be required,
|
|
|
|
* Wait for the first export or module exports that matches the provided filter to be required,
|
|
|
|
* then call the callback with the module as the first argument.
|
|
|
|
* then call the callback with the export or module exports as the first argument.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* If the module is already required, the callback will be called immediately.
|
|
|
|
* If the module containing the export(s) is already required, the callback will be called immediately.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The callback must return a value that will be used as the proxy inner value.
|
|
|
|
* The callback 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 all the module.
|
|
|
|
* If no callback is specified, the default callback will assign the proxy inner value to the plain find result
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param filter A function that takes a module and returns a boolean
|
|
|
|
* @param filter A function that takes an export or module exports and returns a boolean
|
|
|
|
* @param callback A function that takes the found module as its first argument and returns something to use as the proxy inner value. Useful if you want to use a value from the module, instead of all of it. Defaults to the module itself
|
|
|
|
* @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
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function find<T = AnyObject>(filter: FilterFn, callback: (mod: any) => any = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
|
|
|
|
export function find<T = AnyObject>(filter: FilterFn, callback: (mod: any) => any = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
|
|
|
@ -178,7 +201,7 @@ export function find<T = AnyObject>(filter: FilterFn, callback: (mod: any) => an
|
|
|
|
throw new Error("Invalid callback. Expected a function got " + typeof callback);
|
|
|
|
throw new Error("Invalid callback. Expected a function got " + typeof callback);
|
|
|
|
|
|
|
|
|
|
|
|
const [proxy, setInnerValue] = proxyInner<T>(`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.");
|
|
|
|
const [proxy, setInnerValue] = proxyInner<T>(`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, mod => setInnerValue(callback(mod)), { isIndirect: true });
|
|
|
|
waitFor(filter, m => setInnerValue(callback(m)), { isIndirect: true });
|
|
|
|
|
|
|
|
|
|
|
|
if (IS_REPORTER && !isIndirect) {
|
|
|
|
if (IS_REPORTER && !isIndirect) {
|
|
|
|
webpackSearchHistory.push(["find", [proxy, filter]]);
|
|
|
|
webpackSearchHistory.push(["find", [proxy, filter]]);
|
|
|
@ -190,9 +213,9 @@ export function find<T = AnyObject>(filter: FilterFn, callback: (mod: any) => an
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the first component that matches the filter.
|
|
|
|
* Find the first exported component that matches the filter.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param filter A function that takes a module and returns a boolean
|
|
|
|
* @param filter A function that takes an export or module exports and returns a boolean
|
|
|
|
* @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component
|
|
|
|
* @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component
|
|
|
|
* @returns The component if found, or a noop component
|
|
|
|
* @returns The component if found, or a noop component
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -277,7 +300,7 @@ export function findExportedComponent<T extends object = any>(...props: string[]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the first component in a default export that includes all the given code.
|
|
|
|
* Find the first component in an export that includes all the given code.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @example findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR")
|
|
|
|
* @example findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR")
|
|
|
|
* @example findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)", ColorPicker => React.memo(ColorPicker))
|
|
|
|
* @example findComponentByCode(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)", ColorPicker => React.memo(ColorPicker))
|
|
|
@ -290,7 +313,7 @@ export function findComponentByCode<T extends object = any>(...code: string[] |
|
|
|
|
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: any) => LazyComponentType<T>;
|
|
|
|
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: any) => LazyComponentType<T>;
|
|
|
|
const newCode = code as string[];
|
|
|
|
const newCode = code as string[];
|
|
|
|
|
|
|
|
|
|
|
|
const ComponentResult = findComponent<T>(filters.componentByCode(...newCode), parse, { isIndirect: true });
|
|
|
|
const ComponentResult = findComponent<T>(filters.byComponentCode(...newCode), parse, { isIndirect: true });
|
|
|
|
|
|
|
|
|
|
|
|
if (IS_REPORTER) {
|
|
|
|
if (IS_REPORTER) {
|
|
|
|
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newCode]]);
|
|
|
|
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newCode]]);
|
|
|
@ -300,9 +323,9 @@ export function findComponentByCode<T extends object = any>(...code: string[] |
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the first module or default export that includes all the given props.
|
|
|
|
* Find the first module exports or export that includes all the given props.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param props A list of props to search the exports for
|
|
|
|
* @param props A list of props to search the module or exports for
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function findByProps<T = AnyObject>(...props: string[]) {
|
|
|
|
export function findByProps<T = AnyObject>(...props: string[]) {
|
|
|
|
const result = find<T>(filters.byProps(...props), m => m, { isIndirect: true });
|
|
|
|
const result = find<T>(filters.byProps(...props), m => m, { isIndirect: true });
|
|
|
@ -315,7 +338,7 @@ export function findByProps<T = AnyObject>(...props: string[]) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the first default export that includes all the given code.
|
|
|
|
* Find the first export that includes all the given code.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param code A list of code to search each export for
|
|
|
|
* @param code A list of code to search each export for
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -345,32 +368,152 @@ export function findStore<T = GenericStore>(name: string) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the first already required module that matches the filter.
|
|
|
|
* Find the module exports of the first module which the factory includes all the given code.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param filter A function that takes a module and returns a boolean
|
|
|
|
* @param code A list of code to search each factory for
|
|
|
|
* @returns The found module or null
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const cacheFind = traceFunction("cacheFind", function cacheFind(filter: FilterFn) {
|
|
|
|
export function findByFactoryCode<T = AnyObject>(...code: string[]) {
|
|
|
|
|
|
|
|
const result = find<T>(filters.byFactoryCode(...code), m => m, { isIndirect: true });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IS_REPORTER) {
|
|
|
|
|
|
|
|
webpackSearchHistory.push(["findByFactoryCode", [result, ...code]]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Find the first module factory that includes all the given code.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function findModuleFactory(...code: string[]) {
|
|
|
|
|
|
|
|
const filter = filters.byFactoryCode(...code);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [proxy, setInnerValue] = proxyInner<ModuleFactory>(`Webpack module factory 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, (_, { factory }) => setInnerValue(factory));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (proxy[SYM_PROXY_INNER_VALUE] != null) return proxy[SYM_PROXY_INNER_VALUE] as ProxyInner<ModuleFactory>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return proxy;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Find the module exports of the first module which the factory includes all the given code,
|
|
|
|
|
|
|
|
* then map them into an easily usable object via the specified mappers.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @example
|
|
|
|
|
|
|
|
* const Modals = mapMangledModule("headerIdIsManaged:", {
|
|
|
|
|
|
|
|
* openModal: filters.byCode("headerIdIsManaged:"),
|
|
|
|
|
|
|
|
* closeModal: filters.byCode("key==")
|
|
|
|
|
|
|
|
* });
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param code The code or list of code to search each factory for
|
|
|
|
|
|
|
|
* @param mappers Mappers to create the non mangled exports object
|
|
|
|
|
|
|
|
* @returns Unmangled exports as specified in mappers
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function mapMangledModule<S extends PropertyKey>(code: string | string[], mappers: Record<S, FilterFn>) {
|
|
|
|
|
|
|
|
const result = find<Record<S, any>>(filters.byFactoryCode(...Array.isArray(code) ? code : [code]), exports => {
|
|
|
|
|
|
|
|
const mapping = {} as Record<S, any>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
outer:
|
|
|
|
|
|
|
|
for (const newName in mappers) {
|
|
|
|
|
|
|
|
const filter = mappers[newName];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeof exports === "object") {
|
|
|
|
|
|
|
|
for (const exportKey in exports) {
|
|
|
|
|
|
|
|
const exportValue = exports[exportKey];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (exportValue != null && filter(exportValue)) {
|
|
|
|
|
|
|
|
mapping[newName] = exportValue;
|
|
|
|
|
|
|
|
continue outer;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [proxy] = proxyInner(`Webpack mapMangled mapper filter 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.");
|
|
|
|
|
|
|
|
// Use the proxy to throw errors because no export matched the filter
|
|
|
|
|
|
|
|
mapping[newName] = proxy;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return mapping;
|
|
|
|
|
|
|
|
}, { isIndirect: true });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IS_REPORTER) {
|
|
|
|
|
|
|
|
webpackSearchHistory.push(["mapMangledModule", [result, code, mappers]]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type CacheFindResult = {
|
|
|
|
|
|
|
|
/** The find result. `undefined` if nothing was found */
|
|
|
|
|
|
|
|
result?: any;
|
|
|
|
|
|
|
|
/** The id of the module exporting where the result was found. `undefined` if nothing was found */
|
|
|
|
|
|
|
|
id?: PropertyKey;
|
|
|
|
|
|
|
|
/** The key exporting the result. `null` if the find result was all the module exports, `undefined` if nothing was found */
|
|
|
|
|
|
|
|
exportKey?: PropertyKey | null;
|
|
|
|
|
|
|
|
/** The factory of the module exporting the result. `undefined` if nothing was found */
|
|
|
|
|
|
|
|
factory?: ModuleFactory;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Find the first export or module exports from an already required module that matches the filter.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param filter A function that takes an export or module exports and returns a boolean
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export const _cacheFind = traceFunction("cacheFind", function _cacheFind(filter: FilterFn): CacheFindResult {
|
|
|
|
if (typeof filter !== "function")
|
|
|
|
if (typeof filter !== "function")
|
|
|
|
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
|
|
|
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
|
|
|
|
|
|
|
|
|
|
|
for (const key in cache) {
|
|
|
|
for (const key in cache) {
|
|
|
|
const mod = cache[key];
|
|
|
|
const mod = cache[key];
|
|
|
|
if (!mod?.exports) continue;
|
|
|
|
if (!mod?.loaded || mod?.exports == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (filter.$$vencordIsFactoryFilter && filter(wreq.m[key])) {
|
|
|
|
|
|
|
|
return { result: exports, id: key, exportKey: null, factory: wreq.m[key] };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (filter(mod.exports)) {
|
|
|
|
if (filter(mod.exports)) {
|
|
|
|
return mod.exports;
|
|
|
|
return { result: exports, id: key, exportKey: null, factory: wreq.m[key] };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (mod.exports.default && filter(mod.exports.default)) {
|
|
|
|
if (typeof mod.exports !== "object") {
|
|
|
|
return mod.exports.default;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mod.exports.default != null && filter(mod.exports.default)) {
|
|
|
|
|
|
|
|
return { result: exports.default, id: key, exportKey: "default ", factory: wreq.m[key] };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const exportKey in mod.exports) if (exportKey.length <= 3) {
|
|
|
|
|
|
|
|
const exportValue = mod.exports[exportKey];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (exportValue != null && filter(exportValue)) {
|
|
|
|
|
|
|
|
return { result: exportValue, id: key, exportKey, factory: wreq.m[key] };
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
return {};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Find the first export or module exports from an already required module that matches the filter.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param filter A function that takes an export or module exports and returns a boolean
|
|
|
|
|
|
|
|
* @returns The found export or module exports, or undefined
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function cacheFind(filter: FilterFn) {
|
|
|
|
|
|
|
|
const cacheFindResult = _cacheFind(filter);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return cacheFindResult.result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Find the the export or module exports from an all the required modules that match the filter.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param filter A function that takes an export or module exports and returns a boolean
|
|
|
|
|
|
|
|
* @returns An array of all the found export or module exports
|
|
|
|
|
|
|
|
*/
|
|
|
|
export function cacheFindAll(filter: FilterFn) {
|
|
|
|
export function cacheFindAll(filter: FilterFn) {
|
|
|
|
if (typeof filter !== "function")
|
|
|
|
if (typeof filter !== "function")
|
|
|
|
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
|
|
|
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
|
|
@ -378,15 +521,32 @@ export function cacheFindAll(filter: FilterFn) {
|
|
|
|
const ret = [] as any[];
|
|
|
|
const ret = [] as any[];
|
|
|
|
for (const key in cache) {
|
|
|
|
for (const key in cache) {
|
|
|
|
const mod = cache[key];
|
|
|
|
const mod = cache[key];
|
|
|
|
if (!mod?.exports) continue;
|
|
|
|
if (!mod?.loaded || mod?.exports == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (filter.$$vencordIsFactoryFilter && filter(wreq.m[key])) {
|
|
|
|
|
|
|
|
ret.push(mod.exports);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (filter(mod.exports)) {
|
|
|
|
if (filter(mod.exports)) {
|
|
|
|
ret.push(mod.exports);
|
|
|
|
ret.push(mod.exports);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (mod.exports.default && filter(mod.exports.default)) {
|
|
|
|
if (typeof mod.exports !== "object") {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mod.exports.default != null && filter(mod.exports.default)) {
|
|
|
|
ret.push(mod.exports.default);
|
|
|
|
ret.push(mod.exports.default);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const exportKey in mod.exports) if (exportKey.length <= 3) {
|
|
|
|
|
|
|
|
const exportValue = mod.exports[exportKey];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (exportValue != null && filter(exportValue)) {
|
|
|
|
|
|
|
|
ret.push(exportValue);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
return ret;
|
|
|
@ -395,18 +555,19 @@ export function cacheFindAll(filter: FilterFn) {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Same as {@link cacheFind} but in bulk.
|
|
|
|
* Same as {@link cacheFind} but in bulk.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param filterFns Array of filters. Please note that this array will be modified in place, so if you still
|
|
|
|
* @param filterFns Array of filters
|
|
|
|
* need it afterwards, pass a copy.
|
|
|
|
|
|
|
|
* @returns Array of results in the same order as the passed filters
|
|
|
|
* @returns Array of results in the same order as the passed filters
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const cacheFindBulk = traceFunction("cacheFindBulk", function cacheFindBulk(...filterFns: FilterFn[]) {
|
|
|
|
export const cacheFindBulk = traceFunction("cacheFindBulk", function cacheFindBulk(...filterFns: FilterFn[]) {
|
|
|
|
if (!Array.isArray(filterFns))
|
|
|
|
if (!Array.isArray(filterFns)) {
|
|
|
|
throw new Error("Invalid filters. Expected function[] got " + typeof filterFns);
|
|
|
|
throw new Error("Invalid filters. Expected function[] got " + typeof filterFns);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { length } = filterFns;
|
|
|
|
const { length } = filterFns;
|
|
|
|
|
|
|
|
|
|
|
|
if (length === 0)
|
|
|
|
if (length === 0) {
|
|
|
|
throw new Error("Expected at least two filters.");
|
|
|
|
throw new Error("Expected at least two filters.");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (length === 1) {
|
|
|
|
if (length === 1) {
|
|
|
|
if (IS_DEV) {
|
|
|
|
if (IS_DEV) {
|
|
|
@ -419,27 +580,56 @@ export const cacheFindBulk = traceFunction("cacheFindBulk", function cacheFindBu
|
|
|
|
let found = 0;
|
|
|
|
let found = 0;
|
|
|
|
const results = Array(length);
|
|
|
|
const results = Array(length);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const filters = [...filterFns] as Array<FilterFn | undefined>;
|
|
|
|
|
|
|
|
|
|
|
|
outer:
|
|
|
|
outer:
|
|
|
|
for (const key in cache) {
|
|
|
|
for (const key in cache) {
|
|
|
|
const mod = cache[key];
|
|
|
|
const mod = cache[key];
|
|
|
|
if (!mod?.exports) continue;
|
|
|
|
if (!mod?.loaded || mod?.exports == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
for (let j = 0; j < length; j++) {
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
|
|
const filter = filterFns[j];
|
|
|
|
const filter = filters[i];
|
|
|
|
|
|
|
|
if (filter == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (filter.$$vencordIsFactoryFilter && filter(wreq.m[key])) {
|
|
|
|
|
|
|
|
results[i] = mod.exports;
|
|
|
|
|
|
|
|
filters[i] = undefined;
|
|
|
|
|
|
|
|
|
|
|
|
if (filter(mod.exports)) {
|
|
|
|
|
|
|
|
results[j] = mod.exports;
|
|
|
|
|
|
|
|
filterFns.splice(j--, 1);
|
|
|
|
|
|
|
|
if (++found === length) break outer;
|
|
|
|
if (++found === length) break outer;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (mod.exports.default && filter(mod.exports.default)) {
|
|
|
|
if (filter(mod.exports)) {
|
|
|
|
results[j] = mod.exports.default;
|
|
|
|
results[i] = mod.exports;
|
|
|
|
filterFns.splice(j--, 1);
|
|
|
|
filters[i] = undefined;
|
|
|
|
|
|
|
|
|
|
|
|
if (++found === length) break outer;
|
|
|
|
if (++found === length) break outer;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeof mod.exports !== "object") {
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mod.exports.default != null && filter(mod.exports.default)) {
|
|
|
|
|
|
|
|
results[i] = mod.exports.default;
|
|
|
|
|
|
|
|
filters[i] = undefined;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (++found === length) break outer;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const exportKey in mod.exports) if (exportKey.length <= 3) {
|
|
|
|
|
|
|
|
const exportValue = mod.exports[exportKey];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (exportValue != null && filter(mod.exports[key])) {
|
|
|
|
|
|
|
|
results[i] = exportValue;
|
|
|
|
|
|
|
|
filters[i] = undefined;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (++found === length) break outer;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -458,16 +648,17 @@ export const cacheFindBulk = traceFunction("cacheFindBulk", function cacheFindBu
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the id of the first module factory that includes all the given code.
|
|
|
|
* Find the id of the first already loaded module factory that includes all the given code.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const findModuleId = traceFunction("findModuleId", function findModuleId(...code: string[]) {
|
|
|
|
export const cacheFindModuleId = traceFunction("cacheFindModuleId", function cacheFindModuleId(...code: string[]) {
|
|
|
|
outer:
|
|
|
|
outer:
|
|
|
|
for (const id in wreq.m) {
|
|
|
|
for (const id in wreq.m) {
|
|
|
|
const str = wreq.m[id].toString();
|
|
|
|
const str = String(wreq.m[id]);
|
|
|
|
|
|
|
|
|
|
|
|
for (const c of code) {
|
|
|
|
for (const c of code) {
|
|
|
|
if (!str.includes(c)) continue outer;
|
|
|
|
if (!str.includes(c)) continue outer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -475,18 +666,17 @@ export const findModuleId = traceFunction("findModuleId", function findModuleId(
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
logger.warn(err);
|
|
|
|
logger.warn(err);
|
|
|
|
return null;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Find the first module factory that includes all the given code.
|
|
|
|
* Find the first already loaded module factory that includes all the given code.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function findModuleFactory(...code: string[]) {
|
|
|
|
export function cacheFindModuleFactory(...code: string[]) {
|
|
|
|
const id = findModuleId(...code);
|
|
|
|
const id = cacheFindModuleId(...code);
|
|
|
|
if (!id) return null;
|
|
|
|
if (id == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
return wreq.m[id];
|
|
|
|
return wreq.m[id];
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -522,6 +712,82 @@ export function webpackDependantLazyComponent<T extends object = any>(factory: (
|
|
|
|
return LazyComponent<T>(factory, attempts);
|
|
|
|
return LazyComponent<T>(factory, attempts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const DefaultExtractAndLoadChunksRegex = /(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"?([^)]+?)"?\)\)/;
|
|
|
|
|
|
|
|
export const ChunkIdsRegex = /\("([^"]+?)"\)/g;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Extract and load chunks using their entry point.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param code The code or list of code the module factory containing the lazy chunk loading must include
|
|
|
|
|
|
|
|
* @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the first lazy chunk loading found in the module factory
|
|
|
|
|
|
|
|
* @returns A function that returns a promise that resolves with a boolean whether the chunks were loaded, on first call
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function extractAndLoadChunksLazy(code: string | string[], matcher: RegExp = DefaultExtractAndLoadChunksRegex) {
|
|
|
|
|
|
|
|
const module = findModuleFactory(...Array.isArray(code) ? code : [code]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function extractAndLoadChunks() {
|
|
|
|
|
|
|
|
if (module[SYM_PROXY_INNER_VALUE]) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Couldn't find module factory");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const match = String(module).match(canonicalizeMatch(matcher));
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Couldn't find chunk loading in module factory code");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [, rawChunkIds, entryPointId] = match;
|
|
|
|
|
|
|
|
if (Number.isNaN(Number(entryPointId))) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rawChunkIds) {
|
|
|
|
|
|
|
|
const chunkIds = Array.from(rawChunkIds.matchAll(ChunkIdsRegex)).map((m: any) => m[1]);
|
|
|
|
|
|
|
|
await Promise.all(chunkIds.map(id => wreq.e(id)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (wreq.m[entryPointId] == null) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Entry point is not loaded in the module factories, perhaps one of the chunks failed to load");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wreq(entryPointId as any);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IS_REPORTER) {
|
|
|
|
|
|
|
|
webpackSearchHistory.push(["extractAndLoadChunks", [extractAndLoadChunks]]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return extractAndLoadChunks;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function deprecatedRedirect<T extends (...args: any[]) => any>(oldMethod: string, newMethod: string, redirect: T): T {
|
|
|
|
function deprecatedRedirect<T extends (...args: any[]) => any>(oldMethod: string, newMethod: string, redirect: T): T {
|
|
|
|
return ((...args: Parameters<T>) => {
|
|
|
|
return ((...args: Parameters<T>) => {
|
|
|
|
logger.warn(`Method ${oldMethod} is deprecated. Use ${newMethod} instead. For more information read https://github.com/Vendicated/Vencord/pull/2409#issue-2277161516`);
|
|
|
|
logger.warn(`Method ${oldMethod} is deprecated. Use ${newMethod} instead. For more information read https://github.com/Vendicated/Vencord/pull/2409#issue-2277161516`);
|
|
|
@ -606,6 +872,25 @@ export const findComponentByCodeLazy = deprecatedRedirect("findComponentByCodeLa
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const findExportedComponentLazy = deprecatedRedirect("findExportedComponentLazy", "findExportedComponent", findExportedComponent);
|
|
|
|
export const findExportedComponentLazy = deprecatedRedirect("findExportedComponentLazy", "findExportedComponent", findExportedComponent);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @deprecated Use {@link mapMangledModule} instead
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* {@link mapMangledModule}, lazy.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* 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 The code to look for
|
|
|
|
|
|
|
|
* @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 const mapMangledModuleLazy = deprecatedRedirect("mapMangledModuleLazy", "mapMangledModule", mapMangledModule);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @deprecated Use {@link cacheFindAll} instead
|
|
|
|
* @deprecated Use {@link cacheFindAll} instead
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -622,87 +907,13 @@ export const findAll = deprecatedRedirect("findAll", "cacheFindAll", cacheFindAl
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export const findBulk = deprecatedRedirect("findBulk", "cacheFindBulk", cacheFindBulk);
|
|
|
|
export const findBulk = deprecatedRedirect("findBulk", "cacheFindBulk", cacheFindBulk);
|
|
|
|
|
|
|
|
|
|
|
|
export const DefaultExtractAndLoadChunksRegex = /(?:(?:Promise\.all\(\[)?(\i\.e\("[^)]+?"\)[^\]]*?)(?:\]\))?|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/;
|
|
|
|
|
|
|
|
export const ChunkIdsRegex = /\("([^"]+?)"\)/g;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Extract and load chunks using their entry point.
|
|
|
|
* @deprecated Use {@link cacheFindModuleId} instead
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param code An array of all the code the module factory containing the lazy chunk loading must include
|
|
|
|
* Find the id of the first module factory that includes all the given code
|
|
|
|
* @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the first lazy chunk loading found in the module factory
|
|
|
|
* @returns string or null
|
|
|
|
* @returns A promise that resolves with a boolean whether the chunks were loaded
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export async function extractAndLoadChunks(code: string[], matcher: RegExp = DefaultExtractAndLoadChunksRegex) {
|
|
|
|
export const findModuleId = deprecatedRedirect("findModuleId", "cacheFindModuleId", cacheFindModuleId);
|
|
|
|
const module = findModuleFactory(...code);
|
|
|
|
|
|
|
|
if (!module) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Couldn't find module factory");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const match = module.toString().match(canonicalizeMatch(matcher));
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Couldn't find chunk loading in module factory code");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [, rawChunkIds, entryPointId] = match;
|
|
|
|
|
|
|
|
if (Number.isNaN(Number(entryPointId))) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rawChunkIds) {
|
|
|
|
|
|
|
|
const chunkIds = Array.from(rawChunkIds.matchAll(ChunkIdsRegex)).map((m: any) => m[1]);
|
|
|
|
|
|
|
|
await Promise.all(chunkIds.map(id => wreq.e(id)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (wreq.m[entryPointId] == null) {
|
|
|
|
|
|
|
|
const err = new Error("extractAndLoadChunks: Entry point is not loaded in the module factories, perhaps one of the chunks failed to load");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IS_DEV || devToolsOpen) {
|
|
|
|
|
|
|
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
throw err; // Strict behaviour in DevBuilds to fail early and make sure the issue is found
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wreq(entryPointId);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* This is just a wrapper around {@link extractAndLoadChunks} to make our reporter test for your webpack finds.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Extract and load chunks using their entry point.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param code An array of all the code the module factory containing the lazy chunk loading must include
|
|
|
|
|
|
|
|
* @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the first lazy chunk loading found in the module factory
|
|
|
|
|
|
|
|
* @returns A function that returns a promise that resolves with a boolean whether the chunks were loaded, on first call
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function extractAndLoadChunksLazy(code: string[], matcher = DefaultExtractAndLoadChunksRegex) {
|
|
|
|
|
|
|
|
if (IS_REPORTER) webpackSearchHistory.push(["extractAndLoadChunks", [code, matcher]]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return makeLazy(() => extractAndLoadChunks(code, matcher));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Search modules by keyword. This searches the factory methods,
|
|
|
|
* Search modules by keyword. This searches the factory methods,
|
|
|
@ -717,10 +928,10 @@ export function search(...filters: Array<string | RegExp>) {
|
|
|
|
outer:
|
|
|
|
outer:
|
|
|
|
for (const id in factories) {
|
|
|
|
for (const id in factories) {
|
|
|
|
const factory = factories[id];
|
|
|
|
const factory = factories[id];
|
|
|
|
const str: string = factory.toString();
|
|
|
|
const factoryStr = String(factory);
|
|
|
|
for (const filter of filters) {
|
|
|
|
for (const filter of filters) {
|
|
|
|
if (typeof filter === "string" && !str.includes(filter)) continue outer;
|
|
|
|
if (typeof filter === "string" && !factoryStr.includes(filter)) continue outer;
|
|
|
|
if (filter instanceof RegExp && !filter.test(str)) continue outer;
|
|
|
|
if (filter instanceof RegExp && !filter.test(factoryStr)) continue outer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
results[id] = factory;
|
|
|
|
results[id] = factory;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -737,17 +948,17 @@ export function search(...filters: Array<string | RegExp>) {
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param id The id of the module to extract
|
|
|
|
* @param id The id of the module to extract
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function extract(id: string | number) {
|
|
|
|
export function extract(id: PropertyKey) {
|
|
|
|
const mod = wreq.m[id] as Function;
|
|
|
|
const factory = wreq.m[id] as Function;
|
|
|
|
if (!mod) return null;
|
|
|
|
if (!factory) return;
|
|
|
|
|
|
|
|
|
|
|
|
const code = `
|
|
|
|
const code = `
|
|
|
|
// [EXTRACTED] WebpackModule${id}
|
|
|
|
// [EXTRACTED] WebpackModule${String(id)}
|
|
|
|
// WARNING: This module was extracted to be more easily readable.
|
|
|
|
// WARNING: This module was extracted to be more easily readable.
|
|
|
|
// This module is NOT ACTUALLY USED! This means putting breakpoints will have NO EFFECT!!
|
|
|
|
// This module is NOT ACTUALLY USED! This means putting breakpoints will have NO EFFECT!!
|
|
|
|
|
|
|
|
|
|
|
|
0,${mod.toString()}
|
|
|
|
0,${String(factory)}
|
|
|
|
//# sourceURL=ExtractedWebpackModule${id}
|
|
|
|
//# sourceURL=ExtractedWebpackModule${String(id)}
|
|
|
|
`;
|
|
|
|
`;
|
|
|
|
const extracted = (0, eval)(code);
|
|
|
|
const extracted = (0, eval)(code);
|
|
|
|
return extracted as Function;
|
|
|
|
return extracted as Function;
|
|
|
|