pr_01m47d15m3e54sn21z27rpy5n9/services/context/src/extract.test.ts

124 lines6,730 bytesCodeBlame
1import { test } from "node:test";
2import assert from "node:assert/strict";
3
4import { chunk, extract, interesting, packageManager, parseJsonc, parseToml } from "./extract.ts";
5
6const ctx = { project: "web", siblings: ["package.json", "pnpm-lock.yaml", "tsconfig.json"] };
7
8test("only manifests, docs, workflows and ownership are read", () => {
9 for (const path of ["package.json", "Cargo.toml", "go.mod", "pyproject.toml", "README.md", "AGENTS.md", "docs/deploy.md", ".g1t/workflows/ci.yml", ".github/workflows/test.yaml", "openapi.yaml", "wrangler.jsonc", ".g1t/project.yml", "CODEOWNERS"]) {
10 assert.ok(interesting(path), path);
11 }
12 for (const path of ["src/index.ts", "docs/img.png", "node_modules/x/package.json", "apps/web/package.json", "docs/deep/nested.md"]) {
13 assert.ok(!interesting(path), path);
14 }
15});
16
17test("package.json gives the package, its language, its package manager and its scripts", () => {
18 const facts = extract(
19 "package.json",
20 JSON.stringify({
21 name: "@acme/web",
22 version: "1.2.0",
23 scripts: { test: "vitest run", typecheck: "tsc -p .", dev: "vite" },
24 dependencies: { react: "^19" },
25 devDependencies: { typescript: "^5" },
26 workspaces: ["apps/*", "packages/*"],
27 }),
28 ctx,
29 );
30 assert.deepEqual(facts.languages, ["TypeScript"]);
31 assert.equal(facts.packages[0].name, "@acme/web");
32 assert.deepEqual(facts.packages[0].dependencies, ["react", "typescript"]);
33 assert.deepEqual(facts.packages[0].members, ["apps/*", "packages/*"]);
34 const texts = facts.hints.map((hint) => hint.text);
35 assert.ok(texts.some((text) => text.includes("uses pnpm") && text.includes("not npm or yarn or bun")), texts.join("\n"));
36 assert.ok(texts.some((text) => text.includes("`pnpm test` runs the tests: `vitest run`")));
37 assert.ok(texts.some((text) => text.includes("`pnpm run typecheck`")));
38 assert.ok(!texts.some((text) => text.includes("dev")), "dev servers are not worth remembering");
39 assert.ok(texts.some((text) => text.includes("monorepo")));
40 // Facts read from a manifest are certain enough to keep.
41 assert.ok(facts.hints.every((hint) => hint.confidence >= 0.85));
42});
43
44test("Cargo.toml gives a crate or a workspace", () => {
45 const crate = extract(
46 "Cargo.toml",
47 `[package]\nname = "g1t-work" # the work service\nversion = "0.1.0"\n\n[dependencies]\nserde = { workspace = true }\nworker.workspace = true\n\n[dev-dependencies]\npretty = "1"\n`,
48 ctx,
49 );
50 assert.deepEqual(crate.languages, ["Rust"]);
51 assert.equal(crate.packages[0].name, "g1t-work");
52 assert.equal(crate.packages[0].version, "0.1.0");
53 assert.deepEqual(crate.packages[0].dependencies, ["serde", "worker.workspace", "pretty"]);
54 const workspace = extract("Cargo.toml", `[workspace]\nmembers = [\n "crates/a",\n "services/b",\n]\n`, ctx);
55 assert.deepEqual(workspace.packages[0].members, ["crates/a", "services/b"]);
56 assert.match(workspace.hints[0].text, /Cargo workspace \(crates\/a, services\/b\)/);
57});
58
59test("go.mod and pyproject.toml", () => {
60 const go = extract("go.mod", "module github.com/acme/api\n\ngo 1.23\n\nrequire (\n\tgithub.com/go-chi/chi/v5 v5.0.12\n)\n", ctx);
61 assert.equal(go.packages[0].name, "github.com/acme/api");
62 assert.deepEqual(go.packages[0].dependencies, ["github.com/go-chi/chi/v5"]);
63 const py = extract("pyproject.toml", `[project]\nname = "ml"\nversion = "0.3"\ndependencies = ["numpy>=2", "pytest"]\n`, ctx);
64 assert.deepEqual(py.languages, ["Python"]);
65 assert.deepEqual(py.packages[0].dependencies, ["numpy", "pytest"]);
66 assert.ok(py.hints.some((hint) => hint.text.includes("pytest")));
67});
68
69test("wrangler config and OpenAPI become APIs", () => {
70 const worker = extract(
71 "wrangler.jsonc",
72 `{\n // the API\n "name": "g1t-api", "$schema": "https://example.com/x.json",\n "routes": [{ "pattern": "api.g1t.sh", "custom_domain": true },],\n}`,
73 ctx,
74 );
75 assert.equal(worker.apis[0].name, "g1t-api");
76 assert.deepEqual(worker.apis[0].routes, ["api.g1t.sh"]);
77 const spec = extract("openapi.yaml", "openapi: 3.1.0\ninfo:\n title: Billing API\n version: '2'\npaths:\n /invoices:\n get: {}\n post: {}\n", ctx);
78 assert.equal(spec.apis[0].name, "Billing API");
79 assert.deepEqual(spec.apis[0].routes, ["GET /invoices", "POST /invoices"]);
80});
81
82test("AGENTS.md conventions are kept; a README's setup commands wait for review", () => {
83 const agents = extract(
84 "AGENTS.md",
85 "# Working here\n\n- Components live in src/components/ui; import from there.\n- Never edit generated.rs by hand.\n- [Docs](https://x)\n\n```sh\nnpm run db:reset\n```\n",
86 ctx,
87 );
88 assert.equal(agents.doc?.role, "agents");
89 const kinds = agents.hints.map((hint) => [hint.kind, hint.text, hint.confidence]);
90 assert.deepEqual(kinds, [
91 ["convention", "Components live in src/components/ui; import from there.", 0.9],
92 ["gotcha", "Never edit generated.rs by hand.", 0.9],
93 ["fact", "In web, for working here: `npm run db:reset`.", 0.9],
94 ]);
95 const readme = extract("README.md", "# Web\n\nThe storefront.\n\n## Testing\n\n```\n$ TZ=UTC npm test\nnpm test\n```\n\n## Features\n\n- Lots of features that are really great\n", ctx);
96 assert.equal(readme.doc?.title, "Web");
97 assert.equal(readme.doc?.summary, "The storefront.");
98 assert.deepEqual(
99 readme.hints.map((hint) => [hint.text, hint.confidence]),
100 [["In web, for testing: `npm test`.", 0.7]],
101 );
102});
103
104test("owners come from project.yml and CODEOWNERS; workflows say whether they test", () => {
105 assert.deepEqual(extract(".g1t/project.yml", "owners:\n - ana\n - '@bo'\ndependsOn: [api]\n", ctx).owners, ["ana", "bo"]);
106 assert.deepEqual(extract("CODEOWNERS", "# owners\n* @ana @acme/platform\n/docs @cy\n", ctx).owners, ["ana", "cy"]);
107 assert.equal(extract(".g1t/workflows/ci.yml", "jobs:\n t:\n steps:\n - run: npm test\n", ctx).tests, true);
108 assert.equal(extract(".g1t/workflows/deploy.yml", "jobs:\n d:\n steps:\n - run: wrangler deploy\n", ctx).tests, false);
109});
110
111test("a file that does not parse says nothing", () => {
112 assert.deepEqual(extract("package.json", "{ nope", ctx).packages, []);
113});
114
115test("parsers and helpers", () => {
116 assert.deepEqual(parseJsonc('{"a": "http://x//y", /* c */ "b": [1,],}'), { a: "http://x//y", b: [1] });
117 assert.deepEqual(parseToml('x = 1\n[a]\nb = "c" # d\nlist = ["e", \'f\']').a, { b: "c", list: ["e", "f"] });
118 assert.equal(packageManager(["yarn.lock"]), "yarn");
119 assert.equal(packageManager([]), null);
120 const pieces = chunk(`# T\n\nintro\n\n## A\n\n${"a".repeat(2000)}\n\n## B\n\nb`, "T");
121 assert.equal(pieces.length, 4);
122 assert.ok(pieces[2].startsWith("A (continued)"));
123 assert.ok(pieces.every((piece) => piece.length <= 1500 + 40));
124});