diff --git a/src/capability-language/execution-scaffold.ts b/src/capability-language/execution-scaffold.ts index 3a11e02..05025ae 100644 --- a/src/capability-language/execution-scaffold.ts +++ b/src/capability-language/execution-scaffold.ts @@ -71,17 +71,10 @@ export async function executionScaffold( outputs = { nixpkgs, flake-utils, helpers, ... }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; + camino = import (helpers + "/quixos-package-helpers.nix"); in { devShells.default = (import (helpers + "/quixos-package-helpers.nix")).mkCaminoYarnShell { inherit pkgs; }; quixosPackages.checkedArtifacts = context: - import ./package.nix { inherit pkgs context; camino = import (helpers + "/quixos-package-helpers.nix"); }; - }); -} -`, - ); - create( - "package.nix", - `{ pkgs, camino, context }: let plan = builtins.fromJSON (builtins.readFile context.plan); package = pkgs.lib.findFirst (entry: entry.revision == context.packageRevisionId) @@ -103,6 +96,8 @@ in camino.assembleCaminoPackage { }) ++ pkgs.lib.optional (modules != {}) (camino.mkCaminoReactPackage { inherit pkgs context dependencies modules; src = ./.; }); +}; + }); } `, ); diff --git a/src/capability-language/structural-edits.ts b/src/capability-language/structural-edits.ts index 65cab67..2dcc38d 100644 --- a/src/capability-language/structural-edits.ts +++ b/src/capability-language/structural-edits.ts @@ -210,7 +210,8 @@ export const editStructure = (source: string, edit: StructuralEdit): string => { return source; } const identifiers = node.children.filter((entry) => entry.kind === "identifier"); - const position = identifiers[identifiers.length - 1].end; + const targetArguments = node.children.find((entry) => entry.kind === "typeArguments"); + const position = targetArguments?.end ?? identifiers[identifiers.length - 1].end; result = applySourceEdits(source, [{ start: position, end: position, text: ` id ${JSON.stringify(edit.id)}` }]); } else if (edit.operation === "append") { const closing = syntax.tokens.find((token) => token.kind === "RBRACE" && token.end === node.end); diff --git a/src/execution-world/kernel.ts b/src/execution-world/kernel.ts index ca9db0e..fbc6bf7 100644 --- a/src/execution-world/kernel.ts +++ b/src/execution-world/kernel.ts @@ -158,7 +158,7 @@ export function compileKernelProgram(plan: ExecutionPlan): unknown { interface: bound.interfaceRevisionId, ...(!bound.receiver && !bound.via && - (requirement.operations ?? iface.members.flatMap(m=>m.operations.map(o=>o.id))).every( + (requirement.operations ?? iface.members.flatMap((m) => m.operations.map((o) => o.id))).every( (id) => iface.members.flatMap((m) => m.operations).find((o) => o.id === id)?.scope === "class", ) ? { staticAtom: operation.atomId } diff --git a/test/component-scaffold.test.ts b/test/component-scaffold.test.ts index e416f41..a4d9578 100644 --- a/test/component-scaffold.test.ts +++ b/test/component-scaffold.test.ts @@ -63,7 +63,7 @@ test("checked component scaffolding composes with execution handlers without rep assert.equal(await fs.readFile(flake, "utf8"), retainedFlake); assert.match(await fs.readFile(entriesFile, "utf8"), /retained entry comment/); assert.match(await fs.readFile(path.join(root, "src/server.ts"), "utf8"), /echo/); - assert.match(await fs.readFile(path.join(root, "flake.nix"), "utf8"), /import \.\/package\.nix/); + assert.match(await fs.readFile(path.join(root, "flake.nix"), "utf8"), /mkCaminoReactPackage/); await assert.rejects( apply("component", { name: "Card", diff --git a/test/scaffold-recipes.test.ts b/test/scaffold-recipes.test.ts index ef3f61d..7406b0c 100644 --- a/test/scaffold-recipes.test.ts +++ b/test/scaffold-recipes.test.ts @@ -47,7 +47,7 @@ test("execution scaffolds route typed handlers by declared effect and target wit assert.match(await read("src/impl/asyncWork.ts"), /RemoteImplementation/); assert.match(await read("src/impl/both.ts"), /PortableImplementation/); assert.match(await read("flake.nix"), /checkedArtifacts/); - assert.match(await read("package.nix"), /entries.browser/); + assert.match(await read("flake.nix"), /entries.browser/); await assert.rejects(add("both", "transaction targets [browser, server]"), /unique/); await assert.rejects(add("invalid", "snapshot targets [remote]"), /browser\/server/); await assert.rejects(apply("function", { name: "missing", id: "export:missing" }), /explicit execution/); diff --git a/test/structural-edits.test.ts b/test/structural-edits.test.ts index 2f6d389..42ced41 100644 --- a/test/structural-edits.test.ts +++ b/test/structural-edits.test.ts @@ -101,3 +101,17 @@ test("conformance enrollment, major edits, imports, and private attachment remov const imported = editStructure(removed, { operation: "import", kind: "interface", name: "Playable" }); assert.equal(editStructure(imported, { operation: "import", kind: "interface", name: "Playable" }), imported); }); + +test("enrolling a generic conformance or rule places its identity after target arguments", () => { + for (const source of [ + "fragment { conform Game as View {} }", + "fragment { conform Source as View {} }", + ]) { + const enrolled = editStructure(source, { + operation: "conformance-id", + target: { kind: "conformanceDecl" }, + id: "rule:view", + }); + assert.match(enrolled, /as View<[^>]+> id "rule:view"/); + } +});