fix(lib/modules): don't make assumptions about what consumers are filtering
This commit is contained in:
parent
215cd487b9
commit
9a10e9d509
6 changed files with 38 additions and 15 deletions
|
|
@ -132,7 +132,7 @@ export type WithStoreName = FilterGenerator<
|
|||
*/
|
||||
export const withStoreName = createFilterGenerator(
|
||||
([name], _, exports) =>
|
||||
exports.getName?.length === 0 && exports.getName() === name,
|
||||
exports?.getName?.length === 0 && exports.getName() === name,
|
||||
([name]) => `revenge.discord.storeName(${name})`,
|
||||
FilterFlag.RequiresExports,
|
||||
FilterScopes.Uninitialized | FilterScopes.Initialized,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { getCurrentStack } from '@revenge-mod/utils/error'
|
|||
import { cacheFilterResultForId } from '../caches'
|
||||
import { mInitialized } from '../metro/patches'
|
||||
import { metroRequire } from '../metro/runtime'
|
||||
import { isModuleExportBad } from '../metro/utils'
|
||||
import { FilterFlag } from './filters'
|
||||
import type { If } from '@revenge-mod/utils/types'
|
||||
import type { Metro } from '../types'
|
||||
|
|
@ -66,6 +65,8 @@ export const FilterResultFlagToHumanReadable: Record<FilterResultFlag, string> =
|
|||
[FilterResultFlags.Found]: '\u001b[96mexportsless\u001b[0m',
|
||||
}
|
||||
|
||||
const noDefaultExportsCache = new Set<Metro.ModuleID>()
|
||||
|
||||
// The reason this returns a flag is because flags are never falsy, while exports may be falsy when using ID-only filters (eg. `withDependencies`).
|
||||
|
||||
// Currently, we only have options that are relevant for checking exports
|
||||
|
|
@ -92,7 +93,13 @@ export function runFilter(
|
|||
if (exports === undefined) {
|
||||
if (filter.flags & FilterFlag.RequiresExports) return
|
||||
|
||||
if (filter(id)) {
|
||||
const filter_ = filter as Filter<{
|
||||
Result: any
|
||||
RequiresExports: false
|
||||
Scopes: any[]
|
||||
}>
|
||||
|
||||
if (filter_(id)) {
|
||||
if (options?.initialize ?? true) {
|
||||
const module = metroRequire(id)
|
||||
// Check if the required module is not blacklisted
|
||||
|
|
@ -111,7 +118,13 @@ export function runFilter(
|
|||
return
|
||||
}
|
||||
|
||||
if (filter(id, exports))
|
||||
const filter_ = filter as Filter<{
|
||||
Result: any
|
||||
RequiresExports: true
|
||||
Scopes: any[]
|
||||
}>
|
||||
|
||||
if (filter_(id, exports))
|
||||
return cacheFilterResultForId(
|
||||
filter.key,
|
||||
id,
|
||||
|
|
@ -119,9 +132,14 @@ export function runFilter(
|
|||
)
|
||||
|
||||
if (options?.skipDefault) return
|
||||
if (noDefaultExportsCache.has(id)) return
|
||||
if (!('default' in exports)) {
|
||||
noDefaultExportsCache.add(id)
|
||||
return
|
||||
}
|
||||
|
||||
const { default: defaultExport } = exports
|
||||
if (!isModuleExportBad(defaultExport) && filter(id, defaultExport))
|
||||
if (filter_(id, defaultExport))
|
||||
return cacheFilterResultForId(filter.key, id, FilterResultFlags.Default)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { isModuleExportBad } from '@revenge-mod/modules/metro/utils'
|
||||
import { FilterFlag, FilterScopes } from './constants'
|
||||
import { createFilterGenerator } from './utils'
|
||||
import type { Filter, FilterGenerator } from './utils'
|
||||
|
|
@ -26,6 +27,8 @@ type FilterRequiringExports<T> = Filter<{
|
|||
export const withProps = createFilterGenerator<Parameters<WithProps>>(
|
||||
(props, _, exports) => {
|
||||
const type = typeof exports
|
||||
if (isModuleExportBad(exports)) return false
|
||||
|
||||
if (type === 'object' || type === 'function') {
|
||||
for (const prop of props) {
|
||||
if (prop in exports) continue
|
||||
|
|
@ -58,7 +61,7 @@ export type WithProps = FilterGenerator<
|
|||
export const withoutProps = createFilterGenerator<Parameters<WithoutProps>>(
|
||||
(props, _, exports) => {
|
||||
const type = typeof exports
|
||||
if (type === 'object' || type === 'function')
|
||||
if ((type === 'object' && exports !== null) || type === 'function')
|
||||
for (const prop of props) if (prop in exports) return false
|
||||
|
||||
return true
|
||||
|
|
@ -88,8 +91,8 @@ export type WithoutProps = FilterGenerator<
|
|||
*/
|
||||
export const withSingleProp = createFilterGenerator<Parameters<WithSingleProp>>(
|
||||
([prop], _, exports) => {
|
||||
if (typeof exports === 'object' && prop in exports)
|
||||
return Object.keys(exports).length === 1
|
||||
if (typeof exports === 'object' && exports !== null && prop in exports)
|
||||
return Reflect.ownKeys(exports).length === 1
|
||||
|
||||
return false
|
||||
},
|
||||
|
|
@ -133,7 +136,7 @@ export type WithSingleProp = FilterGenerator<
|
|||
* // const SomeClass: { new(): SomeClass, name: 'SomeClass' }
|
||||
*/
|
||||
export const withName = createFilterGenerator<Parameters<WithName>>(
|
||||
([name], _, exports) => exports.name === name,
|
||||
([name], _, exports) => exports?.name === name,
|
||||
([name]) => `revenge.name(${name})`,
|
||||
FilterFlag.RequiresExports,
|
||||
FilterScopes.Initialized,
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ const Helpers: FilterHelpers = Object.setPrototypeOf(
|
|||
* ```ts
|
||||
* const custom = createFilterGenerator<[arg1: number, arg2: string]>(
|
||||
* ([arg1, arg2], id, exports) => {
|
||||
* // WARNING: exports can be Proxy or nullish, so be careful when using it
|
||||
* // filter logic
|
||||
* return true
|
||||
* },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { isProxy } from '@revenge-mod/utils/proxy'
|
||||
import { mDeps, mList } from './patches'
|
||||
import { Initialized } from './runtime'
|
||||
import type { Metro } from '../types'
|
||||
|
|
@ -38,8 +37,11 @@ export function getInitializedModuleExports(
|
|||
return mList.get(id)?.module?.exports
|
||||
}
|
||||
|
||||
const CATCH_ALL_TEST = Symbol()
|
||||
|
||||
/**
|
||||
* Returns whether a particular module export is bad. This is used for filter functions to check whether an export is filterable.
|
||||
* Returns whether a particular module export is bad.
|
||||
* This is used for filter functions to check whether an export is filterable.
|
||||
* @param exp The export to check.
|
||||
*/
|
||||
export function isModuleExportBad(
|
||||
|
|
@ -48,9 +50,7 @@ export function isModuleExportBad(
|
|||
return (
|
||||
// Nullish?
|
||||
exp == null ||
|
||||
// Is it a proxy? (discord-intl has proxy exports)
|
||||
isProxy(exp) ||
|
||||
// Does it have some non-existent key? (Turbo modules)
|
||||
(typeof exp === 'object' && '\u0001' in exp)
|
||||
(typeof exp === 'object' && CATCH_ALL_TEST in exp)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
createFilterGenerator,
|
||||
withDependencies,
|
||||
} from '@revenge-mod/modules/finders/filters'
|
||||
import { isModuleExportBad } from '@revenge-mod/modules/metro/utils'
|
||||
import {
|
||||
ReactJSXRuntimeModuleId,
|
||||
ReactModuleId,
|
||||
|
|
@ -86,7 +87,7 @@ export const withGeneratedIconComponent = createFilterGenerator<
|
|||
Parameters<WithGeneratedIconComponent>
|
||||
>(
|
||||
(names, id, exports) => {
|
||||
if (typeof exports === 'object') {
|
||||
if (typeof exports === 'object' && isModuleExportBad(exports)) {
|
||||
if (typeof exports[names[0]] === 'function')
|
||||
return Object.keys(exports).length === 1
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue