import assert from "node:assert/strict"; import fs from "node:fs"; import vm from "node:vm"; import test from "node:test"; import ts from "typescript"; const modules = new Map(); const routeIndex = []; function load(name) { if (name === "./module-registry.generated.js") return { getWebModuleRoute: module => ({ commands: [`${module.toLowerCase()}.pythonFamilyBatch`] }) }; if (modules.has(name)) return modules.get(name); const source = fs.readFileSync(new URL(`../src/${name.replace(/^\.\//, "").replace(/\.js$/, ".ts")}`, import.meta.url), "utf8"); const code = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 } }).outputText; const module = { exports: {} }; vm.runInNewContext("(function(exports,require,module){" + code + "})", { AbortController, fetch: async () => ({ ok: true, json: async () => ({ schema: "freecad-web-desktop-command-routes/v1", records: routeIndex }) }) })(module.exports, load, module); modules.set(name, module.exports); return module.exports; } const adapter = load("./techdraw-desktop-adapter.js"); const { DesktopCommandDispatcher } = load("./desktop-command-dispatcher.js"); const record = command => ({ id: `TechDraw:desktop:${command}`, command, module: "TechDraw" }); const prepare = (command, args) => adapter.prepareTechDrawCommand(record(command), args, "Current"); const plain = value => JSON.parse(JSON.stringify(value)); test("section task exclusion, ownership and cancellation contracts are preserved", () => { for (const name of ["TechDraw_ComplexSection", "TechDraw_SectionView", "TechDraw_SectionGroup"]) assert.equal(prepare(name, { activeTask: true }).response.error.code, "task_in_progress"); assert.equal(prepare("TechDraw_Image", { taskActive: "yes" }).response.error.code, "invalid_request"); assert.equal(prepare("TechDraw_Image", { document: "Other" }).response.error.code, "invalid_request"); assert.equal(prepare("TechDraw_Image", { action: "cancel" }).args.document, "Current"); }); test("image, projection and projected subelement selections retain their native inputs", () => { const selection = [{ documentId: "Current", object: "View", subelements: ["Face1"] }]; assert.equal(prepare("TechDraw_Image", { selection }).args.owner, "View"); assert.deepEqual(plain(prepare("TechDraw_Hatch", { selection }).args.selection), ["Face1"]); assert.equal(prepare("TechDraw_Hatch", { selection }).args.view, "View"); assert.equal(prepare("TechDraw_View", { selection }).response.error.code, "implementation_required"); assert.deepEqual(plain(prepare("TechDraw_View", { selection: [{ documentId: "Current", object: "Box" }] }).args.sources), ["Box"]); assert.equal(prepare("TechDraw_Image", { selection: [{ documentId: "Other", object: "View" }] }).response.error.code, "invalid_request"); }); test("stack selection is deduplicated and command container policy stays native", () => { assert.deepEqual(plain(prepare("TechDraw_StackTop", { selection: ["View", "View"] }).args.selection), ["View"]); assert.equal(adapter.techDrawRoutePolicy("TechDraw_SectionGroup").familyRoute, true); assert.equal(adapter.techDrawRoutePolicy("TechDraw_StackTop").nativeContainer, true); assert.equal(adapter.techDrawRoutePolicy("Unrelated").nativeContainer, false); }); test("native errors and cancellation remain visible while exposed results continue", () => { const item = record("TechDraw_Image"); const response = status => ({ kind: "result", result: { schema: "freecad-web-techdraw/python-family-batch/v1", records: [{ apiId: item.id, status, code: "bad_image", message: "Native error" }] } }); const cancelled = response("cancelled"); assert.equal(adapter.validateTechDrawResponse(item, cancelled, item.id), cancelled); assert.equal(adapter.validateTechDrawResponse(item, response("error"), item.id).error.code, "bad_image"); assert.equal(adapter.validateTechDrawResponse(item, response("exposed"), item.id), null); }); test("the common dispatcher invokes the module adapter without changing other modules", async () => { const calls = []; const router = { request: async (...args) => { calls.push(args); return { kind: "result", result: { schema: "freecad-web-techdraw/python-family-batch/v1", records: [{ apiId: "TechDraw:desktop:TechDraw_Image", status: "exposed" }] } }; } }; const dispatcher = new DesktopCommandDispatcher(router); await dispatcher.execute(record("TechDraw_Image"), { selection: [{ documentId: "Current", object: "View" }] }, "Current"); assert.equal(calls[0][2].records[0].args.owner, "View"); assert.equal(calls[0][2].records[0].args.document, "Current"); await dispatcher.execute({ id: "Mesh:desktop:Inspect", module: "Mesh", command: "Inspect" }, { value: 4 }, "MeshDoc"); assert.deepEqual(plain(calls[1][2].records[0].args), { value: 4, documentId: "MeshDoc" }); }); test("Part adapter preserves native selection delivery and original error envelopes", async () => { const item = { id: "Part:desktop:Part_BoxSelection", module: "Part", command: "Part_BoxSelection" }; let native = { apiId: item.id, status: "exposed", result: { documentId: "Current", selection: [{ documentId: "Current", object: "Box" }] } }; const changes = [], router = { request: async () => ({ kind: "result", result: { records: [native] } }) }; const dispatcher = new DesktopCommandDispatcher(router); const execute = () => dispatcher.execute(item, {}, "Current", (document, selection) => changes.push({ document, selection })); assert.equal((await execute()).kind, "result"); assert.deepEqual(plain(changes), [{ document: "Current", selection: [{ documentId: "Current", object: "Box" }] }]); native = { ...native, status: "restricted", code: "native_rejected", message: "Original native failure" }; assert.equal((await execute()).error.code, "native_rejected"); assert.equal(changes.length, 1); native = { ...native, status: "exposed", implementationBoundary: "Missing native operation" }; assert.equal((await execute()).kind, "error"); assert.equal(changes.length, 1); native = { apiId: "Part:desktop:Other", status: "exposed" }; assert.equal((await execute()).error.code, "native_protocol_error"); native = { apiId: item.id, status: "exposed", result: { documentId: "Current", selection: [{ documentId: "Other", object: "Box" }] } }; await execute(); assert.equal(changes.length, 1); });