import { describe, expect, it } from "vitest"; import { emitClientGlobalApiRegistration as emitTypeScriptClientGlobalApiRegistration, emitClientSessionApiRegistration as emitTypeScriptClientSessionApiRegistration, } from "../../scripts/codegen/typescript.ts"; import { emitClientGlobalApiRegistration as emitGoClientGlobalApiRegistration, emitClientSessionApiRegistration as emitGoClientSessionApiRegistration, } from "../../scripts/codegen/go.ts"; import { emitClientGlobalApiRegistration as emitPythonClientGlobalApiRegistration, emitClientSessionApiRegistration as emitPythonClientSessionApiRegistration, } from "../../scripts/codegen/python.ts"; const clientSessionSchema: Record = { mixed: { visible: { rpcMethod: "mixed.visible", params: { type: "object", title: "VisibleRequest", properties: { sessionId: { type: "string" }, }, required: ["sessionId"], }, result: { type: "object", title: "VisibleResult", properties: {}, }, }, secret: { rpcMethod: "mixed.secret", visibility: "internal", params: { $ref: "#/definitions/InternalRequest", }, result: { $ref: "#/definitions/InternalResult", }, }, }, internalOnly: { hidden: { rpcMethod: "internalOnly.hidden", visibility: "internal", params: { $ref: "#/definitions/InternalRequest", }, result: { $ref: "#/definitions/InternalResult", }, }, }, }; const allInternalClientSessionSchema: Record = { internalOnly: clientSessionSchema.internalOnly, }; function expectOnlyPublicClientSessionHandlers(code: string): void { expect(code).toContain("mixed.visible"); expect(code).not.toContain("mixed.secret"); expect(code).not.toContain("internalOnly.hidden"); expect(code).not.toContain("InternalRequest"); expect(code).not.toContain("InternalResult"); } describe("client-session API codegen", () => { it("excludes internal methods from TypeScript handlers", () => { const code = emitTypeScriptClientSessionApiRegistration(clientSessionSchema).join("\n"); const allInternalCode = emitTypeScriptClientSessionApiRegistration( allInternalClientSessionSchema ).join("\n"); expectOnlyPublicClientSessionHandlers(code); expect(code).not.toContain("InternalOnlyHandler"); expect(allInternalCode).toContain("export interface ClientSessionApiHandlers {"); expect(allInternalCode).toContain("export function registerClientSessionApiHandlers("); expect(allInternalCode).not.toContain("InternalOnlyHandler"); }); describe("client-global API codegen", () => { it("keeps internal methods out of global registration", () => { const code = emitTypeScriptClientGlobalApiRegistration(clientSessionSchema).join("\n"); expectOnlyPublicClientSessionHandlers(code); expect(code).not.toContain("InternalOnlyHandler"); }); }); describe("client-global host API codegen", () => { const schema = { host: { shutdown: { rpcMethod: "host.shutdown", visibility: "internal", params: { $ref: "#/definitions/HostEmptyResult" }, result: { $ref: "#/definitions/HostEmptyResult" }, }, exited: { rpcMethod: "host.exited", params: { $ref: "#/definitions/HostExitedNotification" }, result: { type: "null" }, notification: true, }, }, }; it("uses named request references for Go child and exit handlers", () => { const lines: string[] = []; emitGoClientGlobalApiRegistration(lines, schema, (name) => name, new Map()); const code = lines.join("\n"); expect(code).toContain('"host.exited"'); expect(code).toContain("request *HostEmptyResult"); expect(code).toContain("request *HostExitedNotification"); expect(code).not.toContain("HostShutdownRequest"); }); it("uses named Python exit references and dictionary child shutdown payloads", () => { const lines: string[] = []; emitPythonClientGlobalApiRegistration(lines, schema, (name) => name === "HostEmptyResult" ? "dict" : name ); const code = lines.join("\n"); expect(code).toContain("request = HostExitedNotification.from_dict(params)"); expect(code).toContain('"host.exited"'); expect(code).not.toContain("HostExitedRequest"); expect(code).toContain("request = dict(params)"); expect(code).toContain("async def shutdown(self, params: dict) -> dict:"); expect(code).not.toContain("dict.from_dict"); expect(code).not.toContain("HostShutdownResult"); expect(code).not.toContain("HostShutdownRequest"); }); }); it("excludes internal methods from Go handlers", () => { const lines: string[] = []; emitGoClientSessionApiRegistration(lines, clientSessionSchema, (name) => name, new Map()); const code = lines.join("\n"); const allInternalLines: string[] = []; emitGoClientSessionApiRegistration( allInternalLines, allInternalClientSessionSchema, (name) => name, new Map() ); const allInternalCode = allInternalLines.join("\n"); expectOnlyPublicClientSessionHandlers(code); expect(code).not.toContain("InternalOnlyHandler"); expect(allInternalCode).toContain("type ClientSessionAPIHandlers struct {"); expect(allInternalCode).toContain("func RegisterClientSessionAPIHandlers("); expect(allInternalCode).not.toContain("InternalOnlyHandler"); expect(allInternalCode).not.toContain("clientSessionHandlerError"); }); it("excludes internal methods from Python handlers", () => { const lines: string[] = []; emitPythonClientSessionApiRegistration(lines, clientSessionSchema, (name) => name); const code = lines.join("\n"); const allInternalLines: string[] = []; emitPythonClientSessionApiRegistration( allInternalLines, allInternalClientSessionSchema, (name) => name ); const allInternalCode = allInternalLines.join("\n"); expectOnlyPublicClientSessionHandlers(code); expect(code).not.toContain("InternalOnlyHandler"); expect(allInternalCode).toContain("class ClientSessionApiHandlers:"); expect(allInternalCode).toContain("def register_client_session_api_handlers("); expect(allInternalCode).not.toContain("InternalOnlyHandler"); }); });