From 88d4dd37acaa63fab1317bb6901306eab3ff0ae1 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Fri, 30 Jan 2026 10:32:53 -0500 Subject: [PATCH 1/2] Openapi3 param default with $ref --- packages/openapi3/src/openapi.ts | 10 ++++++++-- packages/openapi3/test/parameters.test.ts | 22 +++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/openapi3/src/openapi.ts b/packages/openapi3/src/openapi.ts index 1356578c378..ebe16d5643b 100644 --- a/packages/openapi3/src/openapi.ts +++ b/packages/openapi3/src/openapi.ts @@ -1577,7 +1577,7 @@ function createOAPIEmitter( if (!typeSchema) { return undefined; } - const schema = applyEncoding( + let schema = applyEncoding( program, param, applyIntrinsicDecorators(param, typeSchema), @@ -1585,7 +1585,13 @@ function createOAPIEmitter( ); if (param.defaultValue) { - schema.default = getDefaultValue(program, param.defaultValue, param); + const defaultValue = getDefaultValue(program, param.defaultValue, param); + // In OpenAPI 3.0, $ref cannot have sibling properties. + if ("$ref" in schema && specVersion === "3.0.0") { + schema = { allOf: [{ $ref: schema.$ref }], default: defaultValue }; + } else { + schema.default = defaultValue; + } } // Description is already provided in the parameter itself. delete schema.description; diff --git a/packages/openapi3/test/parameters.test.ts b/packages/openapi3/test/parameters.test.ts index 6a861660dc5..f7ff7e6943c 100644 --- a/packages/openapi3/test/parameters.test.ts +++ b/packages/openapi3/test/parameters.test.ts @@ -4,7 +4,7 @@ import { describe, expect, it } from "vitest"; import { OpenAPI3PathParameter, OpenAPI3QueryParameter } from "../src/types.js"; import { supportedVersions, worksFor } from "./works-for.js"; -worksFor(supportedVersions, ({ diagnoseOpenApiFor, openApiFor }) => { +worksFor(supportedVersions, ({ diagnoseOpenApiFor, openApiFor, version }) => { describe("query parameters", () => { async function getQueryParam(code: string): Promise { const res = await openApiFor(code); @@ -616,4 +616,24 @@ worksFor(supportedVersions, ({ diagnoseOpenApiFor, openApiFor }) => { }); }); }); + + it("parmeter with default value and $ref wraps $ref in allOf in OpenAPI 3.0 only", async () => { + const res = await openApiFor( + ` + enum Example { a, b} + op test(@query example?: Example = Example.b): void; + `, + ); + + const schema = res.paths["/"].get.parameters[0].schema; + if (version === "3.0.0") { + // In OpenAPI 3.0, $ref cannot have sibling properties, so we wrap in allOf + expect(schema.allOf).toEqual([{ $ref: "#/components/schemas/Example" }]); + expect(schema.default).toBe("b"); + } else { + // In OpenAPI 3.1+, $ref can have sibling properties + expect(schema.$ref).toBe("#/components/schemas/Example"); + expect(schema.default).toBe("b"); + } + }); }); From e38a521af678b228587d8a03eaabfbdb0bbd56ad Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Fri, 30 Jan 2026 07:38:06 -0800 Subject: [PATCH 2/2] Create fix-openapi3.0-param-default-2026-0-30-15-34-2.md --- .../fix-openapi3.0-param-default-2026-0-30-15-34-2.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .chronus/changes/fix-openapi3.0-param-default-2026-0-30-15-34-2.md diff --git a/.chronus/changes/fix-openapi3.0-param-default-2026-0-30-15-34-2.md b/.chronus/changes/fix-openapi3.0-param-default-2026-0-30-15-34-2.md new file mode 100644 index 00000000000..5a9de920b00 --- /dev/null +++ b/.chronus/changes/fix-openapi3.0-param-default-2026-0-30-15-34-2.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/openapi3" +--- + +Fix parameters with default value resulting in `$ref` with `default` as sibling for OpenAPI 3.0