import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { PROJECT_SUMMARY_MAX_LENGTH, readProjectSummary, summarizeProjectFiles, } from "./project-summary.js"; describe("summarizeProjectFiles", () => { it("takes the README's first prose paragraph and skips headings, badges and code", () => { const readme = [ "# Sugar Rush", "", "[![CI](https://ci.example/badge.svg)](https://ci.example)", "", "```sh", "pnpm install", "```", "", "A **candy** shop game for [kids](https://example.com),", "built with React.", "", "## Setup", ].join("\n"); expect(summarizeProjectFiles({ readme })).toBe("A candy shop game for kids, built with React."); }); it("falls back to a manifest description", () => { expect( summarizeProjectFiles({ readme: "# Title only", packageJson: '{"description":"A CLI"}' }), ).toBe("A CLI"); expect(summarizeProjectFiles({ pyproject: '[project]\ndescription = "Data tools"\n' })).toBe( "Data tools", ); expect(summarizeProjectFiles({ cargoToml: '[package]\ndescription = "Fast parser"' })).toBe( "Fast parser", ); }); it("returns null when nothing describes the project", () => { expect(summarizeProjectFiles({})).toBeNull(); expect(summarizeProjectFiles({ readme: "# Title", packageJson: "not json" })).toBeNull(); }); it("clamps long descriptions", () => { const summary = summarizeProjectFiles({ readme: "word ".repeat(400) }); expect(summary?.length).toBe(PROJECT_SUMMARY_MAX_LENGTH); expect(summary?.endsWith("…")).toBe(true); }); }); describe("readProjectSummary", () => { let directory: string | undefined; afterEach(async () => { if (directory) await rm(directory, { recursive: true, force: true }); directory = undefined; }); it("reads the README of a folder", async () => { directory = await mkdtemp(path.join(tmpdir(), "project-summary-")); await writeFile(path.join(directory, "README.md"), "# App\n\nTracks habits.\n"); expect(await readProjectSummary(directory)).toBe("Tracks habits."); }); it("returns null for an empty folder", async () => { directory = await mkdtemp(path.join(tmpdir(), "project-summary-")); expect(await readProjectSummary(directory)).toBeNull(); }); });