import { describe, expect, it } from "vitest"; import { FactIndex, makeUsageNodeFact } from "../index.js"; import type { UsageNodeFact } from "../index.js"; import { regionsByPrefix, type Region } from "./utils.js"; /** * Build a `usage_node` fact and add it to the index. Tests assert container / * member *relationships*, never literal `nodePath` strings — segments are * opaque (per the usage-node-fact contract). */ function node( ix: FactIndex, nodePath: string, element: string, file = "src/App.tsx" ): UsageNodeFact { const fact = makeUsageNodeFact({ file, nodePath, element, location: { file, line: 1, column: 1 }, }); ix.add(fact); return fact; } function regionFor(regions: Region[], container: UsageNodeFact): Region { const region = regions.find((r) => r.container.id === container.id); if (!region) throw new Error(`no region for container ${container.nodePath}`); return region; } const memberIds = (region: Region) => new Set(region.members.map((m) => m.id)); describe("regionsByPrefix", () => { // ACCEPTANCE §1 — sibling grouping under a container. it("groups sibling children under their container", () => { const ix = new FactIndex(); const n0 = node(ix, "0:0", "ButtonGroup"); const n1 = node(ix, "0:0/0", "Button"); const n2 = node(ix, "0:0/1", "Button"); const regions = regionsByPrefix(ix); const members = memberIds(regionFor(regions, n0)); expect(members.has(n1.id)).toBe(true); expect(members.has(n2.id)).toBe(true); // n1 and n2 are siblings: neither contains the other. expect(regionFor(regions, n1).members).toHaveLength(0); expect(regionFor(regions, n2).members).toHaveLength(0); }); // ACCEPTANCE §2 — opaque conditional segment stays in-region. it("keeps an opaque conditional (expr:) child in the container's region", () => { const ix = new FactIndex(); const n0 = node(ix, "0:0", "ButtonGroup"); const n1 = node(ix, "0:0/0", "Button"); const n2 = node(ix, "0:0/expr:0/0", "Button"); // {show &&