add cycle detection with use

This commit is contained in:
2025-04-14 18:01:41 -05:00
parent 05f284e3fa
commit 8d235ddf12

View File

@@ -45,8 +45,6 @@ prosperon.on('SIGSEGV', function() {
os.exit(1)
})
var use_cache = {}
Object.defineProperty(Function.prototype, "hashify", {
value: function () {
var hash = new Map()
@@ -67,6 +65,8 @@ var canonical = io.realdir(RESPATH) + 'resources.js'
var content = io.slurp(RESPATH)
var resources = js.eval(RESPATH, `(function setup_resources(){${content}})`).call({})
var use_cache = {}
use_cache[resources.canonical('resources.js')] = resources
function print_api(obj) {
@@ -277,9 +277,49 @@ switch(os.platform()) {
break
}
var use_cache = {}
var inProgress = {}
var loadingStack = []
globalThis.use = function use(file) {
if (use_cache[file]) return use_cache[file]
// If we've already begun loading this file in this chain, show the cycle
if (loadingStack.includes(file)) {
// Find where in the stack this file first appeared
let cycleIndex = loadingStack.indexOf(file)
// Extract just the modules in the cycle
let cyclePath = loadingStack.slice(cycleIndex).concat(file)
throw new Error(
`Circular dependency detected while loading "${file}".\n` +
`Module chain: ${loadingStack.join(" -> ")}\n` +
`Cycle specifically: ${cyclePath.join(" -> ")}`
)
}
// Already fully loaded? Return it
if (use_cache[file]) {
return use_cache[file]
}
// If it's loading (but not on the stack), mark it as a new chain entry
// (This is optional if you just rely on loadingStack.
// But if you'd like a simple “already loading” check, keep 'inProgress'.)
if (inProgress[file]) {
throw new Error(`Circular dependency detected while loading "${file}"`)
}
inProgress[file] = true
// Push onto loading stack for chain tracking
loadingStack.push(file)
// Actually load the module
var mod = script_fn(file)
// Done loading, remove from the chain and mark as loaded
loadingStack.pop()
delete inProgress[file]
// Cache and return
use_cache[file] = mod.module_ret
return use_cache[file]
}