diff --git a/packages/cli/generator/plugin/body.ts b/packages/cli/generator/plugin/body.ts index 8513f13889..3815311b16 100644 --- a/packages/cli/generator/plugin/body.ts +++ b/packages/cli/generator/plugin/body.ts @@ -106,6 +106,7 @@ function makeView(type: Type): Schema { let kind: Kind | undefined; switch (type.scalar) { case "string": + case "uuid": case "date": case "date-time": case "bytes": diff --git a/packages/cli/generator/plugin/operation.ts b/packages/cli/generator/plugin/operation.ts index fe055279dd..18d55ea1fb 100644 --- a/packages/cli/generator/plugin/operation.ts +++ b/packages/cli/generator/plugin/operation.ts @@ -374,6 +374,7 @@ function simpleType(type: Type): string | undefined { case "boolean": return "boolean"; case "string": + case "uuid": case "date": case "date-time": case "bytes": diff --git a/packages/cli/package.json b/packages/cli/package.json index 77ab129b7e..c1d2b87266 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -85,7 +85,7 @@ "@cloudflare/codemods": "0.5.1", "@cloudflare/containers-shared": "0.23.0", "@cloudflare/deploy-helpers": "0.22.0", - "@cloudflare/forge": "https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@7e230c1f40514ceffe7001823c158f4f0380f7bd", + "@cloudflare/forge": "https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@ca70d7f5d88da223e243bca25810199876242ea6", "@cloudflare/workers-auth": "0.14.0", "@cloudflare/workers-utils": "0.47.2", "@types/node": "25.9.9", diff --git a/packages/cli/src/__tests__/generator/plugin/forge-model.test.ts b/packages/cli/src/__tests__/generator/plugin/forge-model.test.ts index eddb6b7c69..68fa26428f 100644 --- a/packages/cli/src/__tests__/generator/plugin/forge-model.test.ts +++ b/packages/cli/src/__tests__/generator/plugin/forge-model.test.ts @@ -110,6 +110,64 @@ function listing(schema: Json) { } describe("the forge model", () => { + it("keeps UUID body fields and referenced UUID arrays as string flags", () => { + const files = generateFiles( + create( + { + type: "object", + required: ["id"], + properties: { + id: { type: "string", format: "uuid" }, + parent_id: { type: "string", format: "uuid", nullable: true }, + dataset_ids: { + type: "array", + minItems: 1, + maxItems: 50, + items: { $ref: "#/components/schemas/ID" }, + }, + }, + }, + { ID: { type: "string", format: "uuid" } } + ) + ); + const code = files.get("things/create.ts") ?? ""; + expect(code).toContain('.option(\'id\', {"type":"string"'); + expect(code).toContain('.option(\'parent-id\', {"type":"string"'); + expect(code).toContain( + '.option(\'dataset-ids\', {"type":"string","array":true' + ); + expect(code).toContain("promptForRequiredField('id'"); + expect(code).toContain('id: resolveFileToken(argv["id"]'); + expect(code).toContain('parent_id: resolveFileToken(argv["parent-id"]'); + expect(code).toContain('dataset_ids: argv["dataset-ids"]'); + const metadata = JSON.parse(files.get("_meta/commands.json") ?? "{}"); + expect(metadata.commands[0].options).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "id", type: "string", required: true }), + expect.objectContaining({ name: "parent-id", type: "string" }), + expect.objectContaining({ name: "dataset-ids", type: "string" }), + ]) + ); + }); + + it.each([ + { type: "string", format: "uuid" }, + { type: "string", format: "uuid", nullable: true }, + { + anyOf: [ + { type: "string", format: "uuid" }, + { type: "array", items: { type: "string", format: "uuid" } }, + ], + }, + ])("keeps UUID query parameters as strings: %j", (schema) => { + const files = generateFiles(listing(schema)); + const schemas = JSON.parse(files.get("_meta/schemas.json") ?? "{}"); + expect(schemas.schemas["things list"].queryParams[0].type).toBe("string"); + expect(files.get("things/list.ts")).toContain( + '.option(\'status\', {"type":"string"' + ); + }); + it("retains required and optional scalar intersections and their enum constraints", () => { const d = create( { diff --git a/packages/cli/src/__tests__/helpers/forge-cli.ts b/packages/cli/src/__tests__/helpers/forge-cli.ts index 802ac1109c..734c5d478e 100644 --- a/packages/cli/src/__tests__/helpers/forge-cli.ts +++ b/packages/cli/src/__tests__/helpers/forge-cli.ts @@ -52,7 +52,7 @@ function plugin(): string { entry, [ `import { definePlugin } from ${specifier(require.resolve("@cloudflare/forge/plugin"))};`, - 'import { info } from "forge:plugin/forge@0.2.0";', + 'import { info } from "forge:plugin/forge@0.3.0";', `import { generateCli, generateCliGroup } from ${specifier(fileURLToPath(new URL("../../../generator/plugin/index.ts", import.meta.url)))};`, "", "const config = () => JSON.parse(info().version);", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0bc2c604c6..d9c4c9f61d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -297,8 +297,8 @@ importers: specifier: 0.22.0 version: 0.22.0(patch_hash=d27a1e3a499430577a2dc4919fa5808a28112afbe926c6f65b352c903601c483)(@types/node@25.9.9)(vitest@5.0.5) '@cloudflare/forge': - specifier: https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@7e230c1f40514ceffe7001823c158f4f0380f7bd - version: https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@7e230c1f40514ceffe7001823c158f4f0380f7bd(@bytecodealliance/jco@1.38.0) + specifier: https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@ca70d7f5d88da223e243bca25810199876242ea6 + version: https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@ca70d7f5d88da223e243bca25810199876242ea6(@bytecodealliance/jco@1.38.0) '@cloudflare/workers-auth': specifier: 0.14.0 version: 0.14.0(msw@3.0.3(@types/node@25.9.9)(@voidzero-dev/vite-plus-core@1.3.0(@types/node@25.9.9)(@typescript/native-preview@7.0.0-dev.20260707.2)(esbuild@0.28.2)(tsx@4.21.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0))(graphql@16.14.2)(supports-color@10.2.2)(typescript@6.0.3))(vitest@5.0.5) @@ -720,8 +720,8 @@ packages: '@cloudflare/deploy-helpers@0.22.0': resolution: {integrity: sha512-MEcKDbv8diNjZV9S4OIfho6nRKSHcqq677WMiXJQsN9I8HrCV9DYD9LVlPawOTLXUmxlmL85xWBrSW6i9MkWJw==} - '@cloudflare/forge@https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@7e230c1f40514ceffe7001823c158f4f0380f7bd': - resolution: {integrity: sha512-uEcwB8ILsLCvuS4KK7LeX7ECK/Jz9CESWLtW+60Jw0UDjA7ydV7/8luD+x+tH6YXu7iEdOq0m+GQdc1eL3FqXQ==, tarball: https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@7e230c1f40514ceffe7001823c158f4f0380f7bd} + '@cloudflare/forge@https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@ca70d7f5d88da223e243bca25810199876242ea6': + resolution: {integrity: sha512-h6POFCKOMX96O8RFhV/ZNyQouZdJIbx8e51D4pq6NKxNeCixV4fuSc4bKbieX0xVfF+e81iw5HlG9vKg9twvlw==, tarball: https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@ca70d7f5d88da223e243bca25810199876242ea6} version: 0.1.0 engines: {node: '>=18'} hasBin: true @@ -4283,7 +4283,7 @@ snapshots: - utf-8-validate - vitest - '@cloudflare/forge@https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@7e230c1f40514ceffe7001823c158f4f0380f7bd(@bytecodealliance/jco@1.38.0)': + '@cloudflare/forge@https://pkg.pr.new/cloudflare/forge/@cloudflare/forge@ca70d7f5d88da223e243bca25810199876242ea6(@bytecodealliance/jco@1.38.0)': optionalDependencies: '@bytecodealliance/jco': 1.38.0