From 2cff8ebf07b46ada3d89466904d3ad2bccf9aed1 Mon Sep 17 00:00:00 2001 From: PalmDevs Date: Fri, 4 Jul 2025 21:38:37 +0700 Subject: [PATCH] feat(lib/modules)!: add new options for `lookup` `finders`, `include` prefix from `finders` options, make `utils` functions safe again --- lib/discord/src/actions.ts | 6 +- lib/discord/src/common/flux.ts | 2 +- lib/discord/src/common/utils.ts | 2 +- lib/discord/src/design.ts | 4 +- lib/discord/src/modules/main_tabs_v2.ts | 2 +- lib/discord/src/modules/settings/renderer.ts | 2 +- lib/discord/src/preinit.ts | 2 +- lib/externals/src/browserify.ts | 2 +- lib/externals/src/react-native-clipboard.ts | 2 +- lib/externals/src/react-navigation.ts | 4 +- lib/externals/src/shopify.ts | 2 +- lib/modules/src/finders/_internal.ts | 10 +- lib/modules/src/finders/lookup.ts | 318 +++++++++++-------- lib/modules/src/finders/wait.ts | 8 +- lib/modules/src/metro/utils.ts | 12 +- lib/utils/src/discord.ts | 4 +- 16 files changed, 226 insertions(+), 156 deletions(-) diff --git a/lib/discord/src/actions.ts b/lib/discord/src/actions.ts index b45dfcf..b08996f 100644 --- a/lib/discord/src/actions.ts +++ b/lib/discord/src/actions.ts @@ -40,7 +40,7 @@ export let ActionSheetActionCreators: DiscordModules.Actions.ActionSheetActionCr ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) @@ -66,7 +66,7 @@ export let AlertActionCreators: DiscordModules.Actions.AlertActionCreators = ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) @@ -91,7 +91,7 @@ export let ToastActionCreators: DiscordModules.Actions.ToastActionCreators = byDependencies([DispatcherModuleId, 2]), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/discord/src/common/flux.ts b/lib/discord/src/common/flux.ts index 9b241d9..ef420cf 100644 --- a/lib/discord/src/common/flux.ts +++ b/lib/discord/src/common/flux.ts @@ -28,7 +28,7 @@ export const [Dispatcher, DispatcherModuleId] = lookupModule( ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) as [DiscordModules.Flux.Dispatcher, Metro.ModuleID] diff --git a/lib/discord/src/common/utils.ts b/lib/discord/src/common/utils.ts index 6a49ba2..e5bea5c 100644 --- a/lib/discord/src/common/utils.ts +++ b/lib/discord/src/common/utils.ts @@ -25,7 +25,7 @@ export let TypedEventEmitter: typeof DiscordModules.Utils.TypedEventEmitter = ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/discord/src/design.ts b/lib/discord/src/design.ts index a6995fb..3ef7322 100644 --- a/lib/discord/src/design.ts +++ b/lib/discord/src/design.ts @@ -34,7 +34,7 @@ export let Design: Design = proxify( ), ), { - includeUninitialized: true, + uninitialized: true, }, ) @@ -75,7 +75,7 @@ export let FormSwitch: DiscordModules.Components.FormSwitch = proxify(() => { ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/discord/src/modules/main_tabs_v2.ts b/lib/discord/src/modules/main_tabs_v2.ts index 55dd7a8..385c457 100644 --- a/lib/discord/src/modules/main_tabs_v2.ts +++ b/lib/discord/src/modules/main_tabs_v2.ts @@ -26,7 +26,7 @@ export let RootNavigationRef: RootNavigationRef = proxify( ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/discord/src/modules/settings/renderer.ts b/lib/discord/src/modules/settings/renderer.ts index 7d3cf37..1c8beed 100644 --- a/lib/discord/src/modules/settings/renderer.ts +++ b/lib/discord/src/modules/settings/renderer.ts @@ -34,7 +34,7 @@ export let SettingListRenderer: SettingListRenderer = proxify( ), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/discord/src/preinit.ts b/lib/discord/src/preinit.ts index b5258b9..dfa90bc 100644 --- a/lib/discord/src/preinit.ts +++ b/lib/discord/src/preinit.ts @@ -16,7 +16,7 @@ export const [AppStartPerformance] = lookupModule( byDependencies([relative(-1), undefined, undefined, 2]), ), { - includeUninitialized: true, + uninitialized: true, }, ) as [DiscordModules.AppStartPerformance, Metro.ModuleID] diff --git a/lib/externals/src/browserify.ts b/lib/externals/src/browserify.ts index 5d5f6b2..41f3f6e 100644 --- a/lib/externals/src/browserify.ts +++ b/lib/externals/src/browserify.ts @@ -20,7 +20,7 @@ export let nodeUtil: typeof import('node:util') = proxify( ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/externals/src/react-native-clipboard.ts b/lib/externals/src/react-native-clipboard.ts index 063fa05..743b27f 100644 --- a/lib/externals/src/react-native-clipboard.ts +++ b/lib/externals/src/react-native-clipboard.ts @@ -38,7 +38,7 @@ let ClipboardModule: typeof import('@react-native-clipboard/clipboard') = ]), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/externals/src/react-navigation.ts b/lib/externals/src/react-navigation.ts index c331e67..1c8777a 100644 --- a/lib/externals/src/react-navigation.ts +++ b/lib/externals/src/react-navigation.ts @@ -29,7 +29,7 @@ export let ReactNavigationNative: typeof import('@react-navigation/native') = ), ), { - includeUninitialized: true, + uninitialized: true, }, ) @@ -62,7 +62,7 @@ export let ReactNavigationStack: typeof import('@react-navigation/stack') = ), ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/externals/src/shopify.ts b/lib/externals/src/shopify.ts index e9289e4..5dd1de0 100644 --- a/lib/externals/src/shopify.ts +++ b/lib/externals/src/shopify.ts @@ -30,7 +30,7 @@ export let FlashList: typeof import('@shopify/flash-list') = proxify( // [React, RN, JSXRuntime, (FlashListExports), (Reanimated), (RNBottomSheet), ImportTracker, (BottomSheetFlashList)] ), { - includeUninitialized: true, + uninitialized: true, }, ) diff --git a/lib/modules/src/finders/_internal.ts b/lib/modules/src/finders/_internal.ts index 5678aa5..68d5a9d 100644 --- a/lib/modules/src/finders/_internal.ts +++ b/lib/modules/src/finders/_internal.ts @@ -12,6 +12,12 @@ export interface RunFilterOptions { * @default false */ skipDefault?: boolean + /** + * Whether to allow initializing modules to check their exports. + * + * @default false + */ + initialize?: boolean } export type RunFilterReturnExportsOptions< @@ -79,9 +85,11 @@ export function runFilter( const flag = runFilter(filter, id, __r(id), options) if (!flag) warnDeveloperAboutPartialFilterMatch(id, filter.key) return flag - } else { + } else if (options?.initialize) { return runFilter(filter, id, __r(id), options) } + + return FilterResultFlags.Found } return diff --git a/lib/modules/src/finders/lookup.ts b/lib/modules/src/finders/lookup.ts index e3511e0..e95d48f 100644 --- a/lib/modules/src/finders/lookup.ts +++ b/lib/modules/src/finders/lookup.ts @@ -1,7 +1,7 @@ import { getCurrentStack } from '@revenge-mod/utils/errors' import { proxify } from '@revenge-mod/utils/proxy' import { cache } from '../caches' -import { _inits, _paths, _uninits } from '../metro/_internal' +import { _inits, _metas, _paths, _uninits } from '../metro/_internal' import { getInitializedModuleExports, isModuleInitialized, @@ -9,80 +9,86 @@ import { import { exportsFromFilterResultFlag, runFilter } from './_internal' import type { If } from '@revenge-mod/utils/types' import type { MaybeDefaultExportMatched, Metro } from '../types' -import type { - RunFilterOptions, - RunFilterReturnExportsOptions, -} from './_internal' +import type { RunFilterReturnExportsOptions } from './_internal' import type { Filter, FilterResult } from './filters' -export interface BaseLookupModulesOptions< - IncludeUninitialized extends boolean = boolean, -> extends RunFilterOptions { +interface LookupModulesOptionsWithAll { + /** + * Whether to include all modules in the lookup, including blacklisted ones. + * + * **This overrides {@link BaseLookupModulesOptions.initialized} and {@link BaseLookupModulesOptions.uninitialized}.** + */ + all: O +} + +interface LookupModulesOptionsWithInitializedUninitialized { /** * Whether to include initialized modules in the lookup. * * @default true */ - includeInitialized?: boolean + initialized?: boolean /** * Whether to include uninitialized modules in the lookup. * - * **This will initialize any modules that match the exportsless filter and may cause unintended side effects.** + * Set {@link BaseLookupModulesOptions.initialize} `true` to initialize uninitialized modules. * * @default false */ - includeUninitialized?: IncludeUninitialized - /** - * If the lookup is cached, whether to initialize the cached modules. - */ - initializeCached?: boolean + uninitialized?: U } export type LookupModulesOptions< ReturnNamespace extends boolean = boolean, - IncludeUninitialized extends boolean = boolean, -> = RunFilterReturnExportsOptions & - BaseLookupModulesOptions + Uninitialized extends boolean = boolean, + All extends boolean = boolean, + Initialize extends boolean = boolean, +> = RunFilterReturnExportsOptions & { + /** + * Whether to use cached lookup results. + */ + cached?: boolean + /** + * Whether to initialize matching uninitialized modules. + * + * **This will initialize any modules that match the exportsless filter and may cause unintended side effects.** + */ + initialize?: Initialize +} & If< + All, + LookupModulesOptionsWithAll & { + [K in keyof LookupModulesOptionsWithInitializedUninitialized]?: never + }, + LookupModulesOptionsWithInitializedUninitialized & { + [K in keyof LookupModulesOptionsWithAll]?: never + } + > export type LookupModulesResult< F extends Filter, O extends LookupModulesOptions, > = [ - exports: O extends RunFilterReturnExportsOptions - ? MaybeDefaultExportMatched> - : FilterResult, + exports: O extends LookupModulesOptions + ? LookupFilterResult + : LookupFilterResult | undefined, id: Metro.ModuleID, ] -export type LookupModuleIdsOptions< - IncludeUninitialized extends boolean = boolean, - IncludeAll extends If = If< - IncludeUninitialized, - false, - boolean - >, -> = RunFilterOptions & - ( - | (BaseLookupModulesOptions & { - includeAll?: false - }) - | ({ - /** - * Whether to include all modules, including ones with bad exports. - * This option overrides `includeInitialized` and `includeUninitialized`. - * - * This will filter modules in order of how they're defined. - * - * @default false - */ - includeAll: IncludeAll - } & BaseLookupModulesOptions) - ) +type LookupFilterResult< + F extends Filter, + O extends LookupModulesOptions, +> = O extends RunFilterReturnExportsOptions + ? MaybeDefaultExportMatched> + : FilterResult + +const NotFoundResult: [] = [] + +type LookupNotFoundResult = typeof NotFoundResult /** * Lookup modules. * - * You can lookup uninitialized modules by passing `options.includeUninitialized` when filtering via without-exports filters (eg. `byDependencies`). + * You can lookup uninitialized modules by passing `options.uninitialized` when filtering via exportsless filters (eg. `byDependencies`). * Use the `moduleStateAware` helper to filter dynamically based on whether the module is initialized or not. * * @param filter The filter to use. @@ -101,41 +107,50 @@ export function lookupModules( ): Generator, undefined> export function lookupModules< - F extends O extends BaseLookupModulesOptions + F extends O extends LookupModulesOptions ? Filter : Filter, - O extends LookupModulesOptions, + const O extends LookupModulesOptions, >(filter: F, options: O): Generator, undefined> export function* lookupModules(filter: Filter, options?: LookupModulesOptions) { let notFound = true + let cached: Set | undefined - const reg = cache[filter.key] - // Return early if previous lookup was a full lookup and no modules were found - if (reg === null) return + const init = options?.initialize ?? true + const notInit = !init - const noInitCached = !(options?.initializeCached ?? true) - const cached = new Set() + if (options?.cached ?? true) { + const reg = cache[filter.key] + // Return early if previous lookup was a full lookup and no modules were found + if (reg === null) return - if (reg) - for (const sId in reg) { - const flag = reg[sId] - const id = Number(sId) - let exports: Metro.ModuleExports | undefined + if (reg) { + cached = new Set() - if (isModuleInitialized(id)) - exports = getInitializedModuleExports(id) - else { - if (noInitCached) continue - exports = __r(id) + for (const sId in reg) { + const flag = reg[sId] + const id = Number(sId) + let exports: Metro.ModuleExports | undefined + + if (isModuleInitialized(id)) + exports = getInitializedModuleExports(id) + else { + if (notInit) continue + exports = __r(id) + } + + cached.add(id) + + yield [exportsFromFilterResultFlag(flag, exports, options), id] } - - yield [exportsFromFilterResultFlag(flag, exports, options), id] } + } - if (options?.includeInitialized ?? true) - for (const id of _inits) { - if (cached.has(id)) continue + // Full lookup + if (options?.all) { + for (const id of _metas.keys()) { + if (cached?.has(id)) continue const exports = getInitializedModuleExports(id) const flag = runFilter(filter, id, exports, options) @@ -145,28 +160,49 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) { } } - if (options?.includeUninitialized) - for (const id of _uninits) { - if (cached.has(id)) continue + if (notFound) cache[filter.key] = null // Full lookup, and still not found! + } + // Partial lookup + else { + if (options?.initialized ?? true) + for (const id of _inits) { + if (cached?.has(id)) continue - const flag = runFilter(filter, id) - if (flag) { - notFound = false - yield [ - exportsFromFilterResultFlag( - flag, - getInitializedModuleExports(id), - options, - ), - id, - ] + const exports = getInitializedModuleExports(id) + const flag = runFilter(filter, id, exports, options) + if (flag) { + notFound = false + yield [ + exportsFromFilterResultFlag(flag, exports, options), + id, + ] + } } - } + + if (options?.uninitialized) + for (const id of _uninits) { + if (cached?.has(id)) continue + + const flag = runFilter(filter, id, undefined, options) + if (flag) { + notFound = false + + yield [ + init + ? exportsFromFilterResultFlag( + flag, + getInitializedModuleExports(id), + options, + ) + : undefined, + id, + ] + } + } + } if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) if (notFound) warnDeveloperAboutNoFilterMatch(filter) - - if (notFound) cache[filter.key] = null // Full lookup, and still not found! } /** @@ -185,64 +221,91 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) { */ export function lookupModule( filter: F, -): LookupModulesResult | [] +): LookupModulesResult | LookupNotFoundResult -export function lookupModule( - filter: F, - options: O, -): LookupModulesResult | [] +export function lookupModule< + F extends O extends LookupModulesOptions + ? Filter + : Filter, + const O extends LookupModulesOptions, +>(filter: F, options: O): LookupModulesResult | LookupNotFoundResult export function lookupModule(filter: Filter, options?: LookupModulesOptions) { - const reg = cache[filter.key] - // Return early if previous lookup was a full lookup and no modules were found - if (reg === null) return [] + const init = options?.initialize ?? true + const notInit = !init - const noInitCached = !(options?.initializeCached ?? true) + if (options?.cached ?? true) { + const reg = cache[filter.key] + // Return early if previous lookup was a full lookup and no modules were found + if (reg === null) return NotFoundResult - if (reg) - for (const sId in reg) { - const flag = reg[sId] - const id = Number(sId) - let exports: Metro.ModuleExports + if (reg) + for (const sId in reg) { + const flag = reg[sId] + const id = Number(sId) + let exports: Metro.ModuleExports - if (isModuleInitialized(id)) - exports = getInitializedModuleExports(id) - else { - if (noInitCached) continue - exports = __r(id) + if (isModuleInitialized(id)) + exports = getInitializedModuleExports(id) + else { + if (notInit) continue + exports = __r(id) + } + + return [exportsFromFilterResultFlag(flag, exports, options), id] } + } - return [exportsFromFilterResultFlag(flag, exports, options), id] - } - - if (options?.includeInitialized ?? true) - for (const id of _inits) { + // Full lookup + if (options?.all) { + for (const id of _metas.keys()) { const exports = getInitializedModuleExports(id) const flag = runFilter(filter, id, exports, options) if (flag) return [exportsFromFilterResultFlag(flag, exports, options), id] } - if (options?.includeUninitialized) - for (const id of _uninits) { - const flag = runFilter(filter, id) - if (flag) - return [ - exportsFromFilterResultFlag( - flag, - getInitializedModuleExports(id), - options, - ), - id, - ] - } + if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) + warnDeveloperAboutNoFilterMatch(filter) + + cache[filter.key] = null // Full lookup, and still not found! + + return NotFoundResult + } + // Partial lookup + else { + if (options?.initialized ?? true) + for (const id of _inits) { + const exports = getInitializedModuleExports(id) + const flag = runFilter(filter, id, exports, options) + if (flag) + return [ + exportsFromFilterResultFlag(flag, exports, options), + id, + ] + } + + if (options?.uninitialized) + for (const id of _uninits) { + const flag = runFilter(filter, id, undefined, options) + if (flag) + return [ + init + ? exportsFromFilterResultFlag( + flag, + getInitializedModuleExports(id), + options, + ) + : undefined, + id, + ] + } + } if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) warnDeveloperAboutNoFilterMatch(filter) - cache[filter.key] = null // Full lookup, and still not found! - - return [] + return NotFoundResult } /** @@ -262,9 +325,8 @@ export function lookupModuleByImportedPath( path: string, ): [exports: T, id: Metro.ModuleID] | [] { const id = _paths.get(path) - if (id == null) { - return [] - } + if (id == null) return NotFoundResult + return [getInitializedModuleExports(id), id] } diff --git a/lib/modules/src/finders/wait.ts b/lib/modules/src/finders/wait.ts index d99fdd4..f692ec0 100644 --- a/lib/modules/src/finders/wait.ts +++ b/lib/modules/src/finders/wait.ts @@ -13,11 +13,11 @@ export interface BaseWaitForModulesOptions< IncludeAll extends boolean = boolean, > { /** - * Whether to include all modules, including ones with bad exports. + * Whether to include all modules, including blacklisted ones. * * @default false */ - includeAll?: IncludeAll + all?: IncludeAll } export type WaitForModulesUnsubscribeFunction = () => boolean @@ -79,7 +79,7 @@ export function waitForModules( options?: WaitForModulesOptions, ) { return onAnyModuleInitialized( - options?.includeAll + options?.all ? (id, exports) => { const flag = runFilter(filter, id, exports, options) if (flag) @@ -133,7 +133,7 @@ export function waitForModuleByImportedPath( options?: BaseWaitForModulesOptions, ) { const unsub = onModuleFinishedImporting( - options?.includeAll + options?.all ? (id, cmpPath) => { if (path === cmpPath) { unsub() diff --git a/lib/modules/src/metro/utils.ts b/lib/modules/src/metro/utils.ts index 307ce15..0199ba7 100644 --- a/lib/modules/src/metro/utils.ts +++ b/lib/modules/src/metro/utils.ts @@ -5,21 +5,21 @@ import type { Metro } from '../types' /** * Returns the dependencies of a module. * @param id The module ID. - * @throws {TypeError} If the module with the given ID does not exist. + * @returns The dependency map of the module, or `undefined` if the module does not exist. */ export function getModuleDependencies( id: Metro.ModuleID, ): Metro.DependencyMap | undefined { - return _metas.get(id)![0] + return _metas.get(id)?.[0] } /** * Returns whether a module is initialized. * @param id The module ID. - * @throws {TypeError} If the module with the given ID does not exist. + * @returns `true` if the module is initialized, `false` if it is not initialized, or `undefined` if the module does not exist. */ export function isModuleInitialized(id: Metro.ModuleID): boolean | undefined { - return _metas.get(id)![1] + return _metas.get(id)?.[1] } /** @@ -28,12 +28,12 @@ export function isModuleInitialized(id: Metro.ModuleID): boolean | undefined { * @see {@link isModuleInitialized} to check if the module is initialized. * * @param id The module ID. - * @throws {TypeError} If the module with the given ID does not exist, or is not initialized. + * @returns The exports of the module, or `undefined` if the module is not initialized or does not exist. */ export function getInitializedModuleExports( id: Metro.ModuleID, ): Metro.ModuleExports | undefined { - return _metas.get(id)![2]!.exports + return _metas.get(id)?.[2]?.exports } /** diff --git a/lib/utils/src/discord.ts b/lib/utils/src/discord.ts index 3278497..18b8970 100644 --- a/lib/utils/src/discord.ts +++ b/lib/utils/src/discord.ts @@ -60,7 +60,7 @@ export function lookupGeneratedIconComponent( } return lookupModule(byDependencies<{ [K in N]: FC }>(filter), { - includeInitialized: false, - includeUninitialized: true, + initialized: false, + uninitialized: true, })[0]?.[compName] }