220 lines
5.4 KiB
TypeScript
220 lines
5.4 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { createDirectoryModel } from "../src/directory-model.js";
|
|
import { populateRoutingMetadata } from "../src/routing-metadata.js";
|
|
|
|
describe("routing metadata", () => {
|
|
it("generates tags from file purposes and exports", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/auth",
|
|
role: "Auth layer",
|
|
files: [
|
|
{
|
|
name: "tokens.ts",
|
|
purpose: "JWT generation and validation",
|
|
exports: ["issueToken", "verifyToken"],
|
|
deps: ["crypto"],
|
|
},
|
|
],
|
|
arch: "Auth",
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
expect(model.tags.length).toBeGreaterThan(0);
|
|
expect(model.tags).toContain("jwt");
|
|
expect(model.tags).toContain("token");
|
|
});
|
|
|
|
it("generates symbols from exports", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/utils",
|
|
role: "Utilities",
|
|
files: [
|
|
{
|
|
name: "helpers.ts",
|
|
purpose: "Helpers",
|
|
exports: ["formatDate", "parseUrl", "formatDate"],
|
|
deps: [],
|
|
},
|
|
],
|
|
arch: "Utils",
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
expect(model.symbols.length).toBeGreaterThan(0);
|
|
expect(model.symbols).toContain("formatDate");
|
|
expect(model.symbols).toContain("parseUrl");
|
|
});
|
|
|
|
it("caps tags at default limit", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/big",
|
|
role: "Big module",
|
|
files: Array.from({ length: 20 }, (_, i) => ({
|
|
name: `file${i}.ts`,
|
|
purpose: `Purpose ${i} with many unique words ${i}`,
|
|
exports: [`export${i}A`, `export${i}B`],
|
|
deps: [`dep${i}`],
|
|
})),
|
|
arch: "Big",
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
expect(model.tags.length).toBeLessThanOrEqual(8);
|
|
});
|
|
|
|
it("caps symbols at default limit", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/big",
|
|
role: "Big module",
|
|
files: Array.from({ length: 20 }, (_, i) => ({
|
|
name: `file${i}.ts`,
|
|
purpose: `Purpose ${i}`,
|
|
exports: [`export${i}A`, `export${i}B`],
|
|
deps: [],
|
|
})),
|
|
arch: "Big",
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
expect(model.symbols.length).toBeLessThanOrEqual(8);
|
|
});
|
|
|
|
it("generates workflow hints for source directories", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/cli",
|
|
role: "CLI",
|
|
files: [
|
|
{
|
|
name: "cli.ts",
|
|
purpose: "CLI entrypoint",
|
|
exports: ["main"],
|
|
deps: [],
|
|
},
|
|
{
|
|
name: "cli.test.ts",
|
|
purpose: "CLI tests",
|
|
exports: [],
|
|
deps: [],
|
|
},
|
|
],
|
|
arch: "CLI",
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
expect(model.workflows.length).toBeGreaterThan(0);
|
|
const changeBehavior = model.workflows.find((w) =>
|
|
w.task.includes("change"),
|
|
);
|
|
expect(changeBehavior).toBeDefined();
|
|
});
|
|
|
|
it("omits workflows for non-source directories", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "docs",
|
|
role: "Documentation",
|
|
files: [
|
|
{
|
|
name: "README.md",
|
|
purpose: "Readme",
|
|
exports: [],
|
|
deps: [],
|
|
},
|
|
],
|
|
arch: "Docs",
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
expect(model.workflows).toEqual([]);
|
|
});
|
|
|
|
it("caps workflow hints at default limit", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/cli",
|
|
role: "CLI",
|
|
files: [
|
|
{ name: "cli.ts", purpose: "CLI", exports: ["main"], deps: [] },
|
|
{ name: "config.ts", purpose: "Config", exports: [], deps: [] },
|
|
{ name: "cli.test.ts", purpose: "Tests", exports: [], deps: [] },
|
|
{ name: "commands.ts", purpose: "Commands", exports: [], deps: [] },
|
|
],
|
|
arch: "CLI",
|
|
});
|
|
model.children = ["src/cli/sub"];
|
|
|
|
populateRoutingMetadata(model);
|
|
expect(model.workflows.length).toBeLessThanOrEqual(5);
|
|
});
|
|
|
|
it("workflow hints include read targets for relevant files", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/auth",
|
|
role: "Auth",
|
|
files: [
|
|
{
|
|
name: "tokens.ts",
|
|
purpose: "Tokens",
|
|
exports: ["issueToken"],
|
|
deps: [],
|
|
},
|
|
{
|
|
name: "tokens.test.ts",
|
|
purpose: "Token tests",
|
|
exports: [],
|
|
deps: [],
|
|
},
|
|
],
|
|
arch: "Auth",
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
const testWorkflow = model.workflows.find((w) => w.task.includes("test"));
|
|
expect(testWorkflow).toBeDefined();
|
|
expect(testWorkflow!.read).toContain("tokens.test.ts");
|
|
});
|
|
|
|
it("workflow hints include index targets for directories with children", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src",
|
|
role: "Source",
|
|
files: [
|
|
{
|
|
name: "index.ts",
|
|
purpose: "Exports",
|
|
exports: [],
|
|
deps: [],
|
|
},
|
|
],
|
|
arch: "Source",
|
|
children: ["src/auth", "src/cli"],
|
|
});
|
|
|
|
populateRoutingMetadata(model);
|
|
const exploreWorkflow = model.workflows.find((w) =>
|
|
w.task.includes("explore"),
|
|
);
|
|
expect(exploreWorkflow).toBeDefined();
|
|
expect(exploreWorkflow!.index).toContain("src/auth/.pi-map.index.md");
|
|
expect(exploreWorkflow!.index).toContain("src/cli/.pi-map.index.md");
|
|
});
|
|
|
|
it("respects explicit tagCap and workflowHintCap options", () => {
|
|
const model = createDirectoryModel({
|
|
dir: "src/big",
|
|
role: "Big module",
|
|
files: Array.from({ length: 20 }, (_, i) => ({
|
|
name: `file${i}.ts`,
|
|
purpose: `Purpose ${i} with many unique words ${i}`,
|
|
exports: [`export${i}A`, `export${i}B`],
|
|
deps: [`dep${i}`],
|
|
})),
|
|
arch: "Big",
|
|
children: ["src/big/sub"],
|
|
});
|
|
|
|
populateRoutingMetadata(model, { tagCap: 3, workflowHintCap: 2 });
|
|
expect(model.tags.length).toBeLessThanOrEqual(3);
|
|
expect(model.symbols.length).toBeLessThanOrEqual(3);
|
|
expect(model.workflows.length).toBeLessThanOrEqual(2);
|
|
});
|
|
});
|