Files
quixos-protocol/test/emit-controllers.ts
T

94 lines
4.5 KiB
TypeScript

import assert from "node:assert/strict";
import { readFile, mkdir, writeFile } from "node:fs/promises";
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/index.js";
import { compileQuery } from "../src/query/compile.js";
import { parseControllerCatalog } from "../src/capability-model/controllers.js";
import { presentationDeclarations, preparationArtifact } from "../src/react-build/declarations.js";
import { compileQueryComposition } from "../src/query/composition.js";
import {
compileExecutionPlan,
generateInterfaceClientBindings,
generatePackageQueryClientBindings,
} from "../src/execution-world/index.js";
const read = (file: string) => readFile("test/fixtures/controller-device/" + file, "utf8");
const source = { repository: "https://example.test/device.git", commit: "a".repeat(40) };
const device = compileCapabilityResourceSource(await read("Device.qx"), { source });
assert.ok(device.ok && device.resource.kind === "interface", JSON.stringify(device.diagnostics));
const control = compileCapabilityResourceSource(await read("DeviceController.qx"), { source });
assert.ok(control.ok && control.resource.kind === "interface", JSON.stringify(control.diagnostics));
const iface = device.resource.revision,
controllerInterface = control.resource.revision,
environment = {
interfaces: new Map([
["Device", iface],
["DeviceController", controllerInterface],
]),
interfaceClosure: [iface, controllerInterface],
};
const driver = compileCapabilityResourceSource(await read("Driver.qx"), { source, environment });
assert.ok(driver.ok && driver.resource.kind === "package", JSON.stringify(driver.diagnostics));
const pkg = driver.resource.revision;
pkg.checkedQueries = await Promise.all(
pkg.queries!.map((query) => compileQuery(query, [iface, controllerInterface], read)),
);
pkg.controllers = parseControllerCatalog(
JSON.stringify({
schemaVersion: 1,
controllers: [
{
id: "device-driver",
registry: "enabled",
subject: "device-controller@1",
snapshot: "device:snapshot:call",
remote: "device:apply:call",
input: "value",
},
],
}),
[iface, controllerInterface],
pkg.checkedQueries,
);
const viewRole = compileCapabilityResourceSource(await read("DeviceView.qx"), { source, environment });
assert.ok(viewRole.ok && viewRole.resource.kind === "interface", JSON.stringify(viewRole.diagnostics));
environment.interfaces.set("DeviceView", viewRole.resource.revision);
environment.interfaceClosure.push(viewRole.resource.revision);
const viewer = compileCapabilityResourceSource(await read("Viewer.qx"), {
source: { ...source, repository: "https://example.test/device-viewer.git" },
environment,
});
assert.ok(viewer.ok && viewer.resource.kind === "package", JSON.stringify(viewer.diagnostics));
const viewerPackage = viewer.resource.revision;
viewerPackage.checkedQueries = await Promise.all(
viewerPackage.queries!.map((query) => compileQuery(query, [iface], read)),
);
const preparation = presentationDeclarations(await read("quixos.react.json"), viewerPackage, environment.interfaceClosure);
viewerPackage.buildArtifacts = { [preparationArtifact]: preparation.artifact };
viewerPackage.queryCompositions = preparation.compositions.map((entry) =>
compileQueryComposition(entry, new Map(viewerPackage.checkedQueries!.map((query) => [query.declaration.id, query]))),
);
for (const variant of ["controller", "controller-next"]) {
const extra = variant.endsWith("next")
? 'atom Dashboard id "dashboard"; import package DeviceViewer; presentation DeviceStatus id "device:status" for Device using DeviceViewer.Status;'
: "";
const result = compileCapabilitySource((await read("workspace.qx")).replace(/}\s*$/, extra + "\n}"), "workspace.qx", {
...environment,
packages: new Map([
["Driver", pkg],
...(variant.endsWith("next") ? [["DeviceViewer", viewerPackage] as const] : []),
]),
});
assert.ok(result.ok, JSON.stringify(result.diagnostics));
const plan = compileExecutionPlan(result.workspace),
root = "dist/managed/" + variant;
await mkdir(root, { recursive: true });
await writeFile(root + "/client.ts", generateInterfaceClientBindings({ Device: iface }));
await writeFile(root + "/queries.ts", generatePackageQueryClientBindings(pkg));
for (const [file, value] of Object.entries({
"candidate.json": result.workspace,
"execution-plan.json": plan,
"entry.json": null,
"source.json": { kind: "workspace", ...source },
}))
await writeFile(root + "/" + file, JSON.stringify(value));
}