diff --git a/.chronus/changes/openapi31-tuple-support-2024-10-26-14-50-53.md b/.chronus/changes/openapi31-tuple-support-2024-10-26-14-50-53.md new file mode 100644 index 00000000000..56e473ab7ea --- /dev/null +++ b/.chronus/changes/openapi31-tuple-support-2024-10-26-14-50-53.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/openapi3" +--- + +Adds support for emitting tuples for Open API 3.1 \ No newline at end of file diff --git a/packages/openapi3/src/schema-emitter-3-1.ts b/packages/openapi3/src/schema-emitter-3-1.ts index ccd65b97be8..6eb8c8aecc3 100644 --- a/packages/openapi3/src/schema-emitter-3-1.ts +++ b/packages/openapi3/src/schema-emitter-3-1.ts @@ -10,10 +10,12 @@ import { Program, Scalar, serializeValueAsJson, + Tuple, Type, Union, } from "@typespec/compiler"; import { + ArrayBuilder, AssetEmitter, createAssetEmitter, EmitterOutput, @@ -239,4 +241,19 @@ export class OpenAPI31SchemaEmitter extends OpenAPI3SchemaEmitterBase> { + return new ObjectBuilder({ + type: "array", + prefixItems: this.emitter.emitTupleLiteralValues(tuple), + }); + } + + tupleLiteralValues(tuple: Tuple): EmitterOutput> { + const values = new ArrayBuilder(); + for (const value of tuple.values.values()) { + values.push(this.emitter.emitType(value)); + } + return values; + } } diff --git a/packages/openapi3/test/array.test.ts b/packages/openapi3/test/array.test.ts index eb04eeb8715..c4f100cd73e 100644 --- a/packages/openapi3/test/array.test.ts +++ b/packages/openapi3/test/array.test.ts @@ -226,8 +226,10 @@ worksFor(["3.0.0", "3.1.0"], ({ oapiForModel, openApiFor }) => { strictEqual(res.schemas.Foo.title, "FooArray"); }); +}); - it("can specify tuple defaults using tuple syntax", async () => { +worksFor(["3.0.0"], ({ oapiForModel }) => { + it("can specify tuple defaults using tuple syntax (empty items)", async () => { const res = await oapiForModel( "Pet", ` @@ -258,3 +260,55 @@ worksFor(["3.0.0", "3.1.0"], ({ oapiForModel, openApiFor }) => { }); }); }); + +worksFor(["3.1.0"], ({ oapiForModel }) => { + it("can specify tuple defaults using tuple syntax (prefix items)", async () => { + const res = await oapiForModel( + "Pet", + ` + model Pet { + names: [string, int32] = #["bismarck", 12]; + decimals: [string, decimal] = #["hi", 456.7]; + decimal128s: [string, decimal128] = #["hi", 456.7]; + }; + `, + ); + + deepStrictEqual(res.schemas.Pet.properties.names, { + type: "array", + prefixItems: [{ type: "string" }, { type: "integer", format: "int32" }], + default: ["bismarck", 12], + }); + + deepStrictEqual(res.schemas.Pet.properties.decimals, { + type: "array", + prefixItems: [{ type: "string" }, { type: "number", format: "decimal" }], + default: ["hi", 456.7], + }); + + deepStrictEqual(res.schemas.Pet.properties.decimal128s, { + type: "array", + prefixItems: [{ type: "string" }, { type: "number", format: "decimal128" }], + default: ["hi", 456.7], + }); + }); + + it("can specify tuple with constants", async () => { + const res = await oapiForModel( + "Pet", + ` + model Pet { + names: ["bismark", 32]; + }; + `, + ); + + deepStrictEqual(res.schemas.Pet.properties.names, { + type: "array", + prefixItems: [ + { type: "string", enum: ["bismark"] }, + { type: "number", enum: [32] }, + ], + }); + }); +});