import { existsSync, readdirSync, statSync } from "node:fs"; import { resolve } from "node:path"; import { fileURLToPath, URL } from "node:url"; import type { Plugin } from "vite"; import { defineConfig } from "vitest/config"; const repoRoot = fileURLToPath(new URL("../..", import.meta.url)).replace(/\/+$/, ""); function repoPath(p: string): string { const abs = resolve(repoRoot, p.replace(/^\/+/, "")); if (abs !== repoRoot && !abs.startsWith(`${repoRoot}/`)) { throw new Error(`path outside repo root: ${p}`); } return abs; } function nengineFsPlugin(): Plugin { return { name: "nengine-fs", configureServer(server) { server.middlewares.use((req, res, next) => { if (req.url === "/" || req.url?.startsWith("/?")) { req.url = "/apps/dev/index.html"; next(); return; } const url = new URL(req.url ?? "/", "http://localhost"); const target = url.searchParams.get("p"); if (!target) { next(); return; } let abs: string; try { abs = repoPath(target); } catch { res.statusCode = 404; res.end("bad path"); return; } if (url.pathname === "/__nengine_fs/readdir") { if (!existsSync(abs)) { res.statusCode = 404; res.end("ENOENT"); return; } const entries = readdirSync(abs, { withFileTypes: true }); const body = url.searchParams.get("detailed") === "1" ? JSON.stringify(entries.map((e) => ({ name: e.name, isDirectory: e.isDirectory() }))) : JSON.stringify(entries.map((e) => e.name)); res.setHeader("content-type", "application/json; charset=utf-8"); res.end(body); return; } if (url.pathname === "/__nengine_fs/stat") { if (!existsSync(abs)) { res.statusCode = 404; res.end("ENOENT"); return; } res.setHeader("content-type", "application/json; charset=utf-8"); res.end(JSON.stringify({ isDirectory: statSync(abs).isDirectory() })); return; } if (url.pathname === "/__nengine_fs/exists") { res.setHeader("content-type", "text/plain; charset=utf-8"); res.end(existsSync(abs) ? "1" : "0"); return; } next(); }); }, }; } export default defineConfig({ root: repoRoot, plugins: [nengineFsPlugin()], resolve: { alias: { "@nengine/core": fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)), "@nengine/render": fileURLToPath(new URL("../../packages/render/src/index.ts", import.meta.url)), "node:fs/promises": fileURLToPath(new URL("./src/shim/fs-promises.ts", import.meta.url)), "node:fs": fileURLToPath(new URL("./src/shim/fs.ts", import.meta.url)), "node:path": fileURLToPath(new URL("./src/shim/path.ts", import.meta.url)), "node:url": fileURLToPath(new URL("./src/shim/url.ts", import.meta.url)), }, }, build: { outDir: "apps/dev/dist", emptyOutDir: true, rollupOptions: { input: fileURLToPath(new URL("./index.html", import.meta.url)), }, }, test: { include: ["apps/dev/src/**/*.test.ts"], environment: "node", }, });