// Invoked as `node scripts/vitest-cli-compat.mjs ...` (see package.json `test`); no shebang so the // module also imports cleanly under Vite/Rollup in vitest-cli-compat.test.mjs. The CLI body below is // gated behind `isCliEntrypoint`, so importing this file never spawns vitest. import { spawn } from "node:child_process"; import { chmod, copyFile, mkdtemp, rm } from "node:fs/promises"; import { delimiter, join } from "node:path"; import { tmpdir } from "node:os"; import { fileURLToPath, pathToFileURL } from "node:url"; const defaultAppTestRoot = "apps/web/app/"; const isCliEntrypoint = process.argv[1] ? import.meta.url === pathToFileURL(process.argv[1]).href : false; export function normalizeVitestArgs(vitestArgs) { const brokenTenantArg = vitestArgs.find((arg) => arg.includes("app./")); if (brokenTenantArg) { throw new Error(`Refusing to repair shell-expanded tenant route path "${brokenTenantArg}". Quote paths containing $tenant or use apps/web/app/... explicitly.`); } const repairedArgs = vitestArgs; const hasDefaultAppTestRoot = repairedArgs.includes(defaultAppTestRoot); const hasExplicitTestPath = repairedArgs.some((arg, index) => index > 0 && arg !== defaultAppTestRoot && /^(?:app|apps\/web\/app)\/.*\.test\.[cm]?[jt]sx?$/.test(arg)); if (!hasDefaultAppTestRoot || !hasExplicitTestPath) return repairedArgs; return repairedArgs.filter((arg, index) => { if (arg === defaultAppTestRoot) return false; return !(arg === "--" && repairedArgs[index - 1] === defaultAppTestRoot); }); } export function appendNodeOption(nodeOptions, option) { return [nodeOptions, option].filter(Boolean).join(" "); } async function createPnpmExecCompatShimDir() { const shimDir = await mkdtemp(join(tmpdir(), "toolctrl-vitest-compat-")); await Promise.all(["eslint", "vitest"].map((name) => copyPnpmExecCompatShim(shimDir, name))); return shimDir; } async function copyPnpmExecCompatShim(shimDir, name) { const shimSource = fileURLToPath(new URL(`./${name}-pnpm-exec-shim.cjs`, import.meta.url)); const shimDestination = join(shimDir, name); await copyFile(shimSource, shimDestination); await chmod(shimDestination, 0o755); } if (isCliEntrypoint) { // Computed here (not at module top level) so importing this file for unit tests never touches // `import.meta.url` under Vite, where it is not a file: URL and `fileURLToPath` would throw. const vitestEntry = fileURLToPath(new URL("../node_modules/vitest/vitest.mjs", import.meta.url)); const repoRoot = fileURLToPath(new URL("..", import.meta.url)); const rawArgs = process.argv.slice(2); const args = rawArgs.flatMap((arg) => (arg === "--runInBand" ? ["--single-thread"] : [arg])); const normalizedArgs = normalizeVitestArgs(args); let shimDir; const storageDir = await mkdtemp(join(tmpdir(), "toolctrl-vitest-storage-")); let childEnv = { ...process.env, VITEST_PNPM_EXEC_COMPAT_READY: "1", TOOLCTRL_REPO_ROOT: repoRoot }; if (!process.env.VITEST_PNPM_EXEC_COMPAT_READY) { shimDir = await createPnpmExecCompatShimDir(); childEnv = { ...childEnv, PATH: `${shimDir}${delimiter}${process.env.PATH ?? ""}` }; } childEnv.NODE_OPTIONS = appendNodeOption(childEnv.NODE_OPTIONS, `--localstorage-file=${join(storageDir, "localstorage.json")}`); const child = spawn(process.execPath, [vitestEntry, ...normalizedArgs], { cwd: repoRoot, stdio: "inherit", env: childEnv, }); child.on("exit", async (code, signal) => { await Promise.all([shimDir ? rm(shimDir, { recursive: true, force: true }) : Promise.resolve(), rm(storageDir, { recursive: true, force: true })]); if (signal) { process.kill(process.pid, signal); return; } process.exit(code ?? 1); }); }