import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { listFileSuggestions, type FileSuggestionDependencies } from "./fileSuggestions"; const temporaryRoots: string[] = []; async function tempWorkspace(): Promise { const root = await mkdtemp(join(tmpdir(), "pi-web-files-")); temporaryRoots.push(root); return root; } afterEach(async () => { await Promise.all(temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); }); describe("file suggestions", () => { it("uses tracked git files for tracked-scope suggestions", async () => { const calls: { file: string; args: string[] }[] = []; const deps: FileSuggestionDependencies = { execFile: (file, args) => { calls.push({ file, args }); if (file === "git" && args.join(" ") === "ls-files") return Promise.resolve({ stdout: "src/app.ts\nREADME.md\n" }); return Promise.reject(new Error(`unexpected command: ${file} ${args.join(" ")}`)); }, }; await expect(listFileSuggestions("/repo", "", { scope: "tracked" }, deps)).resolves.toEqual([ { path: "src/", kind: "tracked" }, { path: "README.md", kind: "tracked" }, { path: "src/app.ts", kind: "tracked" }, ]); expect(calls).toEqual([{ file: "git", args: ["ls-files"] }]); }); it("asks ripgrep for hidden and ignored files in all-file scope", async () => { const calls: { file: string; args: string[] }[] = []; const deps: FileSuggestionDependencies = { execFile: (file, args) => { calls.push({ file, args }); return Promise.resolve({ stdout: "node_modules/pkg/index.js\nsrc/app.ts\n" }); }, }; await expect(listFileSuggestions("/repo", "pkg", { scope: "all" }, deps)).resolves.toEqual([ { path: "node_modules/pkg/", kind: "other" }, { path: "node_modules/pkg/index.js", kind: "other" }, ]); expect(calls).toEqual([{ file: "rg", args: ["--files", "--hidden", "--no-ignore"] }]); }); it("falls back to a bounded filesystem scan without directory exclusions when git and rg are unavailable", async () => { const root = await tempWorkspace(); await mkdir(join(root, "src"), { recursive: true }); await mkdir(join(root, "node_modules", "pkg"), { recursive: true }); await writeFile(join(root, "README.md"), "hello"); await writeFile(join(root, "src", "app.ts"), "export {};\n"); await writeFile(join(root, "node_modules", "pkg", "index.js"), "module.exports = {};\n"); const deps: FileSuggestionDependencies = { execFile: (file) => Promise.reject(Object.assign(new Error(`spawn ${file} ENOENT`), { code: "ENOENT" })), }; await expect(listFileSuggestions(root, "", { scope: "all" }, deps)).resolves.toEqual([ { path: "node_modules/", kind: "other" }, { path: "node_modules/pkg/", kind: "other" }, { path: "src/", kind: "other" }, { path: "node_modules/pkg/index.js", kind: "other" }, { path: "README.md", kind: "other" }, { path: "src/app.ts", kind: "other" }, ]); }); });