Files

66 lines
3.2 KiB
TypeScript
Raw Permalink Normal View History

import assert from "node:assert/strict";
import { test } from "node:test";
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
import { formatQx } from "../src/capability-language/source.js";
import { compileExecutionPlan, compileKernelProgram } from "../src/execution-world/index.js";
const contract = `interface Item id "item" revision "item@1" {
operation remove id "remove" : unit -> unit {
call id "remove:call" execution transaction;
}
}`;
const workspace = `workspace Lifecycle id "workspace:lifecycle" revision "workspace:lifecycle@1" commit "${"a".repeat(40)}" {
import interface Item;
atom Node id "node";
conform Node as Item id "node:item" {
private edge Links id "links" {
atom Node projection children id "children" many on-delete "cascade-other";
atom Node projection parent id "parent" optional-one on-delete "detach";
}
bind remove.call to lifecycle.delete;
}
}`;
function compile(ifaceSource = contract, workspaceSource = workspace) {
const iface = compileCapabilityResourceSource(ifaceSource, {
source: { repository: "https://example.test/lifecycle.git", commit: "a".repeat(40) },
});
assert.ok(iface.ok && iface.resource.kind === "interface", JSON.stringify(iface.diagnostics));
return compileCapabilitySource(workspaceSource, "workspace.qx", {
interfaces: new Map([["Item", iface.resource.revision]]),
});
}
test("lifecycle binding and endpoint policies survive formatting and kernel compilation", () => {
const result = compile();
assert.ok(result.ok, JSON.stringify(result.diagnostics));
const formatted = compile(formatQx(contract), formatQx(workspace));
assert.ok(formatted.ok, JSON.stringify(formatted.diagnostics));
const plan = compileExecutionPlan(result.workspace);
assert.equal(compileExecutionPlan(formatted.workspace).digest, plan.digest);
const kernel = compileKernelProgram(plan) as {
operations: { binding: unknown }[];
model: { edges: { a: { onDelete: string }; b: { onDelete: string } }[] };
};
assert.deepEqual(kernel.operations[0]!.binding, { kind: "lifecycle", primitive: "delete" });
assert.equal(kernel.model.edges[0]!.a.onDelete, "cascade-other");
assert.equal(kernel.model.edges[0]!.b.onDelete, "detach");
});
test("deletion rejects browser, snapshot, remote, class, payload and unknown primitive promises", () => {
for (const [iface, ws] of [
[contract.replace("execution transaction", "execution snapshot"), workspace],
[contract.replace("execution transaction", "execution remote"), workspace],
[contract.replace("execution transaction", ""), workspace],
[contract.replace("operation remove", "static operation remove"), workspace],
[contract.replace("unit -> unit", "string -> unit"), workspace],
[contract.replace("unit -> unit", "unit -> string"), workspace],
[contract, workspace.replace("lifecycle.delete", "lifecycle.resurrect")],
]) {
const result = compile(iface, ws);
assert.equal(result.ok, false, iface + ws);
assert.ok(
result.diagnostics.some((d) =>
["invalid-execution-contract", "invalid-lifecycle-binding", "invalid-package-binding"].includes(d.code),
),
JSON.stringify(result.diagnostics),
);
}
});