Files
eezd bc480fb806 Refactor frontend workspaces and centralize API contracts
Organize domain APIs and types under common/apis, shared components under named folders, and private workspace logic alongside each page.

Use Bearer sessions, explicit response envelopes, session-aware routing and streams, and configurable login captcha presentation for the deployed backend contract.

Preserve news, economic calendar, crawler, market, chat, Skills, settings, and demo trading workflows with responsive layouts and explicit configuration saves.

Validate with frontend lint, type checking, 22 test groups, production builds, and deployed desktop/mobile page checks.
2026-10-26 11:39:52 +08:00

44 lines
1.9 KiB
TypeScript

import { existsSync, readFileSync } from "node:fs"
import { createRequire, Module } from "node:module"
import { dirname, resolve } from "node:path"
import { runInNewContext } from "node:vm"
import ts from "typescript"
import { compileScript, parse } from "vue/compiler-sfc"
export const require = createRequire(import.meta.url)
const source = new URL("../src/", import.meta.url).pathname
/** 使用现有 TS/Vue 编译器执行真实模块;只替换 I/O 和浏览器生命周期。 */
export function moduleLoader(mocks: Record<string, unknown>, globals: Record<string, unknown> = {}) {
const cache = new Map<string, Module>()
function load(name: string, parent = source): any {
if (name in mocks) return mocks[name]
if (!name.startsWith("@/") && !name.startsWith("@@/") && !name.startsWith(".")) return require(name)
let filename = name.startsWith("@@/")
? resolve(source, "common", name.slice(3))
: name.startsWith("@/") ? resolve(source, name.slice(2)) : resolve(parent, name)
if (!/\.(?:vue|ts)$/.test(filename)) filename = existsSync(`${filename}.ts`) ? `${filename}.ts` : resolve(filename, "index.ts")
if (cache.has(filename)) return cache.get(filename)!.exports
const mod = new Module(filename)
cache.set(filename, mod)
let script = readFileSync(filename, "utf8")
if (filename.endsWith(".vue")) script = compileScript(parse(script).descriptor, { id: filename }).content
const code = ts.transpileModule(script, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 } }).outputText
runInNewContext(code, {
module: mod,
exports: mod.exports,
require: (value: string) => load(value, dirname(filename)),
console,
Error,
setTimeout,
clearTimeout,
AbortController,
TextDecoder,
URL,
...globals
}, { filename })
return mod.exports
}
return load
}