fix(lib): refactor modules, react, utils
This commit is contained in:
parent
c11a74bc35
commit
bea3439c5e
25 changed files with 206 additions and 205 deletions
|
|
@ -5,7 +5,7 @@ import { AssetRegistry } from './preinit'
|
|||
|
||||
import type { Asset, AssetId, RegisterableAsset } from './types'
|
||||
|
||||
export * from './preinit'
|
||||
export { AssetRegistry, AssetRegistryModuleId } from './preinit'
|
||||
|
||||
// iOS cannot display SVGs
|
||||
let _preferredType: Asset['type'] = ReactNative.Platform.OS === 'ios' ? 'png' : 'svg'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { _mInitingId, _mUninited } from '@revenge-mod/modules/_/metro'
|
||||
import { waitForModules } from '@revenge-mod/modules/finders'
|
||||
import { _initing, _uninits } from '@revenge-mod/modules/_/metro'
|
||||
import { byName, byProps } from '@revenge-mod/modules/finders/filters'
|
||||
import { getModuleDependencies } from '@revenge-mod/modules/metro'
|
||||
import { waitForModules } from '@revenge-mod/modules/finders/wait'
|
||||
import { getModuleDependencies } from '@revenge-mod/modules/metro/utils'
|
||||
|
||||
import { _assets, _metas, _overrides } from './_internal'
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ const unsubAR = waitForModules(byProps<ReactNative.AssetsRegistry>('registerAsse
|
|||
// More fragile way, but also more performant:
|
||||
// There is exactly one asset before the reexported asset registry :/
|
||||
const firstAssetModuleId = id - 1
|
||||
for (const mId of _mUninited) {
|
||||
for (const mId of _uninits) {
|
||||
if (mId < firstAssetModuleId) continue
|
||||
|
||||
const deps = getModuleDependencies(mId)!
|
||||
|
|
@ -53,7 +53,7 @@ const unsubAR = waitForModules(byProps<ReactNative.AssetsRegistry>('registerAsse
|
|||
|
||||
// In-memory cache
|
||||
reg[1][type] = asset
|
||||
_metas.set(asset, [result, _mInitingId])
|
||||
_metas.set(asset, [result, _initing])
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
6
lib/externals/src/browserify.ts
vendored
6
lib/externals/src/browserify.ts
vendored
|
|
@ -1,11 +1,11 @@
|
|||
import { lookupModule } from '@revenge-mod/modules/finders'
|
||||
import { byDependencies, byProps, moduleStateAware, relativeDep } from '@revenge-mod/modules/finders/filters'
|
||||
import { byDependencies, byProps, preferExports, relativeDep } from '@revenge-mod/modules/finders/filters'
|
||||
import { lookupModule } from '@revenge-mod/modules/finders/lookup'
|
||||
import { proxify } from '@revenge-mod/utils/proxy'
|
||||
|
||||
export let nodeUtil: typeof import('node:util') = proxify(
|
||||
() => {
|
||||
const module = lookupModule(
|
||||
moduleStateAware(byProps<typeof nodeUtil>('inspect'), byDependencies([relativeDep(1), [], []])),
|
||||
preferExports(byProps<typeof nodeUtil>('inspect'), byDependencies([relativeDep(1), [], []])),
|
||||
{
|
||||
includeUninitialized: true,
|
||||
},
|
||||
|
|
|
|||
8
lib/externals/src/react-navigation.ts
vendored
8
lib/externals/src/react-navigation.ts
vendored
|
|
@ -1,6 +1,6 @@
|
|||
import { byDependencies, byName, byProps, looseDeps, preferExports } from '@revenge-mod/modules/finders/filters'
|
||||
import { lookupModule, lookupModuleId } from '@revenge-mod/modules/finders/lookup'
|
||||
import { proxify } from '@revenge-mod/utils/proxy'
|
||||
import { lookupModule, lookupModuleId } from '@revenge-mod/modules/finders'
|
||||
import { byDependencies, byName, byProps, looseDeps, moduleStateAware } from '@revenge-mod/modules/finders/filters'
|
||||
|
||||
const _createClassModuleId = lookupModuleId(byName('_createClass'))
|
||||
const _classCallCheckModuleId = lookupModuleId(byName('_classCallCheck'))
|
||||
|
|
@ -8,7 +8,7 @@ const _classCallCheckModuleId = lookupModuleId(byName('_classCallCheck'))
|
|||
export let ReactNavigationNative: typeof import('@react-navigation/native') = proxify(
|
||||
() => {
|
||||
const module = lookupModule(
|
||||
moduleStateAware(
|
||||
preferExports(
|
||||
byProps<typeof ReactNavigationNative>('useLinkTo'),
|
||||
byDependencies(looseDeps([[], looseDeps([[_createClassModuleId, _classCallCheckModuleId]])])),
|
||||
),
|
||||
|
|
@ -27,7 +27,7 @@ export let ReactNavigationNative: typeof import('@react-navigation/native') = pr
|
|||
export let ReactNavigationStack: typeof import('@react-navigation/stack') = proxify(
|
||||
() => {
|
||||
const module = lookupModule(
|
||||
moduleStateAware(
|
||||
preferExports(
|
||||
byProps<typeof ReactNavigationStack>('createStackNavigator'),
|
||||
byDependencies(looseDeps([[], looseDeps([[_createClassModuleId, _classCallCheckModuleId]])])),
|
||||
),
|
||||
|
|
|
|||
6
lib/externals/src/shopify.ts
vendored
6
lib/externals/src/shopify.ts
vendored
|
|
@ -1,5 +1,5 @@
|
|||
import { byDependencies, byProps, moduleStateAware } from '@revenge-mod/modules/finders/filters'
|
||||
import { lookupModule } from '@revenge-mod/modules/finders'
|
||||
import { byDependencies, byProps, preferExports } from '@revenge-mod/modules/finders/filters'
|
||||
import { lookupModule } from '@revenge-mod/modules/finders/lookup'
|
||||
import { proxify } from '@revenge-mod/utils/proxy'
|
||||
|
||||
import { ReactJsxRuntimeModuleId, ReactModuleId, ReactNativeModuleId } from '@revenge-mod/react'
|
||||
|
|
@ -7,7 +7,7 @@ import { ReactJsxRuntimeModuleId, ReactModuleId, ReactNativeModuleId } from '@re
|
|||
export let FlashList: typeof import('@shopify/flash-list') = proxify(
|
||||
() => {
|
||||
const module = lookupModule(
|
||||
moduleStateAware(
|
||||
preferExports(
|
||||
byProps<typeof FlashList>('FlashList'),
|
||||
// biome-ignore lint/suspicious/noSparseArray: don't care
|
||||
byDependencies([ReactModuleId, ReactNativeModuleId, ReactJsxRuntimeModuleId, , , , 2, ,]),
|
||||
|
|
|
|||
|
|
@ -3,21 +3,24 @@
|
|||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"default": "./src/index.ts"
|
||||
},
|
||||
"./finders": {
|
||||
"default": "./src/finders/index.ts"
|
||||
},
|
||||
"./finders/filters": {
|
||||
"default": "./src/finders/filters.ts"
|
||||
},
|
||||
"./metro": {
|
||||
"default": "./src/metro/index.ts"
|
||||
"./finders/find": {
|
||||
"default": "./src/finders/find.ts"
|
||||
},
|
||||
"./finders/lookup": {
|
||||
"default": "./src/finders/lookup.ts"
|
||||
},
|
||||
"./finders/wait": {
|
||||
"default": "./src/finders/wait.ts"
|
||||
},
|
||||
"./metro/subscriptions": {
|
||||
"default": "./src/metro/subscriptions/index.ts"
|
||||
},
|
||||
"./metro/utils": {
|
||||
"default": "./src/metro/utils.ts"
|
||||
},
|
||||
"./native": {
|
||||
"default": "./src/native.ts"
|
||||
},
|
||||
|
|
@ -25,7 +28,7 @@
|
|||
"default": "./src/preinit.ts"
|
||||
},
|
||||
"./types": {
|
||||
"default": "./types.ts"
|
||||
"default": "./src/types.ts"
|
||||
},
|
||||
"./_/metro": {
|
||||
"default": "./src/metro/_internal.ts"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { isModuleExportBad } from '../metro'
|
||||
import { isModuleExportBad } from '../metro/utils'
|
||||
|
||||
import type { If } from '@revenge-mod/utils/types'
|
||||
import type { Metro } from '../../types'
|
||||
import type { Metro } from '../types'
|
||||
import type { Filter } from './filters'
|
||||
|
||||
export interface RunFilterOptions {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { _mInited } from '../metro/_internal'
|
||||
import { _inits } from '../metro/_internal'
|
||||
|
||||
import { getModuleDependencies, initializedModuleHasBadExports, isModuleInitialized } from '../metro'
|
||||
import { getModuleDependencies, initializedModuleHasBadExports, isModuleInitialized } from '../metro/utils'
|
||||
|
||||
import type { If, LogicalOr } from '@revenge-mod/utils/types'
|
||||
import type { Metro } from '../../types'
|
||||
import type { Metro } from '../types'
|
||||
|
||||
export type FilterResult<F> = F extends Filter<infer R, boolean> ? R : never
|
||||
|
||||
|
|
@ -79,8 +79,18 @@ export type ByProps = <T extends Record<string, any> = Record<string, any>>(
|
|||
* ```
|
||||
*/
|
||||
export const byProps = createFilterGenerator<Parameters<ByProps>>(
|
||||
(props, _, exports) =>
|
||||
(typeof exports === 'object' || typeof exports === 'function') && props.every(prop => prop in exports),
|
||||
(props, _, exports) => {
|
||||
if (typeof exports === 'object' || typeof exports === 'function') {
|
||||
for (const prop of props) {
|
||||
if (prop in exports) continue
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
props => `revenge.props(${props.join(',')})`,
|
||||
) as ByProps
|
||||
|
||||
|
|
@ -93,8 +103,12 @@ export type WithoutProps = <T extends Record<string, any>>(prop: string, ...prop
|
|||
* @param props More properties to check for (optional).
|
||||
*/
|
||||
export const withoutProps = createFilterGenerator<Parameters<WithoutProps>>(
|
||||
(props, _, exports) =>
|
||||
(typeof exports === 'object' || typeof exports === 'function') && !props.some(prop => prop in exports),
|
||||
(props, _, exports) => {
|
||||
if (typeof exports === 'object' || typeof exports === 'function')
|
||||
for (const prop of props) if (prop in exports) return false
|
||||
|
||||
return true
|
||||
},
|
||||
props => `revenge.withoutProps(${props.join(',')})`,
|
||||
) as WithoutProps
|
||||
|
||||
|
|
@ -173,7 +187,7 @@ type ByDependencies = <T>(deps: ComparableDependencyMap) => Filter<T, false>
|
|||
*/
|
||||
export const byDependencies = createFilterGenerator<Parameters<ByDependencies>>(
|
||||
([deps], id) => compareDeps(id, deps, deps.l),
|
||||
deps => `revenge.deps(${depsToKey(deps)})`,
|
||||
deps => `revenge.deps(${genDepsKey(deps)})`,
|
||||
) as ByDependencies
|
||||
|
||||
/**
|
||||
|
|
@ -194,21 +208,11 @@ export function looseDeps(deps: ComparableDependencyMap) {
|
|||
* Marks this dependency to compare relatively to the module ID being compared.
|
||||
*
|
||||
* @param id The dependency ID to mark as relative.
|
||||
* @param root Whether this dependency should be relatively to the root module ID. Useless for single-depth comparisons.
|
||||
*/
|
||||
export function relativeDep(id: Metro.ModuleID): RelativeDependency {
|
||||
export function relativeDep(id: Metro.ModuleID, root?: boolean): RelativeDependency {
|
||||
const o = Object(id) as RelativeDependency
|
||||
return o
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this dependency to compare relatively to the module ID that the filter is given.
|
||||
* Useless for single-depth comparisons, but useful for nested comparisons.
|
||||
*
|
||||
* @param id The dependency ID to mark as root relative.
|
||||
*/
|
||||
export function rootRelativeDep(id: Metro.ModuleID): RelativeDependency {
|
||||
const o = Object(id) as RelativeDependency
|
||||
o.r = true
|
||||
if (root) o.r = true
|
||||
return o
|
||||
}
|
||||
|
||||
|
|
@ -249,14 +253,14 @@ function compareDeps(rootOf: Metro.ModuleID, compare: ComparableDependencyMap, l
|
|||
return true
|
||||
}
|
||||
|
||||
function depsToKey(deps: ComparableDependencyMap): string {
|
||||
function genDepsKey(deps: ComparableDependencyMap): string {
|
||||
let key = ''
|
||||
|
||||
for (const dep of deps)
|
||||
if (dep === undefined) key += ','
|
||||
else if (Array.isArray(dep)) {
|
||||
if (dep.l) key += '#'
|
||||
key += `[${depsToKey(dep)}],`
|
||||
key += `[${genDepsKey(dep)}],`
|
||||
} else key += `${(dep as RelativeDependency).r ? `r${dep.valueOf()}` : dep.valueOf()},`
|
||||
|
||||
return key.substring(0, key.length - 1)
|
||||
|
|
@ -408,7 +412,7 @@ export type PreferExports = <WEF extends Filter>(
|
|||
*/
|
||||
export const preferExports = createFilterGenerator<Parameters<PreferExports>>(
|
||||
([withExportsFilter, exportslessFilter], id, exports) => {
|
||||
if (_mInited.has(id)) return withExportsFilter(id, exports)
|
||||
if (_inits.has(id)) return withExportsFilter(id, exports)
|
||||
return exportslessFilter(id)
|
||||
},
|
||||
([f1, f2]) => `revenge.preferExports(${f1.key},${f2.key})`,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ import { type LookupModulesOptions, lookupModule, lookupModuleByImportedPath, lo
|
|||
import { type WaitForModulesOptions, waitForModuleByImportedPath, waitForModules } from './wait'
|
||||
|
||||
import type { If } from '@revenge-mod/utils/types'
|
||||
import type { LookupModuleIdsOptions, MaybeDefaultExportMatched } from '.'
|
||||
import type { Metro } from '../../types'
|
||||
import type { MaybeDefaultExportMatched } from '../types'
|
||||
import type { Metro } from '../types'
|
||||
import type { RunFilterReturnExportsOptions } from './_internal'
|
||||
import type { Filter, FilterResult } from './filters'
|
||||
import type { LookupModuleIdsOptions } from './lookup'
|
||||
|
||||
export interface BaseFindModuleOptions {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
export * from './lookup'
|
||||
export * from './wait'
|
||||
export * from './find'
|
||||
|
||||
/**
|
||||
* Maybe the default export matched instead of the namespace, because you're using `options.returnNamespace`.
|
||||
*/
|
||||
export type MaybeDefaultExportMatched<T> = T | { default: T }
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { _mInited, _mMd, _mPaths, _mUninited } from '../metro/_internal'
|
||||
import { _inits, _metas, _paths, _uninits } from '../metro/_internal'
|
||||
import {
|
||||
type RunFilterOptions,
|
||||
type RunFilterReturnExportsOptions,
|
||||
|
|
@ -6,11 +6,11 @@ import {
|
|||
runFilter,
|
||||
} from './_internal'
|
||||
|
||||
import { getInitializedModuleExports } from '../metro'
|
||||
import { getInitializedModuleExports } from '../metro/utils'
|
||||
|
||||
import type { If } from '@revenge-mod/utils/types'
|
||||
import type { MaybeDefaultExportMatched } from '.'
|
||||
import type { Metro } from '../../types'
|
||||
import type { MaybeDefaultExportMatched } from '../types'
|
||||
import type { Metro } from '../types'
|
||||
import type { Filter, FilterResult } from './filters'
|
||||
|
||||
export interface BaseLookupModulesOptions<IncludeUninitialized extends boolean = boolean> extends RunFilterOptions {
|
||||
|
|
@ -53,6 +53,9 @@ export type LookupModuleIdsOptions<
|
|||
| ({
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -92,12 +95,12 @@ export function* lookupModuleIds<O extends LookupModuleIdsOptions>(
|
|||
options?: O,
|
||||
): Generator<Metro.ModuleID, undefined> {
|
||||
if (options?.includeAll) {
|
||||
for (const id of _mMd.keys()) if (runFilter(filter, id, getInitializedModuleExports(id), options)) yield id
|
||||
for (const id of _metas.keys()) if (runFilter(filter, id, getInitializedModuleExports(id), options)) yield id
|
||||
} else {
|
||||
if (options?.includeInitialized ?? true)
|
||||
for (const id of _mInited) if (runFilter(filter, id, getInitializedModuleExports(id), options)) yield id
|
||||
for (const id of _inits) if (runFilter(filter, id, getInitializedModuleExports(id), options)) yield id
|
||||
|
||||
if (options?.includeUninitialized) for (const id of _mUninited) if (runFilter(filter, id)) yield id
|
||||
if (options?.includeUninitialized) for (const id of _uninits) if (runFilter(filter, id)) yield id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,14 +130,14 @@ export function lookupModules<
|
|||
|
||||
export function* lookupModules(filter: Filter, options?: LookupModulesOptions) {
|
||||
if (options?.includeInitialized ?? true)
|
||||
for (const id of _mInited) {
|
||||
for (const id of _inits) {
|
||||
const exports = getInitializedModuleExports(id)
|
||||
const flag = runFilter(filter, id, exports, options)
|
||||
if (flag) yield exportsFromFilterResultFlag(flag, exports, options)
|
||||
}
|
||||
|
||||
if (options?.includeUninitialized)
|
||||
for (const id of _mUninited)
|
||||
for (const id of _uninits)
|
||||
if (runFilter(filter, id)) {
|
||||
// Run the filter again to ensure we have the correct exports
|
||||
const exports = __r(id)
|
||||
|
|
@ -171,12 +174,12 @@ export function lookupModuleId<O extends LookupModuleIdsOptions>(
|
|||
options?: O,
|
||||
): Metro.ModuleID | undefined {
|
||||
if (options?.includeAll) {
|
||||
for (const id of _mMd.keys()) if (runFilter(filter, id, getInitializedModuleExports(id), options)) return id
|
||||
for (const id of _metas.keys()) if (runFilter(filter, id, getInitializedModuleExports(id), options)) return id
|
||||
} else {
|
||||
if (options?.includeInitialized ?? true)
|
||||
for (const id of _mInited) if (runFilter(filter, id, getInitializedModuleExports(id), options)) return id
|
||||
for (const id of _inits) if (runFilter(filter, id, getInitializedModuleExports(id), options)) return id
|
||||
|
||||
if (options?.includeUninitialized) for (const id of _mUninited) if (runFilter(filter, id)) return id
|
||||
if (options?.includeUninitialized) for (const id of _uninits) if (runFilter(filter, id)) return id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -203,20 +206,20 @@ 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) {
|
||||
for (const id of _inits) {
|
||||
const exports = getInitializedModuleExports(id)
|
||||
const flag = runFilter(filter, id, exports, options)
|
||||
if (flag) return exportsFromFilterResultFlag(flag, exports, options)
|
||||
}
|
||||
|
||||
if (options?.includeUninitialized)
|
||||
for (const id of _mUninited) {
|
||||
for (const id of _uninits)
|
||||
if (runFilter(filter, id)) {
|
||||
const exports = __r(id)
|
||||
// Run the filter again to ensure we have the correct exports
|
||||
const flag = runFilter(filter, id, exports, options)
|
||||
if (flag) return exportsFromFilterResultFlag(flag, exports, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -231,7 +234,7 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) {
|
|||
* ```
|
||||
*/
|
||||
export function lookupModuleIdByImportedPath(path: string): Metro.ModuleID | undefined {
|
||||
return _mPaths.get(path)
|
||||
return _paths.get(path)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -248,6 +251,6 @@ export function lookupModuleIdByImportedPath(path: string): Metro.ModuleID | und
|
|||
* ```
|
||||
*/
|
||||
export function lookupModuleByImportedPath<T = any>(path: string): T | undefined {
|
||||
const id = lookupModuleIdByImportedPath(path)
|
||||
return getInitializedModuleExports(id!)
|
||||
// undefined will also return undefined either way, so we can just non-nullish assert it
|
||||
return getInitializedModuleExports(lookupModuleIdByImportedPath(path)!)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import {
|
||||
getInitializedModuleExports,
|
||||
initializedModuleHasBadExports,
|
||||
onAnyModuleInitialized,
|
||||
onModuleFinishedImporting,
|
||||
} from '../metro'
|
||||
import { onAnyModuleInitialized, onModuleFinishedImporting } from '../metro/subscriptions'
|
||||
import { getInitializedModuleExports, initializedModuleHasBadExports } from '../metro/utils'
|
||||
import { type RunFilterReturnExportsOptions, exportsFromFilterResultFlag, runFilter } from './_internal'
|
||||
|
||||
import type { MaybeDefaultExportMatched } from '.'
|
||||
import type { Metro } from '../../types'
|
||||
import type { MaybeDefaultExportMatched } from '../types'
|
||||
import type { Metro } from '../types'
|
||||
import type { Filter, FilterResult } from './filters'
|
||||
|
||||
export interface BaseWaitForModulesOptions<IncludeAll extends boolean = boolean> {
|
||||
|
|
@ -64,16 +60,18 @@ export function waitForModules(
|
|||
callback: (id: Metro.ModuleID, exports: Metro.ModuleExports) => any,
|
||||
options?: WaitForModulesOptions,
|
||||
) {
|
||||
return options?.includeAll
|
||||
? onAnyModuleInitialized((id, exports) => {
|
||||
const flag = runFilter(filter, id, exports, options)
|
||||
if (flag) callback(id, exportsFromFilterResultFlag(flag, exports, options))
|
||||
})
|
||||
: onAnyModuleInitialized((id, exports) => {
|
||||
if (initializedModuleHasBadExports(id)) return
|
||||
const flag = runFilter(filter, id, exports, options)
|
||||
if (flag) callback(id, exportsFromFilterResultFlag(flag, exports, options))
|
||||
})
|
||||
return onAnyModuleInitialized(
|
||||
options?.includeAll
|
||||
? (id, exports) => {
|
||||
const flag = runFilter(filter, id, exports, options)
|
||||
if (flag) callback(id, exportsFromFilterResultFlag(flag, exports, options))
|
||||
}
|
||||
: (id, exports) => {
|
||||
if (initializedModuleHasBadExports(id)) return
|
||||
const flag = runFilter(filter, id, exports, options)
|
||||
if (flag) callback(id, exportsFromFilterResultFlag(flag, exports, options))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -103,13 +101,22 @@ export function waitForModuleByImportedPath<T = any>(
|
|||
callback: (id: Metro.ModuleID, exports: T) => any,
|
||||
options?: BaseWaitForModulesOptions,
|
||||
) {
|
||||
const unsub = onModuleFinishedImporting((id, cmpPath) => {
|
||||
if (path === cmpPath) {
|
||||
unsub()
|
||||
if (!options?.includeAll && initializedModuleHasBadExports(id)) return
|
||||
callback(id, getInitializedModuleExports(id))
|
||||
}
|
||||
})
|
||||
const unsub = onModuleFinishedImporting(
|
||||
options?.includeAll
|
||||
? (id, cmpPath) => {
|
||||
if (path === cmpPath) {
|
||||
unsub()
|
||||
callback(id, getInitializedModuleExports(id))
|
||||
}
|
||||
}
|
||||
: (id, cmpPath) => {
|
||||
if (path === cmpPath) {
|
||||
unsub()
|
||||
if (initializedModuleHasBadExports(id)) return
|
||||
callback(id, getInitializedModuleExports(id))
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
return unsub
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
export * as finders from './finders'
|
||||
export * as filters from './finders/filters'
|
||||
export * as metro from './metro'
|
||||
export * as native from './native'
|
||||
|
|
@ -1,49 +1,49 @@
|
|||
import { _executeInitializedSubscription, _executeRequiredSubscription } from './subscriptions/_internal'
|
||||
import { _execInitSubs, _execReqSubs } from './subscriptions/_internal'
|
||||
import { isModuleExportsBad } from './utils'
|
||||
|
||||
import type { Metro } from '../../types'
|
||||
import type { Metro } from '../types'
|
||||
|
||||
/** Initializing ID */
|
||||
export let _mInitingId = -1
|
||||
/** Known uninitialized IDs (not blacklisted) */
|
||||
export const _mUninited = new Set<Metro.ModuleID>()
|
||||
export let _initing = -1
|
||||
/** Known uninitialized IDs */
|
||||
export const _uninits = new Set<Metro.ModuleID>()
|
||||
/** Known initialized IDs (not blacklisted) */
|
||||
export const _mInited = new Set<Metro.ModuleID>()
|
||||
export const _inits = new Set<Metro.ModuleID>()
|
||||
|
||||
export const _mPaths = new Map<string, Metro.ModuleID>()
|
||||
export const _mMd = new Map<Metro.ModuleID, [deps: Metro.DependencyMap, initialized: boolean, module?: Metro.Module]>()
|
||||
export const _paths = new Map<string, Metro.ModuleID>()
|
||||
export const _metas = new Map<
|
||||
Metro.ModuleID,
|
||||
[deps: Metro.DependencyMap, initialized: boolean, 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!, false] as typeof _mMd extends Map<any, infer V> ? V : never
|
||||
_mMd.set(id, metadata)
|
||||
_mUninited.add(id)
|
||||
const metadata = [deps!, false] as typeof _metas extends Map<any, infer V> ? V : never
|
||||
_metas.set(id, metadata)
|
||||
_uninits.add(id)
|
||||
|
||||
metroDefine(
|
||||
((global, req, importDefault, importAll, module, exports, deps) => {
|
||||
metadata[1] = true
|
||||
metadata[2] = module
|
||||
|
||||
const prevIId = _mInitingId
|
||||
_mInitingId = id
|
||||
const prevIId = _initing
|
||||
_initing = id
|
||||
|
||||
_executeRequiredSubscription(id)
|
||||
_execReqSubs(id)
|
||||
|
||||
try {
|
||||
origFactory(global, req, importDefault, importAll, module, exports, deps)
|
||||
// Don't use exports here, as modules can set module.exports to a different object
|
||||
if (isModuleExportsBad(module.exports)) throw undefined
|
||||
metadata[1] = true
|
||||
|
||||
// Add the module to the initialized set only if the factory doesn't error or the exports aren't bad
|
||||
_mInited.add(id)
|
||||
} catch {
|
||||
} finally {
|
||||
_mInitingId = prevIId
|
||||
_mUninited.delete(id)
|
||||
// Don't use exports here, as modules can set module.exports to a different object
|
||||
_executeInitializedSubscription(id, module.exports)
|
||||
}
|
||||
if (!isModuleExportsBad(module.exports)) _inits.add(id)
|
||||
_execInitSubs(id, module.exports)
|
||||
} catch {}
|
||||
|
||||
_initing = prevIId
|
||||
_uninits.delete(id)
|
||||
}) satisfies Metro.FactoryFn,
|
||||
id,
|
||||
deps,
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
export * from './subscriptions'
|
||||
export * from './utils'
|
||||
|
||||
// TODO(modules): caching
|
||||
|
|
@ -1,19 +1,18 @@
|
|||
import { _mInitingId, _mPaths } from './_internal'
|
||||
import { _initing, _paths } from './_internal'
|
||||
|
||||
import { _executeImportedPathSubscription } from './subscriptions/_internal'
|
||||
import { _execPathSubs } from './subscriptions/_internal'
|
||||
|
||||
import { waitForModules } from '../finders'
|
||||
import { byProps } from '../finders/filters'
|
||||
import { waitForModules } from '../finders/wait'
|
||||
|
||||
const unsubFFI = waitForModules(byProps('fileFinishedImporting'), (_, exports) => {
|
||||
unsubFFI()
|
||||
|
||||
const unsubForImportTracker = waitForModules(byProps('fileFinishedImporting'), (_, exports) => {
|
||||
const orig = exports.fileFinishedImporting
|
||||
if (orig) {
|
||||
unsubForImportTracker()
|
||||
exports.fileFinishedImporting = (path: string) => {
|
||||
orig(path)
|
||||
const id = _mInitingId
|
||||
_mPaths.set(path, id)
|
||||
_executeImportedPathSubscription(id, path)
|
||||
}
|
||||
exports.fileFinishedImporting = (path: string) => {
|
||||
orig(path)
|
||||
const id = _initing
|
||||
_paths.set(path, id)
|
||||
_execPathSubs(id, path)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,30 +1,32 @@
|
|||
import { _mInitingId } from '../_internal'
|
||||
import type {
|
||||
ModuleFirstRequiredCallback,
|
||||
ModuleInitializedCallback,
|
||||
ModuleWithImportedPathInitializedCallback,
|
||||
} from '.'
|
||||
import type { Metro } from '../../types'
|
||||
|
||||
import type { ModuleInitializedCallback, ModuleRequiredCallback, ModuleWithImportedPathInitializedCallback } from '.'
|
||||
import type { Metro } from '../../../types'
|
||||
|
||||
export const _reqAll = new Set<ModuleRequiredCallback>()
|
||||
export const _reqSpecific = new Map<Metro.ModuleID, Set<ModuleRequiredCallback>>()
|
||||
export const _reqAll = new Set<ModuleFirstRequiredCallback>()
|
||||
export const _req = new Map<Metro.ModuleID, Set<ModuleFirstRequiredCallback>>()
|
||||
export const _initAll = new Set<ModuleInitializedCallback>()
|
||||
export const _initSpecific = new Map<Metro.ModuleID, Set<ModuleInitializedCallback>>()
|
||||
export const _importedPath = new Set<ModuleWithImportedPathInitializedCallback>()
|
||||
export const _init = new Map<Metro.ModuleID, Set<ModuleInitializedCallback>>()
|
||||
export const _path = new Set<ModuleWithImportedPathInitializedCallback>()
|
||||
|
||||
export function _executeRequiredSubscription(id: Metro.ModuleID) {
|
||||
export function _execReqSubs(id: Metro.ModuleID) {
|
||||
for (const cb of _reqAll) cb(id)
|
||||
if (_reqSpecific.has(id)) {
|
||||
for (const cb of _reqSpecific.get(id)!) cb(id)
|
||||
_reqSpecific.delete(id)
|
||||
if (_req.has(id)) {
|
||||
for (const cb of _req.get(id)!) cb(id)
|
||||
_req.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
export function _executeInitializedSubscription(id: Metro.ModuleID, exports: Metro.ModuleExports) {
|
||||
export function _execInitSubs(id: Metro.ModuleID, exports: Metro.ModuleExports) {
|
||||
for (const cb of _initAll) cb(id, exports)
|
||||
if (_initSpecific.has(id)) {
|
||||
for (const cb of _initSpecific.get(id)!) cb(id, exports)
|
||||
_initSpecific.delete(id)
|
||||
if (_init.has(id)) {
|
||||
for (const cb of _init.get(id)!) cb(id, exports)
|
||||
_init.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
export function _executeImportedPathSubscription(id: Metro.ModuleID, path: string) {
|
||||
for (const cb of _importedPath) cb(id, path)
|
||||
export function _execPathSubs(id: Metro.ModuleID, path: string) {
|
||||
for (const cb of _path) cb(id, path)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { _importedPath, _initAll, _initSpecific, _reqAll, _reqSpecific } from './_internal'
|
||||
import { _init, _initAll, _path, _req, _reqAll } from './_internal'
|
||||
|
||||
import type { Metro } from '../../../types'
|
||||
import type { Metro } from '../../types'
|
||||
import type { initializedModuleHasBadExports } from '../utils'
|
||||
|
||||
export type ModuleRequiredCallback = (id: Metro.ModuleID) => void
|
||||
export type ModuleFirstRequiredCallback = (id: Metro.ModuleID) => void
|
||||
export type ModuleInitializedCallback = (id: Metro.ModuleID, exports: Metro.ModuleExports) => void
|
||||
export type ModuleWithImportedPathInitializedCallback = (id: Metro.ModuleID, path: string) => void
|
||||
|
||||
|
|
@ -30,8 +30,12 @@ export function onAnyModuleInitialized(callback: ModuleInitializedCallback) {
|
|||
* @returns A function that unregisters the callback.
|
||||
*/
|
||||
export function onModuleInitialized(id: Metro.ModuleID, callback: ModuleInitializedCallback) {
|
||||
if (!_initSpecific.has(id)) _initSpecific.set(id, new Set())
|
||||
const set = _initSpecific.get(id)!
|
||||
let set = _init.get(id)
|
||||
if (!set) {
|
||||
set = new Set()
|
||||
_init.set(id, set)
|
||||
}
|
||||
|
||||
set.add(callback)
|
||||
return () => set.delete(callback)
|
||||
}
|
||||
|
|
@ -45,8 +49,8 @@ export function onModuleInitialized(id: Metro.ModuleID, callback: ModuleInitiali
|
|||
* @returns A function that unregisters the callback.
|
||||
*/
|
||||
export function onModuleFinishedImporting(callback: ModuleWithImportedPathInitializedCallback) {
|
||||
_importedPath.add(callback)
|
||||
return () => _importedPath.delete(callback)
|
||||
_path.add(callback)
|
||||
return () => _path.delete(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -57,9 +61,9 @@ export function onModuleFinishedImporting(callback: ModuleWithImportedPathInitia
|
|||
* @param callback The callback to be called.
|
||||
* @returns A function that unregisters the callback.
|
||||
*/
|
||||
export function onAnyModuleFirstRequired(callback: ModuleRequiredCallback) {
|
||||
_reqAll.add(id => callback(id))
|
||||
return () => _reqAll.delete(id => callback(id))
|
||||
export function onAnyModuleFirstRequired(callback: ModuleFirstRequiredCallback) {
|
||||
_reqAll.add(callback)
|
||||
return () => _reqAll.delete(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -71,9 +75,13 @@ export function onAnyModuleFirstRequired(callback: ModuleRequiredCallback) {
|
|||
* @param callback The callback to be called.
|
||||
* @returns A function that unregisters the callback.
|
||||
*/
|
||||
export function onModuleFirstRequired(id: Metro.ModuleID, callback: ModuleRequiredCallback) {
|
||||
if (!_reqSpecific.has(id)) _reqSpecific.set(id, new Set())
|
||||
const set = _reqSpecific.get(id)!
|
||||
export function onModuleFirstRequired(id: Metro.ModuleID, callback: ModuleFirstRequiredCallback) {
|
||||
let set = _req.get(id)
|
||||
if (!set) {
|
||||
set = new Set()
|
||||
_req.set(id, set)
|
||||
}
|
||||
|
||||
set.add(callback)
|
||||
return () => set.delete(callback)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { isProxy } from '@revenge-mod/utils/proxy'
|
||||
import { _mInited, _mMd, _mUninited } from './_internal'
|
||||
import { _inits, _metas, _uninits } from './_internal'
|
||||
|
||||
import type { Metro } from '../../types'
|
||||
import type { Metro } from '../types'
|
||||
|
||||
/**
|
||||
* Returns whether an uninitialized module has bad exports.
|
||||
|
|
@ -11,7 +11,7 @@ import type { Metro } from '../../types'
|
|||
* @param id The module ID.
|
||||
*/
|
||||
export function uninitializedModuleHasBadExports(id: Metro.ModuleID): boolean {
|
||||
return !_mUninited.has(id)
|
||||
return !_uninits.has(id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -22,7 +22,7 @@ export function uninitializedModuleHasBadExports(id: Metro.ModuleID): boolean {
|
|||
* @param id The module ID.
|
||||
*/
|
||||
export function initializedModuleHasBadExports(id: Metro.ModuleID): boolean {
|
||||
return !_mInited.has(id)
|
||||
return !_inits.has(id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -30,7 +30,7 @@ export function initializedModuleHasBadExports(id: Metro.ModuleID): boolean {
|
|||
* @param id The module ID.
|
||||
*/
|
||||
export function getModuleDependencies(id: Metro.ModuleID): Metro.DependencyMap | undefined {
|
||||
return _mMd.get(id)?.[0]
|
||||
return _metas.get(id)?.[0]
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,7 +38,7 @@ export function getModuleDependencies(id: Metro.ModuleID): Metro.DependencyMap |
|
|||
* @param id The module ID.
|
||||
*/
|
||||
export function isModuleInitialized(id: Metro.ModuleID): boolean {
|
||||
return _mMd.get(id)?.[1]!
|
||||
return _metas.get(id)?.[1]!
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +46,7 @@ export function isModuleInitialized(id: Metro.ModuleID): boolean {
|
|||
* @param id The module ID.
|
||||
*/
|
||||
export function getInitializedModuleExports(id: Metro.ModuleID): Metro.ModuleExports | undefined {
|
||||
return _mMd.get(id)?.[2]?.exports
|
||||
return _metas.get(id)?.[2]?.exports
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,7 +80,7 @@ export function isModuleExportsBad(exports: Metro.ModuleExports): boolean {
|
|||
// 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
|
||||
// https://github.com/facebook/react-native/blob/master/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp
|
||||
exports === nativeModuleProxy
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { If, Nullish } from '@revenge-mod/utils/types'
|
|||
/**
|
||||
* Metro is a bundler for React Native.
|
||||
*
|
||||
* @see {@link https://github.com/facebook/metro/blob/1361405/packages/metro-runtime/src/polyfills/require.js}
|
||||
* @see {@link https://github.com/facebook/metro/blob/main/packages/metro-runtime/src/polyfills/require.js}
|
||||
*/
|
||||
export namespace Metro {
|
||||
export type DependencyMap = Array<ModuleID>
|
||||
|
|
@ -68,3 +68,8 @@ export namespace Metro {
|
|||
|
||||
export type ModuleExports = any
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe the default export matched instead of the namespace, because you're using `options.returnNamespace`.
|
||||
*/
|
||||
export type MaybeDefaultExportMatched<T> = T | { default: T }
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
"default": "./src/preinit.ts"
|
||||
},
|
||||
"./types": {
|
||||
"default": "./types.ts"
|
||||
"default": "./src/types.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
import { lookupModuleId, lookupModuleIds } from '@revenge-mod/modules/finders'
|
||||
import { byProps } from '@revenge-mod/modules/finders/filters'
|
||||
import { lookupModuleId, lookupModuleIds } from '@revenge-mod/modules/finders/lookup'
|
||||
import { yielded } from '@revenge-mod/utils/generators'
|
||||
|
||||
export * as jsxRuntime from './jsx-runtime'
|
||||
export * from '../types'
|
||||
|
||||
export const ReactModuleId = yielded(lookupModuleIds(byProps<typeof import('react')>('useState')), 1)!
|
||||
export const ReactNativeModuleId = lookupModuleId(byProps<typeof import('react-native')>('AppRegistry'))!
|
||||
export const ReactJsxRuntimeModuleId = yielded(lookupModuleIds(byProps<typeof import('react/jsx-runtime')>('jsx'))!, 1)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@
|
|||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"default": "./src/index.ts"
|
||||
},
|
||||
"./callbacks": {
|
||||
"default": "./src/callbacks.ts"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
export * from './callbacks'
|
||||
export * from './errors'
|
||||
export * from './generators'
|
||||
export * from './logger'
|
||||
export * from './objects'
|
||||
export * from './proxy'
|
||||
export * from './react'
|
||||
export * from './trees'
|
||||
export * from './types'
|
||||
Loading…
Add table
Reference in a new issue