import assert from "node:assert/strict"; import { test } from "node:test"; import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/index.js"; import type { InterfaceRevision, PackageRevision } from "../src/capability-model/types.js"; import { compileQuery } from "../src/query/compile.js"; import { compileQueryComposition } from "../src/query/composition.js"; import { defaultQueryBudgets, type CheckedQuery } from "../src/query/types.js"; import { presentationDeclarations, preparationArtifact, type ReactPreparationArtifact, } from "../src/react-build/declarations.js"; import { completeWorkspace } from "../src/react-build/workspace.js"; const source = { repository: "https://example.test/prepared", commit: "a".repeat(40) }; async function fixture(replacement = "First", change?: (artifact: ReactPreparationArtifact) => void) { const interfaces = new Map(); const resource = (text: string) => { const result = compileCapabilityResourceSource(text, { source, environment: { interfaces, interfaceClosure: [...interfaces.values()] }, }); assert.ok(result.ok, JSON.stringify(result.diagnostics)); return result.resource; }; for (const text of [ 'interface Row id "row" revision "row@1" { queryable value title id "title" : string {get id "title:get" execution snapshot;} queryable value detail id "detail" : string {get id "detail:get" execution snapshot;} }', 'import interface Row; interface Library id "library" revision "library@1" { queryable relation selected id "selected" : optional-one interface Row {resolve id "selected:get" execution snapshot;} }', 'import interface Row; interface RowRole id "row-role" revision "row-role@1" { module render id "row-render" contract "org.quixos.react.subject-only/1" subject interface Row; }', 'import interface Library; interface LibraryRole id "library-role" revision "library-role@1" { module render id "library-render" contract "org.quixos.react.subject-only/1" subject interface Library; }', ]) { const result = resource(text); assert.equal(result.kind, "interface"); if (result.kind === "interface") interfaces.set(result.revision.displayName, result.revision); } const result = resource( 'import interface Row; import interface Library; import interface RowRole; import interface LibraryRole; package UI id "ui" revision "ui@1" { module LibraryCard id "library-card" implements LibraryRole.render; module First id "first" implements RowRole.render; module Second id "second" implements RowRole.render; }', ); assert.equal(result.kind, "package"); if (result.kind !== "package") throw Error("package expected"); const pkg: PackageRevision = result.revision; const checked: CheckedQuery[] = []; for (const [name, iface, fields] of [ ["LibraryData", "library@1", "selected {_camino {ref atom}}"], ["Title", "row@1", "title"], ["Detail", "row@1", "detail"], ]) { for (const local of [false, true]) { const id = name + (local ? "" : "Inputs"); checked.push( await compileQuery( { id, displayName: id, root: { kind: "object", interface: [...interfaces.values()].find((entry) => entry.revisionId === iface)!.revisionId, }, document: id + ".graphql", operation: id, fragments: [], views: [], allowances: [], budgets: { ...defaultQueryBudgets }, watch: local, placement: local ? { kind: "local", sourceQueryId: name + "Inputs" } : { kind: "replica" }, }, [...interfaces.values()], async () => `query ${id} {root {${fields}}}`, ), ); } } pkg.checkedQueries = checked; pkg.queries = checked.map((query) => query.declaration); const input = (query: string) => ({ name: "data", query, root: { from: "input", path: ["subject"] }, arguments: { record: {} }, }); const authored = { modules: { LibraryCard: { inputs: [input("LibraryData")], children: [ { name: "selected", subject: "Row", slot: "selected", with: { from: "result", name: "data", path: ["root", "selected"] }, root: { from: "item", path: ["_camino", "ref"] }, role: { interface: "RowRole", member: "render" }, }, ], }, First: { inputs: [input("Title")] }, Second: { inputs: [input("Detail")] }, }, }; const declarations = presentationDeclarations(JSON.stringify(authored), pkg, [...interfaces.values()]); change?.(declarations.artifact); pkg.buildArtifacts = { [preparationArtifact]: declarations.artifact }; pkg.queryCompositions = declarations.compositions.map((composition) => compileQueryComposition(composition, new Map(checked.map((query) => [query.declaration.id, query]))), ); const workspace = compileCapabilitySource( `workspace Example id "example" revision "example@1" commit "${source.commit}" { import interface Row; import interface Library; import interface RowRole; import interface LibraryRole; import package UI; atom A id "a"; atom B id "b"; conform A as Row id "a-row" {private state TitleA id "title-A" on A : string policy register default "title"; private state DetailA id "detail-A" on A : string policy register default "detail"; bind title.get to state TitleA.read; bind detail.get to state DetailA.read;} conform B as Row id "b-row" {private state TitleB id "title-B" on B : string policy register default "title"; private state DetailB id "detail-B" on B : string policy register default "detail"; bind title.get to state TitleB.read; bind detail.get to state DetailB.read;} conform A as RowRole id "a-role" {bind render to UI.${replacement};} conform B as RowRole id "b-role" {bind render to UI.Second;} }`, "workspace.qx", { interfaces, interfaceClosure: [...interfaces.values()], packages: new Map([["UI", pkg]]) }, ); assert.ok(workspace.ok, JSON.stringify(workspace.diagnostics)); await completeWorkspace(workspace.workspace); return { workspace: workspace.workspace, pkg: workspace.workspace.packageImports[0]!, authored, interfaces }; } test("a local module names its checked role without a synthetic import alias", async () => { const { pkg, authored, interfaces } = await fixture(); const source = structuredClone(authored) as any; source.modules.LibraryCard.children[0].role = { module: "First" }; const declared = presentationDeclarations(JSON.stringify(source), pkg, [...interfaces.values()]); assert.deepEqual(declared.artifact.modules[0]!.children[0]!.role, { interface: "row-role@1", member: "row-render" }); source.modules.LibraryCard.children[0].role = { module: "Missing" }; assert.throws( () => presentationDeclarations(JSON.stringify(source), pkg, [...interfaces.values()]), /local module role/, ); }); test("workspace expands distinct providers' private inputs without parent field declarations", async () => { const { pkg } = await fixture(); const parent = pkg.checkedQueries!.find((query) => query.declaration.id === "react:input:library-card:data")!; const acquisition = pkg.checkedQueries!.find( (query) => query.declaration.id === (parent.declaration.placement?.kind === "local" ? parent.declaration.placement.sourceQueryId : ""), )!; assert.match(acquisition.document, /title/); assert.match(acquisition.document, /detail/); const plan = pkg.queryCompositions!.find((composition) => composition.id === "react:inputs:library-card")!; assert.equal(plan.steps[0]!.query, parent.declaration.id); assert.equal(Object.keys(parent.fragmentContracts ?? {}).length, 2); assert(!pkg.queryCompositions!.some((composition) => composition.id.endsWith(":discovery"))); const original = pkg.checkedQueries!.find((query) => query.declaration.id === "LibraryData")!; assert.deepEqual(parent.output, original.output, "Acquisition-only child fields are not parent requirements"); assert(Object.values(parent.fragmentContracts!).every((entry) => entry.mode === "reference")); }); test("eager cycles and wrongly typed child bindings fail before runtime", async () => { await assert.rejects( fixture("First", (artifact) => { artifact.modules .find((module) => module.module === "first")! .children.push({ name: "again", subject: "row@1", slot: "again", root: { from: "input", path: ["subject"] }, role: { interface: "row-role@1", member: "render" }, }); }), /Eager React preparation cycle/, ); await assert.rejects( fixture("First", (artifact) => { artifact.modules.find((module) => module.module === "library-card")!.children[0]!.root = { literal: "not a reference", }; }), /child root must be/, ); }); test("workspace replacement changes acquisition requirements without changing the parent", async () => { const { pkg } = await fixture("Second"); const parent = pkg.checkedQueries!.find((query) => query.declaration.id === "react:input:library-card:data")!; const acquisition = pkg.checkedQueries!.find( (query) => query.declaration.id === (parent.declaration.placement?.kind === "local" ? parent.declaration.placement.sourceQueryId : ""), )!; assert.doesNotMatch(acquisition.document, /\btitle\b/); assert.match(acquisition.document, /detail/); assert.equal(Object.keys(parent.fragmentContracts ?? {}).length, 1); const previous = (await fixture()).pkg.checkedQueries!.find( (query) => query.declaration.id === parent.declaration.id, )!; assert.deepEqual(parent.output, previous.output); });