import assert from "node:assert/strict"; import test from "node:test"; import { compileCapabilityResourceSource } from "../src/capability-language/index.js"; import { compileQuery } from "../src/query/compile.js"; import type { InterfaceRevision } from "../src/capability-model/types.js"; const source = { repository: "https://example.test/tree", commit: "a".repeat(40) }; function iface(text: string, dependencies: InterfaceRevision[] = []) { const result = compileCapabilityResourceSource(text, { source, environment: { interfaces: new Map(dependencies.map((value) => [value.displayName, value])), interfaceClosure: dependencies, }, }); assert.ok(result.ok, JSON.stringify(result.diagnostics)); if (result.resource.kind !== "interface") throw Error("Expected Interface"); return result.resource.revision; } const item = iface(`interface Item id "item" revision "item@1" { queryable value title id "title" : string {get id "title:get" execution snapshot;} queryable value body id "body" : string {get id "body:get" execution snapshot;} }`); const navigation = iface( `import interface Item; interface Navigation id "nav" revision "nav@1" { queryable value chrome id "chrome" : string {get id "chrome:get" execution snapshot;} queryable relation document id "document" : optional-one interface Item {resolve id "document:resolve" execution snapshot;} queryable relation items id "items" : many interface Item ordered {resolve id "items:resolve" execution snapshot;} }`, [item], ); function declaration(root: InterfaceRevision = item, dependencies: InterfaceRevision[] = []) { const result = compileCapabilityResourceSource( `import interface ${root.displayName}; package Views id "views" revision "views@1" { query Open id "open" root ${root.displayName} document "open.graphql" operation "Open" {replica; max rows 10;} }`, { source, environment: { interfaces: new Map([[root.displayName, root]]), interfaceClosure: [root, item, ...dependencies] }, }, ); assert.ok(result.ok, JSON.stringify(result.diagnostics)); if (result.resource.kind !== "package") throw Error("Expected Package"); return result.resource.revision.queries![0]!; } const fragments = `fragment Heading on Item {title} fragment Body on Item {body}`; test("boundaries remain complete typed projections; ordinary spreads stay inline", async () => { const checked = await compileQuery( declaration(), [item], async () => `query Open {root {...Heading ...Body @boundary(name:"body")}} ${fragments}`, ); assert(checked.tree); assert(!JSON.stringify(checked.output).includes('"body"')); assert(!JSON.stringify(checked.selection).includes('"body"')); const body = checked.tree.nodes.find((node) => node.id === "root/boundary/body")!; assert(body); assert( JSON.stringify(checked.tree.projections.find((projection) => projection.id === body.projection)!.output).includes( '"body"', ), ); assert.equal(checked.tree.nodes[0]!.boundaries[0]!.name, "body"); const ordinary = await compileQuery( declaration(), [item], async () => `query Open {root {...Heading ...Body}} ${fragments}`, ); assert.equal(ordinary.tree, undefined); assert(JSON.stringify(ordinary.output).includes('"body"')); }); test("minimal nullable-root bindings exclude slow siblings and carry child handles", async () => { const checked = await compileQuery( declaration(navigation), [item, navigation], async () => `query Open {root { ...Chrome @boundary(name:"chrome") document {...Heading @boundary(name:"basic") ...Body @boundary(name:"body")} }} fragment Chrome on Navigation {chrome} ${fragments}`, ); const tree = checked.tree!; const binding = tree.nodes[0]!.bindings[0]!; assert.equal(binding.name, "document"); const projection = tree.projections.find((projection) => projection.id === binding.projection)!; assert(!JSON.stringify(projection.selection).includes('"chrome"')); assert(!JSON.stringify(projection.selection).includes('"title"')); assert(!JSON.stringify(projection.selection).includes('"body"')); assert.deepEqual(binding.targets[0]!.path, ["document"]); assert.deepEqual( tree.nodes.find((node) => node.id === binding.targets[0]!.node)!.boundaries.map((boundary) => boundary.name), ["basic", "body"], ); }); test("bounded list bindings preserve entry identity without requesting details", async () => { const checked = await compileQuery( declaration(navigation), [item, navigation], async () => `query Open {root { items(first: 3) {entries {node {...Body @boundary(name:"body")}}} }} fragment Body on Item {body}`, ); const tree = checked.tree!, binding = tree.nodes[0]!.bindings[0]!; assert.deepEqual(binding.targets[0]!.path, ["items", "entries", "[]", "node"]); const projection = tree.projections.find((projection) => projection.id === binding.projection)!; assert(JSON.stringify(projection.selection).includes('"name":"key"')); assert(!JSON.stringify(projection.selection).includes('"name":"body"')); assert(tree.maxOccurrences <= 256); }); test("literal collection windows bound handles independently of detail row budgets", async () => { const source = { ...declaration(navigation), budgets: { ...declaration(navigation).budgets, rows: 20000 } }; const query = (limit: string, variables = "") => `query Open${variables} {root { items(first: ${limit}) {entries {node {...Body @boundary(name:"body")}}} }} fragment Body on Item {body}`; const checked = await compileQuery(source, [item, navigation], async () => query("3")); assert.equal(checked.tree!.maxOccurrences, 7); await assert.rejects( compileQuery(source, [item, navigation], async () => query("200")), /QUERY_TREE_LIMIT/, ); await assert.rejects( compileQuery(source, [item, navigation], async () => query("$first", "($first:Int!)")), /QUERY_TREE_LIMIT/, ); const group = iface( `import interface Item; interface Group id "group" revision "group@1" { queryable relation items id "group:items" : many interface Item ordered {resolve id "group:items:resolve" execution snapshot;} }`, [item], ); const groups = iface( `import interface Group; interface Groups id "groups" revision "groups@1" { queryable relation groups id "groups:groups" : many interface Group ordered {resolve id "groups:groups:resolve" execution snapshot;} }`, [item, group], ); const nested = { ...declaration(groups, [group]), budgets: source.budgets }; const nestedQuery = (outer: number, inner: number) => `query Open {root { groups(first:${outer}) {entries {node {items(first:${inner}) {entries {node {...Body @boundary(name:"body")}}}}}} }} fragment Body on Item {body}`; const bounded = await compileQuery(nested, [item, group, groups], async () => nestedQuery(2, 3)); assert.equal(bounded.tree!.maxOccurrences, 15, "Nested windows multiply instead of reusing the outer bound"); await assert.rejects( compileQuery(nested, [item, group, groups], async () => nestedQuery(20, 20)), /QUERY_TREE_LIMIT/, ); }); test("guards control boundary participation and invalid syntax fails checking", async () => { const checked = await compileQuery( declaration(), [item], async () => `query Open($show:Boolean!) {root { ...Body @boundary(name:"body") @include(if:$show) }} fragment Body on Item {body}`, ); assert.deepEqual(checked.tree!.nodes[0]!.boundaries[0]!.conditions, [ { include: true, value: { kind: "variable", name: "show" } }, ]); for (const [text, error] of [ [`query Open {root {...Body @boundary(name:"")}} fragment Body on Item {body}`, /QUERY_BOUNDARY_NAME/], [ `query Open($name:String!) {root {...Body @boundary(name:$name)}} fragment Body on Item {body}`, /QUERY_BOUNDARY_NAME/, ], [ `query Open {root {...Body @boundary(name:"x") ...Heading @boundary(name:"x")}} ${fragments}`, /QUERY_BOUNDARY_DUPLICATE/, ], [`query Open {root {body @boundary(name:"x")}}`, /QUERY_VALIDATION/], [`query Open {root {...Cycle @boundary(name:"x")}} fragment Cycle on Item {...Cycle}`, /QUERY_VALIDATION/], ] as const) await assert.rejects( compileQuery(declaration(), [item], async () => text), error, ); }); test("equivalent repeated paths share bindings; aliases preserve different windows", async () => { const checked = await compileQuery( declaration(navigation), [item, navigation], async () => `query Open {root { document {...Heading @boundary(name:"basic")} document {...Body @boundary(name:"body")} recent:items(first:2) {entries {node {...Body @boundary(name:"body")}}} earlier:items(first:3) {entries {node {...Body @boundary(name:"body")}}} }} ${fragments}`, ); assert.deepEqual( checked.tree!.nodes[0]!.bindings.map((binding) => binding.name), ["document", "recent", "earlier"], ); assert.deepEqual( checked .tree!.nodes.find((node) => node.id === "root/binding/document")! .boundaries.map((boundary) => boundary.name), ["basic", "body"], ); await assert.rejects( compileQuery( declaration(navigation), [item, navigation], async () => `query Open($show:Boolean!) {root { document @include(if:$show) {...Heading @boundary(name:"basic")} document {...Body @boundary(name:"body")} }} ${fragments}`, ), /QUERY_TREE_BINDING_CONFLICT/, ); });