diff --git a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs index c504f490..93fc7262 100644 --- a/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs +++ b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs @@ -328,19 +328,8 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: b let pField, pProp = generateProperty propName pTy - let enumValuesDoc = XmlDoc.buildEnumDoc propSchema.Enum - let propDoc = - match - propSchema.Description - |> Option.ofObj - |> Option.filter(String.IsNullOrWhiteSpace >> not), - enumValuesDoc - with - | None, None -> null - | Some d, None -> d - | None, Some ev -> ev - | Some d, Some ev -> $"{d}\n{ev}" + XmlDoc.combineDescAndEnum propSchema.Description (XmlDoc.buildEnumDoc propSchema.Enum) if not(isNull propDoc) then pProp.AddXmlDoc propDoc diff --git a/src/SwaggerProvider.DesignTime/OperationCompiler.fs b/src/SwaggerProvider.DesignTime/OperationCompiler.fs index d82de838..8c1eaa57 100644 --- a/src/SwaggerProvider.DesignTime/OperationCompiler.fs +++ b/src/SwaggerProvider.DesignTime/OperationCompiler.fs @@ -502,16 +502,7 @@ type OperationCompiler(schema: OpenApiDocument, defCompiler: DefinitionCompiler, else None - match - p.Description - |> Option.ofObj - |> Option.filter(String.IsNullOrWhiteSpace >> not), - enumDoc - with - | None, None -> null - | Some d, None -> d - | None, Some ev -> ev - | Some d, Some ev -> $"{d}\n{ev}" + XmlDoc.combineDescAndEnum p.Description enumDoc let paramDescriptions = [ for p in openApiParameters -> niceCamelName p.Name, buildParamDesc p diff --git a/src/SwaggerProvider.DesignTime/Utils.fs b/src/SwaggerProvider.DesignTime/Utils.fs index 6eeb3435..0d12f239 100644 --- a/src/SwaggerProvider.DesignTime/Utils.fs +++ b/src/SwaggerProvider.DesignTime/Utils.fs @@ -334,6 +334,22 @@ module XmlDoc = let values = enumValues |> Seq.map formatEnumValue |> String.concat ", " Some $"Allowed values: {values}" + /// Combines a schema description with optional enum-value documentation into a single + /// XML doc string. Returns null if both inputs are absent. + /// Callers use this to avoid duplicating the four-case match expression in every property + /// and parameter doc-building site. + let combineDescAndEnum (description: string) (enumDoc: string option) = + match + description + |> Option.ofObj + |> Option.filter(String.IsNullOrWhiteSpace >> not), + enumDoc + with + | None, None -> null + | Some d, None -> d + | None, Some ev -> ev + | Some d, Some ev -> $"{d}\n{ev}" + /// Builds a structured XML doc string from summary, description, and parameter descriptions. /// paramDescriptions is a sequence of (camelCaseName, description) pairs. let buildXmlDoc (summary: string) (description: string) (paramDescriptions: (string * string) seq) = diff --git a/src/SwaggerProvider.Runtime/RuntimeHelpers.fs b/src/SwaggerProvider.Runtime/RuntimeHelpers.fs index 7a16262c..4807e259 100644 --- a/src/SwaggerProvider.Runtime/RuntimeHelpers.fs +++ b/src/SwaggerProvider.Runtime/RuntimeHelpers.fs @@ -503,6 +503,32 @@ module RuntimeHelpers = let combineUrl (urlA: string) (urlB: string) = sprintf "%s/%s" (urlA.TrimEnd('/')) (urlB.TrimStart('/')) + // Pre-built map of standard HTTP method names to their corresponding static HttpMethod + // instances. Uses an ordinal case-insensitive comparer so callers passing different + // casing (for example, "get") still resolve to the cached standard HttpMethod without + // allocating a normalized string for lookup. + let private standardHttpMethods = + let methods = + [| HttpMethod.Get + HttpMethod.Post + HttpMethod.Put + HttpMethod.Delete + HttpMethod("PATCH") + HttpMethod.Head + HttpMethod.Options + HttpMethod.Trace |] + + let dictionary = + System.Collections.Generic.Dictionary(StringComparer.OrdinalIgnoreCase) + + methods |> Array.iter(fun m -> dictionary.Add(m.Method, m)) + System.Collections.ObjectModel.ReadOnlyDictionary(dictionary) + + let private resolveHttpMethod(method: string) : HttpMethod = + match standardHttpMethods.TryGetValue method with + | true, m -> m + | false, _ -> HttpMethod(method.ToUpperInvariant()) + let createHttpRequest (httpMethod: string) address queryParams = let requestUrl = let fakeHost = "http://fake-host/" @@ -516,7 +542,7 @@ module RuntimeHelpers = builder.Query <- query.ToString() builder.Uri.PathAndQuery.TrimStart('/') - let method = HttpMethod(httpMethod.ToUpper()) + let method = resolveHttpMethod httpMethod new HttpRequestMessage(method, Uri(requestUrl, UriKind.Relative)) let fillHeaders (msg: HttpRequestMessage) (headers: (string * string) seq) =