Files
openclaw/test/scripts/ts-topology.test.ts
2026-03-28 13:49:16 +00:00

155 lines
5.2 KiB
TypeScript

import path from "node:path";
import { describe, expect, it } from "vitest";
import { analyzeTopology } from "../../scripts/lib/ts-topology/analyze.js";
import { renderTextReport } from "../../scripts/lib/ts-topology/reports.js";
import { createFilesystemPublicSurfaceScope } from "../../scripts/lib/ts-topology/scope.js";
import { main } from "../../scripts/ts-topology.ts";
import { createCapturedIo } from "../helpers/captured-io.js";
const repoRoot = path.join(process.cwd(), "test", "fixtures", "ts-topology", "basic");
function buildFixtureScope() {
return createFilesystemPublicSurfaceScope(repoRoot, {
id: "custom",
entrypointRoot: "src/public",
importPrefix: "fixture-sdk",
});
}
describe("ts-topology", () => {
it("collapses canonical symbols exported by multiple public subpaths", () => {
const envelope = analyzeTopology({
repoRoot,
scope: buildFixtureScope(),
report: "public-surface-usage",
});
const sharedThing = envelope.records.find((record) =>
record.exportNames.includes("sharedThing"),
);
expect(sharedThing).toMatchObject({
declarationPath: "src/lib/shared.ts",
declarationLine: 1,
productionExtensions: ["alpha", "beta"],
productionPackages: ["src"],
productionOwners: ["extension:alpha", "extension:beta", "src"],
});
expect(sharedThing?.publicSpecifiers).toEqual(["fixture-sdk", "fixture-sdk/extra"]);
});
it("counts renamed imports, namespace imports, type-only imports, and test-only consumers", () => {
const envelope = analyzeTopology({
repoRoot,
scope: buildFixtureScope(),
report: "public-surface-usage",
});
const aliasedThing = envelope.records.find((record) =>
record.exportNames.includes("aliasedThing"),
);
const sharedType = envelope.records.find((record) => record.exportNames.includes("SharedType"));
const testOnlyThing = envelope.records.find((record) =>
record.exportNames.includes("testOnlyThing"),
);
expect(aliasedThing?.productionRefCount).toBe(1);
expect(sharedType).toMatchObject({
isTypeOnlyCandidate: true,
productionExtensions: ["alpha", "beta"],
productionRefCount: 2,
});
expect(testOnlyThing).toMatchObject({
productionRefCount: 0,
testRefCount: 1,
testConsumers: ["tests/public.test.ts"],
});
});
it("surfaces single-owner shared and unused reports correctly", () => {
const singleOwner = analyzeTopology({
repoRoot,
scope: buildFixtureScope(),
report: "single-owner-shared",
});
const unused = analyzeTopology({
repoRoot,
scope: buildFixtureScope(),
report: "unused-public-surface",
});
expect(singleOwner.records.map((record) => record.exportNames[0])).toContain(
"singleOwnerHelper",
);
expect(singleOwner.records.map((record) => record.exportNames[0])).not.toContain("sharedThing");
expect(unused.records.map((record) => record.exportNames[0])).toEqual(["unusedThing"]);
});
it("renders stable text summaries for the public-surface report", () => {
const envelope = analyzeTopology({
repoRoot,
scope: buildFixtureScope(),
report: "public-surface-usage",
limit: 3,
});
expect(renderTextReport(envelope, 3)).toMatchInlineSnapshot(`
"Scope: custom
Public exports analyzed: 6
Production-used exports: 4
Single-owner shared exports: 2
Unused public exports: 1
Top 2 candidate-to-move exports:
- fixture-sdk:aliasedThing -> src/lib/shared.ts:9 (prodRefs=1, owners=extension:alpha, sharedness=35, move=85)
- fixture-sdk:singleOwnerHelper -> src/lib/shared.ts:5 (prodRefs=1, owners=extension:alpha, sharedness=35, move=85)
Top 1 duplicated public exports:
- fixture-sdk:sharedThing via fixture-sdk, fixture-sdk/extra (src/lib/shared.ts:1)"
`);
});
it("emits stable JSON and filtered report output through the CLI", async () => {
const captured = createCapturedIo();
const jsonExit = await main(
[
"--scope=custom",
"--entrypoint-root=src/public",
"--import-prefix=fixture-sdk",
"--repo-root=test/fixtures/ts-topology/basic",
"--report=single-owner-shared",
"--json",
],
captured.io,
);
expect(jsonExit).toBe(0);
const payload = JSON.parse(captured.readStdout());
expect(payload.report).toBe("single-owner-shared");
expect(
payload.records.map((record: { exportNames: string[] }) => record.exportNames[0]),
).toEqual(["aliasedThing", "singleOwnerHelper"]);
const textCaptured = createCapturedIo();
const textExit = await main(
[
"--scope=custom",
"--entrypoint-root=src/public",
"--import-prefix=fixture-sdk",
"--repo-root=test/fixtures/ts-topology/basic",
"--report=consumer-topology",
"--limit=2",
],
textCaptured.io,
);
expect(textExit).toBe(0);
expect(textCaptured.readStdout()).toMatchInlineSnapshot(`
"Scope: custom
Records with consumers: 5
Top 2 consumer-topology records:
- fixture-sdk:sharedThing prod=3 test=0 internal=0
- fixture-sdk:SharedType prod=2 test=0 internal=0
"
`);
});
});