import { defineConfig, type Plugin } from "vite"; import react from "@vitejs/plugin-react"; import { readFileSync } from "node:fs"; import { resolve, sep } from "node:path"; /** * 开发期源码服务:GET /__source?root=&file=&start=&end= * 按报告里的 location 从磁盘读取真实源码片段,实现「报告 → 代码库」绑定。 * 仅用于本地开发;做了基本的路径穿越防护(结果路径必须落在 root 内)。 */ function sourceServer(): Plugin { return { name: "code-visualize-source-server", configureServer(server) { server.middlewares.use("/__source", (req, res) => { try { const url = new URL(req.url ?? "", "http://localhost"); const root = url.searchParams.get("root") ?? ""; const file = url.searchParams.get("file") ?? ""; const start = Number(url.searchParams.get("start") ?? "1"); const end = Number(url.searchParams.get("end") ?? String(start)); if (!root || !file) { res.statusCode = 400; res.end("missing root/file"); return; } const rootResolved = resolve(root); const target = resolve(rootResolved, file); if (target !== rootResolved && !target.startsWith(rootResolved + sep)) { res.statusCode = 403; res.end("path escapes root"); return; } const content = readFileSync(target, "utf-8"); const allLines = content.split(/\r?\n/); const from = Math.max(1, start); const to = Math.min(allLines.length, Math.max(from, end)); const code = allLines.slice(from - 1, to).join("\n"); res.setHeader("Content-Type", "application/json; charset=utf-8"); res.end(JSON.stringify({ file, startLine: from, endLine: to, code })); } catch (e) { res.statusCode = 404; res.end(e instanceof Error ? e.message : "read error"); } }); }, }; } export default defineConfig({ plugins: [react(), sourceServer()], server: { port: 5300, open: true, }, });