feat(lib/modules): export metro, fix finders result checks, refactor filters to use creator function, add loose dependency checks
This commit is contained in:
parent
e39ad598d9
commit
f9c048b623
9 changed files with 221 additions and 148 deletions
|
|
@ -10,7 +10,7 @@
|
|||
"default": "./src/finders/filters.ts"
|
||||
},
|
||||
"./metro": {
|
||||
"default": "./src/metro.ts"
|
||||
"default": "./src/metro/index.ts"
|
||||
},
|
||||
"./metro/subscriptions": {
|
||||
"default": "./src/metro/subscriptions/index.ts"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { _isExportBad } from '../metro/_internal'
|
||||
import { isModuleExportBad } from '../metro'
|
||||
|
||||
import type { If } from '@revenge-mod/utils/types'
|
||||
import type { Metro } from '../../types/metro'
|
||||
|
|
@ -72,7 +72,7 @@ export function runFilter(
|
|||
const { default: defaultExport } = exports
|
||||
|
||||
// TODO(modules/caches/flags): could cache here that default export is bad
|
||||
if (!options?.esmSkipDefault && !_isExportBad(defaultExport) && filter(id, defaultExport)) {
|
||||
if (!options?.esmSkipDefault && !isModuleExportBad(defaultExport) && filter(id, defaultExport)) {
|
||||
// TODO(modules/finders/caches::esm::default)
|
||||
return FilterResultFlags.ESModuleDefault
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { _mInited, _mMetadatas } from '../metro/_internal'
|
||||
import { _mInited } from '../metro/_internal'
|
||||
|
||||
import { getModuleDependencies } from '../metro'
|
||||
|
||||
import type { If, LogicalOr } from '@revenge-mod/utils/types'
|
||||
import type { Metro } from '../../types/metro'
|
||||
|
|
@ -46,13 +48,13 @@ export function createFilterGenerator<A extends any[]>(
|
|||
): (...args: A) => Filter<object, false>
|
||||
|
||||
export function createFilterGenerator<A extends any[]>(
|
||||
filter: (args: A, id: Metro.ModuleID, exports?: Metro.ModuleExports) => boolean,
|
||||
f: (args: A, id: Metro.ModuleID, exports?: Metro.ModuleExports) => boolean,
|
||||
keyFor: (args: A) => string,
|
||||
): (...args: any[]) => Filter {
|
||||
return (...args: A) => {
|
||||
const f = (id: Metro.ModuleID, exports?: Metro.ModuleExports) => filter(args, id, exports)
|
||||
f.key = keyFor(args)
|
||||
return f
|
||||
const filter = (id: Metro.ModuleID, exports?: Metro.ModuleExports) => f(args, id, exports)
|
||||
filter.key = keyFor(args)
|
||||
return filter
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +76,7 @@ export type ByProps = <T extends Record<string, any> = Record<string, any>>(
|
|||
* ```
|
||||
*/
|
||||
export const byProps = createFilterGenerator<Parameters<ByProps>>(
|
||||
(props, _, exports) => props.every(prop => prop in exports),
|
||||
(props, _, exports) => typeof exports === 'object' && props.every(prop => prop in exports),
|
||||
props => `revenge.props(${props.join(',')})`,
|
||||
) as ByProps
|
||||
|
||||
|
|
@ -117,10 +119,15 @@ export const byName = createFilterGenerator<Parameters<ByName>>(
|
|||
([name]) => `revenge.name(${name})`,
|
||||
) as ByName
|
||||
|
||||
export type ComparableDependencyMap = Array<Metro.ModuleID | undefined | ComparableDependencyMap> & {
|
||||
loose?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter modules by their dependency map.
|
||||
*
|
||||
* @param deps The dependency map to check for, can be a sparse array or have `undefined` for "any dependency". **Order and size matters!**
|
||||
* @param deps The dependency map to check for, can be a sparse array or have `undefined` to be any dependency ("dynamic"). **Order and size matters!**
|
||||
* @see {@link looseDeps} to make comparisons less strict.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
|
|
@ -129,21 +136,78 @@ export const byName = createFilterGenerator<Parameters<ByName>>(
|
|||
* const Logger = await findModule(byDependencies([4, , 2]))
|
||||
* ```
|
||||
*/
|
||||
export const byDependencies = createFilterGenerator<[Array<Metro.ModuleID | undefined>]>(
|
||||
([deps], id) => {
|
||||
const actDeps = _mMetadatas.get(id)![0]
|
||||
if (actDeps.length === deps.length)
|
||||
for (let i = 0; i < deps.length; i++) {
|
||||
const cmp = deps[i]
|
||||
if (Number.isInteger(cmp) && actDeps[i] !== cmp) return false
|
||||
}
|
||||
else return false
|
||||
|
||||
return true
|
||||
},
|
||||
deps => `revenge.deps(${deps.join(',')})`,
|
||||
export const byDependencies = createFilterGenerator<[deps: ComparableDependencyMap]>(
|
||||
([deps], id) => compareDeps(id, deps, deps.loose),
|
||||
deps => `revenge.deps(${depsToKey(deps)})`,
|
||||
)
|
||||
|
||||
/**
|
||||
* Make this set of comparable dependencies as loose, to be used with {@link byDependencies}.
|
||||
*
|
||||
* Making a dependency loose skips the exact length check, but the order of the set dependencies still matters.
|
||||
* If you mark an index as dynamic, the same index must also be present in the other map during comparison to pass.
|
||||
*
|
||||
* @param deps The dependency map to make loose. This permanently modifies the array.
|
||||
* @returns The modified dependency map.
|
||||
*/
|
||||
export function looseDeps(deps: ComparableDependencyMap) {
|
||||
deps.loose = true
|
||||
return deps
|
||||
}
|
||||
|
||||
function compareDeps(of: Metro.ModuleID, compare: ComparableDependencyMap, loose = false): boolean {
|
||||
const stack: Array<[of: Metro.ModuleID[], compare: ComparableDependencyMap, loose: boolean]> = []
|
||||
stack.push([getModuleDependencies(of)!, compare, loose])
|
||||
|
||||
while (stack.length) {
|
||||
const [of, compare, loose] = stack.pop()!
|
||||
if (loose ? of.length < compare.length : of.length !== compare.length) return false
|
||||
|
||||
for (let i = 0; i < compare.length; i++) {
|
||||
const orig = of[i]
|
||||
const cmp = compare[i]
|
||||
if (cmp === undefined) continue
|
||||
|
||||
if (Array.isArray(cmp)) {
|
||||
const dependencies = getModuleDependencies(orig)
|
||||
if (!dependencies) return false
|
||||
stack.push([dependencies, cmp, cmp.loose ?? false])
|
||||
} else if (orig !== cmp) return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function depsToKey(deps: ComparableDependencyMap): string {
|
||||
let key = ''
|
||||
|
||||
for (const dep of deps)
|
||||
if (dep === undefined) key += ','
|
||||
else if (Array.isArray(dep)) {
|
||||
if (dep.loose) key += '#'
|
||||
key += `[${depsToKey(dep)}],`
|
||||
} else key += `${dep},`
|
||||
|
||||
return key.substring(0, key.length - 1)
|
||||
}
|
||||
|
||||
export type Every = {
|
||||
<F1 extends Filter, F2 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
): Filter<FilterResult<F1> & FilterResult<F2>, LogicalOr<IsFilterWithExports<F1>, IsFilterWithExports<F2>>>
|
||||
<F1 extends Filter, F2 extends Filter, F3 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
f3: F3,
|
||||
): Filter<
|
||||
FilterResult<F1> & FilterResult<F2> & FilterResult<F3>,
|
||||
LogicalOr<LogicalOr<IsFilterWithExports<F1>, IsFilterWithExports<F2>>, IsFilterWithExports<F3>>
|
||||
>
|
||||
(...filters: Filter[]): Filter
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines multiple filters into one, returning true if **every** filter matches.
|
||||
*
|
||||
|
|
@ -158,29 +222,25 @@ export const byDependencies = createFilterGenerator<[Array<Metro.ModuleID | unde
|
|||
* ))
|
||||
* ```
|
||||
*/
|
||||
export function every<F1 extends Filter, F2 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
): Filter<FilterResult<F1> & FilterResult<F2>, LogicalOr<IsFilterWithExports<F1>, IsFilterWithExports<F2>>>
|
||||
export const every = createFilterGenerator<[...filters: Filter[]]>(
|
||||
(filters, id, exports) => filters.every(filter => filter(id, exports)),
|
||||
filters => `revenge.every(${filtersToKey(filters)})`,
|
||||
) as Every
|
||||
|
||||
export function every<F1 extends Filter, F2 extends Filter, F3 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
f3: F3,
|
||||
): Filter<
|
||||
FilterResult<F1> & FilterResult<F2> & FilterResult<F3>,
|
||||
LogicalOr<LogicalOr<IsFilterWithExports<F1>, IsFilterWithExports<F2>>, IsFilterWithExports<F3>>
|
||||
>
|
||||
|
||||
export function every(...filters: Filter[]): Filter {
|
||||
const f = (id: Metro.ModuleID, exports?: Metro.ModuleExports) => {
|
||||
for (const filter of filters) if (!filter(id, exports)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
f.key = `revenge.every(${filters.map(filter => filter.key).join(',')})`
|
||||
|
||||
return f
|
||||
export type Some = {
|
||||
<F1 extends Filter, F2 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
): Filter<FilterResult<F1> | FilterResult<F2>, IsFilterWithExports<F1> | IsFilterWithExports<F2>>
|
||||
<F1 extends Filter, F2 extends Filter, F3 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
f3: F3,
|
||||
): Filter<
|
||||
FilterResult<F1> | FilterResult<F2> | FilterResult<F3>,
|
||||
IsFilterWithExports<F1> | IsFilterWithExports<F2> | IsFilterWithExports<F3>
|
||||
>
|
||||
(...filters: Filter[]): Filter
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -197,31 +257,22 @@ export function every(...filters: Filter[]): Filter {
|
|||
* ))
|
||||
* ```
|
||||
*/
|
||||
export function some<F1 extends Filter, F2 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
): Filter<FilterResult<F1> | FilterResult<F2>, IsFilterWithExports<F1> | IsFilterWithExports<F2>>
|
||||
export const some = createFilterGenerator<[...filters: Filter[]]>(
|
||||
(filters, id, exports) => filters.some(filter => filter(id, exports)),
|
||||
filters => `revenge.some(${filtersToKey(filters)})`,
|
||||
) as Some
|
||||
|
||||
export function some<F1 extends Filter, F2 extends Filter, F3 extends Filter>(
|
||||
f1: F1,
|
||||
f2: F2,
|
||||
f3: F3,
|
||||
): Filter<
|
||||
FilterResult<F1> | FilterResult<F2> | FilterResult<F3>,
|
||||
IsFilterWithExports<F1> | IsFilterWithExports<F2> | IsFilterWithExports<F3>
|
||||
>
|
||||
|
||||
export function some(...filters: Filter[]): Filter {
|
||||
const f = (id: Metro.ModuleID, exports?: Metro.ModuleExports) => {
|
||||
for (const filter of filters) if (filter(id, exports)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
f.key = `revenge.some(${filters.map(filter => filter.key).join(',')})`
|
||||
|
||||
return f
|
||||
function filtersToKey(filters: Filter[]): string {
|
||||
let s = ''
|
||||
for (const filter of filters) s += `${filter.key},`
|
||||
return s.substring(0, s.length - 1)
|
||||
}
|
||||
|
||||
export type ModuleStateAware = <IF extends Filter>(
|
||||
initializedFilter: IF,
|
||||
uninitializedFilter: Filter<any, false>,
|
||||
) => Filter<FilterResult<IF>, false>
|
||||
|
||||
/**
|
||||
* Filter modules depending on their initialized state.
|
||||
*
|
||||
|
|
@ -238,16 +289,10 @@ export function some(...filters: Filter[]): Filter {
|
|||
* ))
|
||||
* ```
|
||||
*/
|
||||
export function moduleStateAware<IF extends Filter>(
|
||||
initializedFilter: IF,
|
||||
uninitializedFilter: Filter<any, false>,
|
||||
): Filter<FilterResult<IF>, false> {
|
||||
const f = (id: Metro.ModuleID, exports?: Metro.ModuleExports) => {
|
||||
export const moduleStateAware = createFilterGenerator<Parameters<ModuleStateAware>>(
|
||||
([initializedFilter, uninitializedFilter], id, exports) => {
|
||||
if (_mInited.has(id)) return initializedFilter(id, exports)
|
||||
return uninitializedFilter(id)
|
||||
}
|
||||
|
||||
f.key = `revenge.moduleStateAware(${initializedFilter.key},${uninitializedFilter.key})`
|
||||
|
||||
return f
|
||||
}
|
||||
},
|
||||
([f1, f2]) => `revenge.moduleStateAware(${f1.key},${f2.key})`,
|
||||
) as ModuleStateAware
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function findModule<F extends Filter, O extends FindModuleOptions>(filter
|
|||
return new Promise<O extends RunFilterReturnExportsOptions<true> ? MaybeDefaultExportMatched<Result> : Result>(
|
||||
(ok, err) => {
|
||||
const exports = lookupModule<F, O>(filter, options!)
|
||||
if (exports !== undefined) return ok(exports)
|
||||
if (exports != null) return ok(exports)
|
||||
|
||||
const unsub = waitForModules<F, O>(
|
||||
filter,
|
||||
|
|
@ -105,7 +105,7 @@ export function findModuleId<F extends Filter, O extends FindModuleIdOptions>(
|
|||
export function findModuleId(filter: Filter, options?: FindModuleIdOptions) {
|
||||
return new Promise<Metro.ModuleID>((ok, err) => {
|
||||
const id = lookupModuleId(filter, options)
|
||||
if (id !== undefined) {
|
||||
if (id != null) {
|
||||
ok(id)
|
||||
return
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ export function findModuleId(filter: Filter, options?: FindModuleIdOptions) {
|
|||
export function findModuleByImportedPath<T>(path: string, options?: BaseFindModuleOptions): Promise<T> {
|
||||
return new Promise((ok, err) => {
|
||||
const exports = lookupModuleByImportedPath(path)
|
||||
if (exports !== undefined) {
|
||||
if (exports != null) {
|
||||
ok(exports)
|
||||
return
|
||||
}
|
||||
|
|
@ -221,7 +221,7 @@ export function findModuleSync<F extends Filter, O extends FindModuleSyncOptions
|
|||
|
||||
export function findModuleSync<F extends Filter, O extends FindModuleSyncOptions>(filter: F, options?: O) {
|
||||
const exports = lookupModule(filter, options!)
|
||||
if (exports !== undefined) return exports
|
||||
if (exports != null) return exports
|
||||
|
||||
let value: unknown | undefined
|
||||
const unsub = waitForModules(
|
||||
|
|
@ -261,7 +261,7 @@ export function findModuleByImportedPathSync<T = any>(
|
|||
options?: BaseFindModuleSyncOptions,
|
||||
): T | undefined {
|
||||
const exports = lookupModuleByImportedPath<T>(path)
|
||||
if (exports !== undefined) return exports
|
||||
if (exports != null) return exports
|
||||
|
||||
let value: unknown | undefined
|
||||
const unsub = waitForModuleByImportedPath(path, (_, exports) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { _mInited, _mMetadatas, _mPaths, _mUninited } from '../metro/_internal'
|
||||
import { _mInited, _mPaths, _mUninited } from '../metro/_internal'
|
||||
import {
|
||||
type RunFilterOptions,
|
||||
type RunFilterReturnExportsOptions,
|
||||
|
|
@ -6,6 +6,8 @@ import {
|
|||
runFilterReturnExports,
|
||||
} from './_internal'
|
||||
|
||||
import { getInitializedModuleExports } from '../metro'
|
||||
|
||||
import type { MaybeDefaultExportMatched } from '.'
|
||||
import type { Metro } from '../../types/metro'
|
||||
import type { Filter, FilterResult } from './filters'
|
||||
|
|
@ -71,10 +73,7 @@ export function* lookupModuleIds<O extends LookupModuleIdsOptions>(
|
|||
options?: O,
|
||||
): Generator<Metro.ModuleID, undefined> {
|
||||
if (options?.includeInitialized ?? true)
|
||||
for (const id of _mInited) {
|
||||
const { exports } = _mMetadatas.get(id)![1]!
|
||||
if (runFilter(filter, id, exports, options)) yield id
|
||||
}
|
||||
for (const id of _mInited) if (runFilter(filter, id, getInitializedModuleExports(id), options)) yield id
|
||||
|
||||
if (options?.includeUninitialized) for (const id of _mUninited) if (runFilter(filter, id)) yield id
|
||||
}
|
||||
|
|
@ -106,9 +105,8 @@ export function lookupModules<
|
|||
export function* lookupModules(filter: Filter, options?: LookupModulesOptions) {
|
||||
if (options?.includeInitialized ?? true)
|
||||
for (const id of _mInited) {
|
||||
const { exports } = _mMetadatas.get(id)![1]!
|
||||
const result = runFilterReturnExports(filter, id, exports, options)
|
||||
if (result) yield result
|
||||
const result = runFilterReturnExports(filter, id, getInitializedModuleExports(id), options)
|
||||
if (result != null) yield result
|
||||
}
|
||||
|
||||
if (options?.includeUninitialized) for (const id of _mUninited) if (runFilter(filter, id)) yield __r(id)
|
||||
|
|
@ -142,10 +140,7 @@ export function lookupModuleId<O extends LookupModuleIdsOptions>(
|
|||
options?: O,
|
||||
): Metro.ModuleID | undefined {
|
||||
if (options?.includeInitialized ?? true)
|
||||
for (const id of _mInited) {
|
||||
const { exports } = _mMetadatas.get(id)![1]!
|
||||
if (runFilter(filter, id, exports, options)) return id
|
||||
}
|
||||
for (const id of _mInited) if (runFilter(filter, id, getInitializedModuleExports(id), options)) return id
|
||||
|
||||
if (options?.includeUninitialized) for (const id of _mUninited) if (runFilter(filter, id)) return id
|
||||
}
|
||||
|
|
@ -174,9 +169,8 @@ export function lookupModule<F extends Filter, O extends LookupModulesOptions>(
|
|||
export function lookupModule(filter: Filter, options?: LookupModulesOptions) {
|
||||
if (options?.includeInitialized ?? true)
|
||||
for (const id of _mInited) {
|
||||
const { exports } = _mMetadatas.get(id)![1]!
|
||||
const result = runFilterReturnExports(filter, id, exports, options)
|
||||
if (result) return result
|
||||
const result = runFilterReturnExports(filter, id, getInitializedModuleExports(id), options)
|
||||
if (result != null) return result
|
||||
}
|
||||
|
||||
if (options?.includeUninitialized) for (const id of _mUninited) if (runFilter(filter, id)) return __r(id)
|
||||
|
|
@ -199,5 +193,5 @@ export function lookupModuleByImportedPath<T = any>(path: string): T | undefined
|
|||
const id = _mPaths.get(path)
|
||||
if (id === undefined) return
|
||||
|
||||
if (_mMetadatas.has(id)) return _mMetadatas.get(id)![1]!.exports
|
||||
return getInitializedModuleExports(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { onAnyModuleInitialized, onModuleFinishedImporting } from '../metro'
|
||||
import { _bl, _mMetadatas } from '../metro/_internal'
|
||||
import { getInitializedModuleExports, isBlacklisted, onAnyModuleInitialized, onModuleFinishedImporting } from '../metro'
|
||||
import { runFilterReturnExports, type RunFilterReturnExportsOptions } from './_internal'
|
||||
|
||||
import type { MaybeDefaultExportMatched } from '.'
|
||||
|
|
@ -51,9 +50,9 @@ export function waitForModules(
|
|||
options?: WaitForModulesOptions,
|
||||
) {
|
||||
const unsub = onAnyModuleInitialized((id, exports) => {
|
||||
if (_bl.has(id)) return
|
||||
if (isBlacklisted(id)) return
|
||||
const result = runFilterReturnExports(filter, id, exports, options)
|
||||
if (result) callback(id, exports)
|
||||
if (result != null) callback(id, exports)
|
||||
})
|
||||
|
||||
return unsub
|
||||
|
|
@ -81,9 +80,8 @@ export function waitForModules(
|
|||
export function waitForModuleByImportedPath<T = any>(path: string, callback: (id: Metro.ModuleID, exports: T) => any) {
|
||||
const unsub = onModuleFinishedImporting((id, cmpPath) => {
|
||||
if (path === cmpPath) {
|
||||
const { exports } = _mMetadatas.get(id)![1]!
|
||||
callback(id, exports)
|
||||
unsub()
|
||||
callback(id, getInitializedModuleExports(id))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { isProxy } from '@revenge-mod/utils/proxy'
|
||||
import { _executeSubscription } from './subscriptions/_internal'
|
||||
|
||||
import type { Metro } from '../../types/metro'
|
||||
import { isBlacklisted, isModuleExportBad } from '.'
|
||||
|
||||
export const _bl = new Set<Metro.ModuleID>()
|
||||
|
||||
|
|
@ -12,16 +12,16 @@ export const _mUninited = new Set<Metro.ModuleID>()
|
|||
/** Initialized IDs */
|
||||
export const _mInited = new Set<Metro.ModuleID>()
|
||||
|
||||
export const _mMetadatas = new Map<Metro.ModuleID, [deps: Metro.DependencyMap, module?: Metro.Module]>()
|
||||
export const _mPaths = new Map<string, Metro.ModuleID>()
|
||||
export const _mMd = new Map<Metro.ModuleID, [deps: Metro.DependencyMap, module?: Metro.Module]>()
|
||||
|
||||
export function patchMetroDefine(metroDefine: Metro.DefineFn) {
|
||||
return ((origFactory, id, deps) => {
|
||||
// deps won't be undefined last time I checked
|
||||
const metadata = [deps!] as typeof _mMetadatas extends Map<any, infer V> ? V : never
|
||||
_mMetadatas.set(id, metadata)
|
||||
const metadata = [deps!] as typeof _mMd extends Map<any, infer V> ? V : never
|
||||
_mMd.set(id, metadata)
|
||||
|
||||
if (_bl.has(id)) {
|
||||
if (isBlacklisted(id)) {
|
||||
metroDefine(origFactory, id, deps)
|
||||
return
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ export function patchMetroDefine(metroDefine: Metro.DefineFn) {
|
|||
try {
|
||||
origFactory(g, r, ipD, ipA, m, e, d)
|
||||
|
||||
if (_isExportsBad(m.exports)) _blacklist(id)
|
||||
if (isModuleExportBad(m.exports)) _blacklist(id)
|
||||
// If exports isn't bad, we can put it in the list of initialized modules
|
||||
else _mInited.add(id)
|
||||
} finally {
|
||||
|
|
@ -58,9 +58,9 @@ export function patchMetroDefine(metroDefine: Metro.DefineFn) {
|
|||
*
|
||||
* Blacklisting modules prevents Revenge from doing the following things:
|
||||
*
|
||||
* - Iterating over the module during `find()`s
|
||||
* - Iterating over the module during `find()`s.
|
||||
*
|
||||
* @param id The module ID to blacklist
|
||||
* @param id The module ID to blacklist.
|
||||
* @internal
|
||||
*/
|
||||
export function _blacklist(id: Metro.ModuleID) {
|
||||
|
|
@ -72,34 +72,3 @@ export function _blacklist(id: Metro.ModuleID) {
|
|||
|
||||
// TODO(modules): caching
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 _isExportBad(exp: Metro.ModuleExports[PropertyKey]) {
|
||||
return (
|
||||
// Nullish?
|
||||
exp == null ||
|
||||
// Is it a proxy? (discord-intl has proxy exports)
|
||||
isProxy(exp)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the module has bad exports. If it does, it should be blacklisted and never hooked into.
|
||||
* @param exports The exports of the module
|
||||
* @returns Whether the module has bad exports
|
||||
* @internal
|
||||
*/
|
||||
export function _isExportsBad(exports: Metro.ModuleExports) {
|
||||
return (
|
||||
// Nullish?
|
||||
exports == null ||
|
||||
// Checking if the object is empty
|
||||
(exports.__proto__ === Object.prototype && !Reflect.ownKeys(exports).length) ||
|
||||
// Can't run isProxy() on this because this isn't your typical proxy:
|
||||
// https://github.com/discord/react-native/blob/master/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp
|
||||
exports === nativeModuleProxy
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,72 @@
|
|||
import { isProxy } from '@revenge-mod/utils/proxy'
|
||||
|
||||
import { _bl, _mMd, _mInited } from './_internal'
|
||||
|
||||
import type { Metro } from '../../types/metro'
|
||||
|
||||
import './patches'
|
||||
|
||||
export * from './subscriptions'
|
||||
|
||||
/**
|
||||
* Returns whether a module is blacklisted.
|
||||
* @param id The module ID to check.
|
||||
*/
|
||||
export function isBlacklisted(id: Metro.ModuleID) {
|
||||
return _bl.has(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a module is initialized.
|
||||
* @param id The module ID to check.
|
||||
*/
|
||||
export function isModuleInitialized(id: Metro.ModuleID) {
|
||||
return _mInited.has(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dependencies of a module.
|
||||
* @param id The module ID.
|
||||
*/
|
||||
export function getModuleDependencies(id: Metro.ModuleID) {
|
||||
return _mMd.get(id)?.[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exports of an initialized module.
|
||||
* @param id The module ID.
|
||||
*/
|
||||
export function getInitializedModuleExports(id: Metro.ModuleID) {
|
||||
return _mMd.get(id)?.[1]?.exports
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(exp: Metro.ModuleExports[PropertyKey]) {
|
||||
return (
|
||||
// Nullish?
|
||||
exp == null ||
|
||||
// Is it a proxy? (discord-intl has proxy exports)
|
||||
isProxy(exp)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the module has bad exports. If it does, it should be blacklisted and never hooked into.
|
||||
* @param exports The exports of the module.
|
||||
*/
|
||||
export function isModuleExportsBad(exports: Metro.ModuleExports) {
|
||||
return (
|
||||
// Nullish?
|
||||
exports == null ||
|
||||
// Checking if the object is empty
|
||||
(exports.__proto__ === Object.prototype && !Reflect.ownKeys(exports).length) ||
|
||||
// Can't run isProxy() on this because this isn't your typical proxy:
|
||||
// https://github.com/discord/react-native/blob/master/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp
|
||||
exports === nativeModuleProxy
|
||||
)
|
||||
}
|
||||
|
||||
// TODO(modules): caching
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import '@revenge-mod/assets/patches'
|
||||
|
||||
import { _bl, _mInitingId, _mMetadatas, _mPaths, _mUninited } from './_internal'
|
||||
import { onAnyModuleInitialized } from './subscriptions'
|
||||
import { _mInitingId, _mPaths } from './_internal'
|
||||
|
||||
import { _executeImportedPathSubscription } from './subscriptions/_internal'
|
||||
|
||||
const unsubForImportTracker = onAnyModuleInitialized((id, exports) => {
|
||||
if (_bl.has(id)) return
|
||||
import { waitForModules } from '../finders'
|
||||
import { byProps } from '../finders/filters'
|
||||
|
||||
const unsubForImportTracker = waitForModules(byProps('fileFinishedImporting'), (_, exports) => {
|
||||
const orig = exports.fileFinishedImporting
|
||||
if (orig) {
|
||||
unsubForImportTracker()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue