From c29da672c974bb0c9b5516866e89079a108731f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 13:24:02 +0000 Subject: [PATCH 1/4] improve: surface schema description as XmlDoc on generated object and enum types (+5 tests, 348->353) When an OpenAPI component schema has a top-level `description` field, the generated ProvidedTypeDefinition (both object types and CLI enum types) now gets that description as a TypeProviderXmlDocAttribute. This means IDE tooling (IntelliSense / F# tooltips) will show the schema description when hovering over a generated type, matching the existing behaviour for property and operation-method descriptions. Changes: - DefinitionCompiler.fs: call `AddXmlDoc` on generated object types and named enum types when `schemaObj.Description` is non-null/non-whitespace - Schema.XmlDocTests.fs: 5 new Fact tests covering both object types and enum types with and without descriptions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../DefinitionCompiler.fs | 12 ++ .../Schema.XmlDocTests.fs | 124 ++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs index 93fc7262..1e5823d7 100644 --- a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs +++ b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs @@ -277,6 +277,12 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b let ty = ProvidedTypeDefinition(tyName, Some typeof, isErased = false) registerNew(tyName, ty :> Type) + if + not(isNull schemaObj.Description) + && not(String.IsNullOrWhiteSpace schemaObj.Description) + then + ty.AddXmlDoc schemaObj.Description + // Combine composite schemas let schemaObjProperties = let getProps(s: IOpenApiSchema) = @@ -549,6 +555,12 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b enumTy.SetEnumUnderlyingType underlyingIntType + if + not(isNull schemaObj.Description) + && not(String.IsNullOrWhiteSpace schemaObj.Description) + then + enumTy.AddXmlDoc schemaObj.Description + // String enums need [JsonConverter(typeof)] on the type // so System.Text.Json serialises them as strings rather than integers. // Per-member [JsonStringEnumMemberName] attributes (added below) let it honour diff --git a/tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs b/tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs index 910abce1..22da5127 100644 --- a/tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs @@ -208,3 +208,127 @@ let ``non-enum query parameter does not add Allowed values to XmlDoc``() = doc.IsSome |> shouldEqual true doc.Value |> shouldContainText "Health check" doc.Value |> shouldNotContainText "Allowed values:" + +// ── Type-level XmlDoc (schema descriptions on generated types) ─────────────── + +let private compileSchemaTypes(schemaStr: string) = + let schema = parseSchema schemaStr + let defCompiler = DefinitionCompiler(schema, false, false) + let opCompiler = OperationCompiler(schema, defCompiler, true, false, true) + opCompiler.CompileProvidedClients(defCompiler.Namespace) + defCompiler.Namespace.GetProvidedTypes() + +[] +let ``object type with description gets XmlDoc``() = + let schemaStr = + """openapi: "3.0.0" +info: + title: XmlDocTypeTest + version: "1.0.0" +paths: {} +components: + schemas: + Pet: + type: object + description: "A pet in the system" + properties: + name: + type: string +""" + + let types = compileSchemaTypes schemaStr + let petTy = types |> List.find(fun t -> t.Name = "Pet") + getXmlDocAttr petTy |> shouldEqual(Some "A pet in the system") + +[] +let ``object type without description has no XmlDoc``() = + let schemaStr = + """openapi: "3.0.0" +info: + title: XmlDocTypeTest + version: "1.0.0" +paths: {} +components: + schemas: + Widget: + type: object + properties: + id: + type: integer +""" + + let types = compileSchemaTypes schemaStr + let widgetTy = types |> List.find(fun t -> t.Name = "Widget") + getXmlDocAttr widgetTy |> shouldEqual None + +[] +let ``named string enum type with description gets XmlDoc``() = + let schemaStr = + """openapi: "3.0.0" +info: + title: XmlDocEnumTest + version: "1.0.0" +paths: {} +components: + schemas: + Status: + type: string + description: "The lifecycle status of an item" + enum: + - active + - inactive + - pending +""" + + let types = compileSchemaTypes schemaStr + let statusTy = types |> List.find(fun t -> t.Name = "Status") + + getXmlDocAttr statusTy + |> shouldEqual(Some "The lifecycle status of an item") + +[] +let ``named integer enum type with description gets XmlDoc``() = + let schemaStr = + """openapi: "3.0.0" +info: + title: XmlDocEnumTest + version: "1.0.0" +paths: {} +components: + schemas: + Priority: + type: integer + description: "Priority level (1=low, 2=medium, 3=high)" + enum: + - 1 + - 2 + - 3 +""" + + let types = compileSchemaTypes schemaStr + let priorityTy = types |> List.find(fun t -> t.Name = "Priority") + + getXmlDocAttr priorityTy + |> shouldEqual(Some "Priority level (1=low, 2=medium, 3=high)") + +[] +let ``named enum type without description has no XmlDoc``() = + let schemaStr = + """openapi: "3.0.0" +info: + title: XmlDocEnumTest + version: "1.0.0" +paths: {} +components: + schemas: + Color: + type: string + enum: + - red + - green + - blue +""" + + let types = compileSchemaTypes schemaStr + let colorTy = types |> List.find(fun t -> t.Name = "Color") + getXmlDocAttr colorTy |> shouldEqual None From 2ecdac4fa381081606e26164f41570141824f0fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 2 May 2026 13:24:06 +0000 Subject: [PATCH 2/4] ci: trigger checks From c16f5a760c8ba52a242bcc2fe5bbd9203f77f54b Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Sat, 2 May 2026 18:37:45 +0200 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/SwaggerProvider.DesignTime/DefinitionCompiler.fs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs index 1e5823d7..5b4b6562 100644 --- a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs +++ b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs @@ -277,10 +277,7 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b let ty = ProvidedTypeDefinition(tyName, Some typeof, isErased = false) registerNew(tyName, ty :> Type) - if - not(isNull schemaObj.Description) - && not(String.IsNullOrWhiteSpace schemaObj.Description) - then + if not (String.IsNullOrWhiteSpace schemaObj.Description) then ty.AddXmlDoc schemaObj.Description // Combine composite schemas @@ -555,10 +552,7 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b enumTy.SetEnumUnderlyingType underlyingIntType - if - not(isNull schemaObj.Description) - && not(String.IsNullOrWhiteSpace schemaObj.Description) - then + if not(String.IsNullOrWhiteSpace schemaObj.Description) then enumTy.AddXmlDoc schemaObj.Description // String enums need [JsonConverter(typeof)] on the type From 5e1941e96c6e843995a4eabac2bcf6330ba8a89c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 16:43:05 +0000 Subject: [PATCH 4/4] fix: apply Fantomas formatting to DefinitionCompiler.fs Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/1b744b0e-5d19-4ea2-b95e-23dfe2a564d7 Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- src/SwaggerProvider.DesignTime/DefinitionCompiler.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs index 5b4b6562..4d9b6eb4 100644 --- a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs +++ b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs @@ -277,7 +277,7 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b let ty = ProvidedTypeDefinition(tyName, Some typeof, isErased = false) registerNew(tyName, ty :> Type) - if not (String.IsNullOrWhiteSpace schemaObj.Description) then + if not(String.IsNullOrWhiteSpace schemaObj.Description) then ty.AddXmlDoc schemaObj.Description // Combine composite schemas