From cdb55a3a3537db22c39769ecf9476be2f6e055db Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 13 Dec 2023 14:15:44 -0800 Subject: [PATCH 1/3] Treat bytes array as many binary parts --- packages/openapi3/src/schema-emitter.ts | 26 ++++++++++++++++-------- packages/openapi3/test/multipart.test.ts | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/openapi3/src/schema-emitter.ts b/packages/openapi3/src/schema-emitter.ts index 7e553e8d81..8d458b02c7 100644 --- a/packages/openapi3/src/schema-emitter.ts +++ b/packages/openapi3/src/schema-emitter.ts @@ -305,17 +305,27 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter< return props; } + #isBytesKeptRaw(type: Type) { + const program = this.emitter.getProgram(); + return ( + type.kind === "Scalar" && type.name === "bytes" && getEncode(program, type) === undefined + ); + } + modelPropertyLiteral(prop: ModelProperty): EmitterOutput { const program = this.emitter.getProgram(); const isMultipart = this.#getContentType().startsWith("multipart/"); - if ( - isMultipart && - prop.type.kind === "Scalar" && - prop.type.name === "bytes" && - getEncode(program, prop.type) === undefined && - getEncode(program, prop) === undefined - ) { - return { type: "string", format: "binary" }; + if (isMultipart) { + if (this.#isBytesKeptRaw(prop.type) && getEncode(program, prop) === undefined) { + return { type: "string", format: "binary" }; + } + if ( + prop.type.kind === "Model" && + isArrayModelType(program, prop.type) && + this.#isBytesKeptRaw(prop.type.indexer.value) + ) { + return { type: "array", items: { type: "string", format: "binary" } }; + } } const refSchema = this.emitter.emitTypeReference(prop.type, { diff --git a/packages/openapi3/test/multipart.test.ts b/packages/openapi3/test/multipart.test.ts index aaf66a0c88..a2d43c64fd 100644 --- a/packages/openapi3/test/multipart.test.ts +++ b/packages/openapi3/test/multipart.test.ts @@ -38,6 +38,27 @@ describe("typespec-autorest: multipart", () => { }); }); + it("part of type `bytes[]` produce `type: array, items: {type: string, format: binary}`", async () => { + const res = await openApiFor( + ` + op upload(@header contentType: "multipart/form-data", profileImage: bytes): void; + ` + ); + const op = res.paths["/"].post; + deepStrictEqual(op.requestBody.content["multipart/form-data"], { + schema: { + type: "object", + properties: { + profileImage: { + type: "array", + items: { type: "string", format: "binary" }, + }, + }, + required: ["profileImage"], + }, + }); + }); + it("part of type `string` produce `type: string`", async () => { const res = await openApiFor( ` From 34cefa09cc8baf572e30f256b7715d14b005a2aa Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 13 Dec 2023 14:16:46 -0800 Subject: [PATCH 2/3] changelog --- .../hotfix-multipart-bytes-array_2023-12-13-22-16.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json diff --git a/common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json b/common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json new file mode 100644 index 0000000000..d7f43d26d8 --- /dev/null +++ b/common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/openapi3", + "comment": "Fix: Multipart part of type `bytes[]` is treated as multiple binary part", + "type": "none" + } + ], + "packageName": "@typespec/openapi3" +} From 551eb41579c4505b26ec32e994e4579678b6d578 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 13 Dec 2023 14:40:17 -0800 Subject: [PATCH 3/3] fix --- .../openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json | 2 +- packages/openapi3/test/multipart.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json b/common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json index d7f43d26d8..62d1503483 100644 --- a/common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json +++ b/common/changes/@typespec/openapi3/hotfix-multipart-bytes-array_2023-12-13-22-16.json @@ -2,7 +2,7 @@ "changes": [ { "packageName": "@typespec/openapi3", - "comment": "Fix: Multipart part of type `bytes[]` is treated as multiple binary part", + "comment": "Fix: Multipart part of type `bytes[]` is now treated as multiple binary part", "type": "none" } ], diff --git a/packages/openapi3/test/multipart.test.ts b/packages/openapi3/test/multipart.test.ts index a2d43c64fd..8138ef11f1 100644 --- a/packages/openapi3/test/multipart.test.ts +++ b/packages/openapi3/test/multipart.test.ts @@ -41,7 +41,7 @@ describe("typespec-autorest: multipart", () => { it("part of type `bytes[]` produce `type: array, items: {type: string, format: binary}`", async () => { const res = await openApiFor( ` - op upload(@header contentType: "multipart/form-data", profileImage: bytes): void; + op upload(@header contentType: "multipart/form-data", profileImage: bytes[]): void; ` ); const op = res.paths["/"].post;