46 lines
4.3 KiB
JavaScript
46 lines
4.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
|
|
const protocol = fs.readFileSync(new URL("../../web/protocol/web-engine.ts", import.meta.url), "utf8");
|
|
const registry = fs.readFileSync(new URL("../../web/protocol/web-engine-capabilities.ts", import.meta.url), "utf8");
|
|
const app = fs.readFileSync(new URL("../../web/app/src/app/App.tsx", import.meta.url), "utf8");
|
|
const catalog = JSON.parse(fs.readFileSync(new URL("../../web/app/src/capabilities/blender-feature-route-catalog.json", import.meta.url), "utf8"));
|
|
const commandUnion = protocol.split("export type WebEngineEditCommand =", 2)[1]?.split("/** JSON values", 1)[0] ?? "";
|
|
const commands = new Set([...commandUnion.matchAll(/type:\s*"([A-Za-z0-9]+)"/gu)].map((match) => match[1]));
|
|
commands.add("moveNLAStrip");
|
|
const registered = new Set([...registry.matchAll(/^ ([A-Za-z0-9]+): \{/gmu)].map((match) => match[1]));
|
|
registered.delete("listBlenderOperators");
|
|
registered.delete("invokeBlenderOperator");
|
|
const missing = [...commands].filter((command) => !registered.has(command)).sort();
|
|
const stale = [...registered].filter((command) => !commands.has(command)).sort();
|
|
assert.deepEqual(missing, [], `WebEngine edit commands missing capabilities: ${missing.join(",")}`);
|
|
assert.deepEqual(stale, [], `WebEngine capabilities without edit commands: ${stale.join(",")}`);
|
|
const normalizeCommandIdentifier = (identifier) => String(identifier ?? "").replace(/^(?:web[-_]?command|command):/iu, "");
|
|
const webMainEntries = catalog.entries.filter((entry) => entry.route === "WEB_MAIN" && entry.kind === "web-command");
|
|
const missingWebMainRoutes = webMainEntries.map((entry) => normalizeCommandIdentifier(entry.identifier)).filter((identifier) => identifier && !registered.has(identifier));
|
|
const serverEntries = catalog.entries.filter((entry) => entry.route === "SERVER_NATIVE");
|
|
const missingServerRoutes = serverEntries.filter((entry) => entry.httpRoute !== "/api/server-operator-job").map((entry) => entry.identifier);
|
|
const browserEntries = catalog.entries.filter((entry) => entry.route === "BROWSER_EQUIVALENT");
|
|
const browserGroups = new Set(Object.keys(catalog.browserActionGroups ?? {}));
|
|
const missingBrowserGroups = browserEntries.filter((entry) => !browserGroups.has(entry.browserActionGroup)).map((entry) => entry.identifier);
|
|
const browserCommands = [...new Set(browserEntries.map((entry) => catalog.browserActionGroups?.[entry.browserActionGroup]?.command).filter(Boolean))];
|
|
const missingBrowserCommands = browserCommands.filter((command) => !app.includes(`id: "${command}"`));
|
|
const browserActionableEntries = browserEntries.filter((entry) => {
|
|
const command = catalog.browserActionGroups?.[entry.browserActionGroup]?.command;
|
|
return browserGroups.has(entry.browserActionGroup) && Boolean(command) && app.includes(`id: "${command}"`);
|
|
});
|
|
const runtimeAudit = {
|
|
schemaVersion: 1,
|
|
command: "featureRouteRuntimeAudit",
|
|
status: missingWebMainRoutes.length || missingServerRoutes.length || missingBrowserGroups.length ? "FAILED" : "PASS",
|
|
webMain: { entries: webMainEntries.length, registered: webMainEntries.length - missingWebMainRoutes.length, missing: missingWebMainRoutes },
|
|
serverNative: { entries: serverEntries.length, httpRoute: "/api/server-operator-job", missing: missingServerRoutes },
|
|
browserEquivalent: { entries: browserEntries.length, actionable: browserActionableEntries.length, groups: [...browserGroups].sort(), missing: missingBrowserGroups, missingCommands: missingBrowserCommands },
|
|
behavioralEvidence: { separate: true, status: catalog.behavioralEvidence?.status, verifiedUnits: catalog.behavioralEvidence?.verifiedUnits, unverifiedUnits: catalog.behavioralEvidence?.unverifiedUnits },
|
|
};
|
|
assert.deepEqual(missingWebMainRoutes, [], `WEB_MAIN commands missing capabilities: ${missingWebMainRoutes.join(",")}`);
|
|
assert.deepEqual(missingServerRoutes, [], `SERVER_NATIVE entries missing HTTP route: ${missingServerRoutes.join(",")}`);
|
|
assert.deepEqual(missingBrowserGroups, [], `BROWSER_EQUIVALENT entries missing browser action group: ${missingBrowserGroups.join(",")}`);
|
|
assert.deepEqual(missingBrowserCommands, [], `BROWSER_EQUIVALENT browser action adapters missing from App: ${missingBrowserCommands.join(",")}`);
|
|
process.stdout.write(`web-engine-command-registry-ok commands=${commands.size} featureRouteRuntimeAudit=${JSON.stringify(runtimeAudit)}\n`);
|