diff --git a/.chronus/changes/fixes-opeanapi3-versioned-examples-2025-11-24-10-46-23.md b/.chronus/changes/fixes-opeanapi3-versioned-examples-2025-11-24-10-46-23.md new file mode 100644 index 00000000000..073bc39d9d5 --- /dev/null +++ b/.chronus/changes/fixes-opeanapi3-versioned-examples-2025-11-24-10-46-23.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/openapi3" +--- + +Fixed examples generation for operations with unions and nested enums for versioned services \ No newline at end of file diff --git a/packages/openapi3/src/examples.ts b/packages/openapi3/src/examples.ts index fdc7ced5ab8..90dfbcc45c4 100644 --- a/packages/openapi3/src/examples.ts +++ b/packages/openapi3/src/examples.ts @@ -266,7 +266,10 @@ export function getExampleOrExamples( ) { const [example, type] = examples[0]; const encodeAs = getEncodeAs(program, type); - return { example: serializeValueAsJson(program, example.value, type, encodeAs) }; + const exactValueType = program.checker.getValueExactType(example.value); + return { + example: serializeValueAsJson(program, example.value, exactValueType ?? type, encodeAs), + }; } else { const exampleObj: Record = {}; for (const [index, [example, type]] of examples.entries()) { diff --git a/packages/openapi3/test/examples.test.ts b/packages/openapi3/test/examples.test.ts index b31fc32b01d..b09bf17d367 100644 --- a/packages/openapi3/test/examples.test.ts +++ b/packages/openapi3/test/examples.test.ts @@ -962,4 +962,43 @@ worksFor(supportedVersions, ({ openApiFor }) => { "2021-01-01T00:00:00Z", ); }); + + it("supports example generation for union that contains enums", async () => { + const res = await openApiFor( + ` + @service + namespace MyService { + enum Enum { + a: "a", + b: "b", + } + + model Foo { + entityType: "foo"; + } + + model Bar { + entityType: "bar"; + enumValue: Enum; + } + + @opExample(#{ returnType: #[#{ entityType: "bar", enumValue: Enum.a }] }) + op testOp(): (Foo | Bar)[]; + } + `, + ); + + ok(res.components?.schemas); + ok(res.paths["/"].get); + ok(res.paths["/"].get.responses); + ok("200" in res.paths["/"].get.responses); + ok("content" in res.paths["/"].get.responses["200"]); + ok(res.paths["/"].get.responses["200"].content); + expect(res.paths["/"].get?.responses["200"].content["application/json"].example).toEqual([ + { + entityType: "bar", + enumValue: "a", + }, + ]); + }); }); diff --git a/packages/openapi3/test/versioning.test.ts b/packages/openapi3/test/versioning.test.ts index e1f4108390d..ff7e9afdcaf 100644 --- a/packages/openapi3/test/versioning.test.ts +++ b/packages/openapi3/test/versioning.test.ts @@ -217,5 +217,53 @@ worksFor(supportedVersions, ({ openApiFor, version: specVersion }) => { `, ); }); + + it("supports example generation for union that contains enums", async () => { + const { v1 } = await openApiForVersions( + ` + namespace MyService { + enum Versions { + v1 + } + } + + @versioned(Versions) + @service + namespace MyService { + enum Enum { + a: "a", + b: "b", + } + + model Foo { + entityType: "foo"; + } + + model Bar { + entityType: "bar"; + enumValue: Enum; + } + + @opExample(#{ returnType: #[#{ entityType: "bar", enumValue: Enum.a }] }) + op testOp(): (Foo | Bar)[]; + } + `, + ["v1"], + ); + + strictEqual(v1.info.version, "v1"); + ok(v1.components?.schemas); + ok(v1.paths["/"].get); + ok(v1.paths["/"].get.responses); + ok("200" in v1.paths["/"].get.responses); + ok("content" in v1.paths["/"].get.responses["200"]); + ok(v1.paths["/"].get.responses["200"].content); + deepStrictEqual(v1.paths["/"].get?.responses["200"].content["application/json"].example, [ + { + entityType: "bar", + enumValue: "a", + }, + ]); + }); }); });