chore: new DEBUG_WAITS build flag, improve DBEUG_LOOKUPS build flag logs, other dev env fixes

This commit is contained in:
PalmDevs 2025-07-08 11:24:48 +07:00
parent e9fedc8db4
commit 7645bfdf61
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
11 changed files with 149 additions and 31 deletions

View file

@ -56,6 +56,13 @@ export const FilterResultFlags = {
export type FilterResultFlag = export type FilterResultFlag =
(typeof FilterResultFlags)[keyof typeof FilterResultFlags] (typeof FilterResultFlags)[keyof typeof FilterResultFlags]
export const FilterResultFlagToHumanReadable: Record<FilterResultFlag, string> =
{
[FilterResultFlags.Default]: '\u001b[94mdefault\u001b[0m',
[FilterResultFlags.Namespace]: '\u001b[35mnamespace\u001b[0m',
[FilterResultFlags.Found]: '\u001b[96mexportsless\u001b[0m',
}
// The reason this returns a flag is because flags are never falsy, while exports may be falsy when using ID-only filters (eg. `byDependencies`). // The reason this returns a flag is because flags are never falsy, while exports may be falsy when using ID-only filters (eg. `byDependencies`).
// Currently, we only have options that are relevant for checking exports // Currently, we only have options that are relevant for checking exports
@ -84,8 +91,7 @@ export function runFilter(
if (options?.initialize ?? true) { if (options?.initialize ?? true) {
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) { if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) {
const flag = runFilter(filter, id, __r(id), options) const flag = runFilter(filter, id, __r(id), options)
if (!flag) if (!flag) DEBUG_warnPartialFilterMatch(id, filter.key)
warnDeveloperAboutPartialFilterMatch(id, filter.key)
return flag return flag
} else return runFilter(filter, id, __r(id), options) } else return runFilter(filter, id, __r(id), options)
} }
@ -119,9 +125,8 @@ export function exportsFromFilterResultFlag(
/** /**
* Warns the developer that the filter matched during exportsless comparison, but not during the full comparison. * Warns the developer that the filter matched during exportsless comparison, but not during the full comparison.
* This will cause modules to be initialized unnecessarily, and may cause issues. * This will cause modules to be initialized unnecessarily, and may cause issues.
* @internal
*/ */
function warnDeveloperAboutPartialFilterMatch(id: Metro.ModuleID, key: string) { function DEBUG_warnPartialFilterMatch(id: Metro.ModuleID, key: string) {
nativeLoggingHook( nativeLoggingHook(
`\u001b[33m${key} matched module ${id} partially.\n${getCurrentStack()}\u001b[0m`, `\u001b[33m${key} matched module ${id} partially.\n${getCurrentStack()}\u001b[0m`,
2, 2,

View file

@ -11,10 +11,17 @@ import {
getInitializedModuleExports, getInitializedModuleExports,
isModuleInitialized, isModuleInitialized,
} from '../metro/utils' } from '../metro/utils'
import { exportsFromFilterResultFlag, runFilter } from './_internal' import {
exportsFromFilterResultFlag,
FilterResultFlagToHumanReadable,
runFilter,
} from './_internal'
import type { If, Nullish } from '@revenge-mod/utils/types' import type { If, Nullish } from '@revenge-mod/utils/types'
import type { MaybeDefaultExportMatched, Metro } from '../types' import type { MaybeDefaultExportMatched, Metro } from '../types'
import type { RunFilterReturnExportsOptions } from './_internal' import type {
FilterResultFlag,
RunFilterReturnExportsOptions,
} from './_internal'
import type { Filter, FilterResult } from './filters' import type { Filter, FilterResult } from './filters'
type LookupModulesOptionsWithAll<A extends boolean> = If< type LookupModulesOptionsWithAll<A extends boolean> = If<
@ -177,6 +184,9 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) {
cached.add(id) cached.add(id)
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id, true)
yield [exportsFromFilterResultFlag(flag, exports, options), id] yield [exportsFromFilterResultFlag(flag, exports, options), id]
} }
} }
@ -191,6 +201,10 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) {
const flag = runFilter(filter, id, exports, options) const flag = runFilter(filter, id, exports, options)
if (flag) { if (flag) {
notFound = false notFound = false
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id)
yield [exportsFromFilterResultFlag(flag, exports, options), id] yield [exportsFromFilterResultFlag(flag, exports, options), id]
} }
} }
@ -207,6 +221,10 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) {
const flag = runFilter(filter, id, exports, options) const flag = runFilter(filter, id, exports, options)
if (flag) { if (flag) {
notFound = false notFound = false
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id)
yield [ yield [
exportsFromFilterResultFlag(flag, exports, options), exportsFromFilterResultFlag(flag, exports, options),
id, id,
@ -222,6 +240,9 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) {
if (flag) { if (flag) {
notFound = false notFound = false
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id)
yield [ yield [
exportsFromFilterResultFlag( exportsFromFilterResultFlag(
flag, flag,
@ -235,7 +256,7 @@ export function* lookupModules(filter: Filter, options?: LookupModulesOptions) {
} }
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
if (notFound) warnDeveloperAboutNoFilterMatch(filter) if (notFound) DEBUG_warnLookupNoMatch(filter.key)
} }
/** /**
@ -288,6 +309,9 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) {
exports = __r(id) exports = __r(id)
} }
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id, true)
return [exportsFromFilterResultFlag(flag, exports, options), id] return [exportsFromFilterResultFlag(flag, exports, options), id]
} }
} }
@ -297,12 +321,16 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) {
for (let id = 0; id < mDeps.length; id++) { for (let id = 0; id < mDeps.length; id++) {
const exports = getInitializedModuleExports(id) const exports = getInitializedModuleExports(id)
const flag = runFilter(filter, id, exports, options) const flag = runFilter(filter, id, exports, options)
if (flag) if (flag) {
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id)
return [exportsFromFilterResultFlag(flag, exports, options), id] return [exportsFromFilterResultFlag(flag, exports, options), id]
}
} }
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
warnDeveloperAboutNoFilterMatch(filter) DEBUG_warnLookupNoMatch(filter.key)
cache[filter.key] = null // Full lookup, and still not found! cache[filter.key] = null // Full lookup, and still not found!
@ -314,17 +342,24 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) {
for (const id of mInitialized) { for (const id of mInitialized) {
const exports = getInitializedModuleExports(id) const exports = getInitializedModuleExports(id)
const flag = runFilter(filter, id, exports, options) const flag = runFilter(filter, id, exports, options)
if (flag) if (flag) {
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id)
return [ return [
exportsFromFilterResultFlag(flag, exports, options), exportsFromFilterResultFlag(flag, exports, options),
id, id,
] ]
}
} }
if (options?.uninitialized) if (options?.uninitialized)
for (const id of mUninitialized) { for (const id of mUninitialized) {
const flag = runFilter(filter, id, undefined, options) const flag = runFilter(filter, id, undefined, options)
if (flag) if (flag) {
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__)
DEBUG_logLookupMatched(filter.key, flag, id)
return [ return [
exportsFromFilterResultFlag( exportsFromFilterResultFlag(
flag, flag,
@ -333,11 +368,11 @@ export function lookupModule(filter: Filter, options?: LookupModulesOptions) {
), ),
id, id,
] ]
}
} }
} }
if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) if (__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__) DEBUG_warnLookupNoMatch(filter.key)
warnDeveloperAboutNoFilterMatch(filter)
return NotFoundResult return NotFoundResult
} }
@ -376,17 +411,29 @@ const __DEBUG_TRACER_IGNORE_LIST__ = __BUILD_FLAG_DEBUG_MODULE_LOOKUPS__
) )
: [] : []
/**
* Logs to the developer that a module was found, how it is found, and whether it was a cached result.
*/
function DEBUG_logLookupMatched(
key: string,
flag: FilterResultFlag,
id: Metro.ModuleID,
cached?: boolean,
) {
nativeLoggingHook(
`\u001b[32mSuccessful lookup: \u001b[33m${key}\u001b[0m (matched ${id}, ${FilterResultFlagToHumanReadable[flag]}${cached ? ', \u001b[92mcached\u001b[0m' : ''})`,
1,
)
}
/** /**
* Warns the developer that no module was found for the given filter. * Warns the developer that no module was found for the given filter.
* This is useful for debugging purposes, especially when using filters that are expected to match a module. * This is useful for debugging purposes, especially when using filters that are expected to match a module.
*/ */
function warnDeveloperAboutNoFilterMatch(filter: Filter) { function DEBUG_warnLookupNoMatch(key: string) {
const stack = getCurrentStack() const stack = getCurrentStack()
for (const func of __DEBUG_TRACER_IGNORE_LIST__) for (const func of __DEBUG_TRACER_IGNORE_LIST__)
if (stack.includes(func.name)) return if (stack.includes(func.name)) return
nativeLoggingHook( nativeLoggingHook(`\u001b[31mFailed lookup: ${key}\n${stack}\u001b[0m`, 2)
`\u001b[31mNo module found for filter: ${filter.key}\n${stack}\u001b[0m`,
2,
)
} }

View file

@ -4,9 +4,16 @@ import {
onModuleFinishedImporting, onModuleFinishedImporting,
} from '../metro/subscriptions' } from '../metro/subscriptions'
import { getInitializedModuleExports } from '../metro/utils' import { getInitializedModuleExports } from '../metro/utils'
import { exportsFromFilterResultFlag, runFilter } from './_internal' import {
exportsFromFilterResultFlag,
FilterResultFlagToHumanReadable,
runFilter,
} from './_internal'
import type { MaybeDefaultExportMatched, Metro } from '../types' import type { MaybeDefaultExportMatched, Metro } from '../types'
import type { RunFilterReturnExportsOptions } from './_internal' import type {
FilterResultFlag,
RunFilterReturnExportsOptions,
} from './_internal'
import type { Filter, FilterResult } from './filters' import type { Filter, FilterResult } from './filters'
export interface BaseWaitForModulesOptions<All extends boolean = boolean> { export interface BaseWaitForModulesOptions<All extends boolean = boolean> {
@ -76,20 +83,33 @@ export function waitForModules(
callback: WaitForModulesCallback<any>, callback: WaitForModulesCallback<any>,
options?: WaitForModulesOptions, options?: WaitForModulesOptions,
) { ) {
if (__BUILD_FLAG_DEBUG_MODULE_WAITS__)
nativeLoggingHook(
`\u001b[94mWaiting for module matching: \u001b[93m${filter.key}\u001b[0m`,
1,
)
return onAnyModuleInitialized( return onAnyModuleInitialized(
options?.all options?.all
? (id, exports) => { ? (id, exports) => {
const flag = runFilter(filter, id, exports, options) const flag = runFilter(filter, id, exports, options)
if (flag) if (flag) {
if (__BUILD_FLAG_DEBUG_MODULE_WAITS__)
DEBUG_logWaitMatched(filter.key, id, flag)
callback( callback(
exportsFromFilterResultFlag(flag, exports, options), exportsFromFilterResultFlag(flag, exports, options),
id, id,
) )
}
} }
: (id, exports) => { : (id, exports) => {
if (mInitialized.has(id)) { if (mInitialized.has(id)) {
const flag = runFilter(filter, id, exports, options) const flag = runFilter(filter, id, exports, options)
if (flag) if (flag) {
if (__BUILD_FLAG_DEBUG_MODULE_WAITS__)
DEBUG_logWaitMatched(filter.key, id, flag)
callback( callback(
exportsFromFilterResultFlag( exportsFromFilterResultFlag(
flag, flag,
@ -98,6 +118,7 @@ export function waitForModules(
), ),
id, id,
) )
}
} }
}, },
) )
@ -148,3 +169,17 @@ export function waitForModuleByImportedPath<T = any>(
return unsub return unsub
} }
/**
* Logs to the developer that a module wait has matched.
*/
function DEBUG_logWaitMatched(
key: string,
id: Metro.ModuleID,
flag: FilterResultFlag,
) {
nativeLoggingHook(
`\u001b[32mWait matched: \u001b[33m${key}\u001b[0m (matched ${id}, ${FilterResultFlagToHumanReadable[flag]})`,
1,
)
}

View file

@ -22,7 +22,7 @@ export let mList: Metro.ModuleList
* Here's how Metro sets itself up: * Here's how Metro sets itself up:
* 1. `__METRO_GLOBAL_PREFIX__ = ""` * 1. `__METRO_GLOBAL_PREFIX__ = ""`
* 2. `${__METRO_GLOBAL_PREFIX__}__d = function define(...) {}` * 2. `${__METRO_GLOBAL_PREFIX__}__d = function define(...) {}`
* - Why don't we patch it here? Because we need to know the value of __METRO_GLOBAL_PREFIX__ first * - Why don't we patch it here? Because we need to know the value of `__METRO_GLOBAL_PREFIX__` first
* - And since Revenge runs before everything else, we need to patch in the next steps: * - And since Revenge runs before everything else, we need to patch in the next steps:
* - We chose to patch it in 4. because we can access all the global functions at that point. * - We chose to patch it in 4. because we can access all the global functions at that point.
* 3. `__r = function metroRequire(...) {}` * 3. `__r = function metroRequire(...) {}`

View file

@ -147,7 +147,7 @@ export function proxify<T>(signal: () => T, options?: ProxifyOptions): T {
if (__BUILD_FLAG_DEBUG_PROXIFIED_VALUES__) { if (__BUILD_FLAG_DEBUG_PROXIFIED_VALUES__) {
const v = unproxifyFromHint(hint) const v = unproxifyFromHint(hint)
if (v == null) warnDeveloperAboutNullishProxifiedValue() if (v == null) DEBUG_warnNullishProxifiedValue()
} }
return new Proxy(hint, _handler) return new Proxy(hint, _handler)
@ -242,7 +242,10 @@ export function destructure<T extends object>(
}) })
} }
function warnDeveloperAboutNullishProxifiedValue() { /**
* Warns the developer that the proxified value is nullish.
*/
function DEBUG_warnNullishProxifiedValue() {
nativeLoggingHook( nativeLoggingHook(
`\u001b[33mProxified value is nullish! The signal is may be invalid.\n${getCurrentStack()}\u001b[0m`, `\u001b[33mProxified value is nullish! The signal is may be invalid.\n${getCurrentStack()}\u001b[0m`,
3, 3,

View file

@ -59,6 +59,7 @@ export default async function build(dev = Dev, log = true) {
// See types.d.ts for what these flags do // See types.d.ts for what these flags do
__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__: String(dev), __BUILD_FLAG_DEBUG_MODULE_LOOKUPS__: String(dev),
__BUILD_FLAG_DEBUG_MODULE_WAITS__: String(dev),
__BUILD_FLAG_DEBUG_PROXIFIED_VALUES__: 'false', __BUILD_FLAG_DEBUG_PROXIFIED_VALUES__: 'false',
__BUILD_FLAG_LOG_PROMISE_REJECTIONS__: String(dev), __BUILD_FLAG_LOG_PROMISE_REJECTIONS__: String(dev),
}, },

8
shims/shims.d.ts vendored Normal file
View file

@ -0,0 +1,8 @@
declare global {
// CommonJS modules, we don't want to depend on @types/node
const module: {
exports: any
}
}
export {}

7
shims/tsconfig.json Normal file
View file

@ -0,0 +1,7 @@
{
"extends": ["../tsconfig.json"],
"compilerOptions": {
"types": ["./shims.d.ts"]
},
"include": ["./**/*.ts"]
}

View file

@ -14,6 +14,9 @@ onModuleFirstRequired(IndexModuleId, function onIndexRequired() {
if (__BUILD_FLAG_LOG_PROMISE_REJECTIONS__) if (__BUILD_FLAG_LOG_PROMISE_REJECTIONS__)
require('./patches/log-promise-rejections') require('./patches/log-promise-rejections')
if (__BUILD_ENV__ === 'development')
nativeLoggingHook(`\u001b[31m--- PREINIT STAGE ---\u001b[0m`, 1)
// Initialize preinit libraries // Initialize preinit libraries
require('@revenge-mod/modules/preinit') require('@revenge-mod/modules/preinit')
require('@revenge-mod/react/preinit') require('@revenge-mod/react/preinit')
@ -27,6 +30,12 @@ onModuleFirstRequired(IndexModuleId, function onIndexRequired() {
onModuleInitialized(IndexModuleId, function onIndexInitialized() { onModuleInitialized(IndexModuleId, function onIndexInitialized() {
try { try {
if (__BUILD_ENV__ === 'development')
nativeLoggingHook(
`\u001b[31m--- INIT STAGE ---\u001b[0m`,
1,
)
// Initialize init libraries // Initialize init libraries
require('@revenge-mod/storage/init') require('@revenge-mod/storage/init')
require('@revenge-mod/externals/init') require('@revenge-mod/externals/init')

View file

@ -14,5 +14,5 @@
"~assets/*": ["./dist/assets/generated/*"] "~assets/*": ["./dist/assets/generated/*"]
} }
}, },
"include": ["lib", "src", "shims"] "include": ["lib", "src"]
} }

13
types.d.ts vendored
View file

@ -13,6 +13,7 @@ declare global {
/** /**
* Whether to debug module lookups. * Whether to debug module lookups.
* *
* - Logs successful lookups.
* - Logs failed lookups with stack traces. * - Logs failed lookups with stack traces.
* - Logs partial matches (matches exportless, but not with-exports). * - Logs partial matches (matches exportless, but not with-exports).
*/ */
@ -24,11 +25,13 @@ declare global {
* - Warns if the proxified value is nullish. * - Warns if the proxified value is nullish.
*/ */
const __BUILD_FLAG_DEBUG_PROXIFIED_VALUES__: boolean const __BUILD_FLAG_DEBUG_PROXIFIED_VALUES__: boolean
/**
// CommonJS modules, we don't want to depend on @types/node * Whether to debug module waits.
const module: { *
exports: any * - Logs when a module is waited for.
} * - Logs when a module is found.
*/
const __BUILD_FLAG_DEBUG_MODULE_WAITS__: boolean
export interface ImportMeta { export interface ImportMeta {
glob<T = any>( glob<T = any>(