2025-04-15 15:02:44 +07:00
|
|
|
import { _executeInitializedSubscription, _executeRequiredSubscription } from './subscriptions/_internal'
|
|
|
|
|
import { isModuleExportsBad } from './utils'
|
2025-03-30 23:32:17 +07:00
|
|
|
|
2025-04-05 23:35:01 +07:00
|
|
|
import type { Metro } from '../../types/metro'
|
2025-03-30 23:32:17 +07:00
|
|
|
|
|
|
|
|
/** Initializing ID */
|
|
|
|
|
export let _mInitingId = -1
|
2025-04-15 15:02:44 +07:00
|
|
|
/** Known uninitialized IDs (not blacklisted) */
|
2025-03-30 23:32:17 +07:00
|
|
|
export const _mUninited = new Set<Metro.ModuleID>()
|
2025-04-15 15:02:44 +07:00
|
|
|
/** Known initialized IDs (not blacklisted) */
|
2025-03-30 23:32:17 +07:00
|
|
|
export const _mInited = new Set<Metro.ModuleID>()
|
|
|
|
|
|
|
|
|
|
export const _mPaths = new Map<string, Metro.ModuleID>()
|
2025-04-10 02:03:56 +07:00
|
|
|
export const _mMd = new Map<Metro.ModuleID, [deps: Metro.DependencyMap, module?: Metro.Module]>()
|
2025-03-30 23:32:17 +07:00
|
|
|
|
|
|
|
|
export function patchMetroDefine(metroDefine: Metro.DefineFn) {
|
|
|
|
|
return ((origFactory, id, deps) => {
|
|
|
|
|
// deps won't be undefined last time I checked
|
2025-04-10 02:03:56 +07:00
|
|
|
const metadata = [deps!] as typeof _mMd extends Map<any, infer V> ? V : never
|
|
|
|
|
_mMd.set(id, metadata)
|
2025-04-15 15:02:44 +07:00
|
|
|
_mUninited.add(id)
|
2025-03-30 23:32:17 +07:00
|
|
|
|
2025-04-15 15:02:44 +07:00
|
|
|
metroDefine(
|
|
|
|
|
((global, req, importDefault, importAll, module, exports, deps) => {
|
|
|
|
|
metadata[1] = module
|
2025-03-30 23:32:17 +07:00
|
|
|
|
2025-04-15 15:02:44 +07:00
|
|
|
const prevIId = _mInitingId
|
|
|
|
|
_mInitingId = id
|
2025-03-30 23:32:17 +07:00
|
|
|
|
2025-04-15 15:02:44 +07:00
|
|
|
_executeRequiredSubscription()
|
2025-03-30 23:32:17 +07:00
|
|
|
|
2025-04-15 15:02:44 +07:00
|
|
|
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
|
2025-03-30 23:32:17 +07:00
|
|
|
|
2025-04-15 15:02:44 +07:00
|
|
|
// Add the module to the initialized set only if the factory doesn't error or the exports aren't bad
|
|
|
|
|
_mInited.add(id)
|
|
|
|
|
} catch {
|
|
|
|
|
_blacklist(id)
|
|
|
|
|
} finally {
|
|
|
|
|
_mInitingId = prevIId
|
|
|
|
|
_mUninited.delete(id)
|
|
|
|
|
// Don't use exports here, as modules can set module.exports to a different object
|
|
|
|
|
_executeInitializedSubscription(module.exports)
|
|
|
|
|
}
|
|
|
|
|
}) satisfies Metro.FactoryFn,
|
|
|
|
|
id,
|
|
|
|
|
deps,
|
|
|
|
|
)
|
2025-03-30 23:32:17 +07:00
|
|
|
}) satisfies Metro.DefineFn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-04-15 15:02:44 +07:00
|
|
|
* Blacklists a module. A module can be blacklisted for several reasons:
|
2025-03-30 23:32:17 +07:00
|
|
|
*
|
2025-04-15 15:02:44 +07:00
|
|
|
* - If the module is already initialized, it either means:
|
|
|
|
|
* - The module factory threw an error during initialization
|
|
|
|
|
* - The module exports are bad after initialization
|
|
|
|
|
* - Otherwise, this module is known to be bad from previous caches
|
2025-03-30 23:32:17 +07:00
|
|
|
*
|
2025-04-10 02:03:56 +07:00
|
|
|
* @param id The module ID to blacklist.
|
2025-03-30 23:32:17 +07:00
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
export function _blacklist(id: Metro.ModuleID) {
|
2025-04-11 18:38:38 +07:00
|
|
|
// In case blacklisting happens before the module is initialized
|
|
|
|
|
_mUninited.delete(id)
|
2025-03-30 23:32:17 +07:00
|
|
|
|
|
|
|
|
// Usually we'd also remove the module from _mInited too,
|
|
|
|
|
// but we already have an else block in the patchMetroDefine function that does that for us.
|
|
|
|
|
// _mInited.delete(id)
|
|
|
|
|
|
|
|
|
|
// TODO(modules): caching
|
|
|
|
|
}
|