diff --git a/.chronus/changes/fix-external-docs-properties-2025-10-24-18-22-12.md b/.chronus/changes/fix-external-docs-properties-2025-10-24-18-22-12.md new file mode 100644 index 00000000000..f1e5a51a68d --- /dev/null +++ b/.chronus/changes/fix-external-docs-properties-2025-10-24-18-22-12.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/openapi3" +--- + +Respect `@externalDocs` on properties diff --git a/packages/openapi3/src/schema-emitter.ts b/packages/openapi3/src/schema-emitter.ts index 22117946257..dfcfc8a022a 100644 --- a/packages/openapi3/src/schema-emitter.ts +++ b/packages/openapi3/src/schema-emitter.ts @@ -440,6 +440,7 @@ export class OpenAPI3SchemaEmitterBase< if (isReadonlyProperty(program, prop)) { additionalProps.readOnly = true; } + this.#applyExternalDocs(prop, additionalProps); // Attach any additional OpenAPI extensions attachExtensions(program, prop, additionalProps); diff --git a/packages/openapi3/test/documentation.test.ts b/packages/openapi3/test/documentation.test.ts index 0894c623b65..7c9ff7d7864 100644 --- a/packages/openapi3/test/documentation.test.ts +++ b/packages/openapi3/test/documentation.test.ts @@ -1,5 +1,5 @@ import { deepStrictEqual, strictEqual } from "assert"; -import { it } from "vitest"; +import { expect, it } from "vitest"; import { supportedVersions, worksFor } from "./works-for.js"; worksFor(supportedVersions, ({ openApiFor }) => { @@ -26,8 +26,6 @@ worksFor(supportedVersions, ({ openApiFor }) => { it("supports externalDocs on models", async () => { const openApi = await openApiFor(` - op read(): Foo; - @externalDocs("https://example.com", "more info") model Foo { name: string; @@ -38,4 +36,36 @@ worksFor(supportedVersions, ({ openApiFor }) => { description: "more info", }); }); + + it("supports externalDocs on properties", async () => { + const openApi = await openApiFor(` + model Foo { + @externalDocs("https://example.com", "more info") + name: string; + } + `); + expect(openApi.components.schemas.Foo.properties.name).toEqual({ + type: "string", + externalDocs: { + url: "https://example.com", + description: "more info", + }, + }); + }); + it("supports externalDocs on properties resulting in a $ref", async () => { + const openApi = await openApiFor(` + model Foo { + @externalDocs("https://example.com", "more info") + name: Bar; + } + model Bar {} + `); + expect(openApi.components.schemas.Foo.properties.name).toEqual({ + allOf: [{ $ref: "#/components/schemas/Bar" }], + externalDocs: { + url: "https://example.com", + description: "more info", + }, + }); + }); });