g1t/services/context/src/extract.test.ts
| 1 | import { test } from "node:test"; |
| 2 | import assert from "node:assert/strict"; |
| 3 | |
| 4 | import { chunk, extract, interesting, packageManager, parseJsonc, parseToml } from "./extract.ts"; |
| 5 | |
| 6 | const ctx = { project: "web", siblings: ["package.json", "pnpm-lock.yaml", "tsconfig.json"] }; |
| 7 | |
| 8 | test("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 | |
| 17 | test("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 | |
| 44 | test("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 | |
| 59 | test("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 | |
| 69 | test("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 | |
| 82 | test("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 | |
| 104 | test("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 | |
| 111 | test("a file that does not parse says nothing", () => { |
| 112 | assert.deepEqual(extract("package.json", "{ nope", ctx).packages, []); |
| 113 | }); |
| 114 | |
| 115 | test("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 | }); |