From 80f45ebeed5f300ff6f7b72ec418a8e54c5b6b55 Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:14:57 +0100 Subject: [PATCH 1/9] Encode option-typed query parameters The HTTP client generator had no case for an option-typed [] parameter, so it fell through to the scalar path and emitted `param.ToString()`. For `Some 3` that yields `page=Some%283%29`, and for `None` it throws a NullReferenceException, since F#'s None is null at runtime. An option-typed query parameter now contributes zero or one key=value pair, via Option.map/Option.toList, so None is omitted from the URL and an all-None query leaves the URL bare. Query strings made only of required parameters are byte-identical to before, so no existing generated client changes. This is the client-side half of #546, without that PR's change to SwaggerClientGenerator (which additionally made unannotated Swagger 2 query parameters optional, and was rejected for the churn). Nothing currently generates optional query parameters; this makes it possible for them to be generated correctly when they are. Co-Authored-By: Claude Opus 4.8 --- ConsumePlugin/GeneratedRestClient.fs | 113 ++++++++++++++++++ ConsumePlugin/RestApiExample.fs | 16 +++ .../TestHttpClient/TestOptionalQueryParam.fs | 67 +++++++++++ .../WoofWare.Myriad.Plugins.Test.fsproj | 1 + .../HttpClientGenerator.fs | 13 +- 5 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 WoofWare.Myriad.Plugins.Test/TestHttpClient/TestOptionalQueryParam.fs diff --git a/ConsumePlugin/GeneratedRestClient.fs b/ConsumePlugin/GeneratedRestClient.fs index ccfb308f..2902426b 100644 --- a/ConsumePlugin/GeneratedRestClient.fs +++ b/ConsumePlugin/GeneratedRestClient.fs @@ -2360,6 +2360,119 @@ open System.Net open System.Net.Http open RestEase +/// Module for constructing a REST client. +[] +module ApiWithOptionalQuery = + /// Create a REST client. + let make (client : System.Net.Http.HttpClient) : IApiWithOptionalQuery = + { new IApiWithOptionalQuery with + member _.GetWithMixedQuery + (page : int option, limit : int, search : string option, ct : CancellationToken option) + = + async { + let! ct = Async.CancellationToken + + let queryString = + [ + page + |> Option.map (fun queryParam -> + "page=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + |> Option.toList + + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + search + |> Option.map (fun queryParam -> + "search=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + |> Option.toList + ] + |> List.concat + |> String.concat "&" + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://whatnot.com/" + | v -> v), + System.Uri ( + ("endpoint" + + (if queryString = "" then + "" + else + ((if "endpoint".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.GetWithAllOptionalQuery (since : DateOnly option, ct : CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let queryString = + [ + since + |> Option.map (fun queryParam -> + "since=" + ((queryParam.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString) + ) + |> Option.toList + ] + |> List.concat + |> String.concat "&" + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://whatnot.com/" + | v -> v), + System.Uri ( + ("endpoint" + + (if queryString = "" then + "" + else + ((if "endpoint".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + } +namespace PureGym + +open System +open System.Threading +open System.Threading.Tasks +open System.IO +open System.Net +open System.Net.Http +open RestEase + /// Module for constructing a REST client. [] module ClientWithStringBody = diff --git a/ConsumePlugin/RestApiExample.fs b/ConsumePlugin/RestApiExample.fs index a94c60ca..97ba2c78 100644 --- a/ConsumePlugin/RestApiExample.fs +++ b/ConsumePlugin/RestApiExample.fs @@ -263,6 +263,22 @@ type IApiShadowingGeneratedNames = [] queryString : string * [] limit : int * ?ct : CancellationToken -> Task +[] +[] +type IApiWithOptionalQuery = + // Optional query parameters are omitted from the URL when None. + [] + abstract GetWithMixedQuery : + [] page : int option * + [] limit : int * + [] search : string option * + ?ct : CancellationToken -> + Task + + [] + abstract GetWithAllOptionalQuery : + [] since : DateOnly option * ?ct : CancellationToken -> Task + [] type IClientWithStringBody = // As a POST request of a bare string body, we don't override the Content-Type. diff --git a/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestOptionalQueryParam.fs b/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestOptionalQueryParam.fs new file mode 100644 index 00000000..42669945 --- /dev/null +++ b/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestOptionalQueryParam.fs @@ -0,0 +1,67 @@ +namespace WoofWare.Myriad.Plugins.Test + +open System +open System.Net +open System.Net.Http +open NUnit.Framework +open PureGym +open FsUnitTyped + +[] +module TestOptionalQueryParam = + + let private makeClient (expectedUri : string) : HttpClientMock = + let proc (message : HttpRequestMessage) : HttpResponseMessage Async = + async { + message.Method |> shouldEqual HttpMethod.Get + message.RequestUri.AbsoluteUri |> shouldEqual expectedUri + + let resp = new HttpResponseMessage (HttpStatusCode.OK) + resp.Content <- new StringContent ("response") + return resp + } + + HttpClientMock.make (Uri "https://example.com") proc + + [] + let ``All params present`` () = + use client = makeClient "https://example.com/endpoint?page=3&limit=10&search=hello" + let api = ApiWithOptionalQuery.make client + + api.GetWithMixedQuery(Some 3, 10, Some "hello").Result |> shouldEqual "response" + + [] + let ``First param missing`` () = + use client = makeClient "https://example.com/endpoint?limit=10&search=hello" + let api = ApiWithOptionalQuery.make client + + api.GetWithMixedQuery(None, 10, Some "hello").Result |> shouldEqual "response" + + [] + let ``Last param missing`` () = + use client = makeClient "https://example.com/endpoint?page=3&limit=10" + let api = ApiWithOptionalQuery.make client + + api.GetWithMixedQuery(Some 3, 10, None).Result |> shouldEqual "response" + + [] + let ``Optional params are escaped`` () = + use client = makeClient "https://example.com/endpoint?limit=10&search=a%20b" + let api = ApiWithOptionalQuery.make client + + api.GetWithMixedQuery(None, 10, Some "a b").Result |> shouldEqual "response" + + [] + let ``Sole optional param present`` () = + use client = makeClient "https://example.com/endpoint?since=2024-01-15" + let api = ApiWithOptionalQuery.make client + + api.GetWithAllOptionalQuery(Some (DateOnly (2024, 1, 15))).Result + |> shouldEqual "response" + + [] + let ``Sole optional param missing leaves the URL bare`` () = + use client = makeClient "https://example.com/endpoint" + let api = ApiWithOptionalQuery.make client + + api.GetWithAllOptionalQuery(None).Result |> shouldEqual "response" diff --git a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj index 967e96a3..5ba1aebd 100644 --- a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj +++ b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj @@ -27,6 +27,7 @@ + diff --git a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs index 1ed5bb30..dbf5467b 100644 --- a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs @@ -311,7 +311,8 @@ module internal HttpClientGenerator = |> freshName "queryString" // A list- or array-typed query parameter contributes one key=value pair per - // element ("multi" collection format, RestEase's convention), so the query + // element ("multi" collection format, RestEase's convention), and an option-typed + // one contributes zero or one pair (omitted entirely when None), so the query // string is a runtime computation: we emit a `queryString` binding and then // splice it (with a separator, if it's nonempty) onto the URL. let requestUriTrailer, queryStringBindings = @@ -368,6 +369,16 @@ module internal HttpClientGenerator = (keyEqualsValue eltType (SynExpr.createIdent "queryParam"))) ) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "List" ; "ofSeq" ]) + | OptionType innerType -> + SynExpr.createIdent' paramValueId + |> SynExpr.pipeThroughFunction ( + SynExpr.applyFunction + (SynExpr.createLongIdent [ "Option" ; "map" ]) + (SynExpr.createLambda + "queryParam" + (keyEqualsValue innerType (SynExpr.createIdent "queryParam"))) + ) + |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Option" ; "toList" ]) | ty -> keyEqualsValue ty (SynExpr.createIdent' paramValueId) |> List.singleton From d54ae676002db71d2e5dc16c4eb45309e0131eca Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:28:08 +0100 Subject: [PATCH 2/9] Implement OpenAPI v3 generator Co-Authored-By: GPT-5.6 Sol Ultra --- CHANGELOG.md | 6 + ConsumePlugin/ConsumePlugin.fsproj | 10 + ConsumePlugin/Generated2OpenApiPetstore.fs | 1119 +++++++++ ConsumePlugin/Generated2SwaggerGitea.fs | 312 +-- ConsumePlugin/GeneratedOpenApiPetstore.fs | 152 ++ ConsumePlugin/GeneratedSerde.fs | 2 +- ConsumePlugin/openapi-petstore.json | 328 +++ README.md | 33 +- .../TestSwagger/TestOpenApi3Client.fs | 225 ++ .../TestSwagger/TestOpenApi3Generator.fs | 1463 +++++++++++ .../WoofWare.Myriad.Plugins.Test.fsproj | 2 + WoofWare.Myriad.Plugins/JsonParseGenerator.fs | 1 - .../JsonSerializeGenerator.fs | 8 +- .../OpenApiClientGenerator.fs | 2158 +++++++++++++++++ .../SwaggerClientGenerator.fs | 21 +- .../WoofWare.Myriad.Plugins.fsproj | 1 + 16 files changed, 5674 insertions(+), 167 deletions(-) create mode 100644 ConsumePlugin/Generated2OpenApiPetstore.fs create mode 100644 ConsumePlugin/GeneratedOpenApiPetstore.fs create mode 100644 ConsumePlugin/openapi-petstore.json create mode 100644 WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs create mode 100644 WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs create mode 100644 WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs diff --git a/CHANGELOG.md b/CHANGELOG.md index 992986cf..55833b6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ Notable changes are recorded here. +# Unreleased + +The `swagger-client` generator now accepts OpenAPI 3.0 JSON documents as well as Swagger 2.0 documents. +It generates DTO records and a chained `HttpClient` interface from component schemas, paths, parameters, request bodies, responses, and root server definitions. +Unsupported or structurally ambiguous OpenAPI constructs fail with structured, JSON-pointer-located diagnostics; unconstrained JSON values preserve `null`, and unbounded integers use `BigInteger`. + # WoofWare.Myriad.Plugins 9.1.1, WoofWare.Myriad.Plugins.Attributes 3.8.1 Adds the `[]` attribute, which can be placed on a boolean or flag-valued field when using the `ArgParser` generator. diff --git a/ConsumePlugin/ConsumePlugin.fsproj b/ConsumePlugin/ConsumePlugin.fsproj index 550742ee..2b4ff163 100644 --- a/ConsumePlugin/ConsumePlugin.fsproj +++ b/ConsumePlugin/ConsumePlugin.fsproj @@ -108,6 +108,16 @@ --> + + + openapi-petstore.json + + OpenApiPetstore + + + + GeneratedOpenApiPetstore.fs + swagger-gitea.json diff --git a/ConsumePlugin/Generated2OpenApiPetstore.fs b/ConsumePlugin/Generated2OpenApiPetstore.fs new file mode 100644 index 00000000..f9e1d179 --- /dev/null +++ b/ConsumePlugin/Generated2OpenApiPetstore.fs @@ -0,0 +1,1119 @@ +//------------------------------------------------------------------------------ +// This code was generated by myriad. +// Changes to this file will be lost when the code is regenerated. +//------------------------------------------------------------------------------ + + + +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Module containing JSON serializing extension members for the GenerateMockAttribute2 type +[] +module GenerateMockAttribute2JsonSerializeExtension = + /// Extension methods for JSON parsing + type GenerateMockAttribute2 with + + /// Serialize to a JSON node + static member toJsonNode (input : GenerateMockAttribute2) : System.Text.Json.Nodes.JsonNode = + let node = System.Text.Json.Nodes.JsonObject () + + do + for KeyValue (key, value) in input.AdditionalProperties do + node.Add ( + key, + (fun field -> + match field with + | None -> None + | Some field -> + field + |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> Some + ) + value + |> Option.toObj + ) + + node.Add ( + "value", + (input.Value + |> (fun field -> + match field with + | None -> None + | Some field -> + (field + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + :> System.Text.Json.Nodes.JsonNode + |> Some + ) + |> Option.toObj) + ) + + node :> _ +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Module containing JSON serializing extension members for the HttpClientAttribute2 type +[] +module HttpClientAttribute2JsonSerializeExtension = + /// Extension methods for JSON parsing + type HttpClientAttribute2 with + + /// Serialize to a JSON node + static member toJsonNode (input : HttpClientAttribute2) : System.Text.Json.Nodes.JsonNode = + let node = System.Text.Json.Nodes.JsonObject () + + do + for KeyValue (key, value) in input.AdditionalProperties do + node.Add ( + key, + (fun field -> + match field with + | None -> None + | Some field -> + field + |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> Some + ) + value + |> Option.toObj + ) + + node.Add ( + "value", + (input.Value + |> (fun field -> + match field with + | None -> None + | Some field -> + (field + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + :> System.Text.Json.Nodes.JsonNode + |> Some + ) + |> Option.toObj) + ) + + node :> _ +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Module containing JSON serializing extension members for the JsonParseAttribute2 type +[] +module JsonParseAttribute2JsonSerializeExtension = + /// Extension methods for JSON parsing + type JsonParseAttribute2 with + + /// Serialize to a JSON node + static member toJsonNode (input : JsonParseAttribute2) : System.Text.Json.Nodes.JsonNode = + let node = System.Text.Json.Nodes.JsonObject () + + do + for KeyValue (key, value) in input.AdditionalProperties do + node.Add ( + key, + (fun field -> + match field with + | None -> None + | Some field -> + field + |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> Some + ) + value + |> Option.toObj + ) + + node.Add ( + "value", + (input.Value + |> (fun field -> + match field with + | None -> None + | Some field -> + (field + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + :> System.Text.Json.Nodes.JsonNode + |> Some + ) + |> Option.toObj) + ) + + node :> _ +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Module containing JSON serializing extension members for the JsonSerializeAttribute2 type +[] +module JsonSerializeAttribute2JsonSerializeExtension = + /// Extension methods for JSON parsing + type JsonSerializeAttribute2 with + + /// Serialize to a JSON node + static member toJsonNode (input : JsonSerializeAttribute2) : System.Text.Json.Nodes.JsonNode = + let node = System.Text.Json.Nodes.JsonObject () + + do + for KeyValue (key, value) in input.AdditionalProperties do + node.Add ( + key, + (fun field -> + match field with + | None -> None + | Some field -> + field + |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> Some + ) + value + |> Option.toObj + ) + + node.Add ( + "value", + (input.Value + |> (fun field -> + match field with + | None -> None + | Some field -> + (field + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + :> System.Text.Json.Nodes.JsonNode + |> Some + ) + |> Option.toObj) + ) + + node :> _ +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Module containing JSON serializing extension members for the NewPet type +[] +module NewPetJsonSerializeExtension = + /// Extension methods for JSON parsing + type NewPet with + + /// Serialize to a JSON node + static member toJsonNode (input : NewPet) : System.Text.Json.Nodes.JsonNode = + let node = System.Text.Json.Nodes.JsonObject () + + do + for KeyValue (key, value) in input.AdditionalProperties do + node.Add ( + key, + (fun field -> + match field with + | None -> None + | Some field -> + field + |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> Some + ) + value + |> Option.toObj + ) + + node.Add ( + "name", + (input.Name + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + ) + + node.Add ( + "tag", + (input.Tag + |> (fun field -> + match field with + | None -> None + | Some field -> + (field + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + :> System.Text.Json.Nodes.JsonNode + |> Some + ) + |> Option.toObj) + ) + + node :> _ +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Module containing JSON serializing extension members for the Pet type +[] +module PetJsonSerializeExtension = + /// Extension methods for JSON parsing + type Pet with + + /// Serialize to a JSON node + static member toJsonNode (input : Pet) : System.Text.Json.Nodes.JsonNode = + let node = System.Text.Json.Nodes.JsonObject () + + do + for KeyValue (key, value) in input.AdditionalProperties do + node.Add ( + key, + (fun field -> + match field with + | None -> None + | Some field -> + field + |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> Some + ) + value + |> Option.toObj + ) + + node.Add ( + "id", + (input.Id + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type int64 to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + ) + + node.Add ( + "name", + (input.Name + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + ) + + node.Add ( + "parent", + (input.Parent + |> (fun field -> + match field with + | None -> None + | Some field -> field |> Pet.toJsonNode |> Some + ) + |> Option.toObj) + ) + + node.Add ( + "tag", + (input.Tag + |> (fun field -> + match field with + | None -> None + | Some field -> + (field + |> (fun field -> + let field = System.Text.Json.Nodes.JsonValue.Create field + + (match field with + | null -> + raise ( + System.ArgumentNullException + "Expected type string to be non-null, but received a null value when serialising" + ) + | field -> field) + )) + :> System.Text.Json.Nodes.JsonNode + |> Some + ) + |> Option.toObj) + ) + + node :> _ + +namespace OpenApiPetstore + +/// Module containing JSON parsing extension members for the GenerateMockAttribute2 type +[] +module GenerateMockAttribute2JsonParseExtension = + /// Extension methods for JSON parsing + type GenerateMockAttribute2 with + + /// Parse from a JSON node. + static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : GenerateMockAttribute2 = + let arg_1 = + match node.["value"] |> Option.ofObj with + | None -> None + | Some v -> v.AsValue().GetValue () |> Some + + let arg_0 = + let result = + System.Collections.Generic.Dictionary () + + let node = node.AsObject () + + for KeyValue (key, value) in node do + if key = "value" then + () + else + result.Add ( + key, + match node.[key] |> Option.ofObj with + | None -> None + | Some v -> v |> Some + ) + + result + + { + AdditionalProperties = arg_0 + Value = arg_1 + } +namespace OpenApiPetstore + +/// Module containing JSON parsing extension members for the HttpClientAttribute2 type +[] +module HttpClientAttribute2JsonParseExtension = + /// Extension methods for JSON parsing + type HttpClientAttribute2 with + + /// Parse from a JSON node. + static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : HttpClientAttribute2 = + let arg_1 = + match node.["value"] |> Option.ofObj with + | None -> None + | Some v -> v.AsValue().GetValue () |> Some + + let arg_0 = + let result = + System.Collections.Generic.Dictionary () + + let node = node.AsObject () + + for KeyValue (key, value) in node do + if key = "value" then + () + else + result.Add ( + key, + match node.[key] |> Option.ofObj with + | None -> None + | Some v -> v |> Some + ) + + result + + { + AdditionalProperties = arg_0 + Value = arg_1 + } +namespace OpenApiPetstore + +/// Module containing JSON parsing extension members for the JsonParseAttribute2 type +[] +module JsonParseAttribute2JsonParseExtension = + /// Extension methods for JSON parsing + type JsonParseAttribute2 with + + /// Parse from a JSON node. + static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonParseAttribute2 = + let arg_1 = + match node.["value"] |> Option.ofObj with + | None -> None + | Some v -> v.AsValue().GetValue () |> Some + + let arg_0 = + let result = + System.Collections.Generic.Dictionary () + + let node = node.AsObject () + + for KeyValue (key, value) in node do + if key = "value" then + () + else + result.Add ( + key, + match node.[key] |> Option.ofObj with + | None -> None + | Some v -> v |> Some + ) + + result + + { + AdditionalProperties = arg_0 + Value = arg_1 + } +namespace OpenApiPetstore + +/// Module containing JSON parsing extension members for the JsonSerializeAttribute2 type +[] +module JsonSerializeAttribute2JsonParseExtension = + /// Extension methods for JSON parsing + type JsonSerializeAttribute2 with + + /// Parse from a JSON node. + static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonSerializeAttribute2 = + let arg_1 = + match node.["value"] |> Option.ofObj with + | None -> None + | Some v -> v.AsValue().GetValue () |> Some + + let arg_0 = + let result = + System.Collections.Generic.Dictionary () + + let node = node.AsObject () + + for KeyValue (key, value) in node do + if key = "value" then + () + else + result.Add ( + key, + match node.[key] |> Option.ofObj with + | None -> None + | Some v -> v |> Some + ) + + result + + { + AdditionalProperties = arg_0 + Value = arg_1 + } +namespace OpenApiPetstore + +/// Module containing JSON parsing extension members for the NewPet type +[] +module NewPetJsonParseExtension = + /// Extension methods for JSON parsing + type NewPet with + + /// Parse from a JSON node. + static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : NewPet = + let arg_2 = + match node.["tag"] |> Option.ofObj with + | None -> None + | Some v -> v.AsValue().GetValue () |> Some + + let arg_1 = + match node.["name"] |> Option.ofObj with + | None -> + raise ( + System.Collections.Generic.KeyNotFoundException ( + sprintf "Required key '%s' not found on JSON object" ("name") + ) + ) + | Some node -> node.AsValue().GetValue () + + let arg_0 = + let result = + System.Collections.Generic.Dictionary () + + let node = node.AsObject () + + for KeyValue (key, value) in node do + if key = "name" || key = "tag" then + () + else + result.Add ( + key, + match node.[key] |> Option.ofObj with + | None -> None + | Some v -> v |> Some + ) + + result + + { + AdditionalProperties = arg_0 + Name = arg_1 + Tag = arg_2 + } +namespace OpenApiPetstore + +/// Module containing JSON parsing extension members for the Pet type +[] +module PetJsonParseExtension = + /// Extension methods for JSON parsing + type Pet with + + /// Parse from a JSON node. + static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : Pet = + let arg_4 = + match node.["tag"] |> Option.ofObj with + | None -> None + | Some v -> v.AsValue().GetValue () |> Some + + let arg_3 = + match node.["parent"] |> Option.ofObj with + | None -> None + | Some v -> Pet.jsonParse v |> Some + + let arg_2 = + match node.["name"] |> Option.ofObj with + | None -> + raise ( + System.Collections.Generic.KeyNotFoundException ( + sprintf "Required key '%s' not found on JSON object" ("name") + ) + ) + | Some node -> node.AsValue().GetValue () + + let arg_1 = + match node.["id"] |> Option.ofObj with + | None -> + raise ( + System.Collections.Generic.KeyNotFoundException ( + sprintf "Required key '%s' not found on JSON object" ("id") + ) + ) + | Some node -> node.AsValue().GetValue () + + let arg_0 = + let result = + System.Collections.Generic.Dictionary () + + let node = node.AsObject () + + for KeyValue (key, value) in node do + if key = "id" || key = "name" || key = "parent" || key = "tag" then + () + else + result.Add ( + key, + match node.[key] |> Option.ofObj with + | None -> None + | Some v -> v |> Some + ) + + result + + { + AdditionalProperties = arg_0 + Id = arg_1 + Name = arg_2 + Parent = arg_3 + Tag = arg_4 + } + +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Module for constructing a REST client. +[] +module OpenApiPetstore = + /// Create a REST client. + let make (client : System.Net.Http.HttpClient) : IOpenApiPetstore = + { new IOpenApiPetstore with + member _.CreatePet (body : NewPet, ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ("pets", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Post, + RequestUri = uri + ) + + let queryParams = + new System.Net.Http.StringContent ( + body |> NewPet.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" + ) + + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask + + let! jsonNode = + System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) + |> Async.AwaitTask + + let jsonNode = + (match jsonNode with + | null -> + raise ( + System.ArgumentNullException + "Response from server was the JSON null object; expected a non-nullable type Pet" + ) + | jsonNode -> jsonNode) + + return Pet.jsonParse jsonNode + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.DeletePet (pet_id : int64, ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ( + "pets/{pet-id}".Replace ("{pet-id}", pet_id.ToString () |> System.Uri.EscapeDataString), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Delete, + RequestUri = uri + ) + + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + return () + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.Download (ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ("download", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("Accept", "application/octet-stream") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask + return responseStream + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.Echo (body : string, ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ("echo", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Post, + RequestUri = uri + ) + + let queryParams = new System.Net.Http.StringContent (body, null, "text/plain") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "text/plain") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.EchoAnything + (body : System.Text.Json.Nodes.JsonNode option, ct : System.Threading.CancellationToken option) + = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ("anything", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Post, + RequestUri = uri + ) + + let queryParams = + new System.Net.Http.StringContent ( + body + |> (fun field -> + match field with + | None -> None + | Some field -> + field + |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> Some + ) + |> (fun node -> + match node with + | None -> "null" + | Some node -> node.ToJsonString () + ), + null, + "application/json" + ) + + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask + + let! jsonNode = + System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) + |> Async.AwaitTask + + let jsonNode = jsonNode |> Option.ofObj + + return + match jsonNode with + | None -> None + | Some v -> v |> Some + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.EchoCounter (body : System.Numerics.BigInteger, ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ("counter", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Post, + RequestUri = uri + ) + + let queryParams = + new System.Net.Http.StringContent ( + body + |> (fun field -> + let value = field : System.Numerics.BigInteger + + let node = + System.Text.Json.Nodes.JsonNode.Parse ( + value.ToString ("D", System.Globalization.CultureInfo.InvariantCulture) + ) + + (match node with + | null -> + raise ( + System.ArgumentNullException + "Invariant BigInteger text unexpectedly parsed as JSON null." + ) + | node -> node) + ) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" + ) + + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask + + let! jsonNode = + System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) + |> Async.AwaitTask + + let jsonNode = + (match jsonNode with + | null -> + raise ( + System.ArgumentNullException + "Response from server was the JSON null object; expected a non-nullable type bigint" + ) + | jsonNode -> jsonNode) + + return + System.Numerics.BigInteger.Parse ( + jsonNode.ToJsonString (), + System.Globalization.NumberStyles.Float, + System.Globalization.CultureInfo.InvariantCulture + ) + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.GetCounter (ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ("counter", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("Accept", "application/json") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask + + let! jsonNode = + System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) + |> Async.AwaitTask + + let jsonNode = + (match jsonNode with + | null -> + raise ( + System.ArgumentNullException + "Response from server was the JSON null object; expected a non-nullable type bigint" + ) + | jsonNode -> jsonNode) + + return + System.Numerics.BigInteger.Parse ( + jsonNode.ToJsonString (), + System.Globalization.NumberStyles.Float, + System.Globalization.CultureInfo.InvariantCulture + ) + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.GetPet (pet_id : int64, ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ( + "pets/{pet-id}".Replace ("{pet-id}", pet_id.ToString () |> System.Uri.EscapeDataString), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("Accept", "application/json") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask + + let! jsonNode = + System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) + |> Async.AwaitTask + + let jsonNode = + (match jsonNode with + | null -> + raise ( + System.ArgumentNullException + "Response from server was the JSON null object; expected a non-nullable type Pet" + ) + | jsonNode -> jsonNode) + + return Pet.jsonParse jsonNode + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.GetStatus (ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ("status", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("Accept", "text/plain") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member _.ListPets (limit : int option, ct : System.Threading.CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> System.Uri "https://api.example.test/v1/public/" + | v -> v), + System.Uri ( + ("pets" + + (if "pets".IndexOf (char 63) >= 0 then "&" else "?") + + "limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("Accept", "application/json") + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask + + let! jsonNode = + System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) + |> Async.AwaitTask + + let jsonNode = + (match jsonNode with + | null -> + raise ( + System.ArgumentNullException + "Response from server was the JSON null object; expected a non-nullable type Pet list" + ) + | jsonNode -> jsonNode) + + return + jsonNode.AsArray () + |> Seq.map (fun elt -> + (match elt with + | null -> + raise ( + System.ArgumentNullException + "Expected element of array (element type Pet) to be non-null, but found a null element" + ) + | elt -> Pet.jsonParse elt) + ) + |> List.ofSeq + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + } diff --git a/ConsumePlugin/Generated2SwaggerGitea.fs b/ConsumePlugin/Generated2SwaggerGitea.fs index c216817e..579a4b5d 100644 --- a/ConsumePlugin/Generated2SwaggerGitea.fs +++ b/ConsumePlugin/Generated2SwaggerGitea.fs @@ -21,7 +21,7 @@ module APIErrorJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "message", @@ -94,7 +94,7 @@ module AccessTokenJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "id", @@ -258,7 +258,7 @@ module ActivityPubJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "@context", @@ -304,7 +304,7 @@ module AddCollaboratorOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "permission", @@ -350,7 +350,7 @@ module AddTimeOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created", @@ -441,7 +441,7 @@ module AnnotatedTagObjectJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "sha", @@ -541,7 +541,7 @@ module AttachmentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "browser_download_url", @@ -749,7 +749,7 @@ module BranchProtectionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "approvals_whitelist_teams", @@ -1513,7 +1513,7 @@ module ChangedFileJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "additions", @@ -1775,7 +1775,7 @@ module CommitAffectedFilesJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "filename", @@ -1821,7 +1821,7 @@ module CommitDateOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -1894,7 +1894,7 @@ module CommitMetaJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created", @@ -1994,7 +1994,7 @@ module CommitStatsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "additions", @@ -2094,7 +2094,7 @@ module CommitUserJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "date", @@ -2194,7 +2194,7 @@ module CreateAccessTokenOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "name", @@ -2268,7 +2268,7 @@ module CreateBranchProtectionOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "approvals_whitelist_teams", @@ -2978,7 +2978,7 @@ module CreateBranchRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "new_branch_name", @@ -3042,7 +3042,7 @@ module CreateEmailOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "emails", @@ -3098,7 +3098,7 @@ module CreateForkOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "name", @@ -3171,7 +3171,7 @@ module CreateGPGKeyOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "armored_public_key", @@ -3270,7 +3270,7 @@ module CreateIssueCommentOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -3307,7 +3307,7 @@ module CreateIssueOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "assignee", @@ -3580,7 +3580,7 @@ module CreateKeyOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "key", @@ -3662,7 +3662,7 @@ module CreateLabelOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "color", @@ -3771,7 +3771,7 @@ module CreateMilestoneOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "description", @@ -3898,7 +3898,7 @@ module CreateOAuth2ApplicationOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "confidential_client", @@ -4008,7 +4008,7 @@ module CreateOrgOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "description", @@ -4207,7 +4207,7 @@ module CreatePullRequestOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "assignee", @@ -4489,7 +4489,7 @@ module CreatePullReviewCommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -4616,7 +4616,7 @@ module CreatePushMirrorOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "interval", @@ -4770,7 +4770,7 @@ module CreateReleaseOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -4942,7 +4942,7 @@ module CreateRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "auto_init", @@ -5249,7 +5249,7 @@ module CreateStatusOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "context", @@ -5376,7 +5376,7 @@ module CreateTagOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "message", @@ -5502,7 +5502,7 @@ module CreateTeamOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "can_create_org_repo", @@ -5695,7 +5695,7 @@ module CreateUserOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created_at", @@ -5984,7 +5984,7 @@ module CreateWikiPageOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "content_base64", @@ -6084,7 +6084,7 @@ module CronJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "exec_times", @@ -6238,7 +6238,7 @@ module DeleteEmailOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "emails", @@ -6294,7 +6294,7 @@ module DismissPullReviewOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "message", @@ -6367,7 +6367,7 @@ module EditAttachmentOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "name", @@ -6413,7 +6413,7 @@ module EditBranchProtectionOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "approvals_whitelist_teams", @@ -7069,7 +7069,7 @@ module EditDeadlineOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "due_date", @@ -7106,7 +7106,7 @@ module EditGitHookOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "content", @@ -7187,7 +7187,7 @@ module EditHookOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "active", @@ -7335,7 +7335,7 @@ module EditIssueCommentOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -7372,7 +7372,7 @@ module EditIssueOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "assignee", @@ -7644,7 +7644,7 @@ module EditLabelOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "color", @@ -7771,7 +7771,7 @@ module EditMilestoneOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "description", @@ -7898,7 +7898,7 @@ module EditOrgOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "description", @@ -8079,7 +8079,7 @@ module EditPullRequestOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "allow_maintainer_edit", @@ -8415,7 +8415,7 @@ module EditReactionOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "content", @@ -8461,7 +8461,7 @@ module EditReleaseOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -8677,7 +8677,7 @@ module EditTeamOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "can_create_org_repo", @@ -8870,7 +8870,7 @@ module EditUserOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "active", @@ -9357,7 +9357,7 @@ module EmailJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "email", @@ -9457,7 +9457,7 @@ module ExternalTrackerJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "external_tracker_format", @@ -9584,7 +9584,7 @@ module ExternalWikiJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "external_wiki_url", @@ -9630,7 +9630,7 @@ module FileCommitResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -9839,7 +9839,7 @@ module FileLinksResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "git", @@ -9939,7 +9939,7 @@ module GPGKeyEmailJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "email", @@ -10012,7 +10012,7 @@ module GeneralAPISettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "default_git_trees_per_page", @@ -10139,7 +10139,7 @@ module GeneralAttachmentSettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "allowed_types", @@ -10266,7 +10266,7 @@ module GeneralRepoSettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "http_git_disabled", @@ -10447,7 +10447,7 @@ module GeneralUISettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "allowed_reactions", @@ -10567,7 +10567,7 @@ module GenerateRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "avatar", @@ -10865,7 +10865,7 @@ module GitBlobResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "content", @@ -11019,7 +11019,7 @@ module GitEntryJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "mode", @@ -11200,7 +11200,7 @@ module GitHookJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "content", @@ -11300,7 +11300,7 @@ module GitObjectJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "sha", @@ -11400,7 +11400,7 @@ module GitTreeResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "page", @@ -11611,7 +11611,7 @@ module HookJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "active", @@ -11840,7 +11840,7 @@ module IdentityJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "email", @@ -11913,7 +11913,7 @@ module InternalTrackerJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "allow_only_contributors_to_track_time", @@ -12013,7 +12013,7 @@ module IssueDeadlineJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "due_date", @@ -12097,7 +12097,7 @@ module IssueLabelsOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "labels", @@ -12153,7 +12153,7 @@ module LabelJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "color", @@ -12334,7 +12334,7 @@ module MarkdownOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "Context", @@ -12461,7 +12461,7 @@ module MergePullRequestOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "Do", @@ -12687,7 +12687,7 @@ module MigrateRepoOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "auth_password", @@ -13228,7 +13228,7 @@ module Type7JsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node :> _ namespace Gitea @@ -13247,7 +13247,7 @@ module NodeInfoServicesJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "inbound", @@ -13340,7 +13340,7 @@ module NodeInfoSoftwareJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "homepage", @@ -13467,7 +13467,7 @@ module NodeInfoUsageUsersJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "activeHalfyear", @@ -13567,7 +13567,7 @@ module NotificationCountJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "new", @@ -13613,7 +13613,7 @@ module OAuth2ApplicationJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "client_id", @@ -13831,7 +13831,7 @@ module OrganizationJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "avatar_url", @@ -14120,7 +14120,7 @@ module OrganizationPermissionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "can_create_repository", @@ -14274,7 +14274,7 @@ module PackageFileJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "Size", @@ -14482,7 +14482,7 @@ module PayloadUserJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "email", @@ -14582,7 +14582,7 @@ module PermissionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "admin", @@ -14682,7 +14682,7 @@ module PullRequestMetaJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "merged", @@ -14755,7 +14755,7 @@ module PullReviewRequestOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "reviewers", @@ -14848,7 +14848,7 @@ module PushMirrorJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created", @@ -15083,7 +15083,7 @@ module ReferenceJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "object", @@ -15167,7 +15167,7 @@ module RepoTopicOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "topics", @@ -15223,7 +15223,7 @@ module RepositoryMetaJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "full_name", @@ -15350,7 +15350,7 @@ module ServerVersionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "version", @@ -15396,7 +15396,7 @@ module StopWatchJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created", @@ -15604,7 +15604,7 @@ module SubmitPullReviewOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -15677,7 +15677,7 @@ module TagJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commit", @@ -15877,7 +15877,7 @@ module TeamJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "can_create_org_repo", @@ -16117,7 +16117,7 @@ module TopicNameJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "topics", @@ -16173,7 +16173,7 @@ module TopicResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created", @@ -16327,7 +16327,7 @@ module TransferRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "new_owner", @@ -16401,7 +16401,7 @@ module UpdateFileOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -16624,7 +16624,7 @@ module UserJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "active", @@ -17183,7 +17183,7 @@ module UserHeatmapDataJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "contributions", @@ -17256,7 +17256,7 @@ module UserSettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "description", @@ -17518,7 +17518,7 @@ module UserSettingsOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "description", @@ -17780,7 +17780,7 @@ module WatchInfoJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created_at", @@ -17948,7 +17948,7 @@ module WikiCommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -18043,7 +18043,7 @@ module WikiCommitListJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commits", @@ -18111,7 +18111,7 @@ module WikiPageJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commit_count", @@ -18330,7 +18330,7 @@ module WikiPageMetaDataJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "html_url", @@ -18441,7 +18441,7 @@ module CommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "assets", @@ -18736,7 +18736,7 @@ module CommitStatusJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "context", @@ -18982,7 +18982,7 @@ module ContentsResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "_links", @@ -19390,7 +19390,7 @@ module CreateFileOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -19568,7 +19568,7 @@ module CreateHookOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "active", @@ -19725,7 +19725,7 @@ module CreatePullReviewOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -19847,7 +19847,7 @@ module DeleteFileOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -20025,7 +20025,7 @@ module EditRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "allow_manual_merge", @@ -20725,7 +20725,7 @@ module IssueFormFieldJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "attributes", @@ -20820,7 +20820,7 @@ module IssueTemplateJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "about", @@ -21060,7 +21060,7 @@ module MilestoneJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "closed_at", @@ -21349,7 +21349,7 @@ module NodeInfoUsageJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "localComments", @@ -21433,7 +21433,7 @@ module NotificationSubjectJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "html_url", @@ -21641,7 +21641,7 @@ module PayloadCommitVerificationJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "payload", @@ -21779,7 +21779,7 @@ module PublicKeyJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created_at", @@ -22025,7 +22025,7 @@ module PullReviewJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -22390,7 +22390,7 @@ module PullReviewCommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "body", @@ -22782,7 +22782,7 @@ module ReactionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "content", @@ -22866,7 +22866,7 @@ module ReleaseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "assets", @@ -23269,7 +23269,7 @@ module RepoCollaboratorPermissionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "permission", @@ -23353,7 +23353,7 @@ module RepoCommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -23470,7 +23470,7 @@ module RepoTransferJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "doer", @@ -23533,7 +23533,7 @@ module RepositoryJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "allow_merge_commits", @@ -24844,7 +24844,7 @@ module SearchResultsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "data", @@ -24912,7 +24912,7 @@ module AnnotatedTagJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "message", @@ -25072,7 +25072,7 @@ module CombinedStatusJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commit_url", @@ -25259,7 +25259,7 @@ module CommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "author", @@ -25474,7 +25474,7 @@ module DeployKeyJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created_at", @@ -25720,7 +25720,7 @@ module FileDeleteResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commit", @@ -25775,7 +25775,7 @@ module FileResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commit", @@ -25827,7 +25827,7 @@ module IssueJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "assets", @@ -26399,7 +26399,7 @@ module NodeInfoJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "metadata", @@ -26553,7 +26553,7 @@ module NoteJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commit", @@ -26610,7 +26610,7 @@ module NotificationThreadJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "id", @@ -26786,7 +26786,7 @@ module PRBranchInfoJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "label", @@ -26924,7 +26924,7 @@ module PackageJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created_at", @@ -27111,7 +27111,7 @@ module PayloadCommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "added", @@ -27382,7 +27382,7 @@ module PullRequestJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "allow_maintainer_edit", @@ -28078,7 +28078,7 @@ module TrackedTimeJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "created", @@ -28270,7 +28270,7 @@ module BranchJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "commit", @@ -28526,7 +28526,7 @@ module TimelineCommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node.Add ( "assignee", diff --git a/ConsumePlugin/GeneratedOpenApiPetstore.fs b/ConsumePlugin/GeneratedOpenApiPetstore.fs new file mode 100644 index 00000000..e55e3117 --- /dev/null +++ b/ConsumePlugin/GeneratedOpenApiPetstore.fs @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// This code was generated by myriad. +// Changes to this file will be lost when the code is regenerated. +//------------------------------------------------------------------------------ + + + + + + + + +namespace OpenApiPetstore + +open WoofWare.Myriad.Plugins + +/// Generated representation of the 'GenerateMockAttribute' OpenAPI schema. +[] +type GenerateMockAttribute2 = + { + [] + AdditionalProperties : System.Collections.Generic.Dictionary + [] + Value : string option + } + +/// Generated representation of the 'HttpClientAttribute' OpenAPI schema. +[] +type HttpClientAttribute2 = + { + [] + AdditionalProperties : System.Collections.Generic.Dictionary + [] + Value : string option + } + +/// Generated representation of the 'JsonParseAttribute' OpenAPI schema. +[] +type JsonParseAttribute2 = + { + [] + AdditionalProperties : System.Collections.Generic.Dictionary + [] + Value : string option + } + +/// Generated representation of the 'JsonSerializeAttribute' OpenAPI schema. +[] +type JsonSerializeAttribute2 = + { + [] + AdditionalProperties : System.Collections.Generic.Dictionary + [] + Value : string option + } + +/// Generated representation of the 'NewPet' OpenAPI schema. +[] +type NewPet = + { + [] + AdditionalProperties : System.Collections.Generic.Dictionary + [] + Name : string + [] + Tag : string option + } + +/// Generated representation of the 'Pet' OpenAPI schema. +[] +type Pet = + { + [] + AdditionalProperties : System.Collections.Generic.Dictionary + [] + Id : int64 + [] + Name : string + [] + Parent : Pet option + [] + Tag : string option + } + +/// A compact OpenAPI 3 fixture used to compile the generated client. +[] +type IOpenApiPetstore = + /// Invoke the 'createPet' OpenAPI operation. + [] + [] + [] + abstract CreatePet : + [] body : NewPet * ?ct : System.Threading.CancellationToken -> Pet System.Threading.Tasks.Task + + /// Invoke the 'deletePet' OpenAPI operation. + [] + abstract DeletePet : + [] pet_id : int64 * ?ct : System.Threading.CancellationToken -> + unit System.Threading.Tasks.Task + + /// Invoke the 'download' OpenAPI operation. + [] + [] + abstract Download : ?ct : System.Threading.CancellationToken -> System.IO.Stream System.Threading.Tasks.Task + + /// Invoke the 'echo' OpenAPI operation. + [] + [] + [] + abstract Echo : + [] body : string * ?ct : System.Threading.CancellationToken -> string System.Threading.Tasks.Task + + /// Invoke the 'echoAnything' OpenAPI operation. + [] + [] + [] + abstract EchoAnything : + [] body : System.Text.Json.Nodes.JsonNode option * ?ct : System.Threading.CancellationToken -> + System.Text.Json.Nodes.JsonNode option System.Threading.Tasks.Task + + /// Invoke the 'echoCounter' OpenAPI operation. + [] + [] + [] + abstract EchoCounter : + [] body : System.Numerics.BigInteger * ?ct : System.Threading.CancellationToken -> + System.Numerics.BigInteger System.Threading.Tasks.Task + + /// Invoke the 'getCounter' OpenAPI operation. + [] + [] + abstract GetCounter : + ?ct : System.Threading.CancellationToken -> System.Numerics.BigInteger System.Threading.Tasks.Task + + /// Invoke the 'getPet' OpenAPI operation. + [] + [] + abstract GetPet : + [] pet_id : int64 * ?ct : System.Threading.CancellationToken -> + Pet System.Threading.Tasks.Task + + /// Invoke the 'getStatus' OpenAPI operation. + [] + [] + abstract GetStatus : ?ct : System.Threading.CancellationToken -> string System.Threading.Tasks.Task + + /// Invoke the 'listPets' OpenAPI operation. + [] + [] + abstract ListPets : + [] limit : int option * ?ct : System.Threading.CancellationToken -> + Pet list System.Threading.Tasks.Task diff --git a/ConsumePlugin/GeneratedSerde.fs b/ConsumePlugin/GeneratedSerde.fs index 4de552f5..f3ba4a7b 100644 --- a/ConsumePlugin/GeneratedSerde.fs +++ b/ConsumePlugin/GeneratedSerde.fs @@ -757,7 +757,7 @@ module CollectRemainingJsonSerializeExtension = ) for KeyValue (key, value) in input.Rest do - node.Add (key, id value) + node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) node :> _ namespace ConsumePlugin diff --git a/ConsumePlugin/openapi-petstore.json b/ConsumePlugin/openapi-petstore.json new file mode 100644 index 00000000..27f0c3e4 --- /dev/null +++ b/ConsumePlugin/openapi-petstore.json @@ -0,0 +1,328 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Systematic pet store", + "description": "A compact OpenAPI 3 fixture used to compile the generated client.", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://api.example.test/v1/{tenant}", + "variables": { + "tenant": { + "default": "public" + } + } + } + ], + "paths": { + "/pets": { + "get": { + "operationId": "listPets", + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "All pets", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + } + } + }, + "post": { + "operationId": "createPet", + "requestBody": { + "$ref": "#/components/requestBodies/CreatePet" + }, + "responses": { + "201": { + "$ref": "#/components/responses/PetResponse" + } + } + } + }, + "/pets/{pet-id}": { + "parameters": [ + { + "$ref": "#/components/parameters/PetId" + } + ], + "get": { + "operationId": "getPet", + "responses": { + "200": { + "$ref": "#/components/responses/PetResponse" + } + } + }, + "delete": { + "operationId": "deletePet", + "responses": { + "204": { + "description": "Deleted" + } + } + } + }, + "/status": { + "get": { + "operationId": "getStatus", + "responses": { + "200": { + "description": "Plain-text status", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/download": { + "get": { + "operationId": "download", + "responses": { + "200": { + "description": "Binary payload", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "/echo": { + "post": { + "operationId": "echo", + "requestBody": { + "required": true, + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "responses": { + "200": { + "description": "Echoed text", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/anything": { + "post": { + "operationId": "echoAnything", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": {} + } + } + }, + "responses": { + "200": { + "description": "Any JSON value", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/counter": { + "get": { + "operationId": "getCounter", + "responses": { + "200": { + "description": "An unconstrained-size integer", + "content": { + "application/json": { + "schema": { + "type": "integer" + } + } + } + } + } + }, + "post": { + "operationId": "echoCounter", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "integer" + } + } + } + }, + "responses": { + "200": { + "description": "The same unconstrained-size integer", + "content": { + "application/json": { + "schema": { + "type": "integer" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "NewPet": { + "allOf": [ + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + }, + { + "type": "object", + "properties": { + "tag": { + "type": "string" + } + } + } + ] + }, + "Pet": { + "allOf": [ + { + "$ref": "#/components/schemas/NewPet" + }, + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "parent": { + "$ref": "#/components/schemas/Pet" + } + } + } + ] + }, + "JsonParseAttribute": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + }, + "JsonSerializeAttribute": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + }, + "HttpClientAttribute": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + }, + "GenerateMockAttribute": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + } + }, + "parameters": { + "PetId": { + "name": "pet-id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + }, + "requestBodies": { + "CreatePet": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPet" + } + } + } + } + }, + "responses": { + "PetResponse": { + "description": "A pet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + } + } +} diff --git a/README.md b/README.md index 794218f4..066d2974 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Currently implemented: * `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client). * `GenerateMock` and `GenerateCapturingMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)). * `ArgParser` (to stamp out a basic argument parser). -* `SwaggerClient` (to stamp out an HTTP client for a Swagger API). +* `SwaggerClient` (to stamp out an HTTP client for a Swagger 2.0 or OpenAPI 3.0 API). * `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union). * `RemoveOptions` (to strip `option` modifiers from a type) - this one is particularly half-baked! @@ -229,7 +229,7 @@ It should work fine if you just want to compose a few primitive types, though. ## `SwaggerClient` -Takes a JSON-schema definition of a [Swagger API](https://swagger.io/), and stamps out a client like this: +Takes a JSON definition of a [Swagger 2.0 or OpenAPI 3.0 API](https://swagger.io/), and stamps out a client like this: ```fsharp /// A type which was defined in the Swagger spec @@ -293,6 +293,33 @@ so that the following manoeuvre will result in a generated mock: (Note that you do have to create the `GeneratedSwaggerGitea.fs` file manually before code generation happens. Myriad will throw if that file isn't there, because `Generated2SwaggerGitea.fs` depends on it so Myriad wants to compute its hash. Just make an empty file.) +### OpenAPI 3.0 + +The existing `swagger-client` generator detects the document version from the root `swagger` or `openapi` field, so OpenAPI 3.0 uses the same project configuration and preserves the Swagger 2.0 entry point. +OpenAPI 3.1 is rejected explicitly rather than being interpreted with 3.0 schema semantics. + +The OpenAPI 3.0 path supports: + +* local component references for schemas, parameters, request bodies, and responses; +* primitive schemas and formats, arrays, objects, required properties, `nullable`, `additionalProperties`, compatible object `allOf` intersections, and self-recursive records; +* inherited and operation-level path/query parameters, with operation-level overrides; +* JSON and plain-text request bodies, successful JSON/plain-text/binary responses, and no-content responses; +* root server URLs, including expansion of server-variable defaults; and +* deterministic sanitisation and collision handling for generated F# identifiers. + +The planner fails with a located diagnostic for structural constructs which the generated HTTP/JSON layer cannot represent. +This currently includes OpenAPI 3.1, external references, `oneOf`/`anyOf`/`not`, optional-and-nullable three-state values, mutually recursive groups of records, header/cookie parameters, non-default parameter styles, optional or binary request bodies, and operations whose possible successful responses have incompatible body shapes. + +This is a typed client generator, not a complete OpenAPI validator or policy engine: + +* schema validation keywords such as `enum`, patterns, and numeric bounds are not enforced by the generated F# types; +* security requirements and schemes do not add authentication automatically: configure the caller-supplied `HttpClient` instead; +* the existing JSON codecs represent both an absent optional field and an explicit JSON `null` as `None`, and likewise cannot distinguish a missing required-nullable field from `null` (schemas which require all three states are rejected); and +* optional query parameters are emitted as `option` arguments, with wire-level omission delegated to the chained `HttpClient` generator. + +Unconstrained JSON schemas use `JsonNode option` so that JSON `null` remains representable, and unformatted or extension-formatted integers use `System.Numerics.BigInteger` rather than silently narrowing their range. +Unformatted or unknown-format `number` schemas are rejected because `float` cannot preserve the full JSON number range; explicit `float`, `double`, and `decimal` formats are supported. + ### What's the point? [`SwaggerProvider`](https://github.com/fsprojects/SwaggerProvider) is *absolutely magical*, but it's kind of witchcraft. @@ -302,7 +329,7 @@ Also, builds using `SwaggerProvider` appear to be inherently nondeterministic, e ## Limitations -Swagger API specs appear to be pretty cowboy in the wild. +Swagger and OpenAPI specs appear to be pretty cowboy in the wild. I try to cope with invalid schemas I have seen, but I can't guarantee I do so correctly. Definitely do perform integration tests and let me know of weird specs you encounter, and bits of the (very extensive) Swagger spec I have omitted! diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs new file mode 100644 index 00000000..0da67b9f --- /dev/null +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs @@ -0,0 +1,225 @@ +namespace WoofWare.Myriad.Plugins.Test + +open System +open System.Collections.Generic +open System.IO +open System.Net +open System.Net.Http +open System.Numerics +open System.Text.Json.Nodes +open FsUnitTyped +open NUnit.Framework +open OpenApiPetstore + +[] +module TestOpenApi3Client = + + let private response (status : HttpStatusCode) (body : string option) = + let result = new HttpResponseMessage (status) + + match body with + | None -> () + | Some body -> result.Content <- new StringContent (body) + + result + + [] + let ``Generated OpenAPI client composes server paths, media, bodies, and recursive DTOs`` () = + task { + let mutable calls = 0 + let mutable counterReads = 0 + + let handler (message : HttpRequestMessage) = + async { + calls <- calls + 1 + + match message.Method.Method, message.RequestUri.ToString () with + | "GET", "https://api.example.test/v1/public/pets/42" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "application/json" + + return + response + HttpStatusCode.OK + (Some + """{"id":42,"name":"Ada","parent":{"id":1,"name":"Root"},"metadata":{"source":"fixture"},"discarded":null}""") + | "POST", "https://api.example.test/v1/public/pets" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "application/json" + + message.Content.Headers.ContentType.MediaType |> shouldEqual "application/json" + + let! requestBody = message.Content.ReadAsStringAsync () |> Async.AwaitTask + let requestBody = JsonNode.Parse requestBody + requestBody.["name"].GetValue () |> shouldEqual "Ada" + requestBody.["tag"].GetValue () |> shouldEqual "cat" + + return response HttpStatusCode.Created (Some """{"id":43,"name":"Ada","tag":"cat"}""") + | "DELETE", "https://api.example.test/v1/public/pets/43" -> + return response HttpStatusCode.NoContent None + | "GET", "https://api.example.test/v1/public/status" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "text/plain" + + return response HttpStatusCode.OK (Some "healthy") + | "GET", "https://api.example.test/v1/public/download" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "application/octet-stream" + + return response HttpStatusCode.OK (Some "binary payload") + | "POST", "https://api.example.test/v1/public/echo" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "text/plain" + + message.Content.Headers.ContentType.MediaType |> shouldEqual "text/plain" + let! requestBody = message.Content.ReadAsStringAsync () |> Async.AwaitTask + requestBody |> shouldEqual "hello" + return response HttpStatusCode.OK (Some requestBody) + | "POST", "https://api.example.test/v1/public/anything" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "application/json" + + message.Content.Headers.ContentType.MediaType |> shouldEqual "application/json" + let! requestBody = message.Content.ReadAsStringAsync () |> Async.AwaitTask + requestBody |> shouldEqual "null" + return response HttpStatusCode.OK (Some "null") + | "GET", "https://api.example.test/v1/public/counter" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "application/json" + + counterReads <- counterReads + 1 + + return response HttpStatusCode.OK (Some (if counterReads = 1 then "1e30" else "1.0")) + | "POST", "https://api.example.test/v1/public/counter" -> + message.Headers.Accept + |> Seq.exactlyOne + |> _.MediaType + |> shouldEqual "application/json" + + message.Content.Headers.ContentType.MediaType |> shouldEqual "application/json" + let! requestBody = message.Content.ReadAsStringAsync () |> Async.AwaitTask + requestBody |> shouldEqual "1000000000000000000000000000000" + return response HttpStatusCode.OK (Some requestBody) + | method, uri -> return failwith $"Unexpected generated request: %s{method} %s{uri}" + } + + use httpClient = HttpClientMock.makeNoUri handler + let client = OpenApiPetstore.make httpClient + + let! fetched = client.GetPet 42L + fetched.Id |> shouldEqual 42L + fetched.Name |> shouldEqual "Ada" + fetched.Parent |> Option.map _.Name |> shouldEqual (Some "Root") + + fetched.AdditionalProperties.["metadata"] + |> Option.get + |> fun metadata -> metadata.["source"].GetValue () + |> shouldEqual "fixture" + + fetched.AdditionalProperties.["discarded"] |> shouldEqual None + + let roundTripped = Pet.toJsonNode fetched + + roundTripped.["metadata"].["source"].GetValue () + |> shouldEqual "fixture" + + roundTripped.AsObject().ContainsKey "discarded" |> shouldEqual true + isNull roundTripped.["discarded"] |> shouldEqual true + + let newPet = + { + AdditionalProperties = Dictionary () + Name = "Ada" + Tag = Some "cat" + } + + let! created = client.CreatePet newPet + created.Id |> shouldEqual 43L + created.Tag |> shouldEqual (Some "cat") + + do! client.DeletePet 43L + let! status = client.GetStatus () + status |> shouldEqual "healthy" + + use! download = client.Download () + use reader = new StreamReader (download) + let! downloaded = reader.ReadToEndAsync () + downloaded |> shouldEqual "binary payload" + + let! echoed = client.Echo "hello" + echoed |> shouldEqual "hello" + + let! anything = client.EchoAnything None + anything |> shouldEqual None + + let! counter = client.GetCounter () + counter |> shouldEqual (BigInteger.Pow (10I, 30)) + + let! zeroFractionCounter = client.GetCounter () + zeroFractionCounter |> shouldEqual 1I + + let! echoedCounter = client.EchoCounter counter + echoedCounter |> shouldEqual counter + calls |> shouldEqual 10 + } + + [] + let ``Generated extension-data codecs round-trip every JSON value kind repeatedly`` () = + let extensionCases : (string * JsonNode option) list = + [ + "null", None + "scalar", Some (JsonValue.Create 17 :> JsonNode) + "object", Some (JsonNode.Parse """{"nested":"yes"}""") + "array", Some (JsonNode.Parse """[1,null,"x"]""") + ] + + for caseName, extensionValue in extensionCases do + for hasParent in [ false ; true ] do + let extensions = Dictionary () + extensions.Add (caseName, extensionValue |> Option.map (fun value -> value.DeepClone ())) + + let parent = + if hasParent then + Some + { + AdditionalProperties = Dictionary () + Id = 1L + Name = "Parent" + Parent = None + Tag = None + } + else + None + + let pet = + { + AdditionalProperties = extensions + Id = 2L + Name = "Child" + Parent = parent + Tag = Some "tag" + } + + let first = Pet.toJsonNode pet + let repeatedFromInput = Pet.toJsonNode pet + JsonNode.DeepEquals (first, repeatedFromInput) |> shouldEqual true + + let parsed = Pet.jsonParse first + let second = Pet.toJsonNode parsed + let third = Pet.toJsonNode parsed + JsonNode.DeepEquals (first, second) |> shouldEqual true + JsonNode.DeepEquals (second, third) |> shouldEqual true diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs new file mode 100644 index 00000000..34746a7c --- /dev/null +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs @@ -0,0 +1,1463 @@ +namespace WoofWare.Myriad.Plugins.Test + +open System +open System.Collections.Generic +open System.Text.Json.Nodes +open FsCheck +open FsCheck.FSharp +open FsUnitTyped +open NUnit.Framework +open WoofWare.Myriad.Plugins + +[] +module TestOpenApi3Generator = + + type private GeneratedScalar = + | String + | Boolean + | Int32 + | Int64 + | Float32 + | Float + | Decimal + | Date + | DateTime + | Guid + + type private GeneratedField = + { + Name : string + Scalar : GeneratedScalar + Required : bool + Nullable : bool + } + + let private jsonString (value : string) : JsonNode = JsonValue.Create value + let private jsonBool (value : bool) : JsonNode = JsonValue.Create value + + let private jsonObject (properties : (string * JsonNode) list) : JsonNode = + let result = JsonObject () + + for name, value in properties do + result.Add (name, value) + + result :> JsonNode + + let private jsonArray (values : JsonNode list) : JsonNode = + JsonArray (values |> List.toArray) :> JsonNode + + let private schemaForScalar (scalar : GeneratedScalar) (nullable : bool) : JsonNode = + let typeName, format = + match scalar with + | GeneratedScalar.String -> "string", None + | GeneratedScalar.Boolean -> "boolean", None + | GeneratedScalar.Int32 -> "integer", Some "int32" + | GeneratedScalar.Int64 -> "integer", Some "int64" + | GeneratedScalar.Float32 -> "number", Some "float" + | GeneratedScalar.Float -> "number", Some "double" + | GeneratedScalar.Decimal -> "number", Some "decimal" + | GeneratedScalar.Date -> "string", Some "date" + | GeneratedScalar.DateTime -> "string", Some "date-time" + | GeneratedScalar.Guid -> "string", Some "uuid" + + jsonObject + [ + "type", jsonString typeName + match format with + | None -> () + | Some value -> "format", jsonString value + if nullable then + "nullable", jsonBool true + ] + + let private reference (target : string) : JsonNode = + jsonObject [ "$ref", jsonString ("#/components/schemas/" + target) ] + + let private responseWithSchema (schema : JsonNode) : JsonNode = + jsonObject + [ + "description", jsonString "success" + "content", jsonObject [ "application/json", jsonObject [ "schema", schema ] ] + ] + + let private noContentResponse () : JsonNode = + jsonObject [ "description", jsonString "success" ] + + let private parameter (name : string) (location : string) (required : bool) (schema : JsonNode) : JsonNode = + jsonObject + [ + "name", jsonString name + "in", jsonString location + "required", jsonBool required + "schema", schema + ] + + let private document + (version : string) + (schemas : (string * JsonNode) list) + (path : string) + (pathItem : JsonNode) + : string + = + jsonObject + [ + "openapi", jsonString version + "info", + jsonObject + [ + "title", jsonString "Generated API" + "description", jsonString "Generated test API" + "version", jsonString "1.0.0" + ] + "servers", jsonArray [ jsonObject [ "url", jsonString "/api/v1" ] ] + "paths", jsonObject [ path, pathItem ] + "components", jsonObject [ "schemas", jsonObject schemas ] + ] + |> _.ToJsonString() + + let private standardPathItem + (response : JsonNode) + (pathParameters : JsonNode list) + (operationParameters : JsonNode list) + : JsonNode + = + jsonObject + [ + if not pathParameters.IsEmpty then + "parameters", jsonArray pathParameters + "get", + jsonObject + [ + "operationId", jsonString "getThing" + if not operationParameters.IsEmpty then + "parameters", jsonArray operationParameters + "responses", jsonObject [ "200", response ] + ] + ] + + let private config = Map [ "CLASSNAME", "GeneratedClient" ] + + let private plan (source : string) : OpenApiClientPlan = + match OpenApiClientGenerator.parseAndPlan config source with + | Ok value -> value + | Error diagnostics -> + diagnostics + |> List.map (fun diagnostic -> $"%s{diagnostic.Location}: %s{diagnostic.Message}") + |> String.concat Environment.NewLine + |> failwith + + let private expectedPrimitive (scalar : GeneratedScalar) : OpenApiPrimitive = + match scalar with + | GeneratedScalar.String -> OpenApiPrimitive.String + | GeneratedScalar.Boolean -> OpenApiPrimitive.Boolean + | GeneratedScalar.Int32 -> OpenApiPrimitive.Int32 + | GeneratedScalar.Int64 -> OpenApiPrimitive.Int64 + | GeneratedScalar.Float32 -> OpenApiPrimitive.Float32 + | GeneratedScalar.Float -> OpenApiPrimitive.Float + | GeneratedScalar.Decimal -> OpenApiPrimitive.Decimal + | GeneratedScalar.Date -> OpenApiPrimitive.Date + | GeneratedScalar.DateTime -> OpenApiPrimitive.DateTime + | GeneratedScalar.Guid -> OpenApiPrimitive.Guid + + let private generatedFields : Gen = + gen { + let! count = Gen.choose (1, 8) + + let field = + gen { + let! scalar = + Gen.elements + [ + GeneratedScalar.String + GeneratedScalar.Boolean + GeneratedScalar.Int32 + GeneratedScalar.Int64 + GeneratedScalar.Float32 + GeneratedScalar.Float + GeneratedScalar.Decimal + GeneratedScalar.Date + GeneratedScalar.DateTime + GeneratedScalar.Guid + ] + + let! required = ArbMap.generate ArbMap.defaults + + let! nullable = + if required then + ArbMap.generate ArbMap.defaults + else + Gen.constant false + + return + { + Name = "field" + Scalar = scalar + Required = required + Nullable = nullable + } + } + + let! fields = Gen.listOfLength count field + + return + fields + |> List.mapi (fun index value -> + { value with + Name = $"field%i{index}" + } + ) + } + + let private renderObjectDocument (fields : GeneratedField list) : string = + let properties = + fields + |> List.map (fun field -> field.Name, schemaForScalar field.Scalar field.Nullable) + + let required = + fields + |> List.choose (fun field -> + if field.Required then + Some (jsonString field.Name) + else + None + ) + + let thingSchema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject properties + if not required.IsEmpty then + "required", jsonArray required + ] + + let pathParameter = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + standardPathItem (responseWithSchema (reference "Thing")) [ pathParameter ] [] + |> fun pathItem -> document "3.0.3" [ "Thing", thingSchema ] "/things/{id}" pathItem + + [] + let ``Object planning agrees with an independent field oracle across generated schemas`` () = + let scalarCounts = System.Collections.Generic.Dictionary () + let mutable requiredCount = 0 + let mutable optionalCount = 0 + let mutable nullableCount = 0 + let mutable noRequiredDocuments = 0 + let mutable allRequiredDocuments = 0 + let mutable mixedRequiredDocuments = 0 + let mutable documentsWithNullableFields = 0 + + let property (fields : GeneratedField list) = + let requiredInDocument = fields |> List.filter _.Required |> List.length + + if requiredInDocument = 0 then + noRequiredDocuments <- noRequiredDocuments + 1 + elif requiredInDocument = fields.Length then + allRequiredDocuments <- allRequiredDocuments + 1 + else + mixedRequiredDocuments <- mixedRequiredDocuments + 1 + + if fields |> List.exists _.Nullable then + documentsWithNullableFields <- documentsWithNullableFields + 1 + + for field in fields do + scalarCounts.[field.Scalar] <- + match scalarCounts.TryGetValue field.Scalar with + | true, count -> count + 1 + | false, _ -> 1 + + if field.Required then + requiredCount <- requiredCount + 1 + else + optionalCount <- optionalCount + 1 + + if field.Nullable then + nullableCount <- nullableCount + 1 + + let actual = renderObjectDocument fields |> plan + let actualType = actual.Types |> List.exactlyOne + actualType.SourceName |> shouldEqual "Thing" + + let actualFields = + actualType.Fields |> List.map (fun field -> field.JsonName, field) |> Map + + actualType.Fields |> List.length |> shouldEqual fields.Length + + actualType.Fields + |> List.map _.JsonName + |> Set.ofList + |> shouldEqual (fields |> List.map _.Name |> Set.ofList) + + for expected in fields do + let actualField = actualFields.[expected.Name] + actualField.Required |> shouldEqual expected.Required + + let expectedType = + OpenApiPlannedType.Primitive (expectedPrimitive expected.Scalar) + |> if expected.Required && not expected.Nullable then + id + else + OpenApiPlannedType.Optional + + actualField.Type |> shouldEqual expectedType + + let reordered = fields |> List.rev |> renderObjectDocument |> plan + reordered |> shouldEqual actual + + property + |> Prop.forAll (Arb.fromGen generatedFields) + |> Check.QuickThrowOnFailure + + for scalar in + [ + GeneratedScalar.String + GeneratedScalar.Boolean + GeneratedScalar.Int32 + GeneratedScalar.Int64 + GeneratedScalar.Float32 + GeneratedScalar.Float + GeneratedScalar.Decimal + GeneratedScalar.Date + GeneratedScalar.DateTime + GeneratedScalar.Guid + ] do + let observed = scalarCounts.GetValueOrDefault scalar + + if observed < 8 then + failwith $"Generator only exercised %A{scalar} %i{observed} times" + + if requiredCount < 80 || optionalCount < 80 || nullableCount < 30 then + failwith + $"Insufficient generated distribution: required=%i{requiredCount}, optional=%i{optionalCount}, nullable=%i{nullableCount}" + + if + noRequiredDocuments < 3 + || allRequiredDocuments < 3 + || mixedRequiredDocuments < 20 + || documentsWithNullableFields < 10 + then + failwith + $"Insufficient document distribution: none-required=%i{noRequiredDocuments}, all-required=%i{allRequiredDocuments}, mixed=%i{mixedRequiredDocuments}, nullable=%i{documentsWithNullableFields}" + + [] + let ``Operation parameters override inherited parameters by name and location`` () = + for scalar in [ GeneratedScalar.String ; GeneratedScalar.Int32 ; GeneratedScalar.Int64 ] do + for required in [ false ; true ] do + let inheritedPath = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + let inheritedQuery = + parameter "limit" "query" false (schemaForScalar GeneratedScalar.String false) + + let overridingQuery = + parameter "limit" "query" required (schemaForScalar scalar false) + + let pathItem = + standardPathItem (noContentResponse ()) [ inheritedPath ; inheritedQuery ] [ overridingQuery ] + + let actual = document "3.0.3" [] "/things/{id}" pathItem |> plan + let operation = actual.Operations |> List.exactlyOne + + operation.Parameters |> List.map _.WireName |> shouldEqual [ "id" ; "limit" ] + + let path = operation.Parameters.[0] + path.Location |> shouldEqual OpenApiParameterLocation.Path + path.Required |> shouldEqual true + path.Type |> shouldEqual (OpenApiPlannedType.Primitive OpenApiPrimitive.Int64) + + let limit = operation.Parameters.[1] + limit.Location |> shouldEqual OpenApiParameterLocation.Query + limit.Required |> shouldEqual required + + let expected = + OpenApiPlannedType.Primitive (expectedPrimitive scalar) + |> if required then id else OpenApiPlannedType.Optional + + limit.Type |> shouldEqual expected + + [] + let ``Parameters cannot shadow the generated HTTP client binding`` () = + let clientParameter = + parameter "client" "path" true (schemaForScalar GeneratedScalar.String false) + + let pathItem = standardPathItem (noContentResponse ()) [ clientParameter ] [] + let actual = document "3.0.3" [] "/things/{client}" pathItem |> plan + + let plannedParameter = + actual.Operations |> List.exactlyOne |> _.Parameters |> List.exactlyOne + + plannedParameter.WireName |> shouldEqual "client" + plannedParameter.FSharpName |> shouldEqual "client2" + + let rec private referencedTypeNames (plannedType : OpenApiPlannedType) : Set = + match plannedType with + | OpenApiPlannedType.Named name -> Set.singleton name + | OpenApiPlannedType.List inner + | OpenApiPlannedType.Optional inner -> referencedTypeNames inner + | OpenApiPlannedType.Primitive _ + | OpenApiPlannedType.JsonNode + | OpenApiPlannedType.Stream + | OpenApiPlannedType.Unit -> Set.empty + + [] + let ``Every planned named reference is bound, including self references`` () = + let mutable shortChains = 0 + let mutable longChains = 0 + + let property count = + if count <= 4 then + shortChains <- shortChains + 1 + + if count >= 9 then + longChains <- longChains + 1 + + let chain = + [ + for index in 0..count do + let properties = + if index = 0 then + [ "value", schemaForScalar GeneratedScalar.Int32 false ] + else + [ "previous", reference $"Type%i{index - 1}" ] + + let schema = + jsonObject [ "type", jsonString "object" ; "properties", jsonObject properties ] + + $"Type%i{index}", schema + ] + + let node = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "next", reference "Node" ] + ] + + let pathParameter = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + let pathItem = + standardPathItem (responseWithSchema (reference "Node")) [ pathParameter ] [] + + let actual = + document "3.0.3" (("Node", node) :: chain) "/things/{id}" pathItem |> plan + + let bound = actual.Types |> List.map _.FSharpName |> Set.ofList + + let referenced = + actual.Types + |> List.collect (fun definition -> + [ + yield! + definition.Fields + |> List.collect (fun field -> referencedTypeNames field.Type |> Set.toList) + + match definition.AdditionalProperties with + | None -> () + | Some value -> yield! referencedTypeNames value + ] + ) + |> Set.ofList + + Set.isSubset referenced bound |> shouldEqual true + + let bySource = + actual.Types + |> List.map (fun definition -> definition.SourceName, definition) + |> Map + + let positions = + actual.Types + |> List.mapi (fun index definition -> definition.FSharpName, index) + |> Map + + for index in 1..count do + let current = bySource.[$"Type%i{index}"] + let previous = bySource.[$"Type%i{index - 1}"] + let field = current.Fields |> List.exactlyOne + + field.Type + |> shouldEqual (OpenApiPlannedType.Optional (OpenApiPlannedType.Named previous.FSharpName)) + + positions.[previous.FSharpName] < positions.[current.FSharpName] + |> shouldEqual true + + let node = bySource.["Node"] + + node.Fields + |> List.exactlyOne + |> _.Type + |> shouldEqual (OpenApiPlannedType.Optional (OpenApiPlannedType.Named node.FSharpName)) + + property + |> Prop.forAll (Arb.fromGen (Gen.choose (1, 12))) + |> Check.QuickThrowOnFailure + + if shortChains < 10 || longChains < 10 then + failwith $"Insufficient chain distribution: short=%i{shortChains}, long=%i{longChains}" + + [] + let ``Mutually recursive record components fail explicitly before codec generation`` () = + let schemaA = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "b", reference "B" ] + ] + + let schemaB = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "a", reference "A" ] + ] + + let pathItem = standardPathItem (responseWithSchema (reference "A")) [] [] + + let source = document "3.0.3" [ "A", schemaA ; "B", schemaB ] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly accepted mutually recursive generated codecs" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema) + |> shouldEqual true + + [] + let ``Dangling references always produce a located diagnostic`` () = + let property (PositiveInt suffix) = + let missing = $"Missing%i{suffix}" + + let schema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "child", reference missing ] + ] + + let pathParameter = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + let pathItem = + standardPathItem (responseWithSchema (reference "Thing")) [ pathParameter ] [] + + let source = document "3.0.3" [ "Thing", schema ] "/things/{id}" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith $"Planning unexpectedly accepted dangling reference %s{missing}" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnresolvedReference + && diagnostic.Location.Contains ("/properties/child", StringComparison.Ordinal) + && diagnostic.Message.Contains (missing, StringComparison.Ordinal) + ) + |> shouldEqual true + + Check.QuickThrowOnFailure property + + [] + let ``Required properties without schemas remain required nullable JsonNode fields`` () = + let schema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [] + "required", jsonArray [ jsonString "ghost" ] + ] + + let pathParameter = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + let pathItem = + standardPathItem (responseWithSchema (reference "Thing")) [ pathParameter ] [] + + let source = document "3.0.3" [ "Thing", schema ] "/things/{id}" pathItem + + let actual = source |> plan + let thing = actual.Types |> List.exactlyOne + let ghost = thing.Fields |> List.exactlyOne + ghost.JsonName |> shouldEqual "ghost" + ghost.Required |> shouldEqual true + + ghost.Type + |> shouldEqual (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + + [] + let ``Optional nullable fields fail explicitly because their three states are not representable`` () = + let schema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "value", schemaForScalar GeneratedScalar.String true ] + ] + + let pathParameter = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + let pathItem = + standardPathItem (responseWithSchema (reference "Thing")) [ pathParameter ] [] + + let source = document "3.0.3" [ "Thing", schema ] "/things/{id}" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly conflated missing, null, and present values" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema + && diagnostic.Location.Contains ("/properties/value", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Unconstrained JSON request and response schemas preserve null as an explicit value`` () = + let unconstrained () = jsonObject [] + + let requestBody = + jsonObject + [ + "required", jsonBool true + "content", jsonObject [ "application/json", jsonObject [ "schema", unconstrained () ] ] + ] + + let pathItem = + jsonObject + [ + "post", + jsonObject + [ + "operationId", jsonString "echoAnything" + "requestBody", requestBody + "responses", jsonObject [ "200", responseWithSchema (unconstrained ()) ] + ] + ] + + let actual = document "3.0.3" [] "/anything" pathItem |> plan + let operation = actual.Operations |> List.exactlyOne + let body = operation.Parameters |> List.exactlyOne + body.Location |> shouldEqual OpenApiParameterLocation.Body + body.Required |> shouldEqual true + + body.Type + |> shouldEqual (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + + operation.ReturnType + |> shouldEqual (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + + [] + let ``Optional unconstrained properties fail because all three wire states are legal`` () = + let schema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "value", jsonObject [] ] + ] + + let pathItem = standardPathItem (responseWithSchema (reference "Thing")) [] [] + let source = document "3.0.3" [ "Thing", schema ] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly conflated a missing property with a present JSON null" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema + && diagnostic.Location.EndsWith ("/properties/value", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Unbounded and extension-formatted integers use BigInteger rather than narrowing`` () = + for format in [ None ; Some "uint64" ] do + let schema = + jsonObject + [ + "type", jsonString "integer" + match format with + | None -> () + | Some value -> "format", jsonString value + ] + + let pathItem = standardPathItem (responseWithSchema schema) [] [] + let actual = document "3.0.3" [] "/integer" pathItem |> plan + + actual.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Primitive OpenApiPrimitive.BigInteger) + + [] + let ``Unformatted and unknown-format numbers fail instead of narrowing to double`` () = + for format in [ None ; Some "arbitrary-precision" ] do + let schema = + jsonObject + [ + "type", jsonString "number" + match format with + | None -> () + | Some value -> "format", jsonString value + ] + + let pathItem = standardPathItem (responseWithSchema schema) [] [] + let source = document "3.0.3" [] "/number" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly narrowed an arbitrary JSON number to double" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema + && diagnostic.Location.EndsWith ("/format", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Nullable component schemas stay nullable through references`` () = + let maybe = + jsonObject + [ + "type", jsonString "object" + "nullable", jsonBool true + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + ] + + let holder = + jsonObject + [ + "type", jsonString "object" + "required", jsonArray [ jsonString "value" ] + "properties", jsonObject [ "value", reference "Maybe" ] + ] + + let pathItem = standardPathItem (responseWithSchema (reference "Holder")) [] [] + + let actual = + document "3.0.3" [ "Maybe", maybe ; "Holder", holder ] "/things" pathItem + |> plan + + let maybeType = + actual.Types |> List.find (fun definition -> definition.SourceName = "Maybe") + + let holderType = + actual.Types |> List.find (fun definition -> definition.SourceName = "Holder") + + let value = holderType.Fields |> List.find (fun field -> field.JsonName = "value") + + value.Type + |> shouldEqual (OpenApiPlannedType.Optional (OpenApiPlannedType.Named maybeType.FSharpName)) + + [] + let ``AllOf permits null exactly when its outer constraint and every branch permit it`` () = + let branch name nullable = + jsonObject + [ + "type", jsonString "object" + "nullable", jsonBool nullable + "properties", jsonObject [ name, schemaForScalar GeneratedScalar.String false ] + ] + + let bothNullable = + jsonObject [ "allOf", jsonArray [ branch "left" true ; branch "right" true ] ] + + let onlyOuterNullable = + jsonObject + [ + "nullable", jsonBool true + "allOf", jsonArray [ branch "left" false ; branch "right" false ] + ] + + let responseFor name schema = + let pathItem = standardPathItem (responseWithSchema (reference name)) [] [] + document "3.0.3" [ name, schema ] "/things" pathItem |> plan + + let bothPlan = responseFor "Both" bothNullable + let bothType = bothPlan.Types |> List.exactlyOne + + bothPlan.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Optional (OpenApiPlannedType.Named bothType.FSharpName)) + + let outerPlan = responseFor "Outer" onlyOuterNullable + let outerType = outerPlan.Types |> List.exactlyOne + + outerPlan.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Named outerType.FSharpName) + + [] + let ``Additional-properties modes map exhaustively to their generated value types`` () = + let cases : (string * JsonNode option * OpenApiPlannedType option) list = + [ + "omitted", None, Some (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + "allowed", Some (jsonBool true), Some (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + "forbidden", Some (jsonBool false), None + "typed", + Some (schemaForScalar GeneratedScalar.String false), + Some (OpenApiPlannedType.Primitive OpenApiPrimitive.String) + "typed-nullable", + Some (schemaForScalar GeneratedScalar.String true), + Some (OpenApiPlannedType.Optional (OpenApiPlannedType.Primitive OpenApiPrimitive.String)) + "typed-any", Some (jsonObject []), Some (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + ] + + for caseName, additionalProperties, expected in cases do + let schema = + jsonObject + [ + "type", jsonString "object" + "required", jsonArray [ jsonString "id" ] + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + match additionalProperties with + | None -> () + | Some value -> "additionalProperties", value + ] + + let pathItem = standardPathItem (responseWithSchema (reference "Thing")) [] [] + + let actual = + document "3.0.3" [ "Thing", schema ] $"/things/%s{caseName}" pathItem |> plan + + actual.Types + |> List.exactlyOne + |> _.AdditionalProperties + |> shouldEqual expected + + [] + let ``Closed empty objects fail instead of gaining a synthetic JSON field`` () = + let empty = + jsonObject [ "type", jsonString "object" ; "additionalProperties", jsonBool false ] + + let pathItem = standardPathItem (responseWithSchema (reference "Empty")) [] [] + let source = document "3.0.3" [ "Empty", empty ] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly invented a field for a closed empty object" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema) + |> shouldEqual true + + [] + let ``Required document strings reject explicit JSON null`` () = + let source = + """{"openapi":null,"info":{"title":"API","version":"1"},"paths":{},"components":{"schemas":{}}}""" + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly treated a null OpenAPI version as absent" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.InvalidDocument + && diagnostic.Location = "#/openapi" + ) + |> shouldEqual true + + [] + let ``Optional structural properties reject explicit JSON null`` () = + let source = + """{"openapi":"3.0.3","info":{"title":"API","version":"1"},"servers":null,"paths":{},"components":{"schemas":{}}}""" + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly treated a null servers array as absent" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.InvalidDocument + && diagnostic.Location = "#/servers" + ) + |> shouldEqual true + + [] + let ``Unsupported composition keywords on named objects are not bypassed by references`` () = + let schema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + "oneOf", jsonArray [ jsonObject [ "type", jsonString "object" ] ] + ] + + let pathItem = standardPathItem (responseWithSchema (reference "Thing")) [] [] + let source = document "3.0.3" [ "Thing", schema ] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly ignored oneOf on a referenced object component" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema) + |> shouldEqual true + + [] + let ``AllOf deduplication cannot hide unsupported keywords on a discarded property schema`` () = + let propertySchema includeUnsupportedKeyword = + jsonObject + [ + "type", jsonString "string" + if includeUnsupportedKeyword then + "oneOf", jsonArray [ jsonObject [ "type", jsonString "string" ] ] + ] + + let branch includeUnsupportedKeyword = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "value", propertySchema includeUnsupportedKeyword ] + ] + + let child = jsonObject [ "allOf", jsonArray [ branch false ; branch true ] ] + let pathItem = standardPathItem (responseWithSchema (reference "Child")) [] [] + let source = document "3.0.3" [ "Child", child ] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly hid oneOf on a discarded allOf property" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema + && diagnostic.Location.Contains ("/allOf/1/properties/value", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Anonymous-type cache hits still validate every nested schema occurrence`` () = + let schema includeUnsupportedKeyword = + jsonObject + [ + "type", jsonString "object" + "properties", + jsonObject + [ + "value", + jsonObject + [ + "type", jsonString "string" + if includeUnsupportedKeyword then + "oneOf", jsonArray [ jsonObject [ "type", jsonString "string" ] ] + ] + ] + ] + + let pathItem = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString "getThing" + "responses", + jsonObject + [ + "200", responseWithSchema (schema false) + "201", responseWithSchema (schema true) + ] + ] + ] + + let source = document "3.0.3" [] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly hid oneOf on a cached anonymous type" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema + && diagnostic.Location.Contains ("/responses/201", StringComparison.Ordinal) + && diagnostic.Location.EndsWith ("/properties/value", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Sanitised component and field identifiers remain unique`` () = + let collidingSchema = + jsonObject + [ + "type", jsonString "object" + "properties", + jsonObject + [ + "foo-bar", schemaForScalar GeneratedScalar.String false + "foo_bar", schemaForScalar GeneratedScalar.String false + ] + ] + + let otherSchema = + jsonObject [ "type", jsonString "object" ; "properties", jsonObject [] ] + + let pathParameter = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + let pathItem = + standardPathItem (responseWithSchema (reference "foo-bar")) [ pathParameter ] [] + + let actual = + document "3.0.3" [ "foo-bar", collidingSchema ; "foo_bar", otherSchema ] "/things/{id}" pathItem + |> plan + + let typeNames = actual.Types |> List.map _.FSharpName + typeNames |> Set.ofList |> Set.count |> shouldEqual typeNames.Length + + let fieldNames = + actual.Types + |> List.find (fun definition -> definition.SourceName = "foo-bar") + |> _.Fields + |> List.map _.FSharpName + + fieldNames |> Set.ofList |> Set.count |> shouldEqual fieldNames.Length + + [] + let ``AllOf object composition has the union of its fields`` () = + let baseSchema = + jsonObject + [ + "type", jsonString "object" + "required", jsonArray [ jsonString "id" ] + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + ] + + let extension = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "display-name", schemaForScalar GeneratedScalar.String false ] + ] + + let childSchema = jsonObject [ "allOf", jsonArray [ reference "Base" ; extension ] ] + + let pathParameter = + parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) + + let pathItem = + standardPathItem (responseWithSchema (reference "Child")) [ pathParameter ] [] + + let actual = + document "3.0.3" [ "Base", baseSchema ; "Child", childSchema ] "/things/{id}" pathItem + |> plan + + let child = + actual.Types |> List.find (fun definition -> definition.SourceName = "Child") + + child.Fields + |> List.map _.JsonName + |> Set.ofList + |> shouldEqual (Set [ "id" ; "display-name" ]) + + child.Fields + |> List.find (fun field -> field.JsonName = "id") + |> _.Required + |> shouldEqual true + + [] + let ``Equivalent inline success schemas share one planned type despite annotations and ordering`` () = + let first = + jsonObject + [ + "type", jsonString "object" + "description", jsonString "first spelling" + "required", jsonArray [ jsonString "id" ; jsonString "name" ] + "properties", + jsonObject + [ + "id", schemaForScalar GeneratedScalar.Int64 false + "name", schemaForScalar GeneratedScalar.String false + ] + ] + + let second = + jsonObject + [ + "description", jsonString "same wire shape, different annotation" + "properties", + jsonObject + [ + "name", schemaForScalar GeneratedScalar.String false + "id", schemaForScalar GeneratedScalar.Int64 false + ] + "required", jsonArray [ jsonString "name" ; jsonString "id" ] + "type", jsonString "object" + ] + + let pathItem = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString "getThing" + "responses", + jsonObject [ "200", responseWithSchema first ; "201", responseWithSchema second ] + ] + ] + + let actual = document "3.0.3" [] "/things" pathItem |> plan + actual.Types |> List.length |> shouldEqual 1 + + actual.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Named (actual.Types |> List.exactlyOne |> _.FSharpName)) + + [] + let ``Equivalent inline allOf schemas share one type across branch permutations`` () = + let baseSchema = + jsonObject + [ + "type", jsonString "object" + "required", jsonArray [ jsonString "id" ] + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + ] + + let extension = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "name", schemaForScalar GeneratedScalar.String false ] + ] + + let composed (description : string) (branches : JsonNode list) = + jsonObject + [ + "description", jsonString description + "allOf", jsonArray (branches |> List.map (fun branch -> branch.DeepClone ())) + ] + + let pathItem = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString "getThing" + "responses", + jsonObject + [ + "200", responseWithSchema (composed "first" [ baseSchema ; extension ]) + "201", responseWithSchema (composed "second" [ extension ; baseSchema ]) + ] + ] + ] + + let actual = document "3.0.3" [] "/things" pathItem |> plan + let definition = actual.Types |> List.exactlyOne + + definition.Fields + |> List.map _.JsonName + |> Set.ofList + |> shouldEqual (Set [ "id" ; "name" ]) + + actual.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Named definition.FSharpName) + + [] + let ``Direct and single-branch allOf object schemas share their flattened record type`` () = + let direct = + jsonObject + [ + "type", jsonString "object" + "required", jsonArray [ jsonString "id" ] + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + ] + + let composed = + jsonObject + [ + "description", jsonString "different syntax, same record" + "allOf", jsonArray [ direct.DeepClone () ] + ] + + let pathItem = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString "getThing" + "responses", + jsonObject [ "200", responseWithSchema direct ; "201", responseWithSchema composed ] + ] + ] + + let actual = document "3.0.3" [] "/things" pathItem |> plan + let definition = actual.Types |> List.exactlyOne + definition.Fields |> List.map _.JsonName |> shouldEqual [ "id" ] + + actual.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Named definition.FSharpName) + + [] + let ``Anonymous object deduplication keeps incompatible field types distinct`` () = + let schema scalar = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "value", schemaForScalar scalar false ] + ] + + let pathItem = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString "getThing" + "responses", + jsonObject + [ + "200", responseWithSchema (schema GeneratedScalar.String) + "201", responseWithSchema (schema GeneratedScalar.Int64) + ] + ] + ] + + let source = document "3.0.3" [] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly merged incompatible anonymous record fields" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.AmbiguousSuccessResponse + && diagnostic.Location.EndsWith ("/responses/201", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Media selection exhaustively follows supported priority and ignores insertion order`` () = + let objectSchema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + ] + + let stringSchema = schemaForScalar GeneratedScalar.String false + + let media = + [ + "application/json", objectSchema + "application/problem+json", objectSchema + "text/plain", stringSchema + "application/octet-stream", stringSchema + ] + + for selectedIndex in 0 .. media.Length - 1 do + let selectedName = fst media.[selectedIndex] + let available = media |> List.skip selectedIndex + + let makePlan (entries : (string * JsonNode) list) = + let response = + jsonObject + [ + "description", jsonString "success" + "content", + jsonObject ( + entries + |> List.map (fun (name, schema) -> name, jsonObject [ "schema", schema.DeepClone () ]) + ) + ] + + let pathItem = standardPathItem response [] [] + document "3.0.3" [] "/things" pathItem |> plan + + let forward = makePlan available + let reversed = makePlan (List.rev available) + reversed |> shouldEqual forward + + let operation = forward.Operations |> List.exactlyOne + operation.Accept |> shouldEqual (Some selectedName) + + match selectedIndex with + | 0 + | 1 -> + let definition = forward.Types |> List.exactlyOne + + operation.ReturnType + |> shouldEqual (OpenApiPlannedType.Named definition.FSharpName) + | 2 -> + operation.ReturnType + |> shouldEqual (OpenApiPlannedType.Primitive OpenApiPrimitive.String) + + forward.Types |> shouldEqual [] + | 3 -> + operation.ReturnType |> shouldEqual OpenApiPlannedType.Stream + forward.Types |> shouldEqual [] + | _ -> failwith "Unreachable media case" + + [] + let ``Incompatible successful response media produce a diagnostic at the mutated status`` () = + let response mediaType = + jsonObject + [ + "description", jsonString "success" + "content", + jsonObject + [ + mediaType, jsonObject [ "schema", schemaForScalar GeneratedScalar.String false ] + ] + ] + + let pathItem = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString "getThing" + "responses", + jsonObject [ "200", response "text/plain" ; "201", response "application/octet-stream" ] + ] + ] + + let source = document "3.0.3" [] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly accepted incompatible successful responses" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.AmbiguousSuccessResponse + && diagnostic.Location.EndsWith ("/responses/201", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Default responses constrain unspecified successful statuses unless 2XX covers them`` () = + let response mediaType = + jsonObject + [ + "description", jsonString "response" + "content", + jsonObject + [ + mediaType, jsonObject [ "schema", schemaForScalar GeneratedScalar.String false ] + ] + ] + + let makeSource responses = + let pathItem = + jsonObject + [ + "get", jsonObject [ "operationId", jsonString "getThing" ; "responses", jsonObject responses ] + ] + + document "3.0.3" [] "/things" pathItem + + let incompatible = + makeSource + [ + "200", response "text/plain" + "default", response "application/octet-stream" + ] + + match OpenApiClientGenerator.parseAndPlan config incompatible with + | Ok _ -> failwith "Planning unexpectedly ignored default for unspecified 2xx statuses" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.AmbiguousSuccessResponse + && diagnostic.Location.EndsWith ("/responses/default", StringComparison.Ordinal) + ) + |> shouldEqual true + + let rangeCovered = + makeSource + [ + "2XX", response "text/plain" + "default", response "application/octet-stream" + ] + |> plan + + rangeCovered.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Primitive OpenApiPrimitive.String) + + let defaultOnly = makeSource [ "default", response "text/plain" ] |> plan + + defaultOnly.Operations + |> List.exactlyOne + |> _.Accept + |> shouldEqual (Some "text/plain") + + [] + let ``AllOf rejects fields made impossible by another branch's additionalProperties constraint`` () = + let closed = + jsonObject + [ + "type", jsonString "object" + "additionalProperties", jsonBool false + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + ] + + let extension = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "display-name", schemaForScalar GeneratedScalar.String false ] + ] + + let child = jsonObject [ "allOf", jsonArray [ closed ; extension ] ] + let pathItem = standardPathItem (responseWithSchema (reference "Child")) [] [] + let source = document "3.0.3" [ "Child", child ] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly weakened an allOf additionalProperties constraint" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema) + |> shouldEqual true + + [] + let ``A single path-parameter mismatch mutation always produces a diagnostic`` () = + for missingParameter in [ false ; true ] do + let path, parameters = + if missingParameter then + "/things/{id}", [] + else + "/things", [ parameter "id" "path" true (schemaForScalar GeneratedScalar.Int64 false) ] + + let pathItem = standardPathItem (noContentResponse ()) parameters [] + let source = document "3.0.3" [] path pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly accepted a path/parameter mismatch" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedParameter + ) + |> shouldEqual true + + [] + let ``OpenAPI 3.1 is rejected rather than silently interpreted as 3.0`` () = + let pathItem = standardPathItem (noContentResponse ()) [] [] + let source = document "3.1.0" [] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly accepted OpenAPI 3.1" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedVersion) + |> shouldEqual true + + [] + let ``Paths beginning with multiple slashes are rejected before URI semantics can change them`` () = + let pathItem = standardPathItem (noContentResponse ()) [] [] + let source = document "3.0.3" [] "//things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly allowed the HTTP shell to reinterpret a network-path reference" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.InvalidDocument + && diagnostic.Location.Contains ("~1~1things", StringComparison.Ordinal) + ) + |> shouldEqual true diff --git a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj index 5ba1aebd..e0c118b8 100644 --- a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj +++ b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj @@ -49,6 +49,8 @@ + + diff --git a/WoofWare.Myriad.Plugins/JsonParseGenerator.fs b/WoofWare.Myriad.Plugins/JsonParseGenerator.fs index 753e6685..910e53df 100644 --- a/WoofWare.Myriad.Plugins/JsonParseGenerator.fs +++ b/WoofWare.Myriad.Plugins/JsonParseGenerator.fs @@ -464,7 +464,6 @@ module internal JsonParseGenerator = SynExpr.createLongIdent [ "System" ; "Globalization" ; "CultureInfo" ; "InvariantCulture" ] ] ) - | Measure (_measure, primType) -> parseNumberType options propertyName node primType |> SynExpr.pipeThroughFunction (Measure.getLanguagePrimitivesMeasure primType) diff --git a/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs b/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs index 2af8b74c..f2e7ce36 100644 --- a/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs +++ b/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs @@ -287,7 +287,13 @@ module internal JsonSerializeGenerator = ] |> SynExpr.createLambda "field" |> fun e -> e, false - | JsonNode -> SynExpr.createIdent "id", true + | JsonNode -> + SynExpr.createIdent "node" + |> SynExpr.typeAnnotate (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]) + |> SynExpr.paren + |> SynExpr.callMethod "DeepClone" + |> SynExpr.createLambda "node" + |> fun expr -> expr, true | UnitType -> SynExpr.createLambda "value" diff --git a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs new file mode 100644 index 00000000..b3f23fdd --- /dev/null +++ b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs @@ -0,0 +1,2158 @@ +namespace WoofWare.Myriad.Plugins + +open System +open System.Collections.Generic +open System.Text.Json +open System.Text.Json.Nodes +open System.Text.RegularExpressions +open Fantomas.FCS.Syntax +open Fantomas.FCS.Text.Range +open Fantomas.FCS.Xml +open Myriad.Core +open WoofWare.Whippet.Fantomas + +type internal OpenApiGenerationDiagnosticCode = + | InvalidJson + | InvalidDocument + | UnsupportedVersion + | UnresolvedReference + | UnsupportedSchema + | UnsupportedParameter + | UnsupportedOperation + | AmbiguousSuccessResponse + +type internal OpenApiGenerationDiagnostic = + { + Code : OpenApiGenerationDiagnosticCode + Location : string + Message : string + } + +type internal OpenApiPrimitive = + | String + | Boolean + | Int32 + | Int64 + | BigInteger + | Float32 + | Float + | Decimal + | Date + | DateTime + | Guid + +type internal OpenApiPlannedType = + | Primitive of OpenApiPrimitive + | Named of string + | List of OpenApiPlannedType + | Optional of OpenApiPlannedType + | JsonNode + | Stream + | Unit + +type internal OpenApiPlannedField = + { + JsonName : string + FSharpName : string + Type : OpenApiPlannedType + Required : bool + } + +type internal OpenApiPlannedTypeDefinition = + { + SourceName : string + FSharpName : string + Description : string option + Fields : OpenApiPlannedField list + AdditionalProperties : OpenApiPlannedType option + } + +type internal OpenApiParameterLocation = + | Path + | Query + | Body + +type internal OpenApiPlannedParameter = + { + WireName : string + FSharpName : string + Location : OpenApiParameterLocation + Type : OpenApiPlannedType + Required : bool + } + +type internal OpenApiPlannedOperation = + { + OperationId : string + FSharpName : string + Description : string option + Method : HttpMethod + Path : string + Parameters : OpenApiPlannedParameter list + ReturnType : OpenApiPlannedType + Accept : string option + RequestContentType : string option + } + +type internal OpenApiServerBase = + | BaseAddress of string + | BasePath of string + +type internal OpenApiClientPlan = + { + Namespace : string + InterfaceName : string + Description : string option + CreateMock : bool option + ServerBase : OpenApiServerBase + Types : OpenApiPlannedTypeDefinition list + Operations : OpenApiPlannedOperation list + } + +[] +module internal OpenApiClientGenerator = + + type private LocatedObject = + { + Value : JsonObject + Location : string + } + + type private AdditionalProperties = + | Any + | Forbidden + | Typed of LocatedObject + + type private ObjectShape = + { + Description : string option + Properties : Map + Required : Set + AdditionalProperties : AdditionalProperties + } + + type private ResolvedParameterLocation = + | Path + | Query + | Header + | Cookie + + type private ResolvedParameter = + { + Name : string + Location : ResolvedParameterLocation + Required : bool + Schema : LocatedObject + SourceLocation : string + } + + let private pointerToken (value : string) : string = + let value = value.Replace ("~", "~0", StringComparison.Ordinal) + value.Replace ("/", "~1", StringComparison.Ordinal) + + let private diagnostic + (code : OpenApiGenerationDiagnosticCode) + (location : string) + (message : string) + : OpenApiGenerationDiagnostic + = + { + Code = code + Location = location + Message = message + } + + let private normaliseParameters (parameters : Map) : Map = + parameters + |> Map.toSeq + |> Seq.map (fun (key, value) -> key.ToUpperInvariant (), value) + |> Map.ofSeq + + let private allocateUniqueName + (used : HashSet) + (fallback : string) + (sanitise : string -> string) + (source : string) + : string + = + let baseName = + let result = sanitise source + + if String.IsNullOrWhiteSpace result then + fallback + else + result + + let mutable suffix = 1 + let mutable candidate = baseName + + while not (used.Add candidate) do + suffix <- suffix + 1 + candidate <- $"%s{baseName}%i{suffix}" + + candidate + + let private sanitiseTypeName (value : string) : string = + (Ident.createSanitisedTypeName value).idText + + let private sanitiseParameterName (value : string) : string = + (Ident.createSanitisedParamName value).idText + + let rec private canonicalJson (node : JsonNode) : string = + if isNull node then + "null" + else + match node with + | :? JsonObject as value -> + value + |> Seq.map (fun (KeyValue (name, child)) -> + let name = JsonSerializer.Serialize name + $"%s{name}:%s{canonicalJson child}" + ) + |> Seq.sort + |> String.concat "," + |> fun contents -> "{" + contents + "}" + | :? JsonArray as value -> + value + |> Seq.map canonicalJson + |> String.concat "," + |> fun contents -> $"[%s{contents}]" + | value -> value.ToJsonString () + + /// A canonical description of the F# type shape which this generator emits for a schema. + /// OpenAPI annotations and validation constraints are intentionally absent: until the generated + /// type represents them, they cannot make two generated record definitions distinct. + let rec private schemaShapeKey (includeTopLevelNullable : bool) (node : JsonNode) : string = + let quoted (value : string) = JsonSerializer.Serialize value + + let tryNode (node : JsonObject) (name : string) = + match node.TryGetPropertyValue name with + | true, value when not (isNull value) -> Some value + | _ -> None + + let tryStringValue (node : JsonNode) = + try + Some (node.GetValue ()) + with + | :? InvalidOperationException + | :? FormatException -> None + + let tryBoolValue (node : JsonNode) = + try + Some (node.GetValue ()) + with + | :? InvalidOperationException + | :? FormatException -> None + + match node with + | :? JsonObject as value -> + match tryNode value "$ref" |> Option.bind tryStringValue with + | Some reference -> + let schemaPrefix = "#/components/schemas/" + + let reference = + if reference.StartsWith (schemaPrefix, StringComparison.Ordinal) then + reference.Substring schemaPrefix.Length + |> Uri.UnescapeDataString + |> fun value -> value.Replace ("~1", "/", StringComparison.Ordinal) + |> fun value -> value.Replace ("~0", "~", StringComparison.Ordinal) + |> fun value -> schemaPrefix + value + else + reference + + $"ref(%s{quoted reference})" + | None -> + let typeName = tryNode value "type" |> Option.bind tryStringValue + + let isObject = + typeName = Some "object" + || (typeName.IsNone + && (value.ContainsKey "properties" + || value.ContainsKey "required" + || value.ContainsKey "additionalProperties" + || value.ContainsKey "allOf")) + + let nullable = + includeTopLevelNullable + && ((tryNode value "nullable" |> Option.bind tryBoolValue = Some true) + || (typeName.IsNone && not isObject)) + + let core = + if isObject && value.ContainsKey "allOf" then + match tryNode value "allOf" with + | Some (:? JsonArray as branches) -> + branches + |> Seq.map (schemaShapeKey true) + |> Seq.sort + |> String.concat "," + |> fun branches -> $"allOf[%s{branches}]" + | Some invalid -> $"invalidAllOf(%s{canonicalJson invalid})" + | None -> "invalidAllOf(null)" + elif isObject then + let properties = + match tryNode value "properties" with + | Some (:? JsonObject as properties) -> + properties + |> Seq.map (fun (KeyValue (name, schema)) -> + let schema = if isNull schema then "json" else schemaShapeKey true schema + + $"%s{quoted name}:%s{schema}" + ) + |> Seq.sort + |> String.concat "," + | Some invalid -> $"invalid(%s{canonicalJson invalid})" + | None -> "" + + let required = + match tryNode value "required" with + | Some (:? JsonArray as required) -> + required + |> Seq.map (fun item -> + if isNull item then + "null" + else + match tryStringValue item with + | Some item -> quoted item + | None -> canonicalJson item + ) + |> Seq.distinct + |> Seq.sort + |> String.concat "," + | Some invalid -> $"invalid(%s{canonicalJson invalid})" + | None -> "" + + let additionalProperties = + match tryNode value "additionalProperties" with + | None -> "any" + | Some (:? JsonObject as schema) -> $"typed(%s{schemaShapeKey true schema})" + | Some other -> + match tryBoolValue other with + | Some true -> "any" + | Some false -> "forbidden" + | None -> $"invalid(%s{canonicalJson other})" + + $"object(properties=(%s{properties});required=[%s{required}];additional=%s{additionalProperties})" + else + match typeName with + | None -> "json" + | Some "string" -> + match tryNode value "format" |> Option.bind tryStringValue with + | Some "date" -> "date" + | Some "date-time" -> "date-time" + | Some "uuid" -> "guid" + | _ -> "string" + | Some "boolean" -> "bool" + | Some "integer" -> + match tryNode value "format" |> Option.bind tryStringValue with + | Some "int32" -> "int32" + | Some "int64" -> "int64" + | _ -> "bigint" + | Some "number" -> + match tryNode value "format" |> Option.bind tryStringValue with + | Some "float" -> "float32" + | Some "double" -> "float" + | Some "decimal" -> "decimal" + | Some format -> $"unsupported-number(%s{quoted format})" + | None -> "unsupported-number(unformatted)" + | Some "array" -> + match tryNode value "items" with + | Some items -> $"list(%s{schemaShapeKey true items})" + | None -> "list(json)" + | Some other -> $"unsupported(%s{quoted other})" + + if nullable then $"optional(%s{core})" else core + | invalid -> $"invalid(%s{canonicalJson invalid})" + + let private objectShapeKey (shape : ObjectShape) : string = + let quoted (value : string) = JsonSerializer.Serialize value + + let properties = + shape.Properties + |> Map.toSeq + |> Seq.map (fun (name, schema) -> + let schema = + match schema with + | None -> "optional(json)" + | Some schema -> schemaShapeKey true schema.Value + + $"%s{quoted name}:%s{schema}" + ) + |> String.concat "," + + let required = shape.Required |> Seq.map quoted |> String.concat "," + + let additionalProperties = + match shape.AdditionalProperties with + | AdditionalProperties.Any -> "any" + | AdditionalProperties.Forbidden -> "forbidden" + | AdditionalProperties.Typed schema -> $"typed(%s{schemaShapeKey true schema.Value})" + + $"object(properties=(%s{properties});required=[%s{required}];additional=%s{additionalProperties})" + + let private parseDocument + (parameters : Map) + (root : JsonObject) + : Result + = + let diagnostics = ResizeArray () + + let report code location message = + diagnostics.Add (diagnostic code location message) + + let tryProperty (location : string) (node : JsonObject) (name : string) : JsonNode option = + let propertyLocation = $"%s{location}/%s{pointerToken name}" + + match node.TryGetPropertyValue name with + | false, _ -> None + | true, value when isNull value -> + report InvalidDocument propertyLocation "An optional property cannot be null." + None + | true, value -> Some value + + let tryString (location : string) (node : JsonNode) : string option = + try + Some (node.GetValue ()) + with + | :? InvalidOperationException + | :? FormatException -> + report InvalidDocument location "Expected a JSON string." + None + + let optionalString (location : string) (node : JsonObject) (name : string) : string option = + tryProperty location node name + |> Option.bind (tryString ($"%s{location}/%s{pointerToken name}")) + + let requiredString (location : string) (node : JsonObject) (name : string) : string option = + let propertyLocation = $"%s{location}/%s{pointerToken name}" + + match node.TryGetPropertyValue name with + | false, _ -> + report InvalidDocument propertyLocation "A required string property is missing." + None + | true, value when isNull value -> + report InvalidDocument propertyLocation "A required string property cannot be null." + None + | true, value -> tryString propertyLocation value + + let tryBool (location : string) (node : JsonNode) : bool option = + try + Some (node.GetValue ()) + with + | :? InvalidOperationException + | :? FormatException -> + report InvalidDocument location "Expected a JSON boolean." + None + + let optionalBool (location : string) (node : JsonObject) (name : string) : bool option = + tryProperty location node name + |> Option.bind (tryBool ($"%s{location}/%s{pointerToken name}")) + + let tryObject (location : string) (node : JsonNode) : LocatedObject option = + match node with + | :? JsonObject as value -> + { + Value = value + Location = location + } + |> Some + | _ -> + report InvalidDocument location "Expected a JSON object." + None + + let optionalObject (location : string) (node : JsonObject) (name : string) : LocatedObject option = + tryProperty location node name + |> Option.bind (tryObject ($"%s{location}/%s{pointerToken name}")) + + let tryArray (location : string) (node : JsonNode) : JsonArray option = + match node with + | :? JsonArray as value -> Some value + | _ -> + report InvalidDocument location "Expected a JSON array." + None + + let optionalArray (location : string) (node : JsonObject) (name : string) : JsonArray option = + tryProperty location node name + |> Option.bind (tryArray ($"%s{location}/%s{pointerToken name}")) + + let objectMap (location : string) (node : JsonObject) : Map = + node + |> Seq.choose (fun (KeyValue (name, value)) -> + tryObject ($"%s{location}/%s{pointerToken name}") value + |> Option.map (fun value -> name, value) + ) + |> Map.ofSeq + + let componentMap (components : LocatedObject option) (name : string) : Map = + match + components + |> Option.bind (fun value -> optionalObject value.Location value.Value name) + with + | None -> Map.empty + | Some values -> objectMap values.Location values.Value + + let decodePointerToken + (code : OpenApiGenerationDiagnosticCode) + (location : string) + (value : string) + : string option + = + let value = Uri.UnescapeDataString value + + if Regex.IsMatch (value, "~(?:[^01]|$)") then + report code location $"Reference token '%s{value}' contains an invalid JSON Pointer escape." + None + else + let value = value.Replace ("~1", "/", StringComparison.Ordinal) + value.Replace ("~0", "~", StringComparison.Ordinal) |> Some + + let referenceName + (code : OpenApiGenerationDiagnosticCode) + (expectedPrefix : string) + (referenceLocation : string) + (reference : string) + : string option + = + if reference.StartsWith (expectedPrefix, StringComparison.Ordinal) then + reference.Substring expectedPrefix.Length + |> decodePointerToken code referenceLocation + else + report + code + referenceLocation + $"Only local references below '%s{expectedPrefix}' are supported; got '%s{reference}'." + + None + + let version = requiredString "#" root "openapi" + + match version with + | Some value -> + let parts = value.Split '.' + + if parts.Length < 2 || parts.[0] <> "3" || parts.[1] <> "0" then + report UnsupportedVersion "#/openapi" $"Expected an OpenAPI 3.0.x document, but got '%s{value}'." + | None -> () + + let parameters = normaliseParameters parameters + + let className = + match Map.tryFind "CLASSNAME" parameters with + | Some value when not (String.IsNullOrWhiteSpace value) -> value + | _ -> + report InvalidDocument "#/$parameters/ClassName" "The ClassName Myriad parameter is required." + "GeneratedClient" + + if sanitiseTypeName className <> className then + report + InvalidDocument + "#/$parameters/ClassName" + "ClassName must already be a valid PascalCase F# identifier." + + let createMock = + match Map.tryFind "GENERATEMOCKVISIBILITY" parameters with + | None -> None + | Some value -> + match value.ToLowerInvariant () with + | "internal" -> Some true + | "public" -> Some false + | _ -> + report + InvalidDocument + "#/$parameters/GenerateMockVisibility" + "GenerateMockVisibility must be 'internal' or 'public'." + + None + + let info = optionalObject "#" root "info" + + let description = + info + |> Option.bind (fun value -> optionalString value.Location value.Value "description") + + match info with + | None -> report InvalidDocument "#/info" "The OpenAPI info object is required." + | Some value -> requiredString value.Location value.Value "title" |> ignore + + let components = optionalObject "#" root "components" + let schemaComponents = componentMap components "schemas" + let parameterComponents = componentMap components "parameters" + let requestBodyComponents = componentMap components "requestBodies" + let responseComponents = componentMap components "responses" + + let rawReference (schema : LocatedObject) : (string * string) option = + optionalString schema.Location schema.Value "$ref" + |> Option.map (fun value -> $"%s{schema.Location}/$ref", value) + + let rec isObjectLike (visited : Set) (schema : LocatedObject) : bool = + match rawReference schema with + | Some (location, reference) -> + match referenceName UnsupportedSchema "#/components/schemas/" location reference with + | None -> false + | Some name when Set.contains name visited -> false + | Some name -> + match Map.tryFind name schemaComponents with + | None -> false + | Some target -> isObjectLike (Set.add name visited) target + | None -> + match optionalString schema.Location schema.Value "type" with + | Some "object" -> true + | Some _ -> false + | None -> + schema.Value.ContainsKey "allOf" + || schema.Value.ContainsKey "properties" + || schema.Value.ContainsKey "required" + || schema.Value.ContainsKey "additionalProperties" + + let usedTypeNames = HashSet (StringComparer.Ordinal) + usedTypeNames.Add ("I" + className) |> ignore + + for generatedAttributeName in + [ + "GenerateMockAttribute" + "HttpClientAttribute" + "JsonParseAttribute" + "JsonSerializeAttribute" + ] do + usedTypeNames.Add generatedAttributeName |> ignore + + let objectComponentNames = + schemaComponents + |> Map.toList + |> List.choose (fun (name, schema) -> if isObjectLike Set.empty schema then Some name else None) + + let componentTypeNames = + objectComponentNames + |> List.map (fun sourceName -> + let fsharpName = + allocateUniqueName usedTypeNames "GeneratedType" sanitiseTypeName sourceName + + sourceName, fsharpName + ) + |> Map.ofList + + let definitions = ResizeArray () + + let liftedObjectTypes = + System.Collections.Generic.Dictionary (StringComparer.Ordinal) + + let rec schemaNullableInner (visited : Set) (schema : LocatedObject) : bool = + match rawReference schema with + | Some (location, reference) -> + match referenceName UnresolvedReference "#/components/schemas/" location reference with + | None -> false + | Some name when Set.contains name visited -> false + | Some name -> + match Map.tryFind name schemaComponents with + | None -> false + | Some target -> schemaNullableInner (Set.add name visited) target + | None -> + optionalBool schema.Location schema.Value "nullable" + |> Option.defaultValue false + + let schemaNullable (schema : LocatedObject) : bool = schemaNullableInner Set.empty schema + + let rec schemaAllowsNullInner (visited : Set) (schema : LocatedObject) : bool = + match rawReference schema with + | Some (location, reference) -> + match referenceName UnresolvedReference "#/components/schemas/" location reference with + | None -> false + | Some name when Set.contains name visited -> false + | Some name -> + match Map.tryFind name schemaComponents with + | None -> false + | Some target -> schemaAllowsNullInner (Set.add name visited) target + | None -> + match optionalArray schema.Location schema.Value "allOf" with + | Some branches -> + let outerAllowsNull = + match optionalString schema.Location schema.Value "type" with + | None -> true + | Some _ -> schemaNullable schema + + let branchNullability = + branches + |> Seq.mapi (fun index branch -> + tryObject ($"%s{schema.Location}/allOf/%i{index}") branch + |> Option.map (schemaAllowsNullInner visited) + ) + |> Seq.toList + + outerAllowsNull + && branchNullability.Length = branches.Count + && (branchNullability |> List.forall (Option.defaultValue false)) + | None -> + if not (schema.Value.ContainsKey "type") && not (isObjectLike Set.empty schema) then + // An unconstrained OpenAPI 3.0 Schema Object accepts every JSON value, including null. + true + else + schemaNullable schema + + let schemaAllowsNull (schema : LocatedObject) : bool = schemaAllowsNullInner Set.empty schema + + let reportedUnsupportedSchemaKeywords = HashSet (StringComparer.Ordinal) + + let validateSchemaKeywords (schema : LocatedObject) = + let unsupportedKeywords = + [ "oneOf" ; "anyOf" ; "not" ; "discriminator" ] + |> List.filter schema.Value.ContainsKey + + if not unsupportedKeywords.IsEmpty then + let keywordKey = String.concat "," unsupportedKeywords + let reportKey = $"%s{schema.Location}|%s{keywordKey}" + + if reportedUnsupportedSchemaKeywords.Add reportKey then + let unsupportedKeywords = String.concat ", " unsupportedKeywords + + report + UnsupportedSchema + schema.Location + $"Unsupported shape-changing schema keyword(s): %s{unsupportedKeywords}." + + match + optionalBool schema.Location schema.Value "readOnly", + optionalBool schema.Location schema.Value "writeOnly" + with + | Some true, _ + | _, Some true -> + let reportKey = $"%s{schema.Location}|readOnly/writeOnly" + + if reportedUnsupportedSchemaKeywords.Add reportKey then + report + UnsupportedSchema + schema.Location + "readOnly/writeOnly schemas require separate request and response projections." + | _ -> () + + let hasObjectKeywords = + schema.Value.ContainsKey "properties" + || schema.Value.ContainsKey "required" + || schema.Value.ContainsKey "additionalProperties" + || schema.Value.ContainsKey "allOf" + + match optionalString schema.Location schema.Value "type" with + | Some value when value <> "object" && hasObjectKeywords -> + let reportKey = $"%s{schema.Location}|contradictory-type" + + if reportedUnsupportedSchemaKeywords.Add reportKey then + report + UnsupportedSchema + ($"%s{schema.Location}/type") + $"Schema type '%s{value}' contradicts its object-shape keywords." + | _ -> () + + let validatedSchemaLocations = HashSet (StringComparer.Ordinal) + + let rec validateSchemaTree (schema : LocatedObject) = + if validatedSchemaLocations.Add schema.Location then + match rawReference schema with + | Some _ -> () + | None -> + validateSchemaKeywords schema + optionalString schema.Location schema.Value "format" |> ignore + optionalString schema.Location schema.Value "description" |> ignore + optionalBool schema.Location schema.Value "nullable" |> ignore + + match optionalObject schema.Location schema.Value "properties" with + | None -> () + | Some properties -> + for KeyValue (name, value) in properties.Value do + tryObject ($"%s{properties.Location}/%s{pointerToken name}") value + |> Option.iter validateSchemaTree + + match optionalArray schema.Location schema.Value "required" with + | None -> () + | Some required -> + required + |> Seq.iteri (fun index value -> + tryString ($"%s{schema.Location}/required/%i{index}") value |> ignore + ) + + match optionalObject schema.Location schema.Value "items" with + | None -> () + | Some items -> validateSchemaTree items + + match tryProperty schema.Location schema.Value "additionalProperties" with + | None -> () + | Some (:? JsonObject as value) -> + validateSchemaTree + { + Value = value + Location = $"%s{schema.Location}/additionalProperties" + } + | Some value -> tryBool ($"%s{schema.Location}/additionalProperties") value |> ignore + + match optionalArray schema.Location schema.Value "allOf" with + | None -> () + | Some branches -> + branches + |> Seq.iteri (fun index value -> + tryObject ($"%s{schema.Location}/allOf/%i{index}") value + |> Option.iter validateSchemaTree + ) + + for KeyValue (_, schema) in schemaComponents do + validateSchemaTree schema + + let rec typeForSchema + (aliasStack : Set) + (suggestedName : string) + (schema : LocatedObject) + : OpenApiPlannedType + = + validateSchemaTree schema + + match rawReference schema with + | Some (location, reference) -> + match referenceName UnresolvedReference "#/components/schemas/" location reference with + | None -> OpenApiPlannedType.JsonNode + | Some name -> + match Map.tryFind name schemaComponents with + | None -> + report UnresolvedReference location $"Schema component '%s{name}' does not exist." + OpenApiPlannedType.JsonNode + | Some target -> + match Map.tryFind name componentTypeNames with + | Some typeName -> + let result = OpenApiPlannedType.Named typeName + + if schemaAllowsNull target then + OpenApiPlannedType.Optional result + else + result + | None when Set.contains name aliasStack -> + report + UnsupportedSchema + location + $"Non-object schema reference cycle involving '%s{name}' is unsupported." + + OpenApiPlannedType.JsonNode + | None -> typeForSchema (Set.add name aliasStack) suggestedName target + | None -> + validateSchemaKeywords schema + + let baseType = + if isObjectLike Set.empty schema then + liftObject suggestedName schema + else + match optionalString schema.Location schema.Value "type" with + | None -> OpenApiPlannedType.JsonNode + | Some "string" -> + match optionalString schema.Location schema.Value "format" with + | Some "date" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Date + | Some "date-time" -> OpenApiPlannedType.Primitive OpenApiPrimitive.DateTime + | Some "uuid" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Guid + | _ -> OpenApiPlannedType.Primitive OpenApiPrimitive.String + | Some "boolean" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Boolean + | Some "integer" -> + match optionalString schema.Location schema.Value "format" with + | Some "int32" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Int32 + | Some "int64" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Int64 + | _ -> OpenApiPlannedType.Primitive OpenApiPrimitive.BigInteger + | Some "number" -> + match optionalString schema.Location schema.Value "format" with + | Some "float" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Float32 + | Some "double" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Float + | Some "decimal" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Decimal + | format -> + report + UnsupportedSchema + ($"%s{schema.Location}/format") + (match format with + | None -> "Unformatted JSON numbers have no lossless built-in F# representation." + | Some format -> + $"Number format '%s{format}' has no lossless built-in F# representation.") + + OpenApiPlannedType.JsonNode + | Some "array" -> + match optionalObject schema.Location schema.Value "items" with + | None -> + report + UnsupportedSchema + ($"%s{schema.Location}/items") + "Array schemas must specify items." + + OpenApiPlannedType.List OpenApiPlannedType.JsonNode + | Some items -> + typeForSchema aliasStack ($"%s{suggestedName}Item") items + |> OpenApiPlannedType.List + | Some value -> + report + UnsupportedSchema + ($"%s{schema.Location}/type") + $"Schema type '%s{value}' is unsupported." + + OpenApiPlannedType.JsonNode + + if schemaAllowsNull schema then + OpenApiPlannedType.Optional baseType + else + baseType + + and liftObject (suggestedName : string) (schema : LocatedObject) : OpenApiPlannedType = + // Planning every occurrence preserves diagnostics even when its emitted definition is shared. + let shape = collectObjectShape Set.empty schema + // Nullability and annotations wrap or document each use; the flattened record shape is shared. + let key = objectShapeKey shape + + match liftedObjectTypes.TryGetValue key with + | true, typeName -> OpenApiPlannedType.Named typeName + | false, _ -> + let typeName = + allocateUniqueName usedTypeNames "AnonymousType" sanitiseTypeName suggestedName + + liftedObjectTypes.Add (key, typeName) + buildDefinition suggestedName schema.Location typeName shape |> definitions.Add + OpenApiPlannedType.Named typeName + + and buildDefinition + (sourceName : string) + (sourceLocation : string) + (typeName : string) + (shape : ObjectShape) + : OpenApiPlannedTypeDefinition + = + let allProperties = + (shape.Properties, shape.Required) + ||> Set.fold (fun properties requiredName -> + if Map.containsKey requiredName properties then + properties + else + Map.add requiredName None properties + ) + + if + allProperties.IsEmpty + && shape.AdditionalProperties = AdditionalProperties.Forbidden + then + report + UnsupportedSchema + sourceLocation + "A closed object with no properties has no faithful non-null F# record representation." + + let usedFieldNames = HashSet (StringComparer.Ordinal) + + if shape.AdditionalProperties <> AdditionalProperties.Forbidden then + usedFieldNames.Add "AdditionalProperties" |> ignore + + let fields = + allProperties + |> Map.toList + |> List.map (fun (jsonName, propertySchema) -> + let required = Set.contains jsonName shape.Required + + let fsharpName = allocateUniqueName usedFieldNames "Field" sanitiseTypeName jsonName + + let fieldType = + match propertySchema with + | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode + | Some propertySchema -> + let allowsNull = schemaAllowsNull propertySchema + + if allowsNull && not required then + report + UnsupportedSchema + propertySchema.Location + "An optional property whose schema allows null has three wire states (missing, null, value), which this generated API does not conflate." + + let result = typeForSchema Set.empty ($"%s{typeName}%s{fsharpName}") propertySchema + + if required || allowsNull then + result + else + OpenApiPlannedType.Optional result + + { + JsonName = jsonName + FSharpName = fsharpName + Type = fieldType + Required = required + } + ) + + let additionalProperties = + match shape.AdditionalProperties with + | AdditionalProperties.Forbidden -> None + | AdditionalProperties.Any -> Some (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + | AdditionalProperties.Typed schema -> + typeForSchema Set.empty ($"%s{typeName}AdditionalProperty") schema |> Some + + { + SourceName = sourceName + FSharpName = typeName + Description = shape.Description + Fields = fields + AdditionalProperties = additionalProperties + } + + and collectObjectShape (compositionStack : Set) (schema : LocatedObject) : ObjectShape = + match rawReference schema with + | Some (location, reference) -> + match referenceName UnresolvedReference "#/components/schemas/" location reference with + | None -> emptyObjectShape None + | Some name when Set.contains name compositionStack -> + report UnsupportedSchema location $"Object composition cycle involving '%s{name}' is unsupported." + emptyObjectShape None + | Some name -> + match Map.tryFind name schemaComponents with + | None -> + report UnresolvedReference location $"Schema component '%s{name}' does not exist." + emptyObjectShape None + | Some target -> collectObjectShape (Set.add name compositionStack) target + | None -> + validateSchemaKeywords schema + + match optionalArray schema.Location schema.Value "allOf" with + | Some branches -> + let shapes = + branches + |> Seq.mapi (fun index node -> + tryObject ($"%s{schema.Location}/allOf/%i{index}") node + |> Option.map (fun branch -> + if not (isObjectLike Set.empty branch) then + report + UnsupportedSchema + branch.Location + "Only object-shaped allOf branches can be represented as an F# record." + + collectObjectShape compositionStack branch + ) + ) + |> Seq.choose id + |> Seq.toList + + if + schema.Value.ContainsKey "properties" + || schema.Value.ContainsKey "required" + || schema.Value.ContainsKey "additionalProperties" + then + report + UnsupportedSchema + schema.Location + "An allOf schema with sibling object-shape keywords is not currently supported." + + let merge (left : ObjectShape) (right : ObjectShape) : ObjectShape = + let ensureNoForbiddenIntroductions (constrained : ObjectShape) (other : ObjectShape) = + match constrained.AdditionalProperties with + | AdditionalProperties.Any -> () + | AdditionalProperties.Forbidden + | AdditionalProperties.Typed _ -> + let introduced = + Set.difference + (other.Properties |> Map.toSeq |> Seq.map fst |> Set.ofSeq) + (constrained.Properties |> Map.toSeq |> Seq.map fst |> Set.ofSeq) + + if not introduced.IsEmpty then + report + UnsupportedSchema + schema.Location + "allOf cannot merge fields introduced outside a branch with constrained additionalProperties." + + ensureNoForbiddenIntroductions left right + ensureNoForbiddenIntroductions right left + + let properties = + (left.Properties, right.Properties) + ||> Map.fold (fun current name schema -> + match Map.tryFind name current, schema with + | None, _ -> Map.add name schema current + | Some None, Some value -> Map.add name (Some value) current + | Some None, None -> current + | Some (Some _), None -> current + | Some (Some existing), Some value -> + if schemaShapeKey true existing.Value <> schemaShapeKey true value.Value then + report + UnsupportedSchema + value.Location + $"allOf gives property '%s{name}' incompatible schemas." + + current + ) + + let additionalProperties = + match left.AdditionalProperties, right.AdditionalProperties with + | AdditionalProperties.Any, value + | value, AdditionalProperties.Any -> value + | AdditionalProperties.Forbidden, AdditionalProperties.Forbidden -> + AdditionalProperties.Forbidden + | AdditionalProperties.Typed left, AdditionalProperties.Typed right when + schemaShapeKey true left.Value = schemaShapeKey true right.Value + -> + AdditionalProperties.Typed left + | _ -> + report + UnsupportedSchema + schema.Location + "allOf branches have incompatible additionalProperties constraints." + + AdditionalProperties.Forbidden + + { + Description = None + Properties = properties + Required = Set.union left.Required right.Required + AdditionalProperties = additionalProperties + } + + let description = optionalString schema.Location schema.Value "description" + + match shapes with + | [] -> emptyObjectShape description + | head :: tail -> + { List.fold merge head tail with + Description = description + } + | None -> + let properties = + match optionalObject schema.Location schema.Value "properties" with + | None -> Map.empty + | Some properties -> + properties.Value + |> Seq.choose (fun (KeyValue (name, value)) -> + tryObject ($"%s{properties.Location}/%s{pointerToken name}") value + |> Option.map (fun value -> name, Some value) + ) + |> Map.ofSeq + + let required = + match optionalArray schema.Location schema.Value "required" with + | None -> Set.empty + | Some values -> + values + |> Seq.mapi (fun index value -> tryString ($"%s{schema.Location}/required/%i{index}") value) + |> Seq.choose id + |> Set.ofSeq + + let additionalProperties = + match tryProperty schema.Location schema.Value "additionalProperties" with + | None -> AdditionalProperties.Any + | Some (:? JsonObject as value) -> + AdditionalProperties.Typed + { + Value = value + Location = $"%s{schema.Location}/additionalProperties" + } + | Some value -> + match tryBool ($"%s{schema.Location}/additionalProperties") value with + | Some true -> AdditionalProperties.Any + | Some false -> AdditionalProperties.Forbidden + | None -> AdditionalProperties.Any + + { + Description = optionalString schema.Location schema.Value "description" + Properties = properties + Required = required + AdditionalProperties = additionalProperties + } + + and emptyObjectShape (description : string option) : ObjectShape = + { + Description = description + Properties = Map.empty + Required = Set.empty + AdditionalProperties = AdditionalProperties.Any + } + + for sourceName in objectComponentNames do + let schema = schemaComponents.[sourceName] + let shape = collectObjectShape (Set.singleton sourceName) schema + let typeName = componentTypeNames.[sourceName] + buildDefinition sourceName schema.Location typeName shape |> definitions.Add + + let rec resolveComponentReference + (diagnosticCode : OpenApiGenerationDiagnosticCode) + (prefix : string) + (components : Map) + (visited : Set) + (value : LocatedObject) + : LocatedObject option + = + match rawReference value with + | None -> Some value + | Some (location, reference) -> + match referenceName diagnosticCode prefix location reference with + | None -> None + | Some name when Set.contains name visited -> + report diagnosticCode location $"Reference cycle involving '%s{name}' is unsupported here." + None + | Some name -> + match Map.tryFind name components with + | None -> + report diagnosticCode location $"Component '%s{name}' does not exist." + None + | Some target -> + resolveComponentReference diagnosticCode prefix components (Set.add name visited) target + + let parseParameter (value : LocatedObject) : ResolvedParameter option = + resolveComponentReference UnresolvedReference "#/components/parameters/" parameterComponents Set.empty value + |> Option.bind (fun value -> + let name = requiredString value.Location value.Value "name" + + let location = + requiredString value.Location value.Value "in" + |> Option.bind (fun location -> + match location with + | "path" -> Some ResolvedParameterLocation.Path + | "query" -> Some ResolvedParameterLocation.Query + | "header" -> Some ResolvedParameterLocation.Header + | "cookie" -> Some ResolvedParameterLocation.Cookie + | other -> + report + UnsupportedParameter + ($"%s{value.Location}/in") + $"Parameter location '%s{other}' is unsupported." + + None + ) + + let schema = optionalObject value.Location value.Value "schema" + let hasSchema = value.Value.ContainsKey "schema" + let hasContent = value.Value.ContainsKey "content" + + if hasContent then + report + UnsupportedParameter + ($"%s{value.Location}/content") + "Content-based parameters are not supported." + + if not hasSchema && not hasContent then + report InvalidDocument value.Location "A parameter must contain exactly one of schema or content." + + if hasSchema && schema.IsNone then + report + InvalidDocument + ($"%s{value.Location}/schema") + "A parameter schema must be a non-null JSON object." + + match name, location, schema with + | Some name, Some location, Some schema -> + let required = + optionalBool value.Location value.Value "required" |> Option.defaultValue false + + match location with + | ResolvedParameterLocation.Path when not required -> + report UnsupportedParameter value.Location "Path parameters must specify required: true." + | ResolvedParameterLocation.Query when not (Regex.IsMatch (name, "^[A-Za-z0-9._~-]+$")) -> + report + UnsupportedParameter + ($"%s{value.Location}/name") + "Query parameter names must contain only RFC 3986 unreserved characters." + | ResolvedParameterLocation.Header + | ResolvedParameterLocation.Cookie -> + report + UnsupportedParameter + value.Location + "Header and cookie parameters are not representable by the generated HTTP client." + | _ -> () + + let expectedStyle = + match location with + | ResolvedParameterLocation.Path -> Some "simple" + | ResolvedParameterLocation.Query -> Some "form" + | _ -> None + + match expectedStyle, optionalString value.Location value.Value "style" with + | Some expected, Some actual when actual <> expected -> + report + UnsupportedParameter + ($"%s{value.Location}/style") + $"Only the default '%s{expected}' parameter style is supported." + | _ -> () + + match optionalBool value.Location value.Value "allowReserved" with + | Some true -> + report + UnsupportedParameter + ($"%s{value.Location}/allowReserved") + "allowReserved parameters require a different URI-escaping strategy." + | _ -> () + + { + Name = name + Location = location + Required = required + Schema = schema + SourceLocation = value.Location + } + |> Some + | _ -> None + ) + + let parseParameterList (owner : LocatedObject) : ResolvedParameter list = + match optionalArray owner.Location owner.Value "parameters" with + | None -> [] + | Some values -> + let parsed = + values + |> Seq.mapi (fun index value -> + tryObject ($"%s{owner.Location}/parameters/%i{index}") value + |> Option.bind parseParameter + ) + |> Seq.choose id + |> Seq.toList + + parsed + |> List.groupBy (fun parameter -> parameter.Name, parameter.Location) + |> List.iter (fun ((name, _), values) -> + if values.Length > 1 then + report + InvalidDocument + owner.Location + $"Parameter '%s{name}' is duplicated at the same location." + ) + + parsed + + let mergeParameters + (inherited : ResolvedParameter list) + (operation : ResolvedParameter list) + : ResolvedParameter list + = + let overrides = + operation + |> List.map (fun parameter -> (parameter.Name, parameter.Location), parameter) + |> Map + + [ + for parameter in inherited do + match Map.tryFind (parameter.Name, parameter.Location) overrides with + | Some replacement -> yield replacement + | None -> yield parameter + + let inheritedKeys = + inherited + |> List.map (fun parameter -> parameter.Name, parameter.Location) + |> Set + + for parameter in operation do + if not (Set.contains (parameter.Name, parameter.Location) inheritedKeys) then + yield parameter + ] + + let selectMedia (purpose : string) (content : LocatedObject) : (string * LocatedObject option) option = + let rank (name : string) = + if name.Equals ("application/json", StringComparison.OrdinalIgnoreCase) then + 0 + elif name.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) then + 1 + elif name.Equals ("text/plain", StringComparison.OrdinalIgnoreCase) then + 2 + elif name.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) then + 3 + else + 100 + + let candidates = + content.Value + |> Seq.choose (fun (KeyValue (name, node)) -> + let rank = rank name + + if rank = 100 then + None + else + tryObject ($"%s{content.Location}/%s{pointerToken name}") node + |> Option.map (fun media -> rank, name, media) + ) + |> Seq.sortBy (fun (rank, name, _) -> rank, name) + |> Seq.toList + + match candidates with + | [] -> + report UnsupportedOperation content.Location $"No supported media type was found for %s{purpose}." + None + | (_, selectedName, selected) :: _ -> + let selectedSchema = optionalObject selected.Location selected.Value "schema" + Some (selectedName, selectedSchema) + + let rec isJsonStringType (plannedType : OpenApiPlannedType) : bool = + match plannedType with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> true + | OpenApiPlannedType.Optional inner -> isJsonStringType inner + | _ -> false + + let isJsonMediaType (mediaType : string) : bool = + mediaType.Equals ("application/json", StringComparison.OrdinalIgnoreCase) + || mediaType.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) + + let responseShape (operationName : string) (value : LocatedObject) : OpenApiPlannedType * string option = + let value = + resolveComponentReference + UnresolvedReference + "#/components/responses/" + responseComponents + Set.empty + value + + match value with + | None -> OpenApiPlannedType.JsonNode, None + | Some value -> + match optionalObject value.Location value.Value "content" with + | None -> OpenApiPlannedType.Unit, None + | Some content when content.Value.Count = 0 -> OpenApiPlannedType.Unit, None + | Some content -> + match selectMedia "a response" content with + | None -> OpenApiPlannedType.JsonNode, None + | Some (mediaType, schema) -> + let result = + if mediaType.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) then + match schema with + | None -> () + | Some schema -> + match typeForSchema Set.empty ($"%s{operationName}BinaryResponse") schema with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () + | _ -> + report + UnsupportedOperation + schema.Location + "application/octet-stream responses require a non-null string/binary schema." + + OpenApiPlannedType.Stream + elif mediaType.Equals ("text/plain", StringComparison.OrdinalIgnoreCase) then + match schema with + | None -> () + | Some schema -> + match typeForSchema Set.empty ($"%s{operationName}TextResponse") schema with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () + | _ -> + report + UnsupportedOperation + schema.Location + "text/plain responses require a non-null string schema." + + OpenApiPlannedType.Primitive OpenApiPrimitive.String + else + match schema with + | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode + | Some schema -> typeForSchema Set.empty ($"%s{operationName}Response") schema + + if isJsonMediaType mediaType && isJsonStringType result then + report + UnsupportedOperation + content.Location + "JSON string responses need JSON unquoting, which the generated HTTP shell cannot distinguish from text/plain." + + result, Some mediaType + + let successfulResponses (operationName : string) (responses : LocatedObject) = + let declaredSuccesses = + responses.Value + |> Seq.choose (fun (KeyValue (status, node)) -> + let successful = + if status.Equals ("2XX", StringComparison.OrdinalIgnoreCase) then + true + else + match Int32.TryParse status with + | true, value -> 200 <= value && value < 300 + | false, _ -> false + + if successful then + tryObject ($"%s{responses.Location}/%s{pointerToken status}") node + |> Option.map (fun response -> status, response) + else + None + ) + |> Seq.sortBy fst + |> Seq.toList + + let rangeCoversEverySuccess = + declaredSuccesses + |> List.exists (fun (status, _) -> status.Equals ("2XX", StringComparison.OrdinalIgnoreCase)) + + let candidates = + if rangeCoversEverySuccess then + declaredSuccesses + else + match responses.Value.TryGetPropertyValue "default" with + | false, _ -> declaredSuccesses + | true, value -> + match tryObject ($"%s{responses.Location}/default") value with + | None -> declaredSuccesses + | Some response -> declaredSuccesses @ [ "default", response ] + + match candidates with + | [] -> + report + AmbiguousSuccessResponse + responses.Location + "At least one exact 2xx, 2XX, or default response is required to describe success." + + OpenApiPlannedType.Unit, None + | (_, first) :: rest -> + let firstShape = responseShape operationName first + + for status, response in rest do + let otherShape = responseShape operationName response + + if otherShape <> firstShape then + report + AmbiguousSuccessResponse + ($"%s{responses.Location}/%s{pointerToken status}") + "All possible successful responses must have the same body type and media type." + + firstShape + + let requestBodyParameter + (operationName : string) + (operation : LocatedObject) + : (OpenApiPlannedParameter * string) option + = + match optionalObject operation.Location operation.Value "requestBody" with + | None -> None + | Some body -> + let body = + resolveComponentReference + UnresolvedReference + "#/components/requestBodies/" + requestBodyComponents + Set.empty + body + + body + |> Option.bind (fun body -> + let required = + optionalBool body.Location body.Value "required" |> Option.defaultValue false + + if not required then + report + UnsupportedOperation + body.Location + "Optional request bodies cannot be represented without conflating omission and JSON null." + + match optionalObject body.Location body.Value "content" with + | None -> + report InvalidDocument ($"%s{body.Location}/content") "Request bodies require content." + None + | Some content -> + selectMedia "a request body" content + |> Option.map (fun (mediaType, schema) -> + let plannedType = + if + mediaType.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) + then + OpenApiPlannedType.Stream + elif mediaType.Equals ("text/plain", StringComparison.OrdinalIgnoreCase) then + match schema with + | None -> () + | Some schema -> + match typeForSchema Set.empty ($"%s{operationName}TextRequest") schema with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () + | _ -> + report + UnsupportedOperation + schema.Location + "text/plain request bodies require a non-null string schema." + + OpenApiPlannedType.Primitive OpenApiPrimitive.String + else + match schema with + | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode + | Some schema -> typeForSchema Set.empty ($"%s{operationName}Request") schema + + if mediaType.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) then + report + UnsupportedOperation + content.Location + "Binary request content types are not emitted correctly by the generated HTTP shell." + + if isJsonMediaType mediaType && isJsonStringType plannedType then + report + UnsupportedOperation + content.Location + "JSON string request bodies need JSON quoting, which the generated HTTP shell cannot distinguish from text/plain." + + { + WireName = "body" + FSharpName = "body" + Location = OpenApiParameterLocation.Body + Type = plannedType + Required = required + }, + mediaType + ) + ) + + let parseServerBase () : OpenApiServerBase = + match optionalArray "#" root "servers" with + | None -> OpenApiServerBase.BasePath "/" + | Some servers when servers.Count = 0 -> OpenApiServerBase.BasePath "/" + | Some servers -> + match tryObject "#/servers/0" servers.[0] with + | None -> OpenApiServerBase.BasePath "/" + | Some server -> + let mutable url = + requiredString server.Location server.Value "url" |> Option.defaultValue "/" + + let variables = + match optionalObject server.Location server.Value "variables" with + | None -> Map.empty + | Some variables -> objectMap variables.Location variables.Value + + for found in Regex.Matches (url, "\\{([^{}]+)\\}") |> Seq.cast do + let variableName = found.Groups.[1].Value + + match Map.tryFind variableName variables with + | None -> + report + InvalidDocument + ($"%s{server.Location}/url") + $"Server variable '%s{variableName}' has no definition." + | Some variable -> + match requiredString variable.Location variable.Value "default" with + | None -> () + | Some value -> url <- url.Replace (found.Value, value, StringComparison.Ordinal) + + match Uri.TryCreate (url, UriKind.Absolute) with + | true, _ -> OpenApiServerBase.BaseAddress url + | false, _ -> OpenApiServerBase.BasePath url + + let paths = optionalObject "#" root "paths" + let operations = ResizeArray () + let usedOperationIds = HashSet (StringComparer.Ordinal) + let usedMethodNames = HashSet (StringComparer.Ordinal) + + let methodEntries (pathItem : LocatedObject) = + [ + "get", HttpMethod.Get + "put", HttpMethod.Put + "post", HttpMethod.Post + "delete", HttpMethod.Delete + "options", HttpMethod.Options + "head", HttpMethod.Head + "patch", HttpMethod.Patch + "trace", HttpMethod.Trace + ] + |> List.choose (fun (name, method) -> + optionalObject pathItem.Location pathItem.Value name + |> Option.map (fun operation -> method, operation) + ) + + match paths with + | None -> report InvalidDocument "#/paths" "The OpenAPI paths object is required for client generation." + | Some paths -> + for path, pathItemNode in + paths.Value + |> Seq.map (fun (KeyValue (key, value)) -> key, value) + |> Seq.filter (fun (key, _) -> not (key.StartsWith ("x-", StringComparison.OrdinalIgnoreCase))) + |> Seq.sortBy fst do + if not (path.StartsWith ('/')) then + report + InvalidDocument + ($"%s{paths.Location}/%s{pointerToken path}") + "OpenAPI paths must start with '/'." + elif path.StartsWith ("//", StringComparison.Ordinal) then + report + InvalidDocument + ($"%s{paths.Location}/%s{pointerToken path}") + "Paths beginning with multiple slashes cannot be preserved by the generated URI composition." + + match tryObject ($"%s{paths.Location}/%s{pointerToken path}") pathItemNode with + | None -> () + | Some pathItem -> + if pathItem.Value.ContainsKey "$ref" then + report UnsupportedOperation pathItem.Location "Referenced Path Item Objects are unsupported." + + match optionalArray pathItem.Location pathItem.Value "servers" with + | Some values when values.Count > 0 -> + report + UnsupportedOperation + ($"%s{pathItem.Location}/servers") + "Path-specific servers are unsupported." + | _ -> () + + let inheritedParameters = parseParameterList pathItem + + for httpMethod, operation in methodEntries pathItem do + match optionalArray operation.Location operation.Value "servers" with + | Some values when values.Count > 0 -> + report + UnsupportedOperation + ($"%s{operation.Location}/servers") + "Operation-specific servers are unsupported." + | _ -> () + + let operationId = + match optionalString operation.Location operation.Value "operationId" with + | Some value -> + if not (usedOperationIds.Add value) then + report + InvalidDocument + ($"%s{operation.Location}/operationId") + $"Operation id '%s{value}' is duplicated." + + value + | None -> + let methodName = httpMethod.ToString().ToLowerInvariant () + $"%s{methodName}-%s{path}" + + let operationFSharpName = + allocateUniqueName usedMethodNames "Operation" sanitiseTypeName operationId + + let mergedParameters = + parseParameterList operation |> mergeParameters inheritedParameters + + let templateNames = + Regex.Matches (path, "\\{([^{}]+)\\}") + |> Seq.cast + |> Seq.map (fun value -> value.Groups.[1].Value) + |> Set.ofSeq + + let pathParameters = + mergedParameters + |> List.filter (fun parameter -> parameter.Location = ResolvedParameterLocation.Path) + + for templateName in templateNames do + if not (pathParameters |> List.exists (fun parameter -> parameter.Name = templateName)) then + report + UnsupportedParameter + operation.Location + $"Path template variable '%s{templateName}' has no path parameter." + + for parameter in pathParameters do + if not (Set.contains parameter.Name templateNames) then + report + UnsupportedParameter + parameter.SourceLocation + $"Path parameter '%s{parameter.Name}' does not occur in the path template." + + let usedParameterNames = HashSet (StringComparer.Ordinal) + usedParameterNames.Add "ct" |> ignore + usedParameterNames.Add "body" |> ignore + usedParameterNames.Add "client" |> ignore + + let plannedParameters = + mergedParameters + |> List.choose (fun parameter -> + let location = + match parameter.Location with + | ResolvedParameterLocation.Path -> Some OpenApiParameterLocation.Path + | ResolvedParameterLocation.Query -> Some OpenApiParameterLocation.Query + | ResolvedParameterLocation.Header + | ResolvedParameterLocation.Cookie -> None + + location + |> Option.map (fun location -> + let parameterFSharpName = + allocateUniqueName + usedParameterNames + "parameter" + sanitiseParameterName + parameter.Name + + let parameterType = + typeForSchema + Set.empty + ($"%s{operationFSharpName}%s{parameterFSharpName}") + parameter.Schema + + if schemaAllowsNull parameter.Schema then + report + UnsupportedParameter + parameter.Schema.Location + "Path/query parameter schemas which allow null cannot be represented distinctly from omission." + + match parameterType with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String + | OpenApiPlannedType.Primitive OpenApiPrimitive.Int32 + | OpenApiPlannedType.Primitive OpenApiPrimitive.Int64 -> () + | _ -> + report + UnsupportedParameter + parameter.Schema.Location + "Only string, int32, and int64 path/query parameter schemas currently have an exact wire encoding." + + let parameterType = + if parameter.Required then + parameterType + else + match parameterType with + | OpenApiPlannedType.Optional _ -> parameterType + | _ -> OpenApiPlannedType.Optional parameterType + + { + WireName = parameter.Name + FSharpName = parameterFSharpName + Location = location + Type = parameterType + Required = parameter.Required + } + ) + ) + + let body = requestBodyParameter operationFSharpName operation + + let plannedParameters = + match body with + | None -> plannedParameters + | Some (parameter, _) -> plannedParameters @ [ parameter ] + + let responses = optionalObject operation.Location operation.Value "responses" + + let returnType, accept = + match responses with + | None -> + report + InvalidDocument + ($"%s{operation.Location}/responses") + "Operations require responses." + + OpenApiPlannedType.Unit, None + | Some responses -> successfulResponses operationFSharpName responses + + operations.Add + { + OperationId = operationId + FSharpName = operationFSharpName + Description = + optionalString operation.Location operation.Value "summary" + |> Option.orElseWith (fun () -> + optionalString operation.Location operation.Value "description" + ) + Method = httpMethod + Path = path + Parameters = plannedParameters + ReturnType = returnType + Accept = accept + RequestContentType = body |> Option.map snd + } + + let rec namedDependencies (plannedType : OpenApiPlannedType) : Set = + match plannedType with + | OpenApiPlannedType.Named name -> Set.singleton name + | OpenApiPlannedType.List inner + | OpenApiPlannedType.Optional inner -> namedDependencies inner + | OpenApiPlannedType.Primitive _ + | OpenApiPlannedType.JsonNode + | OpenApiPlannedType.Stream + | OpenApiPlannedType.Unit -> Set.empty + + let definitionsByName = + definitions + |> Seq.map (fun definition -> definition.FSharpName, definition) + |> Map.ofSeq + + let definitionDependencies (definition : OpenApiPlannedTypeDefinition) : Set = + [ + yield! + definition.Fields + |> List.collect (fun field -> namedDependencies field.Type |> Set.toList) + + match definition.AdditionalProperties with + | None -> () + | Some value -> yield! namedDependencies value + ] + |> Set.ofList + // A record can recursively refer to itself; its generated codec member can recursively call itself too. + |> Set.remove definition.FSharpName + |> Set.filter (fun name -> Map.containsKey name definitionsByName) + + let visitedDefinitions = HashSet (StringComparer.Ordinal) + let visitingDefinitions = HashSet (StringComparer.Ordinal) + let reportedCycles = HashSet (StringComparer.Ordinal) + let orderedDefinitions = ResizeArray () + + let rec visitDefinition (name : string) = + if not (visitedDefinitions.Contains name) then + if not (visitingDefinitions.Add name) then + if reportedCycles.Add name then + report + UnsupportedSchema + "#/components/schemas" + $"Mutually recursive schema components involving '%s{name}' cannot use the generated JSON codecs." + else + let definition = definitionsByName.[name] + + for dependency in definitionDependencies definition |> Set.toList |> List.sort do + visitDefinition dependency + + visitingDefinitions.Remove name |> ignore + + if visitedDefinitions.Add name then + orderedDefinitions.Add definition + + for name in definitionsByName |> Map.toList |> List.map fst do + visitDefinition name + + let plan = + { + Namespace = className + InterfaceName = "I" + className + Description = description + CreateMock = createMock + ServerBase = parseServerBase () + Types = orderedDefinitions |> Seq.toList + Operations = operations |> Seq.sortBy _.FSharpName |> Seq.toList + } + + if diagnostics.Count = 0 then + Ok plan + else + diagnostics |> Seq.toList |> Error + + let parseAndPlan + (parameters : Map) + (source : string) + : Result + = + try + match JsonNode.Parse source with + | :? JsonObject as root -> parseDocument parameters root + | _ -> + Error + [ + diagnostic InvalidDocument "#" "The OpenAPI document root must be a JSON object." + ] + with :? JsonException as ex -> + Error [ diagnostic InvalidJson "#" ex.Message ] + + let rec private renderType (plannedType : OpenApiPlannedType) : SynType = + match plannedType with + | OpenApiPlannedType.Primitive primitive -> + match primitive with + | OpenApiPrimitive.String -> SynType.string + | OpenApiPrimitive.Boolean -> SynType.bool + | OpenApiPrimitive.Int32 -> SynType.int + | OpenApiPrimitive.Int64 -> SynType.createLongIdent' [ "int64" ] + | OpenApiPrimitive.BigInteger -> SynType.createLongIdent' [ "System" ; "Numerics" ; "BigInteger" ] + | OpenApiPrimitive.Float32 -> SynType.createLongIdent' [ "float32" ] + | OpenApiPrimitive.Float -> SynType.createLongIdent' [ "float" ] + | OpenApiPrimitive.Decimal -> SynType.createLongIdent' [ "decimal" ] + | OpenApiPrimitive.Date -> SynType.createLongIdent' [ "System" ; "DateOnly" ] + | OpenApiPrimitive.DateTime -> SynType.createLongIdent' [ "System" ; "DateTimeOffset" ] + | OpenApiPrimitive.Guid -> SynType.createLongIdent' [ "System" ; "Guid" ] + | OpenApiPlannedType.Named name -> SynType.named name + | OpenApiPlannedType.List element -> renderType element |> SynType.list + | OpenApiPlannedType.Optional value -> renderType value |> SynType.option + | OpenApiPlannedType.JsonNode -> SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ] + | OpenApiPlannedType.Stream -> SynType.createLongIdent' [ "System" ; "IO" ; "Stream" ] + | OpenApiPlannedType.Unit -> SynType.unit + + let private renderRecord (definition : OpenApiPlannedTypeDefinition) : SynTypeDefn = + let fields = + [ + match definition.AdditionalProperties with + | None -> () + | Some additionalProperties -> + yield + { + Attrs = + [ + SynAttribute.create + (SynLongIdent.createS' + [ "System" ; "Text" ; "Json" ; "Serialization" ; "JsonExtensionData" ]) + (SynExpr.CreateConst ()) + ] + Ident = Some (Ident.create "AdditionalProperties") + Type = + SynType.app' + (SynType.createLongIdent' [ "System" ; "Collections" ; "Generic" ; "Dictionary" ]) + [ SynType.string ; renderType additionalProperties ] + } + |> SynField.make + + for field in definition.Fields do + yield + { + Attrs = + [ + SynAttribute.create + (SynLongIdent.createS' + [ "System" ; "Text" ; "Json" ; "Serialization" ; "JsonPropertyName" ]) + (SynExpr.CreateConst field.JsonName) + ] + Ident = Some (Ident.create field.FSharpName) + Type = renderType field.Type + } + |> SynField.make + ] + + let fields = + if fields.IsEmpty then + [ + { + Attrs = [] + Ident = Some (Ident.create "_SchemaUnspecified") + Type = SynType.obj + } + |> SynField.make + ] + else + fields + + let componentInfo = + SynComponentInfo.create (Ident.create definition.FSharpName) + |> SynComponentInfo.withDocString ( + definition.Description + |> Option.defaultValue $"Generated representation of the '%s{definition.SourceName}' OpenAPI schema." + |> PreXmlDoc.create + ) + |> SynComponentInfo.addAttributes + [ + SynAttribute.create + (SynLongIdent.createS' [ "WoofWare" ; "Myriad" ; "Plugins" ; "JsonParse" ]) + (SynExpr.CreateConst true) + + SynAttribute.create + (SynLongIdent.createS' [ "WoofWare" ; "Myriad" ; "Plugins" ; "JsonSerialize" ]) + (SynExpr.CreateConst true) + ] + + fields |> SynTypeDefnRepr.record |> SynTypeDefn.create componentInfo + + let private renderOperation (operation : OpenApiPlannedOperation) : SynMemberDefn = + let cancellationToken = + SynType.signatureParamOfType + [] + (SynType.createLongIdent' [ "System" ; "Threading" ; "CancellationToken" ]) + true + (Some (Ident.create "ct")) + + let parameterType (parameter : OpenApiPlannedParameter) = + let attributes = + match parameter.Location with + | OpenApiParameterLocation.Path -> + [ + SynAttribute.create + (SynLongIdent.createS' [ "RestEase" ; "Path" ]) + (SynExpr.CreateConst parameter.WireName) + ] + | OpenApiParameterLocation.Query -> + [ + SynAttribute.create + (SynLongIdent.createS' [ "RestEase" ; "Query" ]) + (SynExpr.CreateConst parameter.WireName) + ] + | OpenApiParameterLocation.Body -> + [ + SynAttribute.create (SynLongIdent.createS' [ "RestEase" ; "Body" ]) (SynExpr.CreateConst ()) + ] + + SynType.signatureParamOfType + attributes + (renderType parameter.Type) + false + (Some (Ident.create parameter.FSharpName)) + + let domain = + operation.Parameters + |> List.map parameterType + |> fun parameters -> parameters @ [ cancellationToken ] + |> SynType.tupleNoParen + |> Option.get + + let arity = + SynValInfo.SynValInfo ( + [ + [ + for parameter in operation.Parameters do + yield SynArgInfo.SynArgInfo ([], false, Some (Ident.create parameter.FSharpName)) + + yield SynArgInfo.SynArgInfo ([], true, Some (Ident.create "ct")) + ] + ], + SynArgInfo.SynArgInfo ([], false, None) + ) + + let attributes = + [ + yield + SynAttribute.create + (SynLongIdent.createS' [ "RestEase" ; operation.Method.ToString () ]) + (SynExpr.CreateConst (operation.Path.TrimStart '/')) + + match operation.Accept with + | None -> () + | Some mediaType -> + yield + SynAttribute.create + (SynLongIdent.createS' [ "RestEase" ; "Header" ]) + (SynExpr.tuple [ SynExpr.CreateConst "Accept" ; SynExpr.CreateConst mediaType ]) + + match operation.RequestContentType with + | None -> () + | Some mediaType -> + yield + SynAttribute.create + (SynLongIdent.createS' [ "RestEase" ; "Header" ]) + (SynExpr.tuple [ SynExpr.CreateConst "Content-Type" ; SynExpr.CreateConst mediaType ]) + ] + + renderType operation.ReturnType + |> SynType.task + |> SynType.toFun [ domain ] + |> SynMemberDefn.abstractMember + attributes + (SynIdent.createS operation.FSharpName) + None + arity + (operation.Description + |> Option.defaultValue $"Invoke the '%s{operation.OperationId}' OpenAPI operation." + |> PreXmlDoc.create) + + let private renderPlan (plan : OpenApiClientPlan) : Output = + let typeDeclarations = + plan.Types |> List.map renderRecord |> SynModuleDecl.createTypes + + let interfaceType = + plan.Operations + |> List.map renderOperation + |> SynTypeDefnRepr.interfaceType + |> SynTypeDefn.create ( + let attributes = + [ + yield + SynAttribute.create + (SynLongIdent.createS' [ "WoofWare" ; "Myriad" ; "Plugins" ; "HttpClient" ]) + (SynExpr.CreateConst false) + + match plan.ServerBase with + | OpenApiServerBase.BaseAddress address -> + yield + SynAttribute.create + (SynLongIdent.createS' [ "RestEase" ; "BaseAddress" ]) + (SynExpr.CreateConst address) + | OpenApiServerBase.BasePath path -> + yield + SynAttribute.create + (SynLongIdent.createS' [ "RestEase" ; "BasePath" ]) + (SynExpr.CreateConst path) + + match plan.CreateMock with + | None -> () + | Some isInternal -> + yield + SynAttribute.create + (SynLongIdent.createS' [ "WoofWare" ; "Myriad" ; "Plugins" ; "GenerateMock" ]) + (SynExpr.CreateConst isInternal) + ] + + SynComponentInfo.create (Ident.create plan.InterfaceName) + |> SynComponentInfo.withDocString ( + plan.Description + |> Option.defaultValue "HTTP client generated from an OpenAPI 3.0 document." + |> PreXmlDoc.create + ) + |> SynComponentInfo.addAttributes attributes + ) + + [ + SynModuleDecl.Open ( + SynOpenDeclTarget.ModuleOrNamespace ( + SynLongIdent.createS' [ "WoofWare" ; "Myriad" ; "Plugins" ], + range0 + ), + range0 + ) + typeDeclarations + SynModuleDecl.createTypes [ interfaceType ] + ] + |> SynModuleOrNamespace.createNamespace [ Ident.create plan.Namespace ] + |> List.singleton + |> Output.Ast + + let generate (parameters : Map) (source : string) : Output = + match parseAndPlan parameters source with + | Ok plan -> renderPlan plan + | Error diagnostics -> + diagnostics + |> List.map (fun value -> $"[%O{value.Code}] %s{value.Location}: %s{value.Message}") + |> String.concat Environment.NewLine + |> failwith diff --git a/WoofWare.Myriad.Plugins/SwaggerClientGenerator.fs b/WoofWare.Myriad.Plugins/SwaggerClientGenerator.fs index 1bc23797..aeac7030 100644 --- a/WoofWare.Myriad.Plugins/SwaggerClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/SwaggerClientGenerator.fs @@ -753,6 +753,7 @@ module internal SwaggerClientGenerator = open Myriad.Core open System.IO +open System.Text.Json.Nodes [] module internal SwaggerV2Generator = @@ -1022,8 +1023,18 @@ type SwaggerClientGenerator () = if pars.IsEmpty then failwith "No parameters given. You must supply the parameter in ." - let contents = File.ReadAllText context.InputFilename |> SwaggerV2.parse - - match contents with - | Ok contents -> SwaggerV2Generator.generate pars contents - | Error node -> failwith "Input was not a Swagger 2 spec" + let source = File.ReadAllText context.InputFilename + + let root = + try + JsonNode.Parse source + with :? System.Text.Json.JsonException as ex -> + failwith $"[InvalidJson] #: %s{ex.Message}" + + match root with + | :? JsonObject as root when root.ContainsKey "swagger" -> + match SwaggerV2.parse source with + | Ok contents -> SwaggerV2Generator.generate pars contents + | Error _ -> failwith "Input was not a Swagger 2 spec" + | :? JsonObject as root when root.ContainsKey "openapi" -> OpenApiClientGenerator.generate pars source + | _ -> failwith "Input was neither a Swagger 2 nor an OpenAPI 3 spec" diff --git a/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj b/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj index 15a85da8..3fbc60a3 100644 --- a/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj +++ b/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj @@ -47,6 +47,7 @@ + From ea2eaffce982571e80f1ca5920ec4d5da81cc2ae Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Fri, 10 Jul 2026 12:15:44 +0100 Subject: [PATCH 3/9] Address OpenAPI 3 review feedback --- ConsumePlugin/Generated2OpenApiPetstore.fs | 124 +- ConsumePlugin/Generated2SwaggerGitea.fs | 5428 +++++++++-------- ConsumePlugin/GeneratedSerde.fs | 10 +- .../TestJsonSerialize/TestJsonSerde.fs | 30 + .../TestSwagger/TestOpenApi3Client.fs | 14 +- .../TestSwagger/TestOpenApi3Generator.fs | 173 + .../TestSwagger/TestOpenApi3Parse.fs | 3503 ----------- .../WoofWare.Myriad.Plugins.Test.fsproj | 1 - .../JsonSerializeGenerator.fs | 21 +- WoofWare.Myriad.Plugins/OpenApi3.fs | 1332 ---- .../OpenApiClientGenerator.fs | 75 +- .../WoofWare.Myriad.Plugins.fsproj | 1 - 12 files changed, 3201 insertions(+), 7511 deletions(-) delete mode 100644 WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Parse.fs delete mode 100644 WoofWare.Myriad.Plugins/OpenApi3.fs diff --git a/ConsumePlugin/Generated2OpenApiPetstore.fs b/ConsumePlugin/Generated2OpenApiPetstore.fs index f9e1d179..3a03f5dd 100644 --- a/ConsumePlugin/Generated2OpenApiPetstore.fs +++ b/ConsumePlugin/Generated2OpenApiPetstore.fs @@ -28,7 +28,11 @@ module GenerateMockAttribute2JsonSerializeExtension = | None -> None | Some field -> field - |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) |> Some ) value @@ -49,8 +53,10 @@ module GenerateMockAttribute2JsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -84,7 +90,11 @@ module HttpClientAttribute2JsonSerializeExtension = | None -> None | Some field -> field - |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) |> Some ) value @@ -105,8 +115,10 @@ module HttpClientAttribute2JsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -140,7 +152,11 @@ module JsonParseAttribute2JsonSerializeExtension = | None -> None | Some field -> field - |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) |> Some ) value @@ -161,8 +177,10 @@ module JsonParseAttribute2JsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -196,7 +214,11 @@ module JsonSerializeAttribute2JsonSerializeExtension = | None -> None | Some field -> field - |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) |> Some ) value @@ -217,8 +239,10 @@ module JsonSerializeAttribute2JsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -252,7 +276,11 @@ module NewPetJsonSerializeExtension = | None -> None | Some field -> field - |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) |> Some ) value @@ -268,8 +296,10 @@ module NewPetJsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -289,8 +319,10 @@ module NewPetJsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -324,7 +356,11 @@ module PetJsonSerializeExtension = | None -> None | Some field -> field - |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) + |> (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) |> Some ) value @@ -340,8 +376,10 @@ module PetJsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type int64 to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -356,8 +394,10 @@ module PetJsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -388,8 +428,10 @@ module PetJsonSerializeExtension = (match field with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "field", "Expected type string to be non-null, but received a null value when serialising" + ) ) | field -> field) )) @@ -719,8 +761,10 @@ module OpenApiPetstore = (match jsonNode with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "jsonNode", "Response from server was the JSON null object; expected a non-nullable type Pet" + ) ) | jsonNode -> jsonNode) @@ -836,16 +880,9 @@ module OpenApiPetstore = body |> (fun field -> match field with - | None -> None - | Some field -> - field - |> (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) - |> Some - ) - |> (fun node -> - match node with | None -> "null" - | Some node -> node.ToJsonString () + | Some field -> + (fun node -> (node : System.Text.Json.Nodes.JsonNode).ToJsonString ()) field ), null, "application/json" @@ -894,21 +931,8 @@ module OpenApiPetstore = body |> (fun field -> let value = field : System.Numerics.BigInteger - - let node = - System.Text.Json.Nodes.JsonNode.Parse ( - value.ToString ("D", System.Globalization.CultureInfo.InvariantCulture) - ) - - (match node with - | null -> - raise ( - System.ArgumentNullException - "Invariant BigInteger text unexpectedly parsed as JSON null." - ) - | node -> node) - ) - |> (fun node -> node.ToJsonString ()), + value.ToString ("D", System.Globalization.CultureInfo.InvariantCulture) + ), null, "application/json" ) @@ -928,8 +952,10 @@ module OpenApiPetstore = (match jsonNode with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "jsonNode", "Response from server was the JSON null object; expected a non-nullable type bigint" + ) ) | jsonNode -> jsonNode) @@ -974,8 +1000,10 @@ module OpenApiPetstore = (match jsonNode with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "jsonNode", "Response from server was the JSON null object; expected a non-nullable type bigint" + ) ) | jsonNode -> jsonNode) @@ -1023,8 +1051,10 @@ module OpenApiPetstore = (match jsonNode with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "jsonNode", "Response from server was the JSON null object; expected a non-nullable type Pet" + ) ) | jsonNode -> jsonNode) @@ -1097,8 +1127,10 @@ module OpenApiPetstore = (match jsonNode with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "jsonNode", "Response from server was the JSON null object; expected a non-nullable type Pet list" + ) ) | jsonNode -> jsonNode) @@ -1108,8 +1140,10 @@ module OpenApiPetstore = (match elt with | null -> raise ( - System.ArgumentNullException + System.ArgumentNullException ( + "elt", "Expected element of array (element type Pet) to be non-null, but found a null element" + ) ) | elt -> Pet.jsonParse elt) ) diff --git a/ConsumePlugin/Generated2SwaggerGitea.fs b/ConsumePlugin/Generated2SwaggerGitea.fs index 579a4b5d..72e479fc 100644 --- a/ConsumePlugin/Generated2SwaggerGitea.fs +++ b/ConsumePlugin/Generated2SwaggerGitea.fs @@ -21,7 +21,15 @@ module APIErrorJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "message", @@ -94,7 +102,15 @@ module AccessTokenJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "id", @@ -105,14 +121,14 @@ module AccessTokenJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -258,7 +274,15 @@ module ActivityPubJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "@context", @@ -304,7 +328,15 @@ module AddCollaboratorOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "permission", @@ -350,7 +382,15 @@ module AddTimeOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created", @@ -383,14 +423,14 @@ module AddTimeOptionJsonSerializeExtension = "time", (input.Time |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -441,7 +481,15 @@ module AnnotatedTagObjectJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "sha", @@ -541,7 +589,15 @@ module AttachmentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "browser_download_url", @@ -606,14 +662,14 @@ module AttachmentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -633,14 +689,14 @@ module AttachmentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -687,14 +743,14 @@ module AttachmentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -749,7 +805,15 @@ module BranchProtectionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "approvals_whitelist_teams", @@ -1360,14 +1424,14 @@ module BranchProtectionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1513,7 +1577,15 @@ module ChangedFileJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "additions", @@ -1524,14 +1596,14 @@ module ChangedFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1551,14 +1623,14 @@ module ChangedFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1605,14 +1677,14 @@ module ChangedFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1775,7 +1847,15 @@ module CommitAffectedFilesJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "filename", @@ -1821,7 +1901,15 @@ module CommitDateOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -1894,7 +1982,15 @@ module CommitMetaJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created", @@ -1994,7 +2090,15 @@ module CommitStatsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "additions", @@ -2005,14 +2109,14 @@ module CommitStatsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2032,14 +2136,14 @@ module CommitStatsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2059,14 +2163,14 @@ module CommitStatsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2094,7 +2198,15 @@ module CommitUserJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "date", @@ -2194,7 +2306,15 @@ module CreateAccessTokenOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "name", @@ -2268,7 +2388,15 @@ module CreateBranchProtectionOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "approvals_whitelist_teams", @@ -2852,14 +2980,14 @@ module CreateBranchProtectionOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2978,7 +3106,15 @@ module CreateBranchRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "new_branch_name", @@ -3042,7 +3178,15 @@ module CreateEmailOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "emails", @@ -3098,7 +3242,15 @@ module CreateForkOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "name", @@ -3171,7 +3323,15 @@ module CreateGPGKeyOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "armored_public_key", @@ -3270,7 +3430,15 @@ module CreateIssueCommentOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -3307,7 +3475,15 @@ module CreateIssueOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "assignee", @@ -3468,14 +3644,14 @@ module CreateIssueOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -3500,14 +3676,14 @@ module CreateIssueOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -3580,7 +3756,15 @@ module CreateKeyOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "key", @@ -3662,7 +3846,15 @@ module CreateLabelOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "color", @@ -3771,7 +3963,15 @@ module CreateMilestoneOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "description", @@ -3898,7 +4098,15 @@ module CreateOAuth2ApplicationOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "confidential_client", @@ -4008,7 +4216,15 @@ module CreateOrgOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "description", @@ -4207,7 +4423,15 @@ module CreatePullRequestOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "assignee", @@ -4395,14 +4619,14 @@ module CreatePullRequestOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4427,14 +4651,14 @@ module CreatePullRequestOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4489,7 +4713,15 @@ module CreatePullReviewCommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -4527,14 +4759,14 @@ module CreatePullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4554,14 +4786,14 @@ module CreatePullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4616,7 +4848,15 @@ module CreatePushMirrorOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "interval", @@ -4770,7 +5010,15 @@ module CreateReleaseOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -4942,7 +5190,15 @@ module CreateRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "auto_init", @@ -5249,7 +5505,15 @@ module CreateStatusOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "context", @@ -5376,7 +5640,15 @@ module CreateTagOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "message", @@ -5502,7 +5774,15 @@ module CreateTeamOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "can_create_org_repo", @@ -5695,7 +5975,15 @@ module CreateUserOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created_at", @@ -5904,14 +6192,14 @@ module CreateUserOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -5984,7 +6272,15 @@ module CreateWikiPageOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "content_base64", @@ -6084,7 +6380,15 @@ module CronJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "exec_times", @@ -6095,14 +6399,14 @@ module CronJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -6238,7 +6542,15 @@ module DeleteEmailOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "emails", @@ -6294,7 +6606,15 @@ module DismissPullReviewOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "message", @@ -6367,7 +6687,15 @@ module EditAttachmentOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "name", @@ -6413,7 +6741,15 @@ module EditBranchProtectionOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "approvals_whitelist_teams", @@ -6970,14 +7306,14 @@ module EditBranchProtectionOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -7069,7 +7405,15 @@ module EditDeadlineOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "due_date", @@ -7106,7 +7450,15 @@ module EditGitHookOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "content", @@ -7187,7 +7539,15 @@ module EditHookOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "active", @@ -7335,7 +7695,15 @@ module EditIssueCommentOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -7372,7 +7740,15 @@ module EditIssueOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "assignee", @@ -7501,14 +7877,14 @@ module EditIssueOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -7644,7 +8020,15 @@ module EditLabelOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "color", @@ -7771,7 +8155,15 @@ module EditMilestoneOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "description", @@ -7898,7 +8290,15 @@ module EditOrgOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "description", @@ -8079,7 +8479,15 @@ module EditPullRequestOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "allow_maintainer_edit", @@ -8267,14 +8675,14 @@ module EditPullRequestOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -8299,14 +8707,14 @@ module EditPullRequestOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -8415,7 +8823,15 @@ module EditReactionOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "content", @@ -8461,7 +8877,15 @@ module EditReleaseOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -8677,7 +9101,15 @@ module EditTeamOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "can_create_org_repo", @@ -8870,7 +9302,15 @@ module EditUserOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "active", @@ -9142,14 +9582,14 @@ module EditUserOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -9272,14 +9712,14 @@ module EditUserOptionJsonSerializeExtension = "source_id", (input.SourceId |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -9357,7 +9797,15 @@ module EmailJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "email", @@ -9457,7 +9905,15 @@ module ExternalTrackerJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "external_tracker_format", @@ -9584,7 +10040,15 @@ module ExternalWikiJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "external_wiki_url", @@ -9630,7 +10094,15 @@ module FileCommitResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -9839,7 +10311,15 @@ module FileLinksResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "git", @@ -9939,7 +10419,15 @@ module GPGKeyEmailJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "email", @@ -10012,7 +10500,15 @@ module GeneralAPISettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "default_git_trees_per_page", @@ -10023,14 +10519,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10050,14 +10546,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10077,14 +10573,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10104,14 +10600,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10139,7 +10635,15 @@ module GeneralAttachmentSettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "allowed_types", @@ -10204,14 +10708,14 @@ module GeneralAttachmentSettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10231,14 +10735,14 @@ module GeneralAttachmentSettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10266,7 +10770,15 @@ module GeneralRepoSettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "http_git_disabled", @@ -10447,7 +10959,15 @@ module GeneralUISettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "allowed_reactions", @@ -10567,7 +11087,15 @@ module GenerateRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "avatar", @@ -10865,7 +11393,15 @@ module GitBlobResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "content", @@ -10957,14 +11493,14 @@ module GitBlobResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11019,7 +11555,15 @@ module GitEntryJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "mode", @@ -11111,14 +11655,14 @@ module GitEntryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11200,7 +11744,15 @@ module GitHookJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "content", @@ -11300,7 +11852,15 @@ module GitObjectJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "sha", @@ -11400,7 +11960,15 @@ module GitTreeResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "page", @@ -11411,14 +11979,14 @@ module GitTreeResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11465,14 +12033,14 @@ module GitTreeResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11611,7 +12179,15 @@ module HookJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "active", @@ -11751,14 +12327,14 @@ module HookJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11840,7 +12416,15 @@ module IdentityJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "email", @@ -11913,7 +12497,15 @@ module InternalTrackerJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "allow_only_contributors_to_track_time", @@ -12013,7 +12605,15 @@ module IssueDeadlineJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "due_date", @@ -12097,7 +12697,15 @@ module IssueLabelsOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "labels", @@ -12113,14 +12721,14 @@ module IssueLabelsOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -12153,7 +12761,15 @@ module LabelJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "color", @@ -12245,14 +12861,14 @@ module LabelJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -12334,7 +12950,15 @@ module MarkdownOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "Context", @@ -12461,7 +13085,15 @@ module MergePullRequestOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "Do", @@ -12687,7 +13319,15 @@ module MigrateRepoOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "auth_password", @@ -13166,14 +13806,14 @@ module MigrateRepoOptionsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -13228,7 +13868,15 @@ module Type7JsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node :> _ namespace Gitea @@ -13247,7 +13895,15 @@ module NodeInfoServicesJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "inbound", @@ -13340,7 +13996,15 @@ module NodeInfoSoftwareJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "homepage", @@ -13467,7 +14131,15 @@ module NodeInfoUsageUsersJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "activeHalfyear", @@ -13478,14 +14150,14 @@ module NodeInfoUsageUsersJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -13505,14 +14177,14 @@ module NodeInfoUsageUsersJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -13532,14 +14204,14 @@ module NodeInfoUsageUsersJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -13567,7 +14239,15 @@ module NotificationCountJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "new", @@ -13578,14 +14258,14 @@ module NotificationCountJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -13613,7 +14293,15 @@ module OAuth2ApplicationJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "client_id", @@ -13732,14 +14420,14 @@ module OAuth2ApplicationJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -13831,7 +14519,15 @@ module OrganizationJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "avatar_url", @@ -13923,14 +14619,14 @@ module OrganizationJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14120,7 +14816,15 @@ module OrganizationPermissionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "can_create_repository", @@ -14274,7 +14978,15 @@ module PackageFileJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "Size", @@ -14285,14 +14997,14 @@ module PackageFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14312,14 +15024,14 @@ module PackageFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14482,7 +15194,15 @@ module PayloadUserJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "email", @@ -14582,7 +15302,15 @@ module PermissionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "admin", @@ -14682,7 +15410,15 @@ module PullRequestMetaJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "merged", @@ -14755,7 +15491,15 @@ module PullReviewRequestOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "reviewers", @@ -14848,7 +15592,15 @@ module PushMirrorJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created", @@ -15083,7 +15835,15 @@ module ReferenceJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "object", @@ -15167,7 +15927,15 @@ module RepoTopicOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "topics", @@ -15223,7 +15991,15 @@ module RepositoryMetaJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "full_name", @@ -15261,14 +16037,14 @@ module RepositoryMetaJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -15350,7 +16126,15 @@ module ServerVersionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "version", @@ -15396,7 +16180,15 @@ module StopWatchJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created", @@ -15461,14 +16253,14 @@ module StopWatchJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -15569,14 +16361,14 @@ module StopWatchJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -15604,7 +16396,15 @@ module SubmitPullReviewOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -15677,7 +16477,15 @@ module TagJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commit", @@ -15877,7 +16685,15 @@ module TeamJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "can_create_org_repo", @@ -15942,14 +16758,14 @@ module TeamJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16117,7 +16933,15 @@ module TopicNameJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "topics", @@ -16173,7 +16997,15 @@ module TopicResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created", @@ -16211,14 +17043,14 @@ module TopicResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16238,14 +17070,14 @@ module TopicResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16327,7 +17159,15 @@ module TransferRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "new_owner", @@ -16361,14 +17201,14 @@ module TransferRepoOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16401,7 +17241,15 @@ module UpdateFileOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -16624,7 +17472,15 @@ module UserJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "active", @@ -16770,14 +17626,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16797,14 +17653,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16851,14 +17707,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17094,14 +17950,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17183,7 +18039,15 @@ module UserHeatmapDataJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "contributions", @@ -17194,14 +18058,14 @@ module UserHeatmapDataJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17221,14 +18085,14 @@ module UserHeatmapDataJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17256,7 +18120,15 @@ module UserSettingsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "description", @@ -17518,7 +18390,15 @@ module UserSettingsOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "description", @@ -17780,7 +18660,15 @@ module WatchInfoJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created_at", @@ -17948,7 +18836,15 @@ module WikiCommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -18043,7 +18939,15 @@ module WikiCommitListJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commits", @@ -18076,14 +18980,14 @@ module WikiCommitListJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18111,7 +19015,15 @@ module WikiPageJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commit_count", @@ -18122,14 +19034,14 @@ module WikiPageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18330,7 +19242,15 @@ module WikiPageMetaDataJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "html_url", @@ -18441,7 +19361,15 @@ module CommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "assets", @@ -18555,14 +19483,14 @@ module CommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18636,14 +19564,14 @@ module CommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18736,7 +19664,15 @@ module CommitStatusJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "context", @@ -18839,14 +19775,14 @@ module CommitStatusJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18982,7 +19918,15 @@ module ContentsResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "_links", @@ -19247,14 +20191,14 @@ module ContentsResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -19390,7 +20334,15 @@ module CreateFileOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -19568,7 +20520,15 @@ module CreateHookOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "active", @@ -19725,7 +20685,15 @@ module CreatePullReviewOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -19847,7 +20815,15 @@ module DeleteFileOptionsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -20025,7 +21001,15 @@ module EditRepoOptionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "allow_manual_merge", @@ -20725,7 +21709,15 @@ module IssueFormFieldJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "attributes", @@ -20820,7 +21812,15 @@ module IssueTemplateJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "about", @@ -21060,7 +22060,15 @@ module MilestoneJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "closed_at", @@ -21098,14 +22106,14 @@ module MilestoneJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -21206,14 +22214,14 @@ module MilestoneJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -21233,14 +22241,14 @@ module MilestoneJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -21349,7 +22357,15 @@ module NodeInfoUsageJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "localComments", @@ -21360,14 +22376,14 @@ module NodeInfoUsageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -21387,14 +22403,14 @@ module NodeInfoUsageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -21433,7 +22449,15 @@ module NotificationSubjectJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "html_url", @@ -21641,7 +22665,15 @@ module PayloadCommitVerificationJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "payload", @@ -21779,7 +22811,15 @@ module PublicKeyJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created_at", @@ -21844,14 +22884,14 @@ module PublicKeyJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22025,7 +23065,15 @@ module PullReviewJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -22063,14 +23111,14 @@ module PullReviewJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22171,14 +23219,14 @@ module PullReviewJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22390,7 +23438,15 @@ module PullReviewCommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "body", @@ -22536,14 +23592,14 @@ module PullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22671,14 +23727,14 @@ module PullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22782,7 +23838,15 @@ module ReactionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "content", @@ -22866,7 +23930,15 @@ module ReleaseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "assets", @@ -23018,14 +24090,14 @@ module ReleaseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -23269,7 +24341,15 @@ module RepoCollaboratorPermissionJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "permission", @@ -23353,7 +24433,15 @@ module RepoCommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -23470,7 +24558,15 @@ module RepoTransferJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "doer", @@ -23533,7 +24629,15 @@ module RepositoryJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "allow_merge_commits", @@ -23998,14 +25102,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24187,14 +25291,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24468,14 +25572,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24495,14 +25599,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24609,14 +25713,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24647,14 +25751,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24701,14 +25805,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24782,14 +25886,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24844,7 +25948,15 @@ module SearchResultsJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "data", @@ -24912,7 +26024,15 @@ module AnnotatedTagJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "message", @@ -25072,7 +26192,15 @@ module CombinedStatusJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commit_url", @@ -25197,14 +26325,14 @@ module CombinedStatusJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25259,7 +26387,15 @@ module CommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "author", @@ -25474,7 +26610,15 @@ module DeployKeyJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created_at", @@ -25539,14 +26683,14 @@ module DeployKeyJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25593,14 +26737,14 @@ module DeployKeyJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25720,7 +26864,15 @@ module FileDeleteResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commit", @@ -25775,7 +26927,15 @@ module FileResponseJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commit", @@ -25827,7 +26987,15 @@ module IssueJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "assets", @@ -25947,14 +27115,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26055,14 +27223,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26142,14 +27310,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26196,14 +27364,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26399,7 +27567,15 @@ module NodeInfoJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "metadata", @@ -26553,7 +27729,15 @@ module NoteJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commit", @@ -26610,7 +27794,15 @@ module NotificationThreadJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "id", @@ -26621,14 +27813,14 @@ module NotificationThreadJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26786,7 +27978,15 @@ module PRBranchInfoJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "label", @@ -26862,14 +28062,14 @@ module PRBranchInfoJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26924,7 +28124,15 @@ module PackageJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created_at", @@ -26973,14 +28181,14 @@ module PackageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27111,7 +28319,15 @@ module PayloadCommitJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "added", @@ -27382,7 +28598,15 @@ module PullRequestJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "allow_maintainer_edit", @@ -27518,14 +28742,14 @@ module PullRequestJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27664,14 +28888,14 @@ module PullRequestJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27897,14 +29121,14 @@ module PullRequestJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28078,7 +29302,15 @@ module TrackedTimeJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "created", @@ -28116,14 +29348,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28154,14 +29386,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28181,14 +29413,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28208,14 +29440,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28270,7 +29502,15 @@ module BranchJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "commit", @@ -28400,14 +29640,14 @@ module BranchJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28526,7 +29766,15 @@ module TimelineCommentJsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "assignee", @@ -28651,14 +29899,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28792,14 +30040,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28873,14 +30121,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29041,14 +30289,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29155,14 +30403,14 @@ module LanguageStatisticsJsonSerializeExtension = node.Add ( key, (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int64 to be non-null, but received a null value when serialising" + "Expected type int32 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29187,7 +30435,15 @@ module Type9JsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "data", @@ -29255,7 +30511,15 @@ module Type10JsonSerializeExtension = do for KeyValue (key, value) in input.AdditionalProperties do - node.Add (key, id value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node.Add ( "data", @@ -29404,7 +30668,7 @@ module AccessTokenJsonParseExtension = let arg_1 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -29553,7 +30817,7 @@ module AddTimeOptionJsonParseExtension = sprintf "Required key '%s' not found on JSON object" ("time") ) ) - | Some node -> node.AsValue().GetValue () + | Some node -> node.AsValue().GetValue () let arg_1 = match node.["created"] |> Option.ofObj with @@ -29663,7 +30927,7 @@ module AttachmentJsonParseExtension = let arg_6 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["name"] |> Option.ofObj with @@ -29673,12 +30937,12 @@ module AttachmentJsonParseExtension = let arg_4 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["download_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["created_at"] |> Option.ofObj with @@ -29779,7 +31043,7 @@ module BranchProtectionJsonParseExtension = let arg_21 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_20 = match node.["require_signed_commits"] |> Option.ofObj with @@ -30081,7 +31345,7 @@ module ChangedFileJsonParseExtension = let arg_4 = match node.["deletions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["contents_url"] |> Option.ofObj with @@ -30091,12 +31355,12 @@ module ChangedFileJsonParseExtension = let arg_2 = match node.["changes"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["additions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -30304,17 +31568,17 @@ module CommitStatsJsonParseExtension = let arg_3 = match node.["total"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["deletions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["additions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -30511,7 +31775,7 @@ module CreateBranchProtectionOptionJsonParseExtension = let arg_20 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_19 = match node.["require_signed_commits"] |> Option.ofObj with @@ -31091,7 +32355,7 @@ module CreateIssueOptionJsonParseExtension = let arg_7 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["labels"] |> Option.ofObj with @@ -31104,10 +32368,10 @@ module CreateIssueOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int64) to be non-null, but found a null element" + "Expected element of array (element type int32) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -31573,7 +32837,7 @@ module CreatePullRequestOptionJsonParseExtension = let arg_8 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_7 = match node.["labels"] |> Option.ofObj with @@ -31586,10 +32850,10 @@ module CreatePullRequestOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int64) to be non-null, but found a null element" + "Expected element of array (element type int32) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -31702,12 +32966,12 @@ module CreatePullReviewCommentJsonParseExtension = let arg_3 = match node.["old_position"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["new_position"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["body"] |> Option.ofObj with @@ -32313,7 +33577,7 @@ module CreateUserOptionJsonParseExtension = let arg_9 = match node.["source_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_8 = match node.["send_notify"] |> Option.ofObj with @@ -32503,7 +33767,7 @@ module CronJsonParseExtension = let arg_1 = match node.["exec_times"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -32729,7 +33993,7 @@ module EditBranchProtectionOptionJsonParseExtension = let arg_19 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_18 = match node.["require_signed_commits"] |> Option.ofObj with @@ -33269,7 +34533,7 @@ module EditIssueOptionJsonParseExtension = let arg_5 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["due_date"] |> Option.ofObj with @@ -33581,7 +34845,7 @@ module EditPullRequestOptionJsonParseExtension = let arg_8 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_7 = match node.["labels"] |> Option.ofObj with @@ -33594,10 +34858,10 @@ module EditPullRequestOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int64) to be non-null, but found a null element" + "Expected element of array (element type int32) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -33988,7 +35252,7 @@ module EditUserOptionJsonParseExtension = sprintf "Required key '%s' not found on JSON object" ("source_id") ) ) - | Some node -> node.AsValue().GetValue () + | Some node -> node.AsValue().GetValue () let arg_15 = match node.["restricted"] |> Option.ofObj with @@ -34013,7 +35277,7 @@ module EditUserOptionJsonParseExtension = let arg_11 = match node.["max_repo_creation"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_10 = match node.["login_name"] |> Option.ofObj with @@ -34530,22 +35794,22 @@ module GeneralAPISettingsJsonParseExtension = let arg_4 = match node.["max_response_items"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["default_paging_num"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["default_max_blob_size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["default_git_trees_per_page"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -34596,12 +35860,12 @@ module GeneralAttachmentSettingsJsonParseExtension = let arg_4 = match node.["max_size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["max_files"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["enabled"] |> Option.ofObj with @@ -34955,7 +36219,7 @@ module GitBlobResponseJsonParseExtension = let arg_4 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["sha"] |> Option.ofObj with @@ -35033,7 +36297,7 @@ module GitEntryJsonParseExtension = let arg_4 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["sha"] |> Option.ofObj with @@ -35242,7 +36506,7 @@ module GitTreeResponseJsonParseExtension = let arg_3 = match node.["total_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["sha"] |> Option.ofObj with @@ -35252,7 +36516,7 @@ module GitTreeResponseJsonParseExtension = let arg_1 = match node.["page"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -35352,7 +36616,7 @@ module HookJsonParseExtension = let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["events"] |> Option.ofObj with @@ -35679,10 +36943,10 @@ module IssueLabelsOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int64) to be non-null, but found a null element" + "Expected element of array (element type int32) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -35738,7 +37002,7 @@ module LabelJsonParseExtension = let arg_4 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["exclusive"] |> Option.ofObj with @@ -35973,7 +37237,7 @@ module MigrateRepoOptionsJsonParseExtension = let arg_19 = match node.["uid"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_18 = match node.["service"] |> Option.ofObj with @@ -36331,17 +37595,17 @@ module NodeInfoUsageUsersJsonParseExtension = let arg_3 = match node.["total"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["activeMonth"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["activeHalfyear"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -36386,7 +37650,7 @@ module NotificationCountJsonParseExtension = let arg_1 = match node.["new"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -36453,7 +37717,7 @@ module OAuth2ApplicationJsonParseExtension = let arg_5 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["created"] |> Option.ofObj with @@ -36560,7 +37824,7 @@ module OrganizationJsonParseExtension = let arg_4 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["full_name"] |> Option.ofObj with @@ -36736,12 +38000,12 @@ module PackageFileJsonParseExtension = let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["Size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -37250,7 +38514,7 @@ module RepositoryMetaJsonParseExtension = let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["full_name"] |> Option.ofObj with @@ -37344,7 +38608,7 @@ module StopWatchJsonParseExtension = let arg_7 = match node.["seconds"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["repo_owner_name"] |> Option.ofObj with @@ -37364,7 +38628,7 @@ module StopWatchJsonParseExtension = let arg_3 = match node.["issue_index"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["duration"] |> Option.ofObj with @@ -37639,7 +38903,7 @@ module TeamJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["description"] |> Option.ofObj with @@ -37777,12 +39041,12 @@ module TopicResponseJsonParseExtension = let arg_3 = match node.["repo_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["created"] |> Option.ofObj with @@ -37848,10 +39112,10 @@ module TransferRepoOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int64) to be non-null, but found a null element" + "Expected element of array (element type int32) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -38036,7 +39300,7 @@ module UserJsonParseExtension = let arg_18 = match node.["starred_repos_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_17 = match node.["restricted"] |> Option.ofObj with @@ -38081,7 +39345,7 @@ module UserJsonParseExtension = let arg_9 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_8 = match node.["full_name"] |> Option.ofObj with @@ -38091,12 +39355,12 @@ module UserJsonParseExtension = let arg_7 = match node.["following_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["followers_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["email"] |> Option.ofObj with @@ -38204,12 +39468,12 @@ module UserHeatmapDataJsonParseExtension = let arg_2 = match node.["timestamp"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["contributions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -38596,7 +39860,7 @@ module WikiCommitListJsonParseExtension = let arg_2 = match node.["count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["commits"] |> Option.ofObj with @@ -38694,7 +39958,7 @@ module WikiPageJsonParseExtension = let arg_1 = match node.["commit_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -38829,7 +40093,7 @@ module CommentJsonParseExtension = let arg_8 = match node.["original_author_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_7 = match node.["original_author"] |> Option.ofObj with @@ -38844,7 +40108,7 @@ module CommentJsonParseExtension = let arg_5 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["html_url"] |> Option.ofObj with @@ -38963,7 +40227,7 @@ module CommitStatusJsonParseExtension = let arg_5 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["description"] |> Option.ofObj with @@ -39064,7 +40328,7 @@ module ContentsResponseJsonParseExtension = let arg_11 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_10 = match node.["sha"] |> Option.ofObj with @@ -39989,12 +41253,12 @@ module MilestoneJsonParseExtension = let arg_7 = match node.["open_issues"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["due_on"] |> Option.ofObj with @@ -40014,7 +41278,7 @@ module MilestoneJsonParseExtension = let arg_2 = match node.["closed_issues"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["closed_at"] |> Option.ofObj with @@ -40087,12 +41351,12 @@ module NodeInfoUsageJsonParseExtension = let arg_2 = match node.["localPosts"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["localComments"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -40327,7 +41591,7 @@ module PublicKeyJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["fingerprint"] |> Option.ofObj with @@ -40438,7 +41702,7 @@ module PullReviewJsonParseExtension = let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["html_url"] |> Option.ofObj with @@ -40458,7 +41722,7 @@ module PullReviewJsonParseExtension = let arg_2 = match node.["comments_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["body"] |> Option.ofObj with @@ -40554,7 +41818,7 @@ module PullReviewCommentJsonParseExtension = let arg_11 = match node.["pull_request_review_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_10 = match node.["position"] |> Option.ofObj with @@ -40579,7 +41843,7 @@ module PullReviewCommentJsonParseExtension = let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["html_url"] |> Option.ofObj with @@ -40772,7 +42036,7 @@ module ReleaseJsonParseExtension = let arg_7 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["html_url"] |> Option.ofObj with @@ -41098,7 +42362,7 @@ module RepositoryJsonParseExtension = let arg_51 = match node.["watchers_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_50 = match node.["updated_at"] |> Option.ofObj with @@ -41113,7 +42377,7 @@ module RepositoryJsonParseExtension = let arg_48 = match node.["stars_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_47 = match node.["ssh_url"] |> Option.ofObj with @@ -41123,7 +42387,7 @@ module RepositoryJsonParseExtension = let arg_46 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_45 = match node.["repo_transfer"] |> Option.ofObj with @@ -41133,7 +42397,7 @@ module RepositoryJsonParseExtension = let arg_44 = match node.["release_counter"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_43 = match node.["private"] |> Option.ofObj with @@ -41163,12 +42427,12 @@ module RepositoryJsonParseExtension = let arg_38 = match node.["open_pr_counter"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_37 = match node.["open_issues_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_36 = match node.["name"] |> Option.ofObj with @@ -41223,7 +42487,7 @@ module RepositoryJsonParseExtension = let arg_26 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_25 = match node.["html_url"] |> Option.ofObj with @@ -41258,7 +42522,7 @@ module RepositoryJsonParseExtension = let arg_19 = match node.["forks_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_18 = match node.["fork"] |> Option.ofObj with @@ -41650,7 +42914,7 @@ module CombinedStatusJsonParseExtension = let arg_6 = match node.["total_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["statuses"] |> Option.ofObj with @@ -41902,7 +43166,7 @@ module DeployKeyJsonParseExtension = let arg_5 = match node.["key_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["key"] |> Option.ofObj with @@ -41912,7 +43176,7 @@ module DeployKeyJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["fingerprint"] |> Option.ofObj with @@ -42133,7 +43397,7 @@ module IssueJsonParseExtension = let arg_16 = match node.["original_author_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_15 = match node.["original_author"] |> Option.ofObj with @@ -42143,7 +43407,7 @@ module IssueJsonParseExtension = let arg_14 = match node.["number"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_13 = match node.["milestone"] |> Option.ofObj with @@ -42177,7 +43441,7 @@ module IssueJsonParseExtension = let arg_10 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_9 = match node.["html_url"] |> Option.ofObj with @@ -42197,7 +43461,7 @@ module IssueJsonParseExtension = let arg_6 = match node.["comments"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["closed_at"] |> Option.ofObj with @@ -42521,7 +43785,7 @@ module NotificationThreadJsonParseExtension = let arg_1 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -42583,7 +43847,7 @@ module PRBranchInfoJsonParseExtension = let arg_4 = match node.["repo_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["repo"] |> Option.ofObj with @@ -42670,7 +43934,7 @@ module PackageJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["creator"] |> Option.ofObj with @@ -42919,7 +44183,7 @@ module PullRequestJsonParseExtension = let arg_23 = match node.["number"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_22 = match node.["milestone"] |> Option.ofObj with @@ -42983,7 +44247,7 @@ module PullRequestJsonParseExtension = let arg_13 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_12 = match node.["html_url"] |> Option.ofObj with @@ -43013,7 +44277,7 @@ module PullRequestJsonParseExtension = let arg_7 = match node.["comments"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["closed_at"] |> Option.ofObj with @@ -43163,17 +44427,17 @@ module TrackedTimeJsonParseExtension = let arg_6 = match node.["user_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["time"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["issue_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["issue"] |> Option.ofObj with @@ -43183,7 +44447,7 @@ module TrackedTimeJsonParseExtension = let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["created"] |> Option.ofObj with @@ -43274,7 +44538,7 @@ module BranchJsonParseExtension = let arg_6 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["protected"] |> Option.ofObj with @@ -43380,7 +44644,7 @@ module TimelineCommentJsonParseExtension = let arg_25 = match node.["review_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_24 = match node.["resolve_doer"] |> Option.ofObj with @@ -43420,7 +44684,7 @@ module TimelineCommentJsonParseExtension = let arg_17 = match node.["project_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_16 = match node.["old_title"] |> Option.ofObj with @@ -43435,7 +44699,7 @@ module TimelineCommentJsonParseExtension = let arg_14 = match node.["old_project_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_13 = match node.["old_milestone"] |> Option.ofObj with @@ -43470,7 +44734,7 @@ module TimelineCommentJsonParseExtension = let arg_7 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["html_url"] |> Option.ofObj with @@ -43599,7 +44863,7 @@ module LanguageStatisticsJsonParseExtension = /// Parse from a JSON node. static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : LanguageStatistics = let arg_0 = - let result = System.Collections.Generic.Dictionary () + let result = System.Collections.Generic.Dictionary () let node = node.AsObject () for KeyValue (key, value) in node do @@ -43615,7 +44879,7 @@ module LanguageStatisticsJsonParseExtension = sprintf "Required key '%s' not found on JSON object" (key) ) ) - | Some node -> node.AsValue().GetValue () + | Some node -> node.AsValue().GetValue () ) result @@ -43791,7 +45055,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -43858,14 +45121,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -43882,10 +45137,11 @@ module Gitea = ), System.Uri ( ("admin/cron" - + (if queryString = "" then - "" - else - ((if "admin/cron".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "admin/cron".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -43896,7 +45152,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -43975,14 +45230,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -43999,10 +45246,11 @@ module Gitea = ), System.Uri ( ("admin/hooks" - + (if queryString = "" then - "" - else - ((if "admin/hooks".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "admin/hooks".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -44013,7 +45261,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44080,15 +45327,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44113,7 +45357,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.AdminGetHook (id : int64, ct : System.Threading.CancellationToken option) = + member _.AdminGetHook (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -44143,7 +45387,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44168,7 +45411,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.AdminEditHook (id : int64, body : EditHookOption, ct : System.Threading.CancellationToken option) = + member _.AdminEditHook (id : int, body : EditHookOption, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -44200,15 +45443,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44237,14 +45477,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -44261,10 +45493,11 @@ module Gitea = ), System.Uri ( ("admin/orgs" - + (if queryString = "" then - "" - else - ((if "admin/orgs".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "admin/orgs".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -44275,7 +45508,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44319,15 +45551,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - [ "pattern=" + ((pattern.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -44344,14 +45567,16 @@ module Gitea = ), System.Uri ( ("admin/unadopted" - + (if queryString = "" then - "" + + (if "admin/unadopted".IndexOf (char 63) >= 0 then + "&" else - ((if "admin/unadopted".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString) + + "&pattern=" + + ((pattern.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -44362,7 +45587,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44486,14 +45710,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -44510,10 +45726,11 @@ module Gitea = ), System.Uri ( ("admin/users" - + (if queryString = "" then - "" - else - ((if "admin/users".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "admin/users".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -44524,7 +45741,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44591,15 +45807,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateUserOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateUserOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44628,11 +45841,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "purge=" + ((purge.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -44650,14 +45858,12 @@ module Gitea = System.Uri ( ("admin/users/{username}" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "admin/users/{username}".IndexOf (char 63) >= 0 then + "&" else - ((if "admin/users/{username}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "purge=" + + ((purge.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -44710,15 +45916,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditUserOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditUserOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44778,15 +45981,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - key |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()) + key |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44812,7 +46012,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.AdminDeleteUserPublicKey - (username : string, id : int64, ct : System.Threading.CancellationToken option) + (username : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -44887,15 +46087,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()) + organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44955,15 +46152,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - repository |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + repository |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -44988,7 +46182,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.AdminDeleteHook (id : int64, ct : System.Threading.CancellationToken option) = + member _.AdminDeleteHook (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -45054,15 +46248,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> MarkdownOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> MarkdownOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "text/html" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "text/html") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45098,14 +46289,8 @@ module Gitea = RequestUri = uri ) - let queryParams = new System.Net.Http.StringContent (body) - - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("text/plain; charset=utf-8") - + let queryParams = new System.Net.Http.StringContent (body, null, "text/html") do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "text/html") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45141,7 +46326,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45181,28 +46365,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] - - status_types - |> List.map (fun queryParam -> - "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) - ) - - subject_type - |> List.map (fun queryParam -> - "subject-type=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) - ) - - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -45219,10 +46381,21 @@ module Gitea = ), System.Uri ( ("notifications" - + (if queryString = "" then - "" - else - ((if "notifications".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "notifications".IndexOf (char 63) >= 0 then "&" else "?") + + "all=" + + ((all.ToString ()) |> System.Uri.EscapeDataString) + + "&status-types=" + + ((status_types.ToString ()) |> System.Uri.EscapeDataString) + + "&subject-type=" + + ((subject_type.ToString ()) |> System.Uri.EscapeDataString) + + "&since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -45233,7 +46406,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45283,22 +46455,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ - "last_read_at=" + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString) - ] - [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] - - status_types - |> List.map (fun queryParam -> - "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) - ) - [ "to-status=" + ((to_status.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -45315,10 +46471,15 @@ module Gitea = ), System.Uri ( ("notifications" - + (if queryString = "" then - "" - else - ((if "notifications".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "notifications".IndexOf (char 63) >= 0 then "&" else "?") + + "last_read_at=" + + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString) + + "&all=" + + ((all.ToString ()) |> System.Uri.EscapeDataString) + + "&status-types=" + + ((status_types.ToString ()) |> System.Uri.EscapeDataString) + + "&to-status=" + + ((to_status.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -45329,7 +46490,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45394,7 +46554,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45450,7 +46609,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45481,11 +46639,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "to-status=" + ((to_status.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -45503,14 +46656,12 @@ module Gitea = System.Uri ( ("notifications/threads/{id}" .Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "notifications/threads/{id}".IndexOf (char 63) >= 0 then + "&" else - ((if "notifications/threads/{id}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "to-status=" + + ((to_status.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -45521,7 +46672,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45580,15 +46730,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45617,14 +46764,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -45641,10 +46780,11 @@ module Gitea = ), System.Uri ( ("orgs" - + (if queryString = "" then - "" - else - ((if "orgs".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "orgs".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -45655,7 +46795,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45722,15 +46861,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()) + organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45785,7 +46921,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45879,15 +47014,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45918,14 +47050,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -45942,14 +47066,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/hooks".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then + "&" else - ((if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -45960,7 +47084,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46032,15 +47155,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46065,7 +47185,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgGetHook (org : string, id : int64, ct : System.Threading.CancellationToken option) = + member _.OrgGetHook (org : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46097,7 +47217,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46122,7 +47241,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgDeleteHook (org : string, id : int64, ct : System.Threading.CancellationToken option) = + member _.OrgDeleteHook (org : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46162,7 +47281,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgEditHook - (org : string, id : int64, body : EditHookOption, ct : System.Threading.CancellationToken option) + (org : string, id : int, body : EditHookOption, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46197,15 +47316,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46236,14 +47352,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -46260,14 +47368,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/labels".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "orgs/{org}/labels".IndexOf (char 63) >= 0 then + "&" else - ((if "orgs/{org}/labels".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -46278,7 +47386,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46350,15 +47457,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46383,7 +47487,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgGetLabel (org : string, id : int64, ct : System.Threading.CancellationToken option) = + member _.OrgGetLabel (org : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46415,7 +47519,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46440,7 +47543,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgDeleteLabel (org : string, id : int64, ct : System.Threading.CancellationToken option) = + member _.OrgDeleteLabel (org : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46480,7 +47583,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgEditLabel - (org : string, id : int64, body : EditLabelOption, ct : System.Threading.CancellationToken option) + (org : string, id : int, body : EditLabelOption, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46515,15 +47618,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46554,14 +47654,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -46578,14 +47670,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/members".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "orgs/{org}/members".IndexOf (char 63) >= 0 then + "&" else - ((if "orgs/{org}/members".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -46596,7 +47688,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46718,14 +47809,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -46743,14 +47826,14 @@ module Gitea = System.Uri ( ("orgs/{org}/public_members" .Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "orgs/{org}/public_members".IndexOf (char 63) >= 0 then + "&" else - ((if "orgs/{org}/public_members".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -46761,7 +47844,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46928,14 +48010,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -46952,14 +48026,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "orgs/{org}/repos".IndexOf (char 63) >= 0 then + "&" else - ((if "orgs/{org}/repos".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -46970,7 +48044,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47042,15 +48115,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47081,14 +48151,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -47105,14 +48167,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/teams".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "orgs/{org}/teams".IndexOf (char 63) >= 0 then + "&" else - ((if "orgs/{org}/teams".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -47123,7 +48185,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47195,15 +48256,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47241,18 +48299,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] - [ - "include_desc=" + ((include_desc.ToString ()) |> System.Uri.EscapeDataString) - ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -47270,14 +48316,18 @@ module Gitea = System.Uri ( ("orgs/{org}/teams/search" .Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "orgs/{org}/teams/search".IndexOf (char 63) >= 0 then + "&" else - ((if "orgs/{org}/teams/search".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "q=" + + ((q.ToString ()) |> System.Uri.EscapeDataString) + + "&include_desc=" + + ((include_desc.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -47288,7 +48338,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47326,16 +48375,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - [ "type=" + ((type'.ToString ()) |> System.Uri.EscapeDataString) ] - [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -47353,14 +48392,18 @@ module Gitea = System.Uri ( ("packages/{owner}" .Replace ("{owner}", owner.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "packages/{owner}".IndexOf (char 63) >= 0 then + "&" else - ((if "packages/{owner}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString) + + "&type=" + + ((type'.ToString ()) |> System.Uri.EscapeDataString) + + "&q=" + + ((q.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -47371,7 +48414,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47451,7 +48493,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47567,7 +48608,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47611,7 +48651,7 @@ module Gitea = labels : string, milestones : string, q : string, - priority_repo_id : int64, + priority_repo_id : int, type' : string, since : string, before : string, @@ -47629,38 +48669,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] - [ "labels=" + ((labels.ToString ()) |> System.Uri.EscapeDataString) ] - [ "milestones=" + ((milestones.ToString ()) |> System.Uri.EscapeDataString) ] - [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] - - [ - "priority_repo_id=" - + ((priority_repo_id.ToString ()) |> System.Uri.EscapeDataString) - ] - - [ "type=" + ((type'.ToString ()) |> System.Uri.EscapeDataString) ] - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - [ "assigned=" + ((assigned.ToString ()) |> System.Uri.EscapeDataString) ] - [ "created=" + ((created.ToString ()) |> System.Uri.EscapeDataString) ] - [ "mentioned=" + ((mentioned.ToString ()) |> System.Uri.EscapeDataString) ] - - [ - "review_requested=" - + ((review_requested.ToString ()) |> System.Uri.EscapeDataString) - ] - - [ "owner=" + ((owner.ToString ()) |> System.Uri.EscapeDataString) ] - [ "team=" + ((team.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -47677,14 +48685,42 @@ module Gitea = ), System.Uri ( ("repos/issues/search" - + (if queryString = "" then - "" + + (if "repos/issues/search".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/issues/search".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "state=" + + ((state.ToString ()) |> System.Uri.EscapeDataString) + + "&labels=" + + ((labels.ToString ()) |> System.Uri.EscapeDataString) + + "&milestones=" + + ((milestones.ToString ()) |> System.Uri.EscapeDataString) + + "&q=" + + ((q.ToString ()) |> System.Uri.EscapeDataString) + + "&priority_repo_id=" + + ((priority_repo_id.ToString ()) |> System.Uri.EscapeDataString) + + "&type=" + + ((type'.ToString ()) |> System.Uri.EscapeDataString) + + "&since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString) + + "&assigned=" + + ((assigned.ToString ()) |> System.Uri.EscapeDataString) + + "&created=" + + ((created.ToString ()) |> System.Uri.EscapeDataString) + + "&mentioned=" + + ((mentioned.ToString ()) |> System.Uri.EscapeDataString) + + "&review_requested=" + + ((review_requested.ToString ()) |> System.Uri.EscapeDataString) + + "&owner=" + + ((owner.ToString ()) |> System.Uri.EscapeDataString) + + "&team=" + + ((team.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -47695,7 +48731,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47762,15 +48797,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> MigrateRepoOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> MigrateRepoOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47800,10 +48832,10 @@ module Gitea = q : string, topic : bool, includeDesc : bool, - uid : int64, - priority_owner_id : int64, - team_id : int64, - starredBy : int64, + uid : int, + priority_owner_id : int, + team_id : int, + starredBy : int, private' : bool, is_private : bool, template : bool, @@ -47820,34 +48852,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] - [ "topic=" + ((topic.ToString ()) |> System.Uri.EscapeDataString) ] - [ "includeDesc=" + ((includeDesc.ToString ()) |> System.Uri.EscapeDataString) ] - [ "uid=" + ((uid.ToString ()) |> System.Uri.EscapeDataString) ] - - [ - "priority_owner_id=" - + ((priority_owner_id.ToString ()) |> System.Uri.EscapeDataString) - ] - - [ "team_id=" + ((team_id.ToString ()) |> System.Uri.EscapeDataString) ] - [ "starredBy=" + ((starredBy.ToString ()) |> System.Uri.EscapeDataString) ] - [ "private=" + ((private'.ToString ()) |> System.Uri.EscapeDataString) ] - [ "is_private=" + ((is_private.ToString ()) |> System.Uri.EscapeDataString) ] - [ "template=" + ((template.ToString ()) |> System.Uri.EscapeDataString) ] - [ "archived=" + ((archived.ToString ()) |> System.Uri.EscapeDataString) ] - [ "mode=" + ((mode.ToString ()) |> System.Uri.EscapeDataString) ] - [ "exclusive=" + ((exclusive.ToString ()) |> System.Uri.EscapeDataString) ] - [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] - [ "order=" + ((order.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -47864,10 +48868,41 @@ module Gitea = ), System.Uri ( ("repos/search" - + (if queryString = "" then - "" - else - ((if "repos/search".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "repos/search".IndexOf (char 63) >= 0 then "&" else "?") + + "q=" + + ((q.ToString ()) |> System.Uri.EscapeDataString) + + "&topic=" + + ((topic.ToString ()) |> System.Uri.EscapeDataString) + + "&includeDesc=" + + ((includeDesc.ToString ()) |> System.Uri.EscapeDataString) + + "&uid=" + + ((uid.ToString ()) |> System.Uri.EscapeDataString) + + "&priority_owner_id=" + + ((priority_owner_id.ToString ()) |> System.Uri.EscapeDataString) + + "&team_id=" + + ((team_id.ToString ()) |> System.Uri.EscapeDataString) + + "&starredBy=" + + ((starredBy.ToString ()) |> System.Uri.EscapeDataString) + + "&private=" + + ((private'.ToString ()) |> System.Uri.EscapeDataString) + + "&is_private=" + + ((is_private.ToString ()) |> System.Uri.EscapeDataString) + + "&template=" + + ((template.ToString ()) |> System.Uri.EscapeDataString) + + "&archived=" + + ((archived.ToString ()) |> System.Uri.EscapeDataString) + + "&mode=" + + ((mode.ToString ()) |> System.Uri.EscapeDataString) + + "&exclusive=" + + ((exclusive.ToString ()) |> System.Uri.EscapeDataString) + + "&sort=" + + ((sort.ToString ()) |> System.Uri.EscapeDataString) + + "&order=" + + ((order.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -47878,7 +48913,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47935,7 +48969,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48035,15 +49068,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48142,7 +49172,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48214,7 +49243,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48295,15 +49323,12 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateBranchProtectionOption.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48363,7 +49388,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48475,15 +49499,12 @@ module Gitea = new System.Net.Http.StringContent ( body |> EditBranchProtectionOption.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48514,14 +49535,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -48540,14 +49553,14 @@ module Gitea = ("repos/{owner}/{repo}/branches" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/branches".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/branches".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -48558,7 +49571,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48637,15 +49649,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateBranchRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateBranchRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48705,7 +49714,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48778,14 +49786,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -48804,14 +49804,14 @@ module Gitea = ("repos/{owner}/{repo}/collaborators" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/collaborators".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/collaborators".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -48822,7 +49822,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48987,13 +49986,11 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> AddCollaboratorOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> AddCollaboratorOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -49037,7 +50034,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49077,17 +50073,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "sha=" + ((sha.ToString ()) |> System.Uri.EscapeDataString) ] - [ "path=" + ((path.ToString ()) |> System.Uri.EscapeDataString) ] - [ "stat=" + ((stat.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -49106,14 +50091,20 @@ module Gitea = ("repos/{owner}/{repo}/commits" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/commits".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/commits".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "sha=" + + ((sha.ToString ()) |> System.Uri.EscapeDataString) + + "&path=" + + ((path.ToString ()) |> System.Uri.EscapeDataString) + + "&stat=" + + ((stat.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -49124,7 +50115,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49175,14 +50165,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -49202,14 +50184,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{ref}", ref.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/commits/{ref}/status".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/commits/{ref}/status".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -49220,7 +50202,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49260,16 +50241,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] - [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -49289,14 +50260,18 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{ref}", ref.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/commits/{ref}/statuses".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/commits/{ref}/statuses".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "sort=" + + ((sort.ToString ()) |> System.Uri.EscapeDataString) + + "&state=" + + ((state.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -49307,7 +50282,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49351,11 +50325,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -49374,14 +50343,12 @@ module Gitea = ("repos/{owner}/{repo}/contents" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/contents".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/contents".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "ref=" + + ((ref.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -49392,7 +50359,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49442,11 +50408,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -49466,14 +50427,12 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/contents/{filepath}".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/contents/{filepath}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "ref=" + + ((ref.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -49484,7 +50443,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49552,15 +50510,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49628,15 +50583,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> DeleteFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> DeleteFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49704,15 +50656,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49773,15 +50722,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49818,11 +50764,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -49842,14 +50783,12 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/editorconfig/{filepath}".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/editorconfig/{filepath}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "ref=" + + ((ref.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -49873,14 +50812,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -49899,14 +50830,14 @@ module Gitea = ("repos/{owner}/{repo}/forks" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/forks".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/forks".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -49917,7 +50848,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49991,15 +50921,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateForkOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateForkOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50059,7 +50986,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50119,7 +51045,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50186,7 +51111,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50230,7 +51154,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50289,7 +51212,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50362,7 +51284,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50435,7 +51356,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50474,15 +51394,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "recursive=" + ((recursive.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "per_page=" + ((per_page.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -50502,14 +51413,16 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{sha}", sha.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/git/trees/{sha}".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/git/trees/{sha}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "recursive=" + + ((recursive.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&per_page=" + + ((per_page.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -50520,7 +51433,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50551,14 +51463,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -50577,14 +51481,14 @@ module Gitea = ("repos/{owner}/{repo}/hooks" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/hooks".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/hooks".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -50595,7 +51499,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50669,15 +51572,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50734,7 +51634,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50807,7 +51706,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50917,15 +51815,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditGitHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditGitHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50951,7 +51846,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetHook - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -50985,7 +51880,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51011,7 +51905,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeleteHook - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -51056,7 +51950,7 @@ module Gitea = ( owner : string, repo : string, - id : int64, + id : int, body : EditHookOption, ct : System.Threading.CancellationToken option ) @@ -51095,15 +51989,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51129,16 +52020,11 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoTestHook - (owner : string, repo : string, id : int64, ref : string, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ref : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken - let queryString = - [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -51158,14 +52044,12 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/hooks/{id}/tests".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/hooks/{id}/tests".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "ref=" + + ((ref.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -51217,7 +52101,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51277,26 +52160,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] - [ "labels=" + ((labels.ToString ()) |> System.Uri.EscapeDataString) ] - [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] - [ "type=" + ((type'.ToString ()) |> System.Uri.EscapeDataString) ] - [ "milestones=" + ((milestones.ToString ()) |> System.Uri.EscapeDataString) ] - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - [ "created_by=" + ((created_by.ToString ()) |> System.Uri.EscapeDataString) ] - [ "assigned_by=" + ((assigned_by.ToString ()) |> System.Uri.EscapeDataString) ] - [ - "mentioned_by=" + ((mentioned_by.ToString ()) |> System.Uri.EscapeDataString) - ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -51315,14 +52178,34 @@ module Gitea = ("repos/{owner}/{repo}/issues" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/issues".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/issues".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "state=" + + ((state.ToString ()) |> System.Uri.EscapeDataString) + + "&labels=" + + ((labels.ToString ()) |> System.Uri.EscapeDataString) + + "&q=" + + ((q.ToString ()) |> System.Uri.EscapeDataString) + + "&type=" + + ((type'.ToString ()) |> System.Uri.EscapeDataString) + + "&milestones=" + + ((milestones.ToString ()) |> System.Uri.EscapeDataString) + + "&since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString) + + "&created_by=" + + ((created_by.ToString ()) |> System.Uri.EscapeDataString) + + "&assigned_by=" + + ((assigned_by.ToString ()) |> System.Uri.EscapeDataString) + + "&mentioned_by=" + + ((mentioned_by.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -51333,7 +52216,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51407,15 +52289,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51454,16 +52333,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -51482,14 +52351,18 @@ module Gitea = ("repos/{owner}/{repo}/issues/comments" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/issues/comments".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/issues/comments".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -51500,7 +52373,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51539,7 +52411,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteComment - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -51581,7 +52453,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueListIssueCommentAttachments - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -51615,7 +52487,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51657,8 +52528,8 @@ module Gitea = ( owner : string, repo : string, - id : int64, - attachment_id : int64, + id : int, + attachment_id : int, ct : System.Threading.CancellationToken option ) = @@ -51698,7 +52569,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51727,8 +52597,8 @@ module Gitea = ( owner : string, repo : string, - id : int64, - attachment_id : int64, + id : int, + attachment_id : int, ct : System.Threading.CancellationToken option ) = @@ -51779,8 +52649,8 @@ module Gitea = ( owner : string, repo : string, - id : int64, - attachment_id : int64, + id : int, + attachment_id : int, body : EditAttachmentOptions, ct : System.Threading.CancellationToken option ) @@ -51823,15 +52693,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51857,7 +52724,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetCommentReactions - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -51891,7 +52758,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51933,7 +52799,7 @@ module Gitea = ( owner : string, repo : string, - id : int64, + id : int, content : EditReactionOption, ct : System.Threading.CancellationToken option ) @@ -51972,13 +52838,11 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()) + content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -51988,7 +52852,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetIssue - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52022,7 +52886,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52048,7 +52911,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDelete - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52093,7 +52956,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : EditIssueOption, ct : System.Threading.CancellationToken option ) @@ -52132,15 +52995,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52166,7 +53026,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueListIssueAttachments - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52200,7 +53060,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52242,8 +53101,8 @@ module Gitea = ( owner : string, repo : string, - index : int64, - attachment_id : int64, + index : int, + attachment_id : int, ct : System.Threading.CancellationToken option ) = @@ -52283,7 +53142,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52312,8 +53170,8 @@ module Gitea = ( owner : string, repo : string, - index : int64, - attachment_id : int64, + index : int, + attachment_id : int, ct : System.Threading.CancellationToken option ) = @@ -52364,8 +53222,8 @@ module Gitea = ( owner : string, repo : string, - index : int64, - attachment_id : int64, + index : int, + attachment_id : int, body : EditAttachmentOptions, ct : System.Threading.CancellationToken option ) @@ -52408,15 +53266,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52445,7 +53300,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, since : string, before : string, ct : System.Threading.CancellationToken option @@ -52454,14 +53309,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -52481,14 +53328,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/issues/{index}/comments".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/issues/{index}/comments".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -52499,7 +53346,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52541,7 +53387,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : CreateIssueCommentOption, ct : System.Threading.CancellationToken option ) @@ -52582,15 +53428,12 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateIssueCommentOption.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52616,7 +53459,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteCommentDeprecated - (owner : string, repo : string, index : int, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52662,7 +53505,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : EditDeadlineOption, ct : System.Threading.CancellationToken option ) @@ -52701,15 +53544,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditDeadlineOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditDeadlineOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52735,7 +53575,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetLabels - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52769,7 +53609,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52811,7 +53650,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : IssueLabelsOption, ct : System.Threading.CancellationToken option ) @@ -52850,15 +53689,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52897,7 +53733,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueClearLabels - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52942,7 +53778,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : IssueLabelsOption, ct : System.Threading.CancellationToken option ) @@ -52981,15 +53817,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53028,13 +53861,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueRemoveLabel - ( - owner : string, - repo : string, - index : int64, - id : int64, - ct : System.Threading.CancellationToken option - ) + (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53080,7 +53907,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -53089,14 +53916,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -53116,14 +53935,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/issues/{index}/reactions".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/issues/{index}/reactions".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -53134,7 +53953,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53176,7 +53994,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, content : EditReactionOption, ct : System.Threading.CancellationToken option ) @@ -53215,13 +54033,11 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()) + content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -53231,7 +54047,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteStopWatch - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53273,7 +54089,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueStartStopWatch - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53315,7 +54131,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueStopStopWatch - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53360,7 +54176,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -53369,14 +54185,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -53396,16 +54204,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/issues/{index}/subscriptions".IndexOf (char 63) >= 0 then + "&" else - ((if - "repos/{owner}/{repo}/issues/{index}/subscriptions".IndexOf (char 63) >= 0 - then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -53416,7 +54222,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53455,7 +54260,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueCheckSubscription - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53489,7 +54294,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53518,7 +54322,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, since : string, page : int, limit : int, @@ -53529,16 +54333,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -53558,14 +54352,18 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/issues/{index}/timeline".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/issues/{index}/timeline".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -53576,7 +54374,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53618,7 +54415,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, user : string, since : string, before : string, @@ -53630,17 +54427,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "user=" + ((user.ToString ()) |> System.Uri.EscapeDataString) ] - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -53660,14 +54446,20 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/issues/{index}/times".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/issues/{index}/times".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "user=" + + ((user.ToString ()) |> System.Uri.EscapeDataString) + + "&since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -53678,7 +54470,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53720,7 +54511,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : AddTimeOption, ct : System.Threading.CancellationToken option ) @@ -53759,15 +54550,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> AddTimeOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> AddTimeOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53793,7 +54581,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueResetTime - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53835,13 +54623,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteTime - ( - owner : string, - repo : string, - index : int64, - id : int64, - ct : System.Threading.CancellationToken option - ) + (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53897,16 +54679,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "key_id=" + ((key_id.ToString ()) |> System.Uri.EscapeDataString) ] - [ "fingerprint=" + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -53925,14 +54697,18 @@ module Gitea = ("repos/{owner}/{repo}/keys" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/keys".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/keys".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "key_id=" + + ((key_id.ToString ()) |> System.Uri.EscapeDataString) + + "&fingerprint=" + + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -53943,7 +54719,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54017,15 +54792,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54051,7 +54823,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetKey - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54085,7 +54857,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54111,7 +54882,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeleteKey - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54158,14 +54929,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -54184,14 +54947,14 @@ module Gitea = ("repos/{owner}/{repo}/labels" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/labels".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/labels".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -54202,7 +54965,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54276,15 +55038,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54310,7 +55069,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetLabel - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54344,7 +55103,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54370,7 +55128,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteLabel - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54415,7 +55173,7 @@ module Gitea = ( owner : string, repo : string, - id : int64, + id : int, body : EditLabelOption, ct : System.Threading.CancellationToken option ) @@ -54454,15 +55212,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54519,7 +55274,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54556,11 +55310,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -54580,14 +55329,12 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/media/{filepath}".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/media/{filepath}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "ref=" + + ((ref.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -54619,16 +55366,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] - [ "name=" + ((name.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -54647,14 +55384,18 @@ module Gitea = ("repos/{owner}/{repo}/milestones" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/milestones".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/milestones".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "state=" + + ((state.ToString ()) |> System.Uri.EscapeDataString) + + "&name=" + + ((name.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -54665,7 +55406,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54744,15 +55484,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54812,7 +55549,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54922,15 +55658,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55011,28 +55744,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] - - status_types - |> List.map (fun queryParam -> - "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) - ) - - subject_type - |> List.map (fun queryParam -> - "subject-type=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) - ) - - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -55051,14 +55762,24 @@ module Gitea = ("repos/{owner}/{repo}/notifications" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "all=" + + ((all.ToString ()) |> System.Uri.EscapeDataString) + + "&status-types=" + + ((status_types.ToString ()) |> System.Uri.EscapeDataString) + + "&subject-type=" + + ((subject_type.ToString ()) |> System.Uri.EscapeDataString) + + "&since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -55069,7 +55790,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55121,23 +55841,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] - - status_types - |> List.map (fun queryParam -> - "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) - ) - - [ "to-status=" + ((to_status.ToString ()) |> System.Uri.EscapeDataString) ] - [ - "last_read_at=" + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString) - ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -55156,14 +55859,18 @@ module Gitea = ("repos/{owner}/{repo}/notifications" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "all=" + + ((all.ToString ()) |> System.Uri.EscapeDataString) + + "&status-types=" + + ((status_types.ToString ()) |> System.Uri.EscapeDataString) + + "&to-status=" + + ((to_status.ToString ()) |> System.Uri.EscapeDataString) + + "&last_read_at=" + + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -55174,7 +55881,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55218,8 +55924,8 @@ module Gitea = repo : string, state : string, sort : string, - milestone : int64, - labels : int64 list, + milestone : int, + labels : int list, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -55228,23 +55934,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] - [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] - [ "milestone=" + ((milestone.ToString ()) |> System.Uri.EscapeDataString) ] - - labels - |> List.map (fun queryParam -> - "labels=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) - ) - - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -55263,14 +55952,22 @@ module Gitea = ("repos/{owner}/{repo}/pulls" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/pulls".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/pulls".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "state=" + + ((state.ToString ()) |> System.Uri.EscapeDataString) + + "&sort=" + + ((sort.ToString ()) |> System.Uri.EscapeDataString) + + "&milestone=" + + ((milestone.ToString ()) |> System.Uri.EscapeDataString) + + "&labels=" + + ((labels.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -55281,7 +55978,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55360,15 +56056,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreatePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreatePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55394,7 +56087,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetPullRequest - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -55428,7 +56121,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55457,7 +56149,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : EditPullRequestOption, ct : System.Threading.CancellationToken option ) @@ -55496,15 +56188,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditPullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditPullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55533,7 +56222,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, diffType : string, binary : bool, ct : System.Threading.CancellationToken option @@ -55542,11 +56231,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "binary=" + ((binary.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -55567,14 +56251,12 @@ module Gitea = .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace("{index}", index.ToString () |> System.Uri.EscapeDataString) .Replace ("{diffType}", diffType.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/pulls/{index}.{diffType}".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/pulls/{index}.{diffType}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "binary=" + + ((binary.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -55585,7 +56267,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55598,7 +56279,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -55607,14 +56288,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -55634,14 +56307,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/pulls/{index}/commits".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/pulls/{index}/commits".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -55652,7 +56325,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55694,7 +56366,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, skip_to : string, whitespace : string, page : int, @@ -55705,16 +56377,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "skip-to=" + ((skip_to.ToString ()) |> System.Uri.EscapeDataString) ] - [ "whitespace=" + ((whitespace.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -55734,14 +56396,18 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/pulls/{index}/files".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/pulls/{index}/files".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "skip-to=" + + ((skip_to.ToString ()) |> System.Uri.EscapeDataString) + + "&whitespace=" + + ((whitespace.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -55752,7 +56418,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55791,7 +56456,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoPullRequestIsMerged - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -55836,7 +56501,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : MergePullRequestOption, ct : System.Threading.CancellationToken option ) @@ -55875,13 +56540,11 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> MergePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> MergePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -55891,7 +56554,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoCancelScheduledAutoMerge - (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -55936,7 +56599,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : PullReviewRequestOptions, ct : System.Threading.CancellationToken option ) @@ -55977,15 +56640,12 @@ module Gitea = new System.Net.Http.StringContent ( body |> PullReviewRequestOptions.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56027,7 +56687,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : PullReviewRequestOptions, ct : System.Threading.CancellationToken option ) @@ -56068,13 +56728,11 @@ module Gitea = new System.Net.Http.StringContent ( body |> PullReviewRequestOptions.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -56087,7 +56745,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -56096,14 +56754,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -56123,14 +56773,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/pulls/{index}/reviews".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/pulls/{index}/reviews".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -56141,7 +56791,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56183,7 +56832,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, body : CreatePullReviewOptions, ct : System.Threading.CancellationToken option ) @@ -56222,15 +56871,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreatePullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreatePullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56256,13 +56902,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetPullReview - ( - owner : string, - repo : string, - index : int64, - id : int64, - ct : System.Threading.CancellationToken option - ) + (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -56297,7 +56937,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56326,8 +56965,8 @@ module Gitea = ( owner : string, repo : string, - index : int64, - id : int64, + index : int, + id : int, body : SubmitPullReviewOptions, ct : System.Threading.CancellationToken option ) @@ -56367,15 +57006,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> SubmitPullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> SubmitPullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56401,13 +57037,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeletePullReview - ( - owner : string, - repo : string, - index : int64, - id : int64, - ct : System.Threading.CancellationToken option - ) + (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -56450,13 +57080,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetPullReviewComments - ( - owner : string, - repo : string, - index : int64, - id : int64, - ct : System.Threading.CancellationToken option - ) + (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -56491,7 +57115,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56533,8 +57156,8 @@ module Gitea = ( owner : string, repo : string, - index : int64, - id : int64, + index : int, + id : int, body : DismissPullReviewOptions, ct : System.Threading.CancellationToken option ) @@ -56576,15 +57199,12 @@ module Gitea = new System.Net.Http.StringContent ( body |> DismissPullReviewOptions.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56610,13 +57230,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoUnDismissPullReview - ( - owner : string, - repo : string, - index : int64, - id : int64, - ct : System.Threading.CancellationToken option - ) + (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -56651,7 +57265,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56680,7 +57293,7 @@ module Gitea = ( owner : string, repo : string, - index : int64, + index : int, style : string, ct : System.Threading.CancellationToken option ) @@ -56688,11 +57301,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "style=" + ((style.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -56712,14 +57320,12 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/pulls/{index}/update".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/pulls/{index}/update".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "style=" + + ((style.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -56743,14 +57349,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -56769,14 +57367,14 @@ module Gitea = ("repos/{owner}/{repo}/push_mirrors" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/push_mirrors".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/push_mirrors".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -56787,7 +57385,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56866,15 +57463,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreatePushMirrorOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreatePushMirrorOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56975,7 +57569,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57054,11 +57647,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -57078,14 +57666,12 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/raw/{filepath}".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/raw/{filepath}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "ref=" + + ((ref.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -57118,17 +57704,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "draft=" + ((draft.ToString ()) |> System.Uri.EscapeDataString) ] - [ "pre-release=" + ((pre_release.ToString ()) |> System.Uri.EscapeDataString) ] - [ "per_page=" + ((per_page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -57147,14 +57722,20 @@ module Gitea = ("repos/{owner}/{repo}/releases" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/releases".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/releases".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "draft=" + + ((draft.ToString ()) |> System.Uri.EscapeDataString) + + "&pre-release=" + + ((pre_release.ToString ()) |> System.Uri.EscapeDataString) + + "&per_page=" + + ((per_page.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -57165,7 +57746,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57244,15 +57824,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57311,7 +57888,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57371,7 +57947,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57439,7 +58014,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetRelease - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -57473,7 +58048,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57499,7 +58073,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeleteRelease - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -57544,7 +58118,7 @@ module Gitea = ( owner : string, repo : string, - id : int64, + id : int, body : EditReleaseOption, ct : System.Threading.CancellationToken option ) @@ -57583,15 +58157,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57617,7 +58188,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoListReleaseAttachments - (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -57651,7 +58222,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57693,8 +58263,8 @@ module Gitea = ( owner : string, repo : string, - id : int64, - attachment_id : int64, + id : int, + attachment_id : int, ct : System.Threading.CancellationToken option ) = @@ -57734,7 +58304,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57763,8 +58332,8 @@ module Gitea = ( owner : string, repo : string, - id : int64, - attachment_id : int64, + id : int, + attachment_id : int, ct : System.Threading.CancellationToken option ) = @@ -57815,8 +58384,8 @@ module Gitea = ( owner : string, repo : string, - id : int64, - attachment_id : int64, + id : int, + attachment_id : int, body : EditAttachmentOptions, ct : System.Threading.CancellationToken option ) @@ -57859,15 +58428,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57924,7 +58490,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57994,7 +58559,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58009,14 +58573,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -58035,14 +58591,14 @@ module Gitea = ("repos/{owner}/{repo}/stargazers" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/stargazers".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/stargazers".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -58053,7 +58609,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58106,16 +58661,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] - [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -58135,14 +58680,18 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{sha}", sha.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/statuses/{sha}".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/statuses/{sha}".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "sort=" + + ((sort.ToString ()) |> System.Uri.EscapeDataString) + + "&state=" + + ((state.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -58153,7 +58702,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58234,15 +58782,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateStatusOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateStatusOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58273,14 +58818,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -58299,14 +58836,14 @@ module Gitea = ("repos/{owner}/{repo}/subscribers" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/subscribers".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/subscribers".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -58317,7 +58854,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58389,7 +58925,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58489,7 +59024,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58520,14 +59054,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -58546,14 +59072,14 @@ module Gitea = ("repos/{owner}/{repo}/tags" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/tags".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/tags".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -58564,7 +59090,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58638,15 +59163,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateTagOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateTagOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58706,7 +59228,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58805,7 +59326,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58878,7 +59398,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59002,17 +59521,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "user=" + ((user.ToString ()) |> System.Uri.EscapeDataString) ] - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -59031,14 +59539,20 @@ module Gitea = ("repos/{owner}/{repo}/times" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/times".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/times".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "user=" + + ((user.ToString ()) |> System.Uri.EscapeDataString) + + "&since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -59049,7 +59563,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59122,7 +59635,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59166,14 +59678,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -59192,14 +59696,14 @@ module Gitea = ("repos/{owner}/{repo}/topics" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/topics".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/topics".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -59210,7 +59714,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59271,13 +59774,11 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> RepoTopicOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> RepoTopicOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -59411,15 +59912,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> TransferRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> TransferRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59478,7 +59976,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59537,7 +60034,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59603,15 +60099,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59671,7 +60164,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59781,15 +60273,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59820,14 +60309,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -59846,14 +60327,14 @@ module Gitea = ("repos/{owner}/{repo}/wiki/pages" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/wiki/pages".IndexOf (char 63) >= 0 then + "&" else - ((if "repos/{owner}/{repo}/wiki/pages".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -59864,7 +60345,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59914,11 +60394,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -59938,16 +60413,12 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{pageName}", pageName.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "repos/{owner}/{repo}/wiki/revisions/{pageName}".IndexOf (char 63) >= 0 then + "&" else - ((if - "repos/{owner}/{repo}/wiki/revisions/{pageName}".IndexOf (char 63) >= 0 - then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -59958,7 +60429,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60030,15 +60500,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> GenerateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> GenerateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60063,7 +60530,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.RepoGetByID (id : int64, ct : System.Threading.CancellationToken option) = + member _.RepoGetByID (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60093,7 +60560,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60145,7 +60611,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60197,7 +60662,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60249,7 +60713,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60301,7 +60764,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60353,7 +60815,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60362,7 +60823,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgGetTeam (id : int64, ct : System.Threading.CancellationToken option) = + member _.OrgGetTeam (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60392,7 +60853,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60417,7 +60877,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgDeleteTeam (id : int64, ct : System.Threading.CancellationToken option) = + member _.OrgDeleteTeam (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60486,15 +60946,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> EditTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60520,19 +60977,11 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgListTeamMembers - (id : int64, page : int, limit : int, ct : System.Threading.CancellationToken option) + (id : int, page : int, limit : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -60549,14 +60998,14 @@ module Gitea = ), System.Uri ( ("teams/{id}/members".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "teams/{id}/members".IndexOf (char 63) >= 0 then + "&" else - ((if "teams/{id}/members".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -60567,7 +61016,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60605,7 +61053,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgListTeamMember (id : int64, username : string, ct : System.Threading.CancellationToken option) = + member _.OrgListTeamMember (id : int, username : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60637,7 +61085,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60662,9 +61109,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgRemoveTeamMember - (id : int64, username : string, ct : System.Threading.CancellationToken option) - = + member _.OrgRemoveTeamMember (id : int, username : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60703,7 +61148,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgAddTeamMember (id : int64, username : string, ct : System.Threading.CancellationToken option) = + member _.OrgAddTeamMember (id : int, username : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60743,19 +61188,11 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgListTeamRepos - (id : int64, page : int, limit : int, ct : System.Threading.CancellationToken option) + (id : int, page : int, limit : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -60772,14 +61209,14 @@ module Gitea = ), System.Uri ( ("teams/{id}/repos".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "teams/{id}/repos".IndexOf (char 63) >= 0 then + "&" else - ((if "teams/{id}/repos".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -60790,7 +61227,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60829,7 +61265,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgListTeamRepo - (id : int64, org : string, repo : string, ct : System.Threading.CancellationToken option) + (id : int, org : string, repo : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60863,7 +61299,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60889,7 +61324,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgRemoveTeamRepository - (id : int64, org : string, repo : string, ct : System.Threading.CancellationToken option) + (id : int, org : string, repo : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60931,7 +61366,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgAddTeamRepository - (id : int64, org : string, repo : string, ct : System.Threading.CancellationToken option) + (id : int, org : string, repo : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60976,15 +61411,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -61001,10 +61427,13 @@ module Gitea = ), System.Uri ( ("topics/search" - + (if queryString = "" then - "" - else - ((if "topics/search".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "topics/search".IndexOf (char 63) >= 0 then "&" else "?") + + "q=" + + ((q.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -61015,7 +61444,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61080,7 +61508,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61111,14 +61538,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -61135,14 +61554,14 @@ module Gitea = ), System.Uri ( ("user/applications/oauth2" - + (if queryString = "" then - "" + + (if "user/applications/oauth2".IndexOf (char 63) >= 0 then + "&" else - ((if "user/applications/oauth2".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -61153,7 +61572,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61224,15 +61642,12 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateOAuth2ApplicationOptions.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61257,7 +61672,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserGetOAuth2Application (id : int64, ct : System.Threading.CancellationToken option) = + member _.UserGetOAuth2Application (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61288,7 +61703,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61313,7 +61727,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserDeleteOAuth2Application (id : int64, ct : System.Threading.CancellationToken option) = + member _.UserDeleteOAuth2Application (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61352,7 +61766,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.UserUpdateOAuth2Application - (id : int64, body : CreateOAuth2ApplicationOptions, ct : System.Threading.CancellationToken option) + (id : int, body : CreateOAuth2ApplicationOptions, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61388,15 +61802,12 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateOAuth2ApplicationOptions.toJsonNode - |> (fun node -> node.ToJsonString ()) + |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61448,7 +61859,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61515,15 +61925,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61590,13 +61997,11 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> DeleteEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> DeleteEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -61611,14 +62016,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -61635,10 +62032,11 @@ module Gitea = ), System.Uri ( ("user/followers" - + (if queryString = "" then - "" - else - ((if "user/followers".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/followers".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -61649,7 +62047,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61693,14 +62090,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -61717,10 +62106,11 @@ module Gitea = ), System.Uri ( ("user/following" - + (if queryString = "" then - "" - else - ((if "user/following".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/following".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -61731,7 +62121,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61910,7 +62299,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61919,7 +62307,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserCurrentDeleteGPGKey (id : int64, ct : System.Threading.CancellationToken option) = + member _.UserCurrentDeleteGPGKey (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61962,15 +62350,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "fingerprint=" + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -61987,10 +62366,13 @@ module Gitea = ), System.Uri ( ("user/keys" - + (if queryString = "" then - "" - else - ((if "user/keys".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/keys".IndexOf (char 63) >= 0 then "&" else "?") + + "fingerprint=" + + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -62001,7 +62383,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62068,15 +62449,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62101,7 +62479,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserCurrentGetKey (id : int64, ct : System.Threading.CancellationToken option) = + member _.UserCurrentGetKey (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -62131,7 +62509,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62156,7 +62533,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserCurrentDeleteKey (id : int64, ct : System.Threading.CancellationToken option) = + member _.UserCurrentDeleteKey (id : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -62197,14 +62574,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -62221,10 +62590,11 @@ module Gitea = ), System.Uri ( ("user/orgs" - + (if queryString = "" then - "" - else - ((if "user/orgs".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/orgs".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -62235,7 +62605,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62277,14 +62646,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -62301,10 +62662,11 @@ module Gitea = ), System.Uri ( ("user/repos" - + (if queryString = "" then - "" - else - ((if "user/repos".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/repos".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -62315,7 +62677,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62382,15 +62743,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62442,7 +62800,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62509,15 +62866,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> UserSettingsOptions.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> UserSettingsOptions.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62559,14 +62913,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -62583,10 +62929,11 @@ module Gitea = ), System.Uri ( ("user/starred" - + (if queryString = "" then - "" - else - ((if "user/starred".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/starred".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -62597,7 +62944,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62762,14 +63108,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -62786,14 +63124,14 @@ module Gitea = ), System.Uri ( ("user/stopwatches" - + (if queryString = "" then - "" + + (if "user/stopwatches".IndexOf (char 63) >= 0 then + "&" else - ((if "user/stopwatches".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -62804,7 +63142,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62848,14 +63185,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -62872,14 +63201,14 @@ module Gitea = ), System.Uri ( ("user/subscriptions" - + (if queryString = "" then - "" + + (if "user/subscriptions".IndexOf (char 63) >= 0 then + "&" else - ((if "user/subscriptions".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -62890,7 +63219,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62932,14 +63260,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -62956,10 +63276,11 @@ module Gitea = ), System.Uri ( ("user/teams" - + (if queryString = "" then - "" - else - ((if "user/teams".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/teams".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -62970,7 +63291,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63020,16 +63340,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] - [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63046,10 +63356,15 @@ module Gitea = ), System.Uri ( ("user/times" - + (if queryString = "" then - "" - else - ((if "user/times".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "user/times".IndexOf (char 63) >= 0 then "&" else "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString) + + "&since=" + + ((since.ToString ()) |> System.Uri.EscapeDataString) + + "&before=" + + ((before.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63060,7 +63375,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63099,21 +63413,11 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.UserSearch - (q : string, uid : int64, page : int, limit : int, ct : System.Threading.CancellationToken option) + (q : string, uid : int, page : int, limit : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] - [ "uid=" + ((uid.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63130,10 +63434,15 @@ module Gitea = ), System.Uri ( ("users/search" - + (if queryString = "" then - "" - else - ((if "users/search".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), + + (if "users/search".IndexOf (char 63) >= 0 then "&" else "?") + + "q=" + + ((q.ToString ()) |> System.Uri.EscapeDataString) + + "&uid=" + + ((uid.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63144,7 +63453,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63200,7 +63508,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63231,14 +63538,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63256,14 +63555,14 @@ module Gitea = System.Uri ( ("users/{username}/followers" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/followers".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/followers".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63274,7 +63573,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63318,14 +63616,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63343,14 +63633,14 @@ module Gitea = System.Uri ( ("users/{username}/following" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/following".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/following".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63361,7 +63651,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63471,7 +63760,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63521,15 +63809,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "fingerprint=" + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) ] - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63547,14 +63826,16 @@ module Gitea = System.Uri ( ("users/{username}/keys" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/keys".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/keys".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "fingerprint=" + + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) + + "&page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63565,7 +63846,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63609,14 +63889,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63634,14 +63906,14 @@ module Gitea = System.Uri ( ("users/{username}/orgs" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/orgs".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/orgs".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63652,7 +63924,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63724,7 +63995,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63755,14 +64025,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63780,14 +64042,14 @@ module Gitea = System.Uri ( ("users/{username}/repos" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/repos".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/repos".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63798,7 +64060,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63842,14 +64103,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63867,14 +64120,14 @@ module Gitea = System.Uri ( ("users/{username}/starred" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/starred".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/starred".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63885,7 +64138,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63929,14 +64181,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -63954,14 +64198,14 @@ module Gitea = System.Uri ( ("users/{username}/subscriptions" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/subscriptions".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/subscriptions".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -63972,7 +64216,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64016,14 +64259,6 @@ module Gitea = async { let! ct = Async.CancellationToken - let queryString = - [ - [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] - [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] - ] - |> List.concat - |> String.concat "&" - let uri = System.Uri ( System.Uri ( @@ -64041,14 +64276,14 @@ module Gitea = System.Uri ( ("users/{username}/tokens" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if queryString = "" then - "" + + (if "users/{username}/tokens".IndexOf (char 63) >= 0 then + "&" else - ((if "users/{username}/tokens".IndexOf (char 63) >= 0 then - "&" - else - "?") - + queryString))), + "?") + + "page=" + + ((page.ToString ()) |> System.Uri.EscapeDataString) + + "&limit=" + + ((limit.ToString ()) |> System.Uri.EscapeDataString)), System.UriKind.Relative ) ) @@ -64059,7 +64294,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64132,15 +64366,12 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateAccessTokenOption.toJsonNode |> (fun node -> node.ToJsonString ()) + body |> CreateAccessTokenOption.toJsonNode |> (fun node -> node.ToJsonString ()), + null, + "application/json" ) - do - queryParams.Headers.ContentType <- - System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") - do httpMessage.Content <- queryParams - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64233,7 +64464,6 @@ module Gitea = RequestUri = uri ) - do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response diff --git a/ConsumePlugin/GeneratedSerde.fs b/ConsumePlugin/GeneratedSerde.fs index f3ba4a7b..08d63384 100644 --- a/ConsumePlugin/GeneratedSerde.fs +++ b/ConsumePlugin/GeneratedSerde.fs @@ -757,7 +757,15 @@ module CollectRemainingJsonSerializeExtension = ) for KeyValue (key, value) in input.Rest do - node.Add (key, (fun node -> (node : System.Text.Json.Nodes.JsonNode).DeepClone ()) value) + node.Add ( + key, + (fun node -> + match node |> box with + | null -> Unchecked.defaultof + | _ -> (node : System.Text.Json.Nodes.JsonNode).DeepClone () + ) + value + ) node :> _ namespace ConsumePlugin diff --git a/WoofWare.Myriad.Plugins.Test/TestJsonSerialize/TestJsonSerde.fs b/WoofWare.Myriad.Plugins.Test/TestJsonSerialize/TestJsonSerde.fs index da2a3f0d..36c7c0f8 100644 --- a/WoofWare.Myriad.Plugins.Test/TestJsonSerialize/TestJsonSerde.fs +++ b/WoofWare.Myriad.Plugins.Test/TestJsonSerialize/TestJsonSerde.fs @@ -457,6 +457,36 @@ module TestJsonSerde = CollectRemainingNullable.toJsonNode(toWrite).ToJsonString () |> shouldEqual """{"present":3,"absent":null}""" + [] + let ``Null extension data is written as JSON null`` () = + let toWrite = + { + Rest = [ "nothing", Unchecked.defaultof ] |> dict + Message = None + } + + CollectRemaining.toJsonNode(toWrite).ToJsonString () + |> shouldEqual """{"message":null,"nothing":null}""" + + [] + let ``Null serialization failures identify the parameter and explain the invariant`` () = + let toWrite = + { + Header = Unchecked.defaultof + Value = "value" + } + + let error = + Assert.Throws (fun () -> HeaderAndValue.toJsonNode toWrite |> ignore) + + error.ParamName |> shouldEqual "field" + + error.Message.Contains ( + "Expected type string to be non-null, but received a null value when serialising", + StringComparison.Ordinal + ) + |> shouldEqual true + [] let ``Can collect extension data, nested`` () = let str = diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs index 0da67b9f..2fb97e60 100644 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs @@ -93,8 +93,8 @@ module TestOpenApi3Client = message.Content.Headers.ContentType.MediaType |> shouldEqual "application/json" let! requestBody = message.Content.ReadAsStringAsync () |> Async.AwaitTask - requestBody |> shouldEqual "null" - return response HttpStatusCode.OK (Some "null") + JsonNode.Parse requestBody |> ignore + return response HttpStatusCode.OK (Some requestBody) | "GET", "https://api.example.test/v1/public/counter" -> message.Headers.Accept |> Seq.exactlyOne @@ -166,6 +166,14 @@ module TestOpenApi3Client = let! anything = client.EchoAnything None anything |> shouldEqual None + let anythingBody = JsonNode.Parse """{"nested":[1,null,"value"]}""" + let! echoedAnything = client.EchoAnything (Some anythingBody) + + JsonNode.DeepEquals (echoedAnything |> Option.get, anythingBody) + |> shouldEqual true + + isNull anythingBody.Parent |> shouldEqual true + let! counter = client.GetCounter () counter |> shouldEqual (BigInteger.Pow (10I, 30)) @@ -174,7 +182,7 @@ module TestOpenApi3Client = let! echoedCounter = client.EchoCounter counter echoedCounter |> shouldEqual counter - calls |> shouldEqual 10 + calls |> shouldEqual 11 } [] diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs index 34746a7c..fb16e07f 100644 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs @@ -871,6 +871,179 @@ module TestOpenApi3Generator = ) |> shouldEqual true + [] + let ``Parameterized JSON media types use their base media type and JSON schema`` () = + let responseMediaType = "application/problem+json; charset=utf-8" + let requestMediaType = "application/json; charset=utf-8" + + let operation = + jsonObject + [ + "operationId", jsonString "createThing" + "requestBody", + jsonObject + [ + "required", jsonBool true + "content", + jsonObject + [ + requestMediaType, + jsonObject [ "schema", schemaForScalar GeneratedScalar.Int64 false ] + ] + ] + "responses", + jsonObject + [ + "200", + jsonObject + [ + "description", jsonString "success" + "content", + jsonObject + [ + responseMediaType, + jsonObject [ "schema", schemaForScalar GeneratedScalar.Int64 false ] + ] + ] + ] + ] + + let source = document "3.0.3" [] "/things" (jsonObject [ "post", operation ]) + let actual = plan source |> _.Operations |> List.exactlyOne + + actual.RequestContentType |> shouldEqual (Some "application/json") + actual.Accept |> shouldEqual (Some "application/problem+json") + + actual.Parameters + |> List.exactlyOne + |> _.Type + |> shouldEqual (OpenApiPlannedType.Primitive OpenApiPrimitive.Int64) + + actual.ReturnType + |> shouldEqual (OpenApiPlannedType.Primitive OpenApiPrimitive.Int64) + + [] + let ``Unsupported media diagnostics list the content keys`` () = + let response = + jsonObject + [ + "description", jsonString "success" + "content", jsonObject [ "application/xml", jsonObject [] ; "image/png", jsonObject [] ] + ] + + let source = document "3.0.3" [] "/things" (standardPathItem response [] []) + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly accepted unsupported response media" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedOperation + && diagnostic.Message.Contains ("application/xml", StringComparison.Ordinal) + && diagnostic.Message.Contains ("image/png", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Additional document servers are diagnosed instead of silently ignored`` () = + let source = + jsonObject + [ + "openapi", jsonString "3.0.3" + "info", jsonObject [ "title", jsonString "API" ; "version", jsonString "1" ] + "servers", + jsonArray + [ + jsonObject [ "url", jsonString "https://first.example" ] + jsonObject [ "url", jsonString "https://second.example" ] + ] + "paths", jsonObject [] + "components", jsonObject [ "schemas", jsonObject [] ] + ] + |> _.ToJsonString() + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly ignored additional document servers" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedOperation + && diagnostic.Location = "#/servers" + && diagnostic.Message.Contains ("first", StringComparison.OrdinalIgnoreCase) + ) + |> shouldEqual true + + [] + let ``Generated types cannot shadow namespaces used by emitted code`` () = + let objectSchema fieldName = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ fieldName, schemaForScalar GeneratedScalar.String false ] + ] + + let schemas = + [ + "System", objectSchema "systemValue" + "RestEase", objectSchema "restEaseValue" + "WoofWare", objectSchema "woofWareValue" + "GeneratedClient", objectSchema "clientValue" + ] + + let actual = + document "3.0.3" schemas "/things" (standardPathItem (noContentResponse ()) [] []) + |> plan + + actual.Types + |> List.map (fun definition -> definition.SourceName, definition.FSharpName) + |> Map.ofList + |> shouldEqual ( + Map + [ + "GeneratedClient", "GeneratedClient2" + "RestEase", "RestEase2" + "System", "System2" + "WoofWare", "WoofWare2" + ] + ) + + [] + let ``Fallback operation ids participate in duplicate detection`` () = + let operation operationId = + jsonObject + [ + match operationId with + | None -> () + | Some value -> "operationId", jsonString value + "responses", jsonObject [ "200", noContentResponse () ] + ] + + let source = + jsonObject + [ + "openapi", jsonString "3.0.3" + "info", jsonObject [ "title", jsonString "API" ; "version", jsonString "1" ] + "paths", + jsonObject + [ + "/other", jsonObject [ "get", operation (Some "get-/things") ] + "/things", jsonObject [ "get", operation None ] + ] + "components", jsonObject [ "schemas", jsonObject [] ] + ] + |> _.ToJsonString() + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly accepted colliding explicit and fallback operation ids" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.InvalidDocument + && diagnostic.Message.Contains ("get-/things", StringComparison.Ordinal) + && diagnostic.Message.Contains ("duplicated", StringComparison.Ordinal) + ) + |> shouldEqual true + [] let ``Unsupported composition keywords on named objects are not bypassed by references`` () = let schema = diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Parse.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Parse.fs deleted file mode 100644 index add81e77..00000000 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Parse.fs +++ /dev/null @@ -1,3503 +0,0 @@ -namespace WoofWare.Myriad.Plugins.Test - -open WoofWare.Myriad.Plugins.OpenApi3 -open System.Text.Json.Nodes -open NUnit.Framework -open WoofWare.Expect - -[] -[] -module TestOpenApi3Parse = - [] - let ``Prepare to bulk-update tests`` () = - // GlobalBuilderConfig.enterBulkUpdateMode () - () - - [] - let ``Update all tests`` () = - GlobalBuilderConfig.updateAllSnapshots () - - type Dummy = class end - - [] - let ``API with examples`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "api-with-examples.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.0.0"", - ""Info"": { - ""Title"": ""Simple API overview"", - ""Description"": null, - ""TermsOfService"": null, - ""Contact"": null, - ""License"": null, - ""Version"": ""2.0.0"" - }, - ""Servers"": null, - ""Paths"": { - ""Fields"": { - ""/"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": ""List API versions"", - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""listVersionsv2"", - ""Parameters"": null, - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""200 response"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": null, - ""Example"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""foo"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Summary"": null, - ""Description"": null, - ""Value"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""versions"": [ - { - ""status"": ""CURRENT"", - ""updated"": ""2011-01-21T11:33:21Z"", - ""id"": ""v2.0"", - ""links"": [ - { - ""href"": ""http://127.0.0.1:8774/v2/"", - ""rel"": ""self"" - } - ] - }, - { - ""status"": ""EXPERIMENTAL"", - ""updated"": ""2013-07-23T11:33:21Z"", - ""id"": ""v3.0"", - ""links"": [ - { - ""href"": ""http://127.0.0.1:8774/v3/"", - ""rel"": ""self"" - } - ] - } - ] - } - ] - } - } - ] - } - } - ] - }, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""300"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""300 response"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": null, - ""Example"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""foo"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Summary"": null, - ""Description"": null, - ""Value"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""versions"": [ - { - ""status"": ""CURRENT"", - ""updated"": ""2011-01-21T11:33:21Z"", - ""id"": ""v2.0"", - ""links"": [ - { - ""href"": ""http://127.0.0.1:8774/v2/"", - ""rel"": ""self"" - } - ] - }, - { - ""status"": ""EXPERIMENTAL"", - ""updated"": ""2013-07-23T11:33:21Z"", - ""id"": ""v3.0"", - ""links"": [ - { - ""href"": ""http://127.0.0.1:8774/v3/"", - ""rel"": ""self"" - } - ] - } - ] - } - ] - } - } - ] - } - } - ] - }, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/v2"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": ""Show API version details"", - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""getVersionDetailsv2"", - ""Parameters"": null, - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""200 response"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": null, - ""Example"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""foo"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Summary"": null, - ""Description"": null, - ""Value"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""version"": { - ""status"": ""CURRENT"", - ""updated"": ""2011-01-21T11:33:21Z"", - ""media-types"": [ - { - ""base"": ""application/xml"", - ""type"": ""application/vnd.openstack.compute\u002Bxml;version=2"" - }, - { - ""base"": ""application/json"", - ""type"": ""application/vnd.openstack.compute\u002Bjson;version=2"" - } - ], - ""id"": ""v2.0"", - ""links"": [ - { - ""href"": ""http://127.0.0.1:8774/v2/"", - ""rel"": ""self"" - }, - { - ""href"": ""http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf"", - ""type"": ""application/pdf"", - ""rel"": ""describedby"" - }, - { - ""href"": ""http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl"", - ""type"": ""application/vnd.sun.wadl\u002Bxml"", - ""rel"": ""describedby"" - }, - { - ""href"": ""http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl"", - ""type"": ""application/vnd.sun.wadl\u002Bxml"", - ""rel"": ""describedby"" - } - ] - } - } - ] - } - } - ] - } - } - ] - }, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""203"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""203 response"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": null, - ""Example"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""foo"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Summary"": null, - ""Description"": null, - ""Value"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""version"": { - ""status"": ""CURRENT"", - ""updated"": ""2011-01-21T11:33:21Z"", - ""media-types"": [ - { - ""base"": ""application/xml"", - ""type"": ""application/vnd.openstack.compute\u002Bxml;version=2"" - }, - { - ""base"": ""application/json"", - ""type"": ""application/vnd.openstack.compute\u002Bjson;version=2"" - } - ], - ""id"": ""v2.0"", - ""links"": [ - { - ""href"": ""http://23.253.228.211:8774/v2/"", - ""rel"": ""self"" - }, - { - ""href"": ""http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf"", - ""type"": ""application/pdf"", - ""rel"": ""describedby"" - }, - { - ""href"": ""http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl"", - ""type"": ""application/vnd.sun.wadl\u002Bxml"", - ""rel"": ""describedby"" - } - ] - } - } - ] - } - } - ] - } - } - ] - }, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - }, - ""Components"": null, - ""Security"": null, - ""Tags"": null, - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``Callback example`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "callback-example.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.0.0"", - ""Info"": { - ""Title"": ""Callback Example"", - ""Description"": null, - ""TermsOfService"": null, - ""Contact"": null, - ""License"": null, - ""Version"": ""1.0.0"" - }, - ""Servers"": null, - ""Paths"": { - ""Fields"": { - ""/streams"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": null, - ""Put"": null, - ""Post"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": ""subscribes a client to receive out-of-band data"", - ""ExternalDocs"": null, - ""OperationId"": null, - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""callbackUrl"", - ""In"": { - ""Case"": ""Query"" - }, - ""Description"": ""the location where data will be sent. Must be network accessible\nby the source server\n"", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""201"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""subscription successfully created"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": { - ""onData"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Patterns"": { - ""{$request.query.callbackUrl}/data"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": null, - ""Put"": null, - ""Post"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": null, - ""Parameters"": null, - ""RequestBody"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""subscription payload"", - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Required"": null - } - ] - }, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""202"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""Your server implementation should return this HTTP status code\nif the data was received successfully\n"", - ""Headers"": null, - ""Content"": null, - ""Links"": null - } - ] - }, - ""204"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""Your server should return this HTTP status code if no longer interested\nin further updates\n"", - ""Headers"": null, - ""Content"": null, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - } - ] - } - }, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - }, - ""Components"": null, - ""Security"": null, - ""Tags"": null, - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``Link example`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "link-example.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.0.0"", - ""Info"": { - ""Title"": ""Link Example"", - ""Description"": null, - ""TermsOfService"": null, - ""Contact"": null, - ""License"": null, - ""Version"": ""1.0.0"" - }, - ""Servers"": null, - ""Paths"": { - ""Fields"": { - ""/2.0/repositories/{username}"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""getRepositoriesByOwner"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""username"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""repositories owned by the supplied user"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": { - ""userRepository"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/links/UserRepository"" - } - ] - } - } - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/2.0/repositories/{username}/{slug}"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""getRepository"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""username"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""slug"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""The repository"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/repository"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": { - ""repositoryPullRequests"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/links/RepositoryPullRequests"" - } - ] - } - } - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/2.0/repositories/{username}/{slug}/pullrequests"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""getPullRequestsByRepository"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""username"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""slug"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""state"", - ""In"": { - ""Case"": ""Query"" - }, - ""Description"": null, - ""Required"": null, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""an array of pull request objects"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/2.0/repositories/{username}/{slug}/pullrequests/{pid}"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""getPullRequestsById"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""username"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""slug"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""pid"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""a pull request object"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/pullrequest"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": { - ""pullRequestMerge"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/links/PullRequestMerge"" - } - ] - } - } - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/2.0/repositories/{username}/{slug}/pullrequests/{pid}/merge"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": null, - ""Put"": null, - ""Post"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""mergePullRequest"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""username"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""slug"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""pid"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""204"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""the PR was successfully merged"", - ""Headers"": null, - ""Content"": null, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/2.0/users/{username}"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""getUserByName"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""username"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": null, - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""The User"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/user"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": { - ""userRepositories"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/links/UserRepositories"" - } - ] - } - } - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - }, - ""Components"": { - ""Schemas"": { - ""pullrequest"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""repository"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""user"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - } - }, - ""Responses"": null, - ""Parameters"": null, - ""Examples"": null, - ""RequestBodies"": null, - ""Headers"": null, - ""SecuritySchemes"": null, - ""Links"": { - ""PullRequestMerge"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Operation"": { - ""Case"": ""Id"", - ""Fields"": [ - ""mergePullRequest"" - ] - }, - ""Parameters"": { - ""pid"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/id"" - ] - }, - ""slug"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/repository/slug"" - ] - }, - ""username"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/author/username"" - ] - } - }, - ""RequestBody"": null, - ""Description"": null, - ""Server"": null - } - ] - }, - ""RepositoryPullRequests"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Operation"": { - ""Case"": ""Id"", - ""Fields"": [ - ""getPullRequestsByRepository"" - ] - }, - ""Parameters"": { - ""slug"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/slug"" - ] - }, - ""username"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/owner/username"" - ] - } - }, - ""RequestBody"": null, - ""Description"": null, - ""Server"": null - } - ] - }, - ""UserRepositories"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Operation"": { - ""Case"": ""Id"", - ""Fields"": [ - ""getRepositoriesByOwner"" - ] - }, - ""Parameters"": { - ""username"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/username"" - ] - } - }, - ""RequestBody"": null, - ""Description"": null, - ""Server"": null - } - ] - }, - ""UserRepository"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Operation"": { - ""Case"": ""Id"", - ""Fields"": [ - ""getRepository"" - ] - }, - ""Parameters"": { - ""slug"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/slug"" - ] - }, - ""username"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""$response.body#/owner/username"" - ] - } - }, - ""RequestBody"": null, - ""Description"": null, - ""Server"": null - } - ] - } - }, - ""Callbacks"": null - }, - ""Security"": null, - ""Tags"": null, - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``Non-oauth scopes example`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "non-oauth-scopes.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.1.0"", - ""Info"": { - ""Title"": ""Non-oAuth Scopes example"", - ""Description"": null, - ""TermsOfService"": null, - ""Contact"": null, - ""License"": null, - ""Version"": ""1.0.0"" - }, - ""Servers"": null, - ""Paths"": { - ""Fields"": { - ""/users"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": null, - ""Parameters"": null, - ""RequestBody"": null, - ""Responses"": null, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": [ - { - ""Fields"": { - ""bearerAuth"": [ - ""read:users"", - ""public"" - ] - } - } - ], - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - }, - ""Components"": { - ""Schemas"": null, - ""Responses"": null, - ""Parameters"": null, - ""Examples"": null, - ""RequestBodies"": null, - ""Headers"": null, - ""SecuritySchemes"": { - ""bearerAuth"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Case"": ""Http"", - ""Fields"": [ - ""note: non-oauth scopes are not defined at the securityScheme level"", - ""bearer"", - ""jwt"" - ] - } - ] - } - }, - ""Links"": null, - ""Callbacks"": null - }, - ""Security"": null, - ""Tags"": null, - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``Petstore example`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "petstore.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.0.0"", - ""Info"": { - ""Title"": ""Swagger Petstore"", - ""Description"": null, - ""TermsOfService"": null, - ""Contact"": null, - ""License"": { - ""Name"": ""MIT"", - ""Url"": null - }, - ""Version"": ""1.0.0"" - }, - ""Servers"": [ - { - ""Url"": ""http://petstore.swagger.io/v1"", - ""Description"": null, - ""Variables"": null - } - ], - ""Paths"": { - ""Fields"": { - ""/pets"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": [ - ""pets"" - ], - ""Summary"": ""List all pets"", - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""listPets"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""limit"", - ""In"": { - ""Case"": ""Query"" - }, - ""Description"": ""How many items to return at one time (max 100)"", - ""Required"": false, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""unexpected error"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Error"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""A paged array of pets"", - ""Headers"": { - ""x-next"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""A link to the next page of responses"", - ""Required"": null, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - }, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Pets"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": { - ""Tags"": [ - ""pets"" - ], - ""Summary"": ""Create a pet"", - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""createPets"", - ""Parameters"": null, - ""RequestBody"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Pet"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Required"": true - } - ] - }, - ""Responses"": { - ""Default"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""unexpected error"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Error"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""Patterns"": { - ""201"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""Null response"", - ""Headers"": null, - ""Content"": null, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/pets/{petId}"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": [ - ""pets"" - ], - ""Summary"": ""Info for a specific pet"", - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""showPetById"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""petId"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""The id of the pet to retrieve"", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""unexpected error"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Error"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""Expected response to a valid request"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Pet"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - }, - ""Components"": { - ""Schemas"": { - ""Error"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Pet"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Pets"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - } - }, - ""Responses"": null, - ""Parameters"": null, - ""Examples"": null, - ""RequestBodies"": null, - ""Headers"": null, - ""SecuritySchemes"": null, - ""Links"": null, - ""Callbacks"": null - }, - ""Security"": null, - ""Tags"": null, - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``Petstore expanded example`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "petstore-expanded.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.0.0"", - ""Info"": { - ""Title"": ""Swagger Petstore"", - ""Description"": ""A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification"", - ""TermsOfService"": ""http://swagger.io/terms/"", - ""Contact"": { - ""Name"": ""Swagger API Team"", - ""Url"": ""http://swagger.io"", - ""Email"": ""apiteam@swagger.io"" - }, - ""License"": { - ""Name"": ""Apache 2.0"", - ""Url"": ""https://www.apache.org/licenses/LICENSE-2.0.html"" - }, - ""Version"": ""1.0.0"" - }, - ""Servers"": [ - { - ""Url"": ""https://petstore.swagger.io/v2"", - ""Description"": null, - ""Variables"": null - } - ], - ""Paths"": { - ""Fields"": { - ""/pets"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": ""Returns all pets from the system that the user has access to\nNam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.\n\nSed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.\n"", - ""ExternalDocs"": null, - ""OperationId"": ""findPets"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""tags"", - ""In"": { - ""Case"": ""Query"" - }, - ""Description"": ""tags to filter by"", - ""Required"": false, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": ""form"", - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""limit"", - ""In"": { - ""Case"": ""Query"" - }, - ""Description"": ""maximum number of results to return"", - ""Required"": false, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""unexpected error"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Error"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""pet response"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": ""Creates a new pet in the store. Duplicates are allowed"", - ""ExternalDocs"": null, - ""OperationId"": ""addPet"", - ""Parameters"": null, - ""RequestBody"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""Pet to add to the store"", - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/NewPet"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Required"": true - } - ] - }, - ""Responses"": { - ""Default"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""unexpected error"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Error"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""pet response"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Pet"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/pets/{id}"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": ""Returns a user based on a single ID, if the user does not have access to the pet"", - ""ExternalDocs"": null, - ""OperationId"": ""find pet by id"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""id"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""ID of pet to fetch"", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""unexpected error"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Error"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""pet response"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Pet"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": { - ""Tags"": null, - ""Summary"": null, - ""Description"": ""deletes a single pet based on the ID supplied"", - ""ExternalDocs"": null, - ""OperationId"": ""deletePet"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""id"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""ID of pet to delete"", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""unexpected error"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/Error"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""Patterns"": { - ""204"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""pet deleted"", - ""Headers"": null, - ""Content"": null, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - }, - ""Components"": { - ""Schemas"": { - ""Error"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""NewPet"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Pet"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - } - }, - ""Responses"": null, - ""Parameters"": null, - ""Examples"": null, - ""RequestBodies"": null, - ""Headers"": null, - ""SecuritySchemes"": null, - ""Links"": null, - ""Callbacks"": null - }, - ""Security"": null, - ""Tags"": null, - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``Tictactoe example`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "tictactoe.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.1.0"", - ""Info"": { - ""Title"": ""Tic Tac Toe"", - ""Description"": ""This API allows writing down marks on a Tic Tac Toe board\nand requesting the state of the board or of individual squares.\n"", - ""TermsOfService"": null, - ""Contact"": null, - ""License"": null, - ""Version"": ""1.0.0"" - }, - ""Servers"": null, - ""Paths"": { - ""Fields"": { - ""/board"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": [ - ""Gameplay"" - ], - ""Summary"": ""Get the whole board"", - ""Description"": ""Retrieves the current state of the board and the winner."", - ""ExternalDocs"": null, - ""OperationId"": ""get-board"", - ""Parameters"": null, - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""OK"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/status"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": [ - { - ""Fields"": { - ""defaultApiKey"": [] - } - }, - { - ""Fields"": { - ""app2AppOauth"": [ - ""board:read"" - ] - } - } - ], - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/board/{row}/{column}"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": [ - ""Gameplay"" - ], - ""Summary"": ""Get a single board square"", - ""Description"": ""Retrieves the requested square."", - ""ExternalDocs"": null, - ""OperationId"": ""get-square"", - ""Parameters"": null, - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""OK"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/mark"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""400"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""The provided parameters are incorrect"", - ""Headers"": null, - ""Content"": { - ""text/html"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/errorMessage"" - } - ] - }, - ""Example"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""Illegal coordinates"" - ] - }, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": [ - { - ""Fields"": { - ""bearerHttpAuthentication"": [] - } - }, - { - ""Fields"": { - ""user2AppOauth"": [ - ""board:read"" - ] - } - } - ], - ""Servers"": null - }, - ""Put"": { - ""Tags"": [ - ""Gameplay"" - ], - ""Summary"": ""Set a single board square"", - ""Description"": ""Places a mark on the board and retrieves the whole board and the winner (if any)."", - ""ExternalDocs"": null, - ""OperationId"": ""put-square"", - ""Parameters"": null, - ""RequestBody"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/mark"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Required"": true - } - ] - }, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""OK"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/status"" - } - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""400"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""The provided parameters are incorrect"", - ""Headers"": null, - ""Content"": { - ""text/html"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/errorMessage"" - } - ] - }, - ""Example"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""illegalCoordinates"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Summary"": null, - ""Description"": null, - ""Value"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""Illegal coordinates."" - ] - } - } - ] - }, - ""invalidMark"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Summary"": null, - ""Description"": null, - ""Value"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""Invalid Mark (X or O)."" - ] - } - } - ] - }, - ""notEmpty"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Summary"": null, - ""Description"": null, - ""Value"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""Square is not empty."" - ] - } - } - ] - } - } - ] - }, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": [ - { - ""Fields"": { - ""bearerHttpAuthentication"": [] - } - }, - { - ""Fields"": { - ""user2AppOauth"": [ - ""board:write"" - ] - } - } - ], - ""Servers"": null - }, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": [ - { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/parameters/rowParam"" - } - ] - }, - { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/parameters/columnParam"" - } - ] - } - ] - } - } - }, - ""Components"": { - ""Schemas"": { - ""board"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""coordinate"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""errorMessage"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""mark"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""status"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""winner"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - } - }, - ""Responses"": null, - ""Parameters"": { - ""columnParam"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""column"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""Board column (horizontal coordinate)"", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/coordinate"" - } - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - ""rowParam"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""row"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""Board row (vertical coordinate)"", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/coordinate"" - } - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - }, - ""Examples"": null, - ""RequestBodies"": null, - ""Headers"": null, - ""SecuritySchemes"": { - ""app2AppOauth"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Case"": ""Oauth2"", - ""Fields"": [ - null, - { - ""Implicit"": null, - ""Password"": null, - ""ClientCredentials"": { - ""AuthorizationUrl"": null, - ""TokenUrl"": ""https://learn.openapis.org/oauth/2.0/token"", - ""RefreshUrl"": null, - ""Scopes"": { - ""board:read"": ""Read the board"" - } - }, - ""AuthorizationCode"": null - } - ] - } - ] - }, - ""basicHttpAuthentication"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Case"": ""Http"", - ""Fields"": [ - ""Basic HTTP Authentication"", - ""Basic"", - null - ] - } - ] - }, - ""bearerHttpAuthentication"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Case"": ""Http"", - ""Fields"": [ - ""Bearer token using a JWT"", - ""Bearer"", - ""JWT"" - ] - } - ] - }, - ""defaultApiKey"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Case"": ""ApiKey"", - ""Fields"": [ - ""API key provided in console"", - ""api-key"", - { - ""Case"": ""Header"" - } - ] - } - ] - }, - ""user2AppOauth"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Case"": ""Oauth2"", - ""Fields"": [ - null, - { - ""Implicit"": null, - ""Password"": null, - ""ClientCredentials"": null, - ""AuthorizationCode"": { - ""AuthorizationUrl"": ""https://learn.openapis.org/oauth/2.0/auth"", - ""TokenUrl"": ""https://learn.openapis.org/oauth/2.0/token"", - ""RefreshUrl"": null, - ""Scopes"": { - ""board:read"": ""Read the board"", - ""board:write"": ""Write to the board"" - } - } - } - ] - } - ] - } - }, - ""Links"": null, - ""Callbacks"": null - }, - ""Security"": null, - ""Tags"": [ - { - ""Name"": ""Gameplay"", - ""Description"": null, - ""ExternalDocs"": null - } - ], - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``uspto example`` () = - let resource = - Assembly.getEmbeddedResource typeof.Assembly "uspto.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.0.1"", - ""Info"": { - ""Title"": ""USPTO Data Set API"", - ""Description"": ""The Data Set API (DSAPI) allows the public users to discover and search USPTO exported data sets. This is a generic API that allows USPTO users to make any CSV based data files searchable through API. With the help of GET call, it returns the list of data fields that are searchable. With the help of POST call, data can be fetched based on the filters on the field names. Please note that POST call is used to search the actual data. The reason for the POST call is that it allows users to specify any complex search criteria without worry about the GET size limitations as well as encoding of the input parameters."", - ""TermsOfService"": null, - ""Contact"": { - ""Name"": ""Open Data Portal"", - ""Url"": ""https://developer.uspto.gov"", - ""Email"": ""developer@uspto.gov"" - }, - ""License"": null, - ""Version"": ""1.0.0"" - }, - ""Servers"": [ - { - ""Url"": ""{scheme}://developer.uspto.gov/ds-api"", - ""Description"": null, - ""Variables"": { - ""scheme"": { - ""Enum"": [ - ""https"", - ""http"" - ], - ""Default"": ""https"", - ""Description"": ""The Data Set API is accessible via https and http"" - } - } - } - ], - ""Paths"": { - ""Fields"": { - ""/"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": [ - ""metadata"" - ], - ""Summary"": ""List available data sets"", - ""Description"": null, - ""ExternalDocs"": null, - ""OperationId"": ""list-data-sets"", - ""Parameters"": null, - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""Returns a list of data sets"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice2Of2"", - ""Fields"": [ - { - ""Ref"": ""#/components/schemas/dataSetList"" - } - ] - }, - ""Example"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""total"": 2, - ""apis"": [ - { - ""apiKey"": ""oa_citations"", - ""apiVersionNumber"": ""v1"", - ""apiUrl"": ""https://developer.uspto.gov/ds-api/oa_citations/v1/fields"", - ""apiDocumentationUrl"": ""https://developer.uspto.gov/ds-api-docs/index.html?url=https://developer.uspto.gov/ds-api/swagger/docs/oa_citations.json"" - }, - { - ""apiKey"": ""cancer_moonshot"", - ""apiVersionNumber"": ""v1"", - ""apiUrl"": ""https://developer.uspto.gov/ds-api/cancer_moonshot/v1/fields"", - ""apiDocumentationUrl"": ""https://developer.uspto.gov/ds-api-docs/index.html?url=https://developer.uspto.gov/ds-api/swagger/docs/cancer_moonshot.json"" - } - ] - } - ] - }, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/{dataset}/{version}/fields"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": { - ""Tags"": [ - ""metadata"" - ], - ""Summary"": ""Provides the general information about the API and the list of fields that can be used to query the dataset."", - ""Description"": ""This GET API returns the list of all the searchable field names that are in the oa_citations. Please see the \u0027fields\u0027 attribute which returns an array of field names. Each field or a combination of fields can be searched using the syntax options shown below."", - ""ExternalDocs"": null, - ""OperationId"": ""list-searchable-fields"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""dataset"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""Name of the dataset."", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""oa_citations"" - ] - }, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""version"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""Version of the dataset."", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - ""v1"" - ] - }, - ""Content"": null - } - ] - } - ], - ""RequestBody"": null, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""The dataset API for the given version is found and it is accessible to consume."", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""404"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""The combination of dataset name and version is not found in the system or it is not published yet to be consumed by public."", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Put"": null, - ""Post"": null, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - }, - ""/{dataset}/{version}/records"": { - ""Ref"": null, - ""Summary"": null, - ""Description"": null, - ""Get"": null, - ""Put"": null, - ""Post"": { - ""Tags"": [ - ""search"" - ], - ""Summary"": ""Provides search capability for the data set with the given search criteria."", - ""Description"": ""This API is based on Solr/Lucene Search. The data is indexed using SOLR. This GET API returns the list of all the searchable field names that are in the Solr Index. Please see the \u0027fields\u0027 attribute which returns an array of field names. Each field or a combination of fields can be searched using the Solr/Lucene Syntax. Please refer https://lucene.apache.org/core/3_6_2/queryparsersyntax.html#Overview for the query syntax. List of field names that are searchable can be determined using above GET api."", - ""ExternalDocs"": null, - ""OperationId"": ""perform-search"", - ""Parameters"": [ - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""version"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""Version of the dataset."", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - }, - { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Name"": ""dataset"", - ""In"": { - ""Case"": ""Path"" - }, - ""Description"": ""Name of the dataset. In this case, the default value is oa_citations"", - ""Required"": true, - ""Deprecated"": null, - ""AllowEmptyValue"": null, - ""Style"": null, - ""Explode"": null, - ""AllowReserved"": null, - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Content"": null - } - ] - } - ], - ""RequestBody"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": null, - ""Content"": { - ""application/x-www-form-urlencoded"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Required"": null - } - ] - }, - ""Responses"": { - ""Default"": null, - ""Patterns"": { - ""200"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""successful operation"", - ""Headers"": null, - ""Content"": { - ""application/json"": { - ""Schema"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - }, - ""Example"": null, - ""Encoding"": null - } - }, - ""Links"": null - } - ] - }, - ""404"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - { - ""Description"": ""No matching record found for the given criteria."", - ""Headers"": null, - ""Content"": null, - ""Links"": null - } - ] - } - } - }, - ""Callbacks"": null, - ""Deprecated"": null, - ""Security"": null, - ""Servers"": null - }, - ""Delete"": null, - ""Options"": null, - ""Head"": null, - ""Patch"": null, - ""Trace"": null, - ""Servers"": null, - ""Parameters"": null - } - } - }, - ""Components"": { - ""Schemas"": { - ""dataSetList"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - } - }, - ""Responses"": null, - ""Parameters"": null, - ""Examples"": null, - ""RequestBodies"": null, - ""Headers"": null, - ""SecuritySchemes"": null, - ""Links"": null, - ""Callbacks"": null - }, - ""Security"": null, - ""Tags"": [ - { - ""Name"": ""metadata"", - ""Description"": ""Find out about the data sets"", - ""ExternalDocs"": null - }, - { - ""Name"": ""search"", - ""Description"": ""Search a data set"", - ""ExternalDocs"": null - } - ], - ""ExternalDocs"": null -}" - - return actual - } - - [] - let ``webhook example`` () = - // Webhooks aren't mentioned in the 3.0.0 spec so we have no information here. - let resource = - Assembly.getEmbeddedResource typeof.Assembly "webhook-example.json" - |> JsonNode.Parse - |> _.AsObject() - - let actual = OpenApiSpec.Parse resource - - expect { - snapshotJson - @"{ - ""OpenApi"": ""3.1.0"", - ""Info"": { - ""Title"": ""Webhook Example"", - ""Description"": null, - ""TermsOfService"": null, - ""Contact"": null, - ""License"": null, - ""Version"": ""1.0.0"" - }, - ""Servers"": null, - ""Paths"": null, - ""Components"": { - ""Schemas"": { - ""Pet"": { - ""Case"": ""Choice1Of2"", - ""Fields"": [ - null - ] - } - }, - ""Responses"": null, - ""Parameters"": null, - ""Examples"": null, - ""RequestBodies"": null, - ""Headers"": null, - ""SecuritySchemes"": null, - ""Links"": null, - ""Callbacks"": null - }, - ""Security"": null, - ""Tags"": null, - ""ExternalDocs"": null -}" - - return actual - } diff --git a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj index e0c118b8..f94704e0 100644 --- a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj +++ b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj @@ -51,7 +51,6 @@ - diff --git a/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs b/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs index f2e7ce36..4d558a82 100644 --- a/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs +++ b/WoofWare.Myriad.Plugins/JsonSerializeGenerator.fs @@ -288,10 +288,23 @@ module internal JsonSerializeGenerator = |> SynExpr.createLambda "field" |> fun e -> e, false | JsonNode -> - SynExpr.createIdent "node" - |> SynExpr.typeAnnotate (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]) - |> SynExpr.paren - |> SynExpr.callMethod "DeepClone" + let jsonNodeType = + SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ] + + [ + SynExpr.createLongIdent [ "Unchecked" ; "defaultof" ] + |> SynExpr.typeApp [ jsonNodeType ] + |> SynMatchClause.create SynPat.createNull + SynExpr.createIdent "node" + |> SynExpr.typeAnnotate jsonNodeType + |> SynExpr.paren + |> SynExpr.callMethod "DeepClone" + |> SynMatchClause.create (SynPat.named "_") + ] + |> SynExpr.createMatch ( + SynExpr.createIdent "node" + |> SynExpr.pipeThroughFunction (SynExpr.createIdent "box") + ) |> SynExpr.createLambda "node" |> fun expr -> expr, true | UnitType -> diff --git a/WoofWare.Myriad.Plugins/OpenApi3.fs b/WoofWare.Myriad.Plugins/OpenApi3.fs deleted file mode 100644 index d21c9630..00000000 --- a/WoofWare.Myriad.Plugins/OpenApi3.fs +++ /dev/null @@ -1,1332 +0,0 @@ -module internal WoofWare.Myriad.Plugins.OpenApi3 - -open System -open System.Text.Json.Nodes - -type ExternalDocumentation = - { - /// A short description of the target documentation, possibly in CommonMark. - Description : string option - /// The URL for the target documentation. - Url : Uri - } - - static member Parse (node : JsonObject) : ExternalDocumentation = - let description = asOpt node "description" - let url = asString node "url" |> Uri - - { - Description = description - Url = url - } - -type Schema = - | Schema of unit - - static member Parse (_ : JsonObject) : Schema = Schema () - -type Example = - { - /// Short description for the example. - Summary : string option - /// Long description for the example, possibly CommonMark. - Description : string option - Value : Choice option - } - - static member Parse (node : JsonObject) : Example = - let description = asOpt node "description" - let summary = asOpt node "summary" - let externalValue = asOpt node "externalValue" |> Option.map Uri - - let value = - match externalValue with - | Some u -> Choice2Of2 u |> Some - | None -> - match node.TryGetPropertyValue "value" with - | true, v -> Choice1Of2 v |> Some - | false, _ -> None - - { - Summary = summary - Description = description - Value = value - } - -type Reference = - { - /// The reference string. - Ref : string - } - - static member Parse (node : JsonObject) : Reference = - let ref = asString node "$ref" - - { - Ref = ref - } - -type Tag = - { - /// The name of the tag. - Name : string - /// A short description for the tag, possibly CommonMark. - Description : string option - /// Additional external documentation for this tag. - ExternalDocs : ExternalDocumentation option - } - - static member Parse (node : JsonObject) : Tag = - let name = asString node "name" - let description = asOpt node "description" - let docs = asObjOpt node "externalDocs" |> Option.map ExternalDocumentation.Parse - - { - Name = name - Description = description - ExternalDocs = docs - } - -type ServerVariable = - { - /// An enumeration of string values to be used if the substitution options are from a limited set. - Enum : string list option - /// The default value to use for substitution, and to send, if an alternate value is not supplied. - /// Unlike the Schema Object’s default, this value MUST be provided by the consumer. - Default : string - /// An optional description for the server variable, possibly in CommonMark. - Description : string option - } - - static member Parse (node : JsonObject) : ServerVariable = - let enum = asArrOpt' node "enum" - let default' = asString node "default" - let description = asOpt node "description" - - { - Enum = enum - Default = default' - Description = description - } - -type Server = - { - /// A URL to the target host. - /// This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served. - /// Variable substitutions will be made when a variable is named in {brackets}. - Url : string - /// Describes the host designated by the URL, possibly with CommonMark. - Description : string option - /// Used for substituting in the Url. - Variables : Map option - } - - static member Parse (node : JsonObject) : Server = - let url = asString node "url" - let description = asOpt node "description" - - let variables = - match node.TryGetPropertyValue "variables" with - | false, _ -> None - | true, o -> - o.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> k, ServerVariable.Parse (v.AsObject ())) - |> Map.ofSeq - |> Some - - { - Url = url - Description = description - Variables = variables - } - -type StringFormat = - /// base64-encoded characters - | Byte - /// any sequence of octets - | Binary - /// As defined by full-date - RFC3339 Section 5.6 - | Date - /// As defined by date-time - RFC3339 Section 5.6 - | DateTime - /// A hint to UIs to obscure input - | Password - | Verbatim of string - -type IntegerFormat = - /// Signed 32 bits - | Int32 - /// Signed 64 bits - | Int64 - | Verbatim of string - -type NumberFormat = - | Float - | Double - | Verbatim of string - -type DataFormat = - | Integer of IntegerFormat option - | Number of NumberFormat option - | String of StringFormat option - | Boolean of format : string option - -type Contact = - { - /// The identifying name of the contact person/organization. - Name : string option - /// The URL pointing to the contact information. - Url : Uri option - /// This MUST be in email address format. - Email : string option - } - - static member Parse (node : JsonObject) : Contact = - let name = asOpt node "name" - let url = asOpt node "url" |> Option.map Uri - let email = asOpt node "email" - - { - Email = email - Url = url - Name = name - } - -type License = - { - /// The license name used for the API. - Name : string - /// A URL to the license used for the API. - Url : Uri option - } - - static member Parse (node : JsonObject) : License = - let url = asOpt node "url" |> Option.map Uri - let name = asString node "name" - - { - Name = name - Url = url - } - -type OpenApiInfo = - { - /// Title of the application - Title : string - /// Short description of the application, might be in CommonMark - Description : string option - /// Link to the ToS of the application - TermsOfService : Uri option - /// The contact information for the exposed API. - Contact : Contact option - /// The license information for the exposed API. - License : License option - /// The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API implementation version). - Version : string - } - - static member Parse (node : JsonObject) : OpenApiInfo = - let title = asString node "title" - let version = asString node "version" - let desc = asOpt node "description" - let termsOfService = asOpt node "termsOfService" |> Option.map Uri - let contact = asObjOpt node "contact" |> Option.map Contact.Parse - let license = asObjOpt node "license" |> Option.map License.Parse - - { - Title = title - Description = desc - TermsOfService = termsOfService - Contact = contact - License = license - Version = version - } - -type Encoding = - { - /// The Content-Type for encoding a specific property. - /// Default value depends on the property type: - /// for string with format being binary – application/octet-stream; - /// for other primitive types – text/plain; - /// for object - application/json; - /// for array – the default is defined based on the inner type. - /// The value can be a specific media type (e.g. application/json), a wildcard media type (e.g. image/*), or a comma-separated list of the two types. - ContentType : string option - /// A map allowing additional information to be provided as headers, for example Content-Disposition. - /// Content-Type is described separately and SHALL be ignored in this section. - /// This property SHALL be ignored if the request body media type is not a multipart. - Headers : Map> option - /// Describes how a specific property value will be serialized depending on its type. - /// See Parameter Object for details on the style property. - /// The behavior follows the same values as query parameters, including default values. - /// This property SHALL be ignored if the request body media type is not application/x-www-form-urlencoded. - Style : string option - /// When this is true, property values of type array or object generate separate parameters for each value of the array, or key-value-pair of the map. - /// For other types of properties this property has no effect. - /// When style is form, the default value is true. - /// For all other styles, the default value is false. - /// This property SHALL be ignored if the request body media type is not application/x-www-form-urlencoded. - Explode : bool option - /// Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986] Section 2.2 :/?#[]@!$&'()*+,;= - /// to be included without percent-encoding. - /// The default value is false. - /// This property SHALL be ignored if the request body media type is not application/x-www-form-urlencoded. - AllowReserved : bool option - } - - static member Parse (node : JsonObject) : Encoding = - let contentType = asOpt node "contentType" - let style = asOpt node "style" - let explode = asOpt node "explode" - let allowReserved = asOpt node "allowReserved" - - let headers = - match node.TryGetPropertyValue "headers" with - | false, _ -> None - | true, o -> - o.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Header.Parse obj) - - k, parsed - ) - |> Map.ofSeq - |> Some - - { - ContentType = contentType - Headers = headers - Style = style - Explode = explode - AllowReserved = allowReserved - } - -and MediaType = - { - /// The schema defining the type used for the request body. - Schema : Choice option - Example : Choice>> option - /// A map between a property name and its encoding information. - /// The key, being the property name, MUST exist in the schema as a property. - /// The encoding object SHALL only apply to requestBody objects when the media type is multipart or application/x-www-form-urlencoded. - Encoding : Map option - } - - static member Parse (node : JsonObject) : MediaType = - let schema = - match node.TryGetPropertyValue "schema" with - | false, _ -> None - | true, s -> - let obj = s.AsObject () - - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) |> Some - else - Choice1Of2 (Schema.Parse obj) |> Some - - let example = - match node.TryGetPropertyValue "example" with - | true, e -> Choice1Of2 e |> Some - | false, _ -> - match node.TryGetPropertyValue "examples" with - | false, _ -> None - | true, e -> - e.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Example.Parse obj) - - k, parsed - ) - |> Map.ofSeq - |> Choice2Of2 - |> Some - - let encoding = - match node.TryGetPropertyValue "encoding" with - | false, _ -> None - | true, e -> - e.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> k, Encoding.Parse (v.AsObject ())) - |> Map.ofSeq - |> Some - - { - Schema = schema - Example = example - Encoding = encoding - } - -/// The Header Object basically follows the structure of the Parameter Object. -/// All traits that are affected by the location MUST be applicable to a location of header (for example, style). -and Header = - { - /// A brief description of the header, possibly CommonMark. - Description : string option - /// Determines whether this header is mandatory. - /// If the header location is “path”, this property is REQUIRED and its value MUST be true. - /// Otherwise, the property MAY be included and its default value is false. - Required : bool option - /// Specifies that a header is deprecated and SHOULD be transitioned out of usage. - Deprecated : bool option - /// Sets the ability to pass empty-valued headers. - /// This is valid only for query headers and allows sending a header with an empty value. - /// Default value is false. - /// If style is used, and if behavior is n/a (cannot be serialized), the value of allowEmptyValue SHALL be ignored. - AllowEmptyValue : bool option - /// Describes how the header value will be serialized depending on the type of the header value. - /// Default values (based on value of in): for query - form; for path - simple; for header - simple; for cookie - form. - Style : string option - /// When this is true, header values of type array or object generate separate headers for each value of the array or key-value pair of the map. - /// For other types of headers this property has no effect. - /// When style is form, the default value is true. - /// For all other styles, the default value is false. - Explode : bool option - /// Determines whether the header value SHOULD allow reserved characters, as defined by [RFC3986] Section 2.2 :/?#[]@!$&'()*+,;= - /// to be included without percent-encoding. - /// This property only applies to headers with an in value of query. - /// The default value is false. - AllowReserved : bool option - /// The schema defining the type used for the header. - Schema : Choice option - Example : Choice>> option - /// A map containing the representations for the header. - /// The key is the media type and the value describes it. - /// The map MUST only contain one entry. - Content : Map option - } - - static member Parse (node : JsonObject) : Header = - let description = asOpt node "description" - let required = asOpt node "required" - let deprecated = asOpt node "deprecated" - let allowEmptyValue = asOpt node "allowEmptyValue" - let style = asOpt node "style" - let explode = asOpt node "explode" - let allowReserved = asOpt node "allowReserved" - - let schema = - match node.TryGetPropertyValue "schema" with - | false, _ -> None - | true, s -> - let obj = s.AsObject () - - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) |> Some - else - Choice1Of2 (Schema.Parse obj) |> Some - - let example = - match node.TryGetPropertyValue "example" with - | true, e -> Choice1Of2 e |> Some - | false, _ -> - match node.TryGetPropertyValue "examples" with - | false, _ -> None - | true, e -> - e.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Example.Parse obj) - - k, parsed - ) - |> Map.ofSeq - |> Choice2Of2 - |> Some - - let content = - match node.TryGetPropertyValue "content" with - | false, _ -> None - | true, c -> - c.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> k, MediaType.Parse (v.AsObject ())) - |> Map.ofSeq - |> Some - - { - Description = description - Required = required - Deprecated = deprecated - AllowEmptyValue = allowEmptyValue - Style = style - Explode = explode - AllowReserved = allowReserved - Schema = schema - Example = example - Content = content - } - -type LinkOperation = - /// A relative or absolute reference to an OAS operation. - /// This field is mutually exclusive of the operationId field, and MUST point to an Operation Object. - /// Relative operationRef values MAY be used to locate an existing Operation Object in the OpenAPI definition. - | Ref of string - /// The name of an existing, resolvable OAS operation, as defined with a unique operationId. - /// This field is mutually exclusive of the operationRef field. - | Id of string - -type RuntimeExpression = | RuntimeExpression of unit - -type Link = - { - /// A relative or absolute reference to an OAS operation. - /// This field is mutually exclusive of the operationId field, and MUST point to an Operation Object. Relative operationRef values MAY be used to locate an existing Operation Object in the OpenAPI definition. - Operation : LinkOperation option - /// A map representing parameters to pass to an operation as specified with operationId or identified via operationRef. - /// The key is the parameter name to be used, whereas the value can be a constant or an expression to be evaluated and passed to the linked operation. - /// The parameter name can be qualified using the parameter location [{in}.]{name} for operations that use the same parameter name in different locations (e.g. path.id). - Parameters : Map> option - /// A literal value or {expression} to use as a request body when calling the target operation. - RequestBody : Choice option - /// A description of the link, possibly CommonMark. - Description : string option - /// A server object to be used by the target operation. - Server : Server option - } - - static member Parse (node : JsonObject) : Link = - let operation = - match node.TryGetPropertyValue "operationRef" with - | true, ref -> LinkOperation.Ref (ref.GetValue ()) |> Some - | false, _ -> - match node.TryGetPropertyValue "operationId" with - | true, id -> LinkOperation.Id (id.GetValue ()) |> Some - | false, _ -> None - - let parameters = - match node.TryGetPropertyValue "parameters" with - | false, _ -> None - | true, p -> - p.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - // In OpenAPI spec, this can be any value or {expression} - // For simplicity, treating non-string values as JsonNode - k, Choice1Of2 v - ) - |> Map.ofSeq - |> Some - - let requestBody = - match node.TryGetPropertyValue "requestBody" with - | false, _ -> None - | true, rb -> Choice1Of2 rb |> Some - - let description = asOpt node "description" - let server = asObjOpt node "server" |> Option.map Server.Parse - - { - Operation = operation - Parameters = parameters - RequestBody = requestBody - Description = description - Server = server - } - -type Response = - { - /// A short description of the response, possibly CommonMark. - Description : string - /// Maps a header name to its definition. - /// [RFC7230] Page 22 states header names are case insensitive. - /// If a response header is defined with the name "Content-Type", it SHALL be ignored. - Headers : Map> option - /// A map containing descriptions of potential response payloads. - /// The key is a media type or media type range, see [RFC7231] Appendix D, and the value describes it. - /// For responses that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/* - Content : Map option - /// A map of operations links that can be followed from the response. - /// The key of the map is a short name for the link, following the naming constraints of the names for Component Objects. - Links : Map> option - } - - static member Parse (node : JsonObject) : Response = - let description = asString node "description" - - let headers = - match node.TryGetPropertyValue "headers" with - | false, _ -> None - | true, h -> - h.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Header.Parse obj) - - k, parsed - ) - |> Map.ofSeq - |> Some - - let content = - match node.TryGetPropertyValue "content" with - | false, _ -> None - | true, c -> - c.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> k, MediaType.Parse (v.AsObject ())) - |> Map.ofSeq - |> Some - - let links = - match node.TryGetPropertyValue "links" with - | false, _ -> None - | true, l -> - l.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Link.Parse obj) - - k, parsed - ) - |> Map.ofSeq - |> Some - - { - Description = description - Headers = headers - Content = content - Links = links - } - -type Responses = - { - /// The documentation of responses other than the ones declared for specific HTTP response codes. - /// Use this field to cover undeclared responses. - Default : Choice option - /// Map from HTTP status code to expected response. - /// The keys are allowed to be "2XX" for example, hence being strings and not ints. - Patterns : Map> option - } - - static member Parse (node : JsonObject) : Responses = - let default' = - match node.TryGetPropertyValue "default" with - | false, _ -> None - | true, d -> - let obj = d.AsObject () - - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) |> Some - else - Choice1Of2 (Response.Parse obj) |> Some - - // All other properties are HTTP status codes - let patterns = - node - |> Seq.choose (fun (KeyValue (k, v)) -> - if k = "default" then - None - else - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Response.Parse obj) - - Some (k, parsed) - ) - |> Map.ofSeq - |> function - | m when m.IsEmpty -> None - | m -> Some m - - { - Default = default' - Patterns = patterns - } - -type SecuritySchemeIn = - | Query - | Header - | Cookie - -type OauthFlow = - { - /// The authorization URL to be used for this flow. - /// Required for "implicit" and "authorizationCode". - AuthorizationUrl : Uri option - /// The token URL to be used for this flow. - /// Required for "password", "clientCredentials", "authorizationCode". - TokenUrl : Uri option - /// The URL to be used for obtaining refresh tokens. - RefreshUrl : Uri option - /// The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it. - /// Required for "oauth2". - Scopes : Map option - } - - static member Parse (node : JsonObject) : OauthFlow = - let authorizationUrl = asOpt node "authorizationUrl" |> Option.map Uri - let tokenUrl = asOpt node "tokenUrl" |> Option.map Uri - let refreshUrl = asOpt node "refreshUrl" |> Option.map Uri - - let scopes = - asObjOpt node "scopes" - |> Option.map (fun s -> s |> Seq.map (fun (KeyValue (k, v)) -> k, v.GetValue ()) |> Map.ofSeq) - - { - AuthorizationUrl = authorizationUrl - TokenUrl = tokenUrl - RefreshUrl = refreshUrl - Scopes = scopes - } - -type SecurityRequirement = - { - /// Each name MUST correspond to a security scheme which is declared in the Security Schemes under the Components Object. - /// If the security scheme is of type "oauth2" or "openIdConnect", then the value is a list of scope names required for the execution. - /// For other security scheme types, the array MUST be empty. - Fields : Map option - } - - static member Parse (node : JsonObject) : SecurityRequirement = - // The entire object is the security requirement - let fields = - node - |> Seq.map (fun (KeyValue (k, v)) -> - let scopes = v.AsArray () |> Seq.map (fun s -> s.GetValue ()) |> Seq.toList - k, scopes - ) - |> Map.ofSeq - |> function - | m when m.IsEmpty -> None - | m -> Some m - - { - Fields = fields - } - -type OauthFlows = - { - /// Configuration for the OAuth Implicit flow - Implicit : OauthFlow option - /// Configuration for the OAuth Resource Owner Password flow - Password : OauthFlow option - /// Configuration for the OAuth Client Credentials flow. - ClientCredentials : OauthFlow option - /// Configuration for the OAuth Authorization Code flow. - AuthorizationCode : OauthFlow option - } - - static member Parse (node : JsonObject) : OauthFlows = - let implicit = asObjOpt node "implicit" |> Option.map OauthFlow.Parse - let password = asObjOpt node "password" |> Option.map OauthFlow.Parse - - let clientCredentials = - asObjOpt node "clientCredentials" |> Option.map OauthFlow.Parse - - let authorizationCode = - asObjOpt node "authorizationCode" |> Option.map OauthFlow.Parse - - { - Implicit = implicit - Password = password - ClientCredentials = clientCredentials - AuthorizationCode = authorizationCode - } - -type SecurityScheme = - | ApiKey of description : string option * name : string * inValue : SecuritySchemeIn - | Http of description : string option * scheme : string * bearerFormat : string option - | Oauth2 of description : string option * OauthFlows - | OpenIdConnect of description : string option * url : Uri - - static member Parse (node : JsonObject) : SecurityScheme = - let type' = asString node "type" - let description = asOpt node "description" - - match type' with - | "apiKey" -> - let name = asString node "name" - - let inValue = - match asString node "in" with - | "query" -> SecuritySchemeIn.Query - | "header" -> SecuritySchemeIn.Header - | "cookie" -> SecuritySchemeIn.Cookie - | other -> failwithf "Unknown 'in' value for apiKey: %s" other - - SecurityScheme.ApiKey (description, name, inValue) - | "http" -> - let scheme = asString node "scheme" - let bearerFormat = asOpt node "bearerFormat" - SecurityScheme.Http (description, scheme, bearerFormat) - | "oauth2" -> - let flows = asObj node "flows" |> OauthFlows.Parse - SecurityScheme.Oauth2 (description, flows) - | "openIdConnect" -> - let url = asString node "openIdConnectUrl" |> Uri - SecurityScheme.OpenIdConnect (description, url) - | other -> failwithf "Unknown security scheme type: %s" other - -type ParameterIn = - /// Used together with Path Templating, where the parameter value is actually part of the operation’s URL. - /// This does not include the host or base path of the API. - /// For example, in /items/{itemId}, the path parameter is itemId. - | Path - /// Custom headers that are expected as part of the request. - /// Note that [RFC7230] Page 22 states header names are case insensitive. - | Header - /// Parameters that are appended to the URL. For example, in /items?id=###, the query parameter is id. - | Query - /// Used to pass a specific cookie value to the API. - | Cookie - -/// A unique parameter is defined by a combination of a name and location. -type Parameter = - { - /// Name of the parameter, case sensitive. - /// If in is "path", the name field MUST correspond to the associated path segment from the path field in the Paths Object. - /// See Path Templating for further information. - /// If in is "header" and the name field is "Accept", "Content-Type" or "Authorization", the parameter definition SHALL be ignored. - /// For all other cases, the name corresponds to the parameter name used by the in property. - Name : string - /// The location of the parameter. - In : ParameterIn - /// A brief description of the parameter, possibly CommonMark. - Description : string option - /// Determines whether this parameter is mandatory. - /// If the parameter location is “path”, this property is REQUIRED and its value MUST be true. - /// Otherwise, the property MAY be included and its default value is false. - Required : bool option - /// Specifies that a parameter is deprecated and SHOULD be transitioned out of usage. - Deprecated : bool option - /// Sets the ability to pass empty-valued parameters. - /// This is valid only for query parameters and allows sending a parameter with an empty value. - /// Default value is false. - /// If style is used, and if behavior is n/a (cannot be serialized), the value of allowEmptyValue SHALL be ignored. - AllowEmptyValue : bool option - /// Describes how the parameter value will be serialized depending on the type of the parameter value. - /// Default values (based on value of in): for query - form; for path - simple; for header - simple; for cookie - form. - Style : string option - /// When this is true, parameter values of type array or object generate separate parameters for each value of the array or key-value pair of the map. - /// For other types of parameters this property has no effect. - /// When style is form, the default value is true. - /// For all other styles, the default value is false. - Explode : bool option - /// Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986] Section 2.2 :/?#[]@!$&'()*+,;= - /// to be included without percent-encoding. - /// This property only applies to parameters with an in value of query. - /// The default value is false. - AllowReserved : bool option - /// The schema defining the type used for the parameter. - Schema : Choice option - Example : Choice>> option - /// A map containing the representations for the parameter. - /// The key is the media type and the value describes it. - /// The map MUST only contain one entry. - Content : Map option - } - - static member Parse (node : JsonObject) : Parameter = - let name = asString node "name" - - let in' = - match asString node "in" with - | "path" -> ParameterIn.Path - | "header" -> ParameterIn.Header - | "query" -> ParameterIn.Query - | "cookie" -> ParameterIn.Cookie - | other -> failwithf "Unknown 'in' value for parameter: %s" other - - let description = asOpt node "description" - let required = asOpt node "required" - let deprecated = asOpt node "deprecated" - let allowEmptyValue = asOpt node "allowEmptyValue" - let style = asOpt node "style" - let explode = asOpt node "explode" - let allowReserved = asOpt node "allowReserved" - - let schema = - match node.TryGetPropertyValue "schema" with - | false, _ -> None - | true, s -> - let obj = s.AsObject () - - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) |> Some - else - Choice1Of2 (Schema.Parse obj) |> Some - - let example = - match node.TryGetPropertyValue "example" with - | true, e -> Choice1Of2 e |> Some - | false, _ -> - match node.TryGetPropertyValue "examples" with - | false, _ -> None - | true, e -> - e.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Example.Parse obj) - - k, parsed - ) - |> Map.ofSeq - |> Choice2Of2 - |> Some - - let content = - match node.TryGetPropertyValue "content" with - | false, _ -> None - | true, c -> - c.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> k, MediaType.Parse (v.AsObject ())) - |> Map.ofSeq - |> Some - - { - Name = name - In = in' - Description = description - Required = required - Deprecated = deprecated - AllowEmptyValue = allowEmptyValue - Style = style - Explode = explode - AllowReserved = allowReserved - Schema = schema - Example = example - Content = content - } - -type RequestBody = - { - /// A brief description of the request body. This could contain examples of use. - /// Possibly CommonMark. - Description : string option - /// The content of the request body. - /// The key is a media type or media type range, see [RFC7231] Appendix D, and the value describes it. - /// For requests that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/* - Content : Map - /// Determines if the request body is required in the request. Defaults to false. - Required : bool option - } - - static member Parse (node : JsonObject) : RequestBody = - let description = asOpt node "description" - - let content = - asObj node "content" - |> Seq.map (fun (KeyValue (k, v)) -> k, MediaType.Parse (v.AsObject ())) - |> Map.ofSeq - - let required = asOpt node "required" - - { - Description = description - Content = content - Required = required - } - -type Callback = - { - /// For the semantics of the keys, see https://spec.openapis.org/oas/v3.0.0#key-expression - Patterns : Map option - } - - static member Parse (node : JsonObject) : Callback = - let patterns = - node - |> Seq.map (fun (KeyValue (k, v)) -> k, PathItem.Parse (v.AsObject ())) - |> Map.ofSeq - |> function - | m when m.IsEmpty -> None - | m -> Some m - - { - Patterns = patterns - } - -and Operation = - { - /// A list of tags for API documentation control. - /// Tags can be used for logical grouping of operations by resources or any other qualifier. - Tags : string list option - /// A short summary of what the operation does. - Summary : string option - /// A verbose explanation of the operation behavior, possibly in CommonMark. - Description : string option - /// Additional external documentation for this operation. - ExternalDocs : ExternalDocumentation option - /// Unique string used to identify the operation. - /// The id MUST be unique among all operations described in the API. - /// Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, - /// it is RECOMMENDED to follow common programming naming conventions. - OperationId : string option - /// A list of parameters that are applicable for this operation. - /// If a parameter is already defined at the Path Item, the new definition will override it but can never remove it. - /// The list MUST NOT include duplicated parameters. - /// A unique parameter is defined by a combination of a name and location. - /// The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object’s components/parameters. - Parameters : Choice list option - /// The request body applicable for this operation. - /// The requestBody is only supported in HTTP methods where the HTTP 1.1 specification [RFC7231] Section 4.3.1 has explicitly defined semantics for request bodies. - /// In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers. - RequestBody : Choice option - /// The list of possible responses as they are returned from executing this operation. - /// Per the spec these are required, but one of the official examples lacks them. - Responses : Responses option - /// A map of possible out-of band callbacks related to the parent operation. - /// The key is a unique identifier for the Callback Object. - /// Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses. - /// The key value used to identify the callback object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation. - Callbacks : Map> option - /// Default value is "false". - Deprecated : bool option - /// A declaration of which security mechanisms can be used for this operation. - /// The list of values includes alternative security requirement objects that can be used. - /// Only one of the security requirement objects need to be satisfied to authorize a request. - /// This definition overrides any declared top-level security. - /// To remove a top-level security declaration, an empty array can be used. - Security : SecurityRequirement list option - /// An alternative server array to service this operation. - /// If an alternative server object is specified at the Path Item Object or Root level, it will be overridden by this value. - Servers : Server list option - } - - static member Parse (node : JsonObject) : Operation = - let tags = asArrOpt' node "tags" - let summary = asOpt node "summary" - let description = asOpt node "description" - - let externalDocs = - asObjOpt node "externalDocs" |> Option.map ExternalDocumentation.Parse - - let operationId = asOpt node "operationId" - - let parameters = - match node.TryGetPropertyValue "parameters" with - | false, _ -> None - | true, p -> - p.AsArray () - |> Seq.map (fun v -> - let obj = v.AsObject () - - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Parameter.Parse obj) - ) - |> Seq.toList - |> Some - - let requestBody = - match node.TryGetPropertyValue "requestBody" with - | false, _ -> None - | true, rb -> - let obj = rb.AsObject () - - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) |> Some - else - Choice1Of2 (RequestBody.Parse obj) |> Some - - let responses = asObjOpt node "responses" |> Option.map Responses.Parse - - let callbacks = - match node.TryGetPropertyValue "callbacks" with - | false, _ -> None - | true, c -> - c.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Callback.Parse obj) - - k, parsed - ) - |> Map.ofSeq - |> Some - - let deprecated = asOpt node "deprecated" - - let security = - match node.TryGetPropertyValue "security" with - | false, _ -> None - | true, s -> - s.AsArray () - |> Seq.map (fun v -> SecurityRequirement.Parse (v.AsObject ())) - |> Seq.toList - |> Some - - let servers = - match node.TryGetPropertyValue "servers" with - | false, _ -> None - | true, s -> - s.AsArray () - |> Seq.map (fun v -> Server.Parse (v.AsObject ())) - |> Seq.toList - |> Some - - { - Tags = tags - Summary = summary - Description = description - ExternalDocs = externalDocs - OperationId = operationId - Parameters = parameters - RequestBody = requestBody - Responses = responses - Callbacks = callbacks - Deprecated = deprecated - Security = security - Servers = servers - } - -and PathItem = - { - /// Allows for an external definition of this path item. - /// The referenced structure MUST be in the format of a Path Item Object. - /// If there are conflicts between the referenced definition and this Path Item’s definition, the behavior is undefined. - Ref : string option - /// A string summary, intended to apply to all operations in this path. - Summary : string option - /// A string description, intended to apply to all operations in this path, possibly in CommonMark - Description : string option - /// A definition of a GET operation on this path. - Get : Operation option - /// A definition of a PUT operation on this path. - Put : Operation option - /// A definition of a POST operation on this path. - Post : Operation option - /// A definition of a DELETE operation on this path. - Delete : Operation option - /// A definition of an OPTIONS operation on this path. - Options : Operation option - /// A definition of a HEAD operation on this path. - Head : Operation option - /// A definition of a PATCH operation on this path. - Patch : Operation option - /// A definition of a TRACE operation on this path. - Trace : Operation option - /// An alternative server array to service all operations in this path. - Servers : Server list option - /// A list of parameters that are applicable for all the operations described under this path. - /// These parameters can be overridden at the operation level, but cannot be removed there. - /// The list MUST NOT include duplicated parameters. - /// A unique parameter is defined by a combination of a name and location. - /// The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object’s components/parameters. - Parameters : Choice list option - } - - static member Parse (node : JsonObject) : PathItem = - let ref = asOpt node "$ref" - let summary = asOpt node "summary" - let description = asOpt node "description" - let get = asObjOpt node "get" |> Option.map Operation.Parse - let put = asObjOpt node "put" |> Option.map Operation.Parse - let post = asObjOpt node "post" |> Option.map Operation.Parse - let delete = asObjOpt node "delete" |> Option.map Operation.Parse - let options = asObjOpt node "options" |> Option.map Operation.Parse - let head = asObjOpt node "head" |> Option.map Operation.Parse - let patch = asObjOpt node "patch" |> Option.map Operation.Parse - let trace = asObjOpt node "trace" |> Option.map Operation.Parse - - let servers = - match node.TryGetPropertyValue "servers" with - | false, _ -> None - | true, s -> - s.AsArray () - |> Seq.map (fun v -> Server.Parse (v.AsObject ())) - |> Seq.toList - |> Some - - let parameters = - match node.TryGetPropertyValue "parameters" with - | false, _ -> None - | true, p -> - p.AsArray () - |> Seq.map (fun v -> - let obj = v.AsObject () - - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (Parameter.Parse obj) - ) - |> Seq.toList - |> Some - - { - Ref = ref - Summary = summary - Description = description - Get = get - Put = put - Post = post - Delete = delete - Options = options - Head = head - Patch = patch - Trace = trace - Servers = servers - Parameters = parameters - } - -type Paths = - { - /// A relative path to an individual endpoint. - /// The field name MUST begin with a slash. - /// The path is appended (no relative URL resolution) to the expanded URL from the Server Object’s url field in order to construct the full URL. - /// Path templating is allowed. - /// When matching URLs, concrete (non-templated) paths would be matched before their templated counterparts. - /// Templated paths with the same hierarchy but different templated names MUST NOT exist as they are identical. - /// In case of ambiguous matching, it’s up to the tooling to decide which one to use. - Fields : Map option - } - - static member Parse (node : JsonObject) : Paths = - let fields = - node - |> Seq.map (fun (KeyValue (k, v)) -> k, PathItem.Parse (v.AsObject ())) - |> Map.ofSeq - |> function - | m when m.IsEmpty -> None - | m -> Some m - - { - Fields = fields - } - -type Components = - { - Schemas : Map> option - Responses : Map> option - Parameters : Map> option - Examples : Map> option - RequestBodies : Map> option - Headers : Map> option - SecuritySchemes : Map> option - Links : Map> option - Callbacks : Map> option - } - - static member Parse (node : JsonObject) : Components = - let parseMap (key : string) (parser : JsonObject -> 'T) = - match node.TryGetPropertyValue key with - | false, _ -> None - | true, o -> - o.AsObject () - |> Seq.map (fun (KeyValue (k, v)) -> - let obj = v.AsObject () - - let parsed = - if obj.ContainsKey "$ref" then - Choice2Of2 (Reference.Parse obj) - else - Choice1Of2 (parser obj) - - k, parsed - ) - |> Map.ofSeq - |> Some - - { - Schemas = parseMap "schemas" Schema.Parse - Responses = parseMap "responses" Response.Parse - Parameters = parseMap "parameters" Parameter.Parse - Examples = parseMap "examples" Example.Parse - RequestBodies = parseMap "requestBodies" RequestBody.Parse - Headers = parseMap "headers" Header.Parse - SecuritySchemes = parseMap "securitySchemes" SecurityScheme.Parse - Links = parseMap "links" Link.Parse - Callbacks = parseMap "callbacks" Callback.Parse - } - -type OpenApiSpec = - { - OpenApi : Version - Info : OpenApiInfo - Servers : Server list option - /// According to the spec, this is required, but then one of their own examples - /// does not contain a Paths. - Paths : Paths option - Components : Components option - Security : SecurityRequirement list option - Tags : Tag list option - ExternalDocs : ExternalDocumentation option - } - - static member Parse (node : JsonObject) : OpenApiSpec = - let openapi = asString node "openapi" |> Version - let info = asObj node "info" |> OpenApiInfo.Parse - - let servers = - match node.TryGetPropertyValue "servers" with - | false, _ -> None - | true, s -> - s.AsArray () - |> Seq.map (fun v -> Server.Parse (v.AsObject ())) - |> Seq.toList - |> Some - - let paths = asObjOpt node "paths" |> Option.map Paths.Parse - let components = asObjOpt node "components" |> Option.map Components.Parse - - let security = - match node.TryGetPropertyValue "security" with - | false, _ -> None - | true, s -> - s.AsArray () - |> Seq.map (fun v -> SecurityRequirement.Parse (v.AsObject ())) - |> Seq.toList - |> Some - - let tags = - match node.TryGetPropertyValue "tags" with - | false, _ -> None - | true, t -> - t.AsArray () - |> Seq.map (fun v -> Tag.Parse (v.AsObject ())) - |> Seq.toList - |> Some - - let externalDocs = - asObjOpt node "externalDocs" |> Option.map ExternalDocumentation.Parse - - { - OpenApi = openapi - Info = info - Servers = servers - Paths = paths - Components = components - Security = security - Tags = tags - ExternalDocs = externalDocs - } diff --git a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs index b3f23fdd..0df7cfac 100644 --- a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs @@ -604,16 +604,20 @@ module internal OpenApiClientGenerator = || schema.Value.ContainsKey "additionalProperties" let usedTypeNames = HashSet (StringComparer.Ordinal) - usedTypeNames.Add ("I" + className) |> ignore - for generatedAttributeName in + for reservedTypeName in [ + className + "I" + className + "System" + "RestEase" + "WoofWare" "GenerateMockAttribute" "HttpClientAttribute" "JsonParseAttribute" "JsonSerializeAttribute" ] do - usedTypeNames.Add generatedAttributeName |> ignore + usedTypeNames.Add reservedTypeName |> ignore let objectComponentNames = schemaComponents @@ -1328,8 +1332,18 @@ module internal OpenApiClientGenerator = yield parameter ] + let mediaTypeWithoutParameters (name : string) : string = + match name.IndexOf ';' with + | -1 -> name.Trim () + | separator -> (name.Substring (0, separator)).Trim () + + let mediaTypeEquals (expected : string) (actual : string) : bool = + (mediaTypeWithoutParameters actual).Equals (expected, StringComparison.OrdinalIgnoreCase) + let selectMedia (purpose : string) (content : LocatedObject) : (string * LocatedObject option) option = let rank (name : string) = + let name = mediaTypeWithoutParameters name + if name.Equals ("application/json", StringComparison.OrdinalIgnoreCase) then 0 elif name.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) then @@ -1357,11 +1371,26 @@ module internal OpenApiClientGenerator = match candidates with | [] -> - report UnsupportedOperation content.Location $"No supported media type was found for %s{purpose}." + let keys = + content.Value + |> Seq.map (fun (KeyValue (name, _)) -> name) + |> Seq.sort + |> String.concat "', '" + |> fun value -> + if String.IsNullOrEmpty value then + "(none)" + else + $"'%s{value}'" + + report + UnsupportedOperation + content.Location + $"No supported media type was found for %s{purpose}. Content keys: %s{keys}." + None | (_, selectedName, selected) :: _ -> let selectedSchema = optionalObject selected.Location selected.Value "schema" - Some (selectedName, selectedSchema) + Some (mediaTypeWithoutParameters selectedName, selectedSchema) let rec isJsonStringType (plannedType : OpenApiPlannedType) : bool = match plannedType with @@ -1370,6 +1399,8 @@ module internal OpenApiClientGenerator = | _ -> false let isJsonMediaType (mediaType : string) : bool = + let mediaType = mediaTypeWithoutParameters mediaType + mediaType.Equals ("application/json", StringComparison.OrdinalIgnoreCase) || mediaType.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) @@ -1393,7 +1424,7 @@ module internal OpenApiClientGenerator = | None -> OpenApiPlannedType.JsonNode, None | Some (mediaType, schema) -> let result = - if mediaType.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) then + if mediaTypeEquals "application/octet-stream" mediaType then match schema with | None -> () | Some schema -> @@ -1406,7 +1437,7 @@ module internal OpenApiClientGenerator = "application/octet-stream responses require a non-null string/binary schema." OpenApiPlannedType.Stream - elif mediaType.Equals ("text/plain", StringComparison.OrdinalIgnoreCase) then + elif mediaTypeEquals "text/plain" mediaType then match schema with | None -> () | Some schema -> @@ -1525,11 +1556,9 @@ module internal OpenApiClientGenerator = selectMedia "a request body" content |> Option.map (fun (mediaType, schema) -> let plannedType = - if - mediaType.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) - then + if mediaTypeEquals "application/octet-stream" mediaType then OpenApiPlannedType.Stream - elif mediaType.Equals ("text/plain", StringComparison.OrdinalIgnoreCase) then + elif mediaTypeEquals "text/plain" mediaType then match schema with | None -> () | Some schema -> @@ -1547,7 +1576,7 @@ module internal OpenApiClientGenerator = | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode | Some schema -> typeForSchema Set.empty ($"%s{operationName}Request") schema - if mediaType.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) then + if mediaTypeEquals "application/octet-stream" mediaType then report UnsupportedOperation content.Location @@ -1575,6 +1604,12 @@ module internal OpenApiClientGenerator = | None -> OpenApiServerBase.BasePath "/" | Some servers when servers.Count = 0 -> OpenApiServerBase.BasePath "/" | Some servers -> + if servers.Count > 1 then + report + UnsupportedOperation + "#/servers" + "Only the first document-level server is supported; additional server entries would be ignored." + match tryObject "#/servers/0" servers.[0] with | None -> OpenApiServerBase.BasePath "/" | Some server -> @@ -1669,19 +1704,15 @@ module internal OpenApiClientGenerator = "Operation-specific servers are unsupported." | _ -> () - let operationId = + let operationId, operationIdLocation = match optionalString operation.Location operation.Value "operationId" with - | Some value -> - if not (usedOperationIds.Add value) then - report - InvalidDocument - ($"%s{operation.Location}/operationId") - $"Operation id '%s{value}' is duplicated." - - value + | Some value -> value, $"%s{operation.Location}/operationId" | None -> let methodName = httpMethod.ToString().ToLowerInvariant () - $"%s{methodName}-%s{path}" + $"%s{methodName}-%s{path}", operation.Location + + if not (usedOperationIds.Add operationId) then + report InvalidDocument operationIdLocation $"Operation id '%s{operationId}' is duplicated." let operationFSharpName = allocateUniqueName usedMethodNames "Operation" sanitiseTypeName operationId diff --git a/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj b/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj index 3fbc60a3..24dd5012 100644 --- a/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj +++ b/WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj @@ -46,7 +46,6 @@ - From f98764eb9c0dff108138426b7a52dafa3aa939d0 Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Fri, 10 Jul 2026 13:05:38 +0100 Subject: [PATCH 4/9] Refactor OpenAPI 3 schema planning --- ConsumePlugin/Generated2OpenApiPetstore.fs | 43 +- ConsumePlugin/Generated2SwaggerGitea.fs | 3848 +++++++++++------ .../TestSwagger/TestOpenApi3Generator.fs | 94 + .../OpenApiClientGenerator.fs | 2796 ++++++------ 4 files changed, 4065 insertions(+), 2716 deletions(-) diff --git a/ConsumePlugin/Generated2OpenApiPetstore.fs b/ConsumePlugin/Generated2OpenApiPetstore.fs index 3a03f5dd..d98c45f5 100644 --- a/ConsumePlugin/Generated2OpenApiPetstore.fs +++ b/ConsumePlugin/Generated2OpenApiPetstore.fs @@ -741,11 +741,13 @@ module OpenApiPetstore = let queryParams = new System.Net.Http.StringContent ( - body |> NewPet.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> NewPet.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask @@ -844,7 +846,12 @@ module OpenApiPetstore = RequestUri = uri ) - let queryParams = new System.Net.Http.StringContent (body, null, "text/plain") + let queryParams = new System.Net.Http.StringContent (body) + + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("text/plain; charset=utf-8") + do httpMessage.Content <- queryParams do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask @@ -883,11 +890,13 @@ module OpenApiPetstore = | None -> "null" | Some field -> (fun node -> (node : System.Text.Json.Nodes.JsonNode).ToJsonString ()) field - ), - null, - "application/json" + ) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask @@ -932,11 +941,13 @@ module OpenApiPetstore = |> (fun field -> let value = field : System.Numerics.BigInteger value.ToString ("D", System.Globalization.CultureInfo.InvariantCulture) - ), - null, - "application/json" + ) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask @@ -1093,6 +1104,11 @@ module OpenApiPetstore = async { let! ct = Async.CancellationToken + let queryString = + [ [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( (match client.BaseAddress with @@ -1100,9 +1116,10 @@ module OpenApiPetstore = | v -> v), System.Uri ( ("pets" - + (if "pets".IndexOf (char 63) >= 0 then "&" else "?") - + "limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "pets".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) diff --git a/ConsumePlugin/Generated2SwaggerGitea.fs b/ConsumePlugin/Generated2SwaggerGitea.fs index 72e479fc..110380db 100644 --- a/ConsumePlugin/Generated2SwaggerGitea.fs +++ b/ConsumePlugin/Generated2SwaggerGitea.fs @@ -121,14 +121,14 @@ module AccessTokenJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -423,14 +423,14 @@ module AddTimeOptionJsonSerializeExtension = "time", (input.Time |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -662,14 +662,14 @@ module AttachmentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -689,14 +689,14 @@ module AttachmentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -743,14 +743,14 @@ module AttachmentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1424,14 +1424,14 @@ module BranchProtectionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1596,14 +1596,14 @@ module ChangedFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1623,14 +1623,14 @@ module ChangedFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -1677,14 +1677,14 @@ module ChangedFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2109,14 +2109,14 @@ module CommitStatsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2136,14 +2136,14 @@ module CommitStatsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2163,14 +2163,14 @@ module CommitStatsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -2980,14 +2980,14 @@ module CreateBranchProtectionOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -3644,14 +3644,14 @@ module CreateIssueOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -3676,14 +3676,14 @@ module CreateIssueOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4619,14 +4619,14 @@ module CreatePullRequestOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4651,14 +4651,14 @@ module CreatePullRequestOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4759,14 +4759,14 @@ module CreatePullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -4786,14 +4786,14 @@ module CreatePullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -6192,14 +6192,14 @@ module CreateUserOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -6399,14 +6399,14 @@ module CronJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -7306,14 +7306,14 @@ module EditBranchProtectionOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -7877,14 +7877,14 @@ module EditIssueOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -8675,14 +8675,14 @@ module EditPullRequestOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -8707,14 +8707,14 @@ module EditPullRequestOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -9582,14 +9582,14 @@ module EditUserOptionJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -9712,14 +9712,14 @@ module EditUserOptionJsonSerializeExtension = "source_id", (input.SourceId |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10519,14 +10519,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10546,14 +10546,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10573,14 +10573,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10600,14 +10600,14 @@ module GeneralAPISettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10708,14 +10708,14 @@ module GeneralAttachmentSettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -10735,14 +10735,14 @@ module GeneralAttachmentSettingsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11493,14 +11493,14 @@ module GitBlobResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11655,14 +11655,14 @@ module GitEntryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -11979,14 +11979,14 @@ module GitTreeResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -12033,14 +12033,14 @@ module GitTreeResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -12327,14 +12327,14 @@ module HookJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -12721,14 +12721,14 @@ module IssueLabelsOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -12861,14 +12861,14 @@ module LabelJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -13806,14 +13806,14 @@ module MigrateRepoOptionsJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14150,14 +14150,14 @@ module NodeInfoUsageUsersJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14177,14 +14177,14 @@ module NodeInfoUsageUsersJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14204,14 +14204,14 @@ module NodeInfoUsageUsersJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14258,14 +14258,14 @@ module NotificationCountJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14420,14 +14420,14 @@ module OAuth2ApplicationJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14619,14 +14619,14 @@ module OrganizationJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -14997,14 +14997,14 @@ module PackageFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -15024,14 +15024,14 @@ module PackageFileJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16037,14 +16037,14 @@ module RepositoryMetaJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16253,14 +16253,14 @@ module StopWatchJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16361,14 +16361,14 @@ module StopWatchJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -16758,14 +16758,14 @@ module TeamJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17043,14 +17043,14 @@ module TopicResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17070,14 +17070,14 @@ module TopicResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17201,14 +17201,14 @@ module TransferRepoOptionJsonSerializeExtension = for mem in field do arr.Add ( (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17626,14 +17626,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17653,14 +17653,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17707,14 +17707,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -17950,14 +17950,14 @@ module UserJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18058,14 +18058,14 @@ module UserHeatmapDataJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18085,14 +18085,14 @@ module UserHeatmapDataJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -18980,14 +18980,14 @@ module WikiCommitListJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -19034,14 +19034,14 @@ module WikiPageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -19483,14 +19483,14 @@ module CommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -19564,14 +19564,14 @@ module CommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -19775,14 +19775,14 @@ module CommitStatusJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -20191,14 +20191,14 @@ module ContentsResponseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22106,14 +22106,14 @@ module MilestoneJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22214,14 +22214,14 @@ module MilestoneJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22241,14 +22241,14 @@ module MilestoneJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22376,14 +22376,14 @@ module NodeInfoUsageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22403,14 +22403,14 @@ module NodeInfoUsageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -22884,14 +22884,14 @@ module PublicKeyJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -23111,14 +23111,14 @@ module PullReviewJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -23219,14 +23219,14 @@ module PullReviewJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -23592,14 +23592,14 @@ module PullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -23727,14 +23727,14 @@ module PullReviewCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -24090,14 +24090,14 @@ module ReleaseJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25102,14 +25102,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25291,14 +25291,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25572,14 +25572,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25599,14 +25599,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25713,14 +25713,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25751,14 +25751,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25805,14 +25805,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -25886,14 +25886,14 @@ module RepositoryJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26325,14 +26325,14 @@ module CombinedStatusJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26683,14 +26683,14 @@ module DeployKeyJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -26737,14 +26737,14 @@ module DeployKeyJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27115,14 +27115,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27223,14 +27223,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27310,14 +27310,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27364,14 +27364,14 @@ module IssueJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -27813,14 +27813,14 @@ module NotificationThreadJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28062,14 +28062,14 @@ module PRBranchInfoJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28181,14 +28181,14 @@ module PackageJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28742,14 +28742,14 @@ module PullRequestJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -28888,14 +28888,14 @@ module PullRequestJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29121,14 +29121,14 @@ module PullRequestJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29348,14 +29348,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29386,14 +29386,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29413,14 +29413,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29440,14 +29440,14 @@ module TrackedTimeJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29640,14 +29640,14 @@ module BranchJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -29899,14 +29899,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -30040,14 +30040,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -30121,14 +30121,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -30289,14 +30289,14 @@ module TimelineCommentJsonSerializeExtension = | Some field -> (field |> (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -30403,14 +30403,14 @@ module LanguageStatisticsJsonSerializeExtension = node.Add ( key, (fun field -> - let field = System.Text.Json.Nodes.JsonValue.Create field + let field = System.Text.Json.Nodes.JsonValue.Create field (match field with | null -> raise ( System.ArgumentNullException ( "field", - "Expected type int32 to be non-null, but received a null value when serialising" + "Expected type int64 to be non-null, but received a null value when serialising" ) ) | field -> field) @@ -30668,7 +30668,7 @@ module AccessTokenJsonParseExtension = let arg_1 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -30817,7 +30817,7 @@ module AddTimeOptionJsonParseExtension = sprintf "Required key '%s' not found on JSON object" ("time") ) ) - | Some node -> node.AsValue().GetValue () + | Some node -> node.AsValue().GetValue () let arg_1 = match node.["created"] |> Option.ofObj with @@ -30927,7 +30927,7 @@ module AttachmentJsonParseExtension = let arg_6 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["name"] |> Option.ofObj with @@ -30937,12 +30937,12 @@ module AttachmentJsonParseExtension = let arg_4 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["download_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["created_at"] |> Option.ofObj with @@ -31043,7 +31043,7 @@ module BranchProtectionJsonParseExtension = let arg_21 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_20 = match node.["require_signed_commits"] |> Option.ofObj with @@ -31345,7 +31345,7 @@ module ChangedFileJsonParseExtension = let arg_4 = match node.["deletions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["contents_url"] |> Option.ofObj with @@ -31355,12 +31355,12 @@ module ChangedFileJsonParseExtension = let arg_2 = match node.["changes"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["additions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -31568,17 +31568,17 @@ module CommitStatsJsonParseExtension = let arg_3 = match node.["total"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["deletions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["additions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -31775,7 +31775,7 @@ module CreateBranchProtectionOptionJsonParseExtension = let arg_20 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_19 = match node.["require_signed_commits"] |> Option.ofObj with @@ -32355,7 +32355,7 @@ module CreateIssueOptionJsonParseExtension = let arg_7 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["labels"] |> Option.ofObj with @@ -32368,10 +32368,10 @@ module CreateIssueOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int32) to be non-null, but found a null element" + "Expected element of array (element type int64) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -32837,7 +32837,7 @@ module CreatePullRequestOptionJsonParseExtension = let arg_8 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_7 = match node.["labels"] |> Option.ofObj with @@ -32850,10 +32850,10 @@ module CreatePullRequestOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int32) to be non-null, but found a null element" + "Expected element of array (element type int64) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -32966,12 +32966,12 @@ module CreatePullReviewCommentJsonParseExtension = let arg_3 = match node.["old_position"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["new_position"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["body"] |> Option.ofObj with @@ -33577,7 +33577,7 @@ module CreateUserOptionJsonParseExtension = let arg_9 = match node.["source_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_8 = match node.["send_notify"] |> Option.ofObj with @@ -33767,7 +33767,7 @@ module CronJsonParseExtension = let arg_1 = match node.["exec_times"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -33993,7 +33993,7 @@ module EditBranchProtectionOptionJsonParseExtension = let arg_19 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_18 = match node.["require_signed_commits"] |> Option.ofObj with @@ -34533,7 +34533,7 @@ module EditIssueOptionJsonParseExtension = let arg_5 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["due_date"] |> Option.ofObj with @@ -34845,7 +34845,7 @@ module EditPullRequestOptionJsonParseExtension = let arg_8 = match node.["milestone"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_7 = match node.["labels"] |> Option.ofObj with @@ -34858,10 +34858,10 @@ module EditPullRequestOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int32) to be non-null, but found a null element" + "Expected element of array (element type int64) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -35252,7 +35252,7 @@ module EditUserOptionJsonParseExtension = sprintf "Required key '%s' not found on JSON object" ("source_id") ) ) - | Some node -> node.AsValue().GetValue () + | Some node -> node.AsValue().GetValue () let arg_15 = match node.["restricted"] |> Option.ofObj with @@ -35277,7 +35277,7 @@ module EditUserOptionJsonParseExtension = let arg_11 = match node.["max_repo_creation"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_10 = match node.["login_name"] |> Option.ofObj with @@ -35794,22 +35794,22 @@ module GeneralAPISettingsJsonParseExtension = let arg_4 = match node.["max_response_items"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["default_paging_num"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["default_max_blob_size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["default_git_trees_per_page"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -35860,12 +35860,12 @@ module GeneralAttachmentSettingsJsonParseExtension = let arg_4 = match node.["max_size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["max_files"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["enabled"] |> Option.ofObj with @@ -36219,7 +36219,7 @@ module GitBlobResponseJsonParseExtension = let arg_4 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["sha"] |> Option.ofObj with @@ -36297,7 +36297,7 @@ module GitEntryJsonParseExtension = let arg_4 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["sha"] |> Option.ofObj with @@ -36506,7 +36506,7 @@ module GitTreeResponseJsonParseExtension = let arg_3 = match node.["total_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["sha"] |> Option.ofObj with @@ -36516,7 +36516,7 @@ module GitTreeResponseJsonParseExtension = let arg_1 = match node.["page"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -36616,7 +36616,7 @@ module HookJsonParseExtension = let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["events"] |> Option.ofObj with @@ -36943,10 +36943,10 @@ module IssueLabelsOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int32) to be non-null, but found a null element" + "Expected element of array (element type int64) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -37002,7 +37002,7 @@ module LabelJsonParseExtension = let arg_4 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["exclusive"] |> Option.ofObj with @@ -37237,7 +37237,7 @@ module MigrateRepoOptionsJsonParseExtension = let arg_19 = match node.["uid"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_18 = match node.["service"] |> Option.ofObj with @@ -37595,17 +37595,17 @@ module NodeInfoUsageUsersJsonParseExtension = let arg_3 = match node.["total"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["activeMonth"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["activeHalfyear"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -37650,7 +37650,7 @@ module NotificationCountJsonParseExtension = let arg_1 = match node.["new"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -37717,7 +37717,7 @@ module OAuth2ApplicationJsonParseExtension = let arg_5 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["created"] |> Option.ofObj with @@ -37824,7 +37824,7 @@ module OrganizationJsonParseExtension = let arg_4 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["full_name"] |> Option.ofObj with @@ -38000,12 +38000,12 @@ module PackageFileJsonParseExtension = let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["Size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -38514,7 +38514,7 @@ module RepositoryMetaJsonParseExtension = let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["full_name"] |> Option.ofObj with @@ -38608,7 +38608,7 @@ module StopWatchJsonParseExtension = let arg_7 = match node.["seconds"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["repo_owner_name"] |> Option.ofObj with @@ -38628,7 +38628,7 @@ module StopWatchJsonParseExtension = let arg_3 = match node.["issue_index"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["duration"] |> Option.ofObj with @@ -38903,7 +38903,7 @@ module TeamJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["description"] |> Option.ofObj with @@ -39041,12 +39041,12 @@ module TopicResponseJsonParseExtension = let arg_3 = match node.["repo_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["created"] |> Option.ofObj with @@ -39112,10 +39112,10 @@ module TransferRepoOptionJsonParseExtension = raise ( System.ArgumentNullException ( "elt", - "Expected element of array (element type int32) to be non-null, but found a null element" + "Expected element of array (element type int64) to be non-null, but found a null element" ) ) - | elt -> elt.AsValue().GetValue ()) + | elt -> elt.AsValue().GetValue ()) ) |> List.ofSeq |> Some @@ -39300,7 +39300,7 @@ module UserJsonParseExtension = let arg_18 = match node.["starred_repos_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_17 = match node.["restricted"] |> Option.ofObj with @@ -39345,7 +39345,7 @@ module UserJsonParseExtension = let arg_9 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_8 = match node.["full_name"] |> Option.ofObj with @@ -39355,12 +39355,12 @@ module UserJsonParseExtension = let arg_7 = match node.["following_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["followers_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["email"] |> Option.ofObj with @@ -39468,12 +39468,12 @@ module UserHeatmapDataJsonParseExtension = let arg_2 = match node.["timestamp"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["contributions"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -39860,7 +39860,7 @@ module WikiCommitListJsonParseExtension = let arg_2 = match node.["count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["commits"] |> Option.ofObj with @@ -39958,7 +39958,7 @@ module WikiPageJsonParseExtension = let arg_1 = match node.["commit_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -40093,7 +40093,7 @@ module CommentJsonParseExtension = let arg_8 = match node.["original_author_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_7 = match node.["original_author"] |> Option.ofObj with @@ -40108,7 +40108,7 @@ module CommentJsonParseExtension = let arg_5 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["html_url"] |> Option.ofObj with @@ -40227,7 +40227,7 @@ module CommitStatusJsonParseExtension = let arg_5 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["description"] |> Option.ofObj with @@ -40328,7 +40328,7 @@ module ContentsResponseJsonParseExtension = let arg_11 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_10 = match node.["sha"] |> Option.ofObj with @@ -41253,12 +41253,12 @@ module MilestoneJsonParseExtension = let arg_7 = match node.["open_issues"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["due_on"] |> Option.ofObj with @@ -41278,7 +41278,7 @@ module MilestoneJsonParseExtension = let arg_2 = match node.["closed_issues"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["closed_at"] |> Option.ofObj with @@ -41351,12 +41351,12 @@ module NodeInfoUsageJsonParseExtension = let arg_2 = match node.["localPosts"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["localComments"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -41591,7 +41591,7 @@ module PublicKeyJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["fingerprint"] |> Option.ofObj with @@ -41702,7 +41702,7 @@ module PullReviewJsonParseExtension = let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["html_url"] |> Option.ofObj with @@ -41722,7 +41722,7 @@ module PullReviewJsonParseExtension = let arg_2 = match node.["comments_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["body"] |> Option.ofObj with @@ -41818,7 +41818,7 @@ module PullReviewCommentJsonParseExtension = let arg_11 = match node.["pull_request_review_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_10 = match node.["position"] |> Option.ofObj with @@ -41843,7 +41843,7 @@ module PullReviewCommentJsonParseExtension = let arg_6 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["html_url"] |> Option.ofObj with @@ -42036,7 +42036,7 @@ module ReleaseJsonParseExtension = let arg_7 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["html_url"] |> Option.ofObj with @@ -42362,7 +42362,7 @@ module RepositoryJsonParseExtension = let arg_51 = match node.["watchers_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_50 = match node.["updated_at"] |> Option.ofObj with @@ -42377,7 +42377,7 @@ module RepositoryJsonParseExtension = let arg_48 = match node.["stars_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_47 = match node.["ssh_url"] |> Option.ofObj with @@ -42387,7 +42387,7 @@ module RepositoryJsonParseExtension = let arg_46 = match node.["size"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_45 = match node.["repo_transfer"] |> Option.ofObj with @@ -42397,7 +42397,7 @@ module RepositoryJsonParseExtension = let arg_44 = match node.["release_counter"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_43 = match node.["private"] |> Option.ofObj with @@ -42427,12 +42427,12 @@ module RepositoryJsonParseExtension = let arg_38 = match node.["open_pr_counter"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_37 = match node.["open_issues_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_36 = match node.["name"] |> Option.ofObj with @@ -42487,7 +42487,7 @@ module RepositoryJsonParseExtension = let arg_26 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_25 = match node.["html_url"] |> Option.ofObj with @@ -42522,7 +42522,7 @@ module RepositoryJsonParseExtension = let arg_19 = match node.["forks_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_18 = match node.["fork"] |> Option.ofObj with @@ -42914,7 +42914,7 @@ module CombinedStatusJsonParseExtension = let arg_6 = match node.["total_count"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["statuses"] |> Option.ofObj with @@ -43166,7 +43166,7 @@ module DeployKeyJsonParseExtension = let arg_5 = match node.["key_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["key"] |> Option.ofObj with @@ -43176,7 +43176,7 @@ module DeployKeyJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["fingerprint"] |> Option.ofObj with @@ -43397,7 +43397,7 @@ module IssueJsonParseExtension = let arg_16 = match node.["original_author_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_15 = match node.["original_author"] |> Option.ofObj with @@ -43407,7 +43407,7 @@ module IssueJsonParseExtension = let arg_14 = match node.["number"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_13 = match node.["milestone"] |> Option.ofObj with @@ -43441,7 +43441,7 @@ module IssueJsonParseExtension = let arg_10 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_9 = match node.["html_url"] |> Option.ofObj with @@ -43461,7 +43461,7 @@ module IssueJsonParseExtension = let arg_6 = match node.["comments"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["closed_at"] |> Option.ofObj with @@ -43785,7 +43785,7 @@ module NotificationThreadJsonParseExtension = let arg_1 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_0 = let result = @@ -43847,7 +43847,7 @@ module PRBranchInfoJsonParseExtension = let arg_4 = match node.["repo_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["repo"] |> Option.ofObj with @@ -43934,7 +43934,7 @@ module PackageJsonParseExtension = let arg_3 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_2 = match node.["creator"] |> Option.ofObj with @@ -44183,7 +44183,7 @@ module PullRequestJsonParseExtension = let arg_23 = match node.["number"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_22 = match node.["milestone"] |> Option.ofObj with @@ -44247,7 +44247,7 @@ module PullRequestJsonParseExtension = let arg_13 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_12 = match node.["html_url"] |> Option.ofObj with @@ -44277,7 +44277,7 @@ module PullRequestJsonParseExtension = let arg_7 = match node.["comments"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["closed_at"] |> Option.ofObj with @@ -44427,17 +44427,17 @@ module TrackedTimeJsonParseExtension = let arg_6 = match node.["user_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["time"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_4 = match node.["issue_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_3 = match node.["issue"] |> Option.ofObj with @@ -44447,7 +44447,7 @@ module TrackedTimeJsonParseExtension = let arg_2 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_1 = match node.["created"] |> Option.ofObj with @@ -44538,7 +44538,7 @@ module BranchJsonParseExtension = let arg_6 = match node.["required_approvals"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_5 = match node.["protected"] |> Option.ofObj with @@ -44644,7 +44644,7 @@ module TimelineCommentJsonParseExtension = let arg_25 = match node.["review_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_24 = match node.["resolve_doer"] |> Option.ofObj with @@ -44684,7 +44684,7 @@ module TimelineCommentJsonParseExtension = let arg_17 = match node.["project_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_16 = match node.["old_title"] |> Option.ofObj with @@ -44699,7 +44699,7 @@ module TimelineCommentJsonParseExtension = let arg_14 = match node.["old_project_id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_13 = match node.["old_milestone"] |> Option.ofObj with @@ -44734,7 +44734,7 @@ module TimelineCommentJsonParseExtension = let arg_7 = match node.["id"] |> Option.ofObj with | None -> None - | Some v -> v.AsValue().GetValue () |> Some + | Some v -> v.AsValue().GetValue () |> Some let arg_6 = match node.["html_url"] |> Option.ofObj with @@ -44863,7 +44863,7 @@ module LanguageStatisticsJsonParseExtension = /// Parse from a JSON node. static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : LanguageStatistics = let arg_0 = - let result = System.Collections.Generic.Dictionary () + let result = System.Collections.Generic.Dictionary () let node = node.AsObject () for KeyValue (key, value) in node do @@ -44879,7 +44879,7 @@ module LanguageStatisticsJsonParseExtension = sprintf "Required key '%s' not found on JSON object" (key) ) ) - | Some node -> node.AsValue().GetValue () + | Some node -> node.AsValue().GetValue () ) result @@ -45055,6 +45055,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45121,6 +45122,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -45137,11 +45146,10 @@ module Gitea = ), System.Uri ( ("admin/cron" - + (if "admin/cron".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "admin/cron".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -45152,6 +45160,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45230,6 +45239,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -45246,11 +45263,10 @@ module Gitea = ), System.Uri ( ("admin/hooks" - + (if "admin/hooks".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "admin/hooks".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -45261,6 +45277,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45327,12 +45344,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45357,7 +45377,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.AdminGetHook (id : int, ct : System.Threading.CancellationToken option) = + member _.AdminGetHook (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -45387,6 +45407,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45411,7 +45432,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.AdminEditHook (id : int, body : EditHookOption, ct : System.Threading.CancellationToken option) = + member _.AdminEditHook (id : int64, body : EditHookOption, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -45443,12 +45464,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45477,6 +45501,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -45493,11 +45525,10 @@ module Gitea = ), System.Uri ( ("admin/orgs" - + (if "admin/orgs".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "admin/orgs".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -45508,6 +45539,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45551,6 +45583,15 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + [ "pattern=" + ((pattern.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -45567,16 +45608,14 @@ module Gitea = ), System.Uri ( ("admin/unadopted" - + (if "admin/unadopted".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString) - + "&pattern=" - + ((pattern.ToString ()) |> System.Uri.EscapeDataString)), + ((if "admin/unadopted".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -45587,6 +45626,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45710,6 +45750,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -45726,11 +45774,10 @@ module Gitea = ), System.Uri ( ("admin/users" - + (if "admin/users".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "admin/users".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -45741,6 +45788,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45807,12 +45855,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateUserOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateUserOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45841,6 +45892,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "purge=" + ((purge.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -45858,12 +45914,14 @@ module Gitea = System.Uri ( ("admin/users/{username}" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "admin/users/{username}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "purge=" - + ((purge.ToString ()) |> System.Uri.EscapeDataString)), + ((if "admin/users/{username}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -45916,12 +45974,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditUserOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditUserOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -45981,12 +46042,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - key |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + key |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46012,7 +46076,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.AdminDeleteUserPublicKey - (username : string, id : int, ct : System.Threading.CancellationToken option) + (username : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46087,12 +46151,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46152,12 +46219,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - repository |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + repository |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46182,7 +46252,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.AdminDeleteHook (id : int, ct : System.Threading.CancellationToken option) = + member _.AdminDeleteHook (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -46248,12 +46318,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> MarkdownOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "text/html" + body |> MarkdownOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "text/html") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46289,8 +46362,14 @@ module Gitea = RequestUri = uri ) - let queryParams = new System.Net.Http.StringContent (body, null, "text/html") + let queryParams = new System.Net.Http.StringContent (body) + + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("text/plain; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "text/html") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46326,6 +46405,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46365,6 +46445,28 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] + + status_types + |> List.map (fun queryParam -> + "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + + subject_type + |> List.map (fun queryParam -> + "subject-type=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -46381,21 +46483,10 @@ module Gitea = ), System.Uri ( ("notifications" - + (if "notifications".IndexOf (char 63) >= 0 then "&" else "?") - + "all=" - + ((all.ToString ()) |> System.Uri.EscapeDataString) - + "&status-types=" - + ((status_types.ToString ()) |> System.Uri.EscapeDataString) - + "&subject-type=" - + ((subject_type.ToString ()) |> System.Uri.EscapeDataString) - + "&since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "notifications".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -46406,6 +46497,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46455,6 +46547,22 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ + "last_read_at=" + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString) + ] + [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] + + status_types + |> List.map (fun queryParam -> + "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + [ "to-status=" + ((to_status.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -46471,15 +46579,10 @@ module Gitea = ), System.Uri ( ("notifications" - + (if "notifications".IndexOf (char 63) >= 0 then "&" else "?") - + "last_read_at=" - + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString) - + "&all=" - + ((all.ToString ()) |> System.Uri.EscapeDataString) - + "&status-types=" - + ((status_types.ToString ()) |> System.Uri.EscapeDataString) - + "&to-status=" - + ((to_status.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "notifications".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -46490,6 +46593,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46554,6 +46658,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46609,6 +46714,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46639,6 +46745,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "to-status=" + ((to_status.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -46656,12 +46767,14 @@ module Gitea = System.Uri ( ("notifications/threads/{id}" .Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if "notifications/threads/{id}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "to-status=" - + ((to_status.ToString ()) |> System.Uri.EscapeDataString)), + ((if "notifications/threads/{id}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -46672,6 +46785,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46730,12 +46844,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46764,6 +46881,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -46780,11 +46905,10 @@ module Gitea = ), System.Uri ( ("orgs" - + (if "orgs".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "orgs".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -46795,6 +46919,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46861,12 +46986,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + organization |> CreateOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -46921,6 +47049,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47014,12 +47143,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditOrgOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47050,6 +47182,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -47066,14 +47206,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/hooks".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -47084,6 +47224,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47155,12 +47296,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47185,7 +47329,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgGetHook (org : string, id : int, ct : System.Threading.CancellationToken option) = + member _.OrgGetHook (org : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -47217,6 +47361,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47241,7 +47386,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgDeleteHook (org : string, id : int, ct : System.Threading.CancellationToken option) = + member _.OrgDeleteHook (org : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -47281,7 +47426,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgEditHook - (org : string, id : int, body : EditHookOption, ct : System.Threading.CancellationToken option) + (org : string, id : int64, body : EditHookOption, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -47316,12 +47461,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47352,6 +47500,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -47368,14 +47524,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/labels".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if "orgs/{org}/labels".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "orgs/{org}/labels".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -47386,6 +47542,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47457,12 +47614,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47487,7 +47647,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgGetLabel (org : string, id : int, ct : System.Threading.CancellationToken option) = + member _.OrgGetLabel (org : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -47519,6 +47679,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47543,7 +47704,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgDeleteLabel (org : string, id : int, ct : System.Threading.CancellationToken option) = + member _.OrgDeleteLabel (org : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -47583,7 +47744,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgEditLabel - (org : string, id : int, body : EditLabelOption, ct : System.Threading.CancellationToken option) + (org : string, id : int64, body : EditLabelOption, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -47618,12 +47779,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47654,6 +47818,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -47670,14 +47842,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/members".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if "orgs/{org}/members".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "orgs/{org}/members".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -47688,6 +47860,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -47809,6 +47982,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -47826,14 +48007,14 @@ module Gitea = System.Uri ( ("orgs/{org}/public_members" .Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if "orgs/{org}/public_members".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "orgs/{org}/public_members".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -47844,6 +48025,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48010,6 +48192,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -48026,14 +48216,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if "orgs/{org}/repos".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "orgs/{org}/repos".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -48044,6 +48234,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48115,12 +48306,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48151,6 +48345,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -48167,14 +48369,14 @@ module Gitea = ), System.Uri ( ("orgs/{org}/teams".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if "orgs/{org}/teams".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "orgs/{org}/teams".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -48185,6 +48387,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48256,12 +48459,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48299,6 +48505,18 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] + [ + "include_desc=" + ((include_desc.ToString ()) |> System.Uri.EscapeDataString) + ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -48316,18 +48534,14 @@ module Gitea = System.Uri ( ("orgs/{org}/teams/search" .Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString) - + (if "orgs/{org}/teams/search".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "q=" - + ((q.ToString ()) |> System.Uri.EscapeDataString) - + "&include_desc=" - + ((include_desc.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "orgs/{org}/teams/search".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -48338,6 +48552,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48375,6 +48590,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + [ "type=" + ((type'.ToString ()) |> System.Uri.EscapeDataString) ] + [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -48392,18 +48617,14 @@ module Gitea = System.Uri ( ("packages/{owner}" .Replace ("{owner}", owner.ToString () |> System.Uri.EscapeDataString) - + (if "packages/{owner}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString) - + "&type=" - + ((type'.ToString ()) |> System.Uri.EscapeDataString) - + "&q=" - + ((q.ToString ()) |> System.Uri.EscapeDataString)), + ((if "packages/{owner}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -48414,6 +48635,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48493,6 +48715,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48608,6 +48831,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48651,7 +48875,7 @@ module Gitea = labels : string, milestones : string, q : string, - priority_repo_id : int, + priority_repo_id : int64, type' : string, since : string, before : string, @@ -48669,6 +48893,38 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] + [ "labels=" + ((labels.ToString ()) |> System.Uri.EscapeDataString) ] + [ "milestones=" + ((milestones.ToString ()) |> System.Uri.EscapeDataString) ] + [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] + + [ + "priority_repo_id=" + + ((priority_repo_id.ToString ()) |> System.Uri.EscapeDataString) + ] + + [ "type=" + ((type'.ToString ()) |> System.Uri.EscapeDataString) ] + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + [ "assigned=" + ((assigned.ToString ()) |> System.Uri.EscapeDataString) ] + [ "created=" + ((created.ToString ()) |> System.Uri.EscapeDataString) ] + [ "mentioned=" + ((mentioned.ToString ()) |> System.Uri.EscapeDataString) ] + + [ + "review_requested=" + + ((review_requested.ToString ()) |> System.Uri.EscapeDataString) + ] + + [ "owner=" + ((owner.ToString ()) |> System.Uri.EscapeDataString) ] + [ "team=" + ((team.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -48685,42 +48941,14 @@ module Gitea = ), System.Uri ( ("repos/issues/search" - + (if "repos/issues/search".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "state=" - + ((state.ToString ()) |> System.Uri.EscapeDataString) - + "&labels=" - + ((labels.ToString ()) |> System.Uri.EscapeDataString) - + "&milestones=" - + ((milestones.ToString ()) |> System.Uri.EscapeDataString) - + "&q=" - + ((q.ToString ()) |> System.Uri.EscapeDataString) - + "&priority_repo_id=" - + ((priority_repo_id.ToString ()) |> System.Uri.EscapeDataString) - + "&type=" - + ((type'.ToString ()) |> System.Uri.EscapeDataString) - + "&since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString) - + "&assigned=" - + ((assigned.ToString ()) |> System.Uri.EscapeDataString) - + "&created=" - + ((created.ToString ()) |> System.Uri.EscapeDataString) - + "&mentioned=" - + ((mentioned.ToString ()) |> System.Uri.EscapeDataString) - + "&review_requested=" - + ((review_requested.ToString ()) |> System.Uri.EscapeDataString) - + "&owner=" - + ((owner.ToString ()) |> System.Uri.EscapeDataString) - + "&team=" - + ((team.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/issues/search".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -48731,6 +48959,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48797,12 +49026,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> MigrateRepoOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> MigrateRepoOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48832,10 +49064,10 @@ module Gitea = q : string, topic : bool, includeDesc : bool, - uid : int, - priority_owner_id : int, - team_id : int, - starredBy : int, + uid : int64, + priority_owner_id : int64, + team_id : int64, + starredBy : int64, private' : bool, is_private : bool, template : bool, @@ -48852,6 +49084,34 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] + [ "topic=" + ((topic.ToString ()) |> System.Uri.EscapeDataString) ] + [ "includeDesc=" + ((includeDesc.ToString ()) |> System.Uri.EscapeDataString) ] + [ "uid=" + ((uid.ToString ()) |> System.Uri.EscapeDataString) ] + + [ + "priority_owner_id=" + + ((priority_owner_id.ToString ()) |> System.Uri.EscapeDataString) + ] + + [ "team_id=" + ((team_id.ToString ()) |> System.Uri.EscapeDataString) ] + [ "starredBy=" + ((starredBy.ToString ()) |> System.Uri.EscapeDataString) ] + [ "private=" + ((private'.ToString ()) |> System.Uri.EscapeDataString) ] + [ "is_private=" + ((is_private.ToString ()) |> System.Uri.EscapeDataString) ] + [ "template=" + ((template.ToString ()) |> System.Uri.EscapeDataString) ] + [ "archived=" + ((archived.ToString ()) |> System.Uri.EscapeDataString) ] + [ "mode=" + ((mode.ToString ()) |> System.Uri.EscapeDataString) ] + [ "exclusive=" + ((exclusive.ToString ()) |> System.Uri.EscapeDataString) ] + [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] + [ "order=" + ((order.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -48868,41 +49128,10 @@ module Gitea = ), System.Uri ( ("repos/search" - + (if "repos/search".IndexOf (char 63) >= 0 then "&" else "?") - + "q=" - + ((q.ToString ()) |> System.Uri.EscapeDataString) - + "&topic=" - + ((topic.ToString ()) |> System.Uri.EscapeDataString) - + "&includeDesc=" - + ((includeDesc.ToString ()) |> System.Uri.EscapeDataString) - + "&uid=" - + ((uid.ToString ()) |> System.Uri.EscapeDataString) - + "&priority_owner_id=" - + ((priority_owner_id.ToString ()) |> System.Uri.EscapeDataString) - + "&team_id=" - + ((team_id.ToString ()) |> System.Uri.EscapeDataString) - + "&starredBy=" - + ((starredBy.ToString ()) |> System.Uri.EscapeDataString) - + "&private=" - + ((private'.ToString ()) |> System.Uri.EscapeDataString) - + "&is_private=" - + ((is_private.ToString ()) |> System.Uri.EscapeDataString) - + "&template=" - + ((template.ToString ()) |> System.Uri.EscapeDataString) - + "&archived=" - + ((archived.ToString ()) |> System.Uri.EscapeDataString) - + "&mode=" - + ((mode.ToString ()) |> System.Uri.EscapeDataString) - + "&exclusive=" - + ((exclusive.ToString ()) |> System.Uri.EscapeDataString) - + "&sort=" - + ((sort.ToString ()) |> System.Uri.EscapeDataString) - + "&order=" - + ((order.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "repos/search".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -48913,6 +49142,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -48969,6 +49199,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49068,12 +49299,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49172,6 +49406,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49243,6 +49478,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49323,12 +49559,15 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateBranchProtectionOption.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49388,6 +49627,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49499,12 +49739,15 @@ module Gitea = new System.Net.Http.StringContent ( body |> EditBranchProtectionOption.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49535,6 +49778,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -49553,14 +49804,14 @@ module Gitea = ("repos/{owner}/{repo}/branches" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/branches".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/branches".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -49571,6 +49822,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49649,12 +49901,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateBranchRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateBranchRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49714,6 +49969,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49786,6 +50042,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -49804,14 +50068,14 @@ module Gitea = ("repos/{owner}/{repo}/collaborators" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/collaborators".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/collaborators".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -49822,6 +50086,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -49986,11 +50251,13 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> AddCollaboratorOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> AddCollaboratorOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -50034,6 +50301,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50073,6 +50341,17 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "sha=" + ((sha.ToString ()) |> System.Uri.EscapeDataString) ] + [ "path=" + ((path.ToString ()) |> System.Uri.EscapeDataString) ] + [ "stat=" + ((stat.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -50091,20 +50370,14 @@ module Gitea = ("repos/{owner}/{repo}/commits" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/commits".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "sha=" - + ((sha.ToString ()) |> System.Uri.EscapeDataString) - + "&path=" - + ((path.ToString ()) |> System.Uri.EscapeDataString) - + "&stat=" - + ((stat.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/commits".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -50115,6 +50388,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50165,6 +50439,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -50184,14 +50466,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{ref}", ref.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/commits/{ref}/status".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/commits/{ref}/status".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -50202,6 +50484,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50241,6 +50524,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] + [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -50260,18 +50553,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{ref}", ref.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/commits/{ref}/statuses".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "sort=" - + ((sort.ToString ()) |> System.Uri.EscapeDataString) - + "&state=" - + ((state.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/commits/{ref}/statuses".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -50282,6 +50571,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50325,6 +50615,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -50343,12 +50638,14 @@ module Gitea = ("repos/{owner}/{repo}/contents" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/contents".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "ref=" - + ((ref.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/contents".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -50359,6 +50656,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50408,6 +50706,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -50427,12 +50730,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/contents/{filepath}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "ref=" - + ((ref.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/contents/{filepath}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -50443,6 +50748,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50510,12 +50816,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50583,12 +50892,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> DeleteFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> DeleteFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50656,12 +50968,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50722,12 +51037,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> UpdateFileOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50764,6 +51082,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -50783,12 +51106,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/editorconfig/{filepath}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "ref=" - + ((ref.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/editorconfig/{filepath}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -50812,6 +51137,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -50830,14 +51163,14 @@ module Gitea = ("repos/{owner}/{repo}/forks" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/forks".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/forks".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -50848,6 +51181,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50921,12 +51255,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateForkOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateForkOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -50986,6 +51323,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51045,6 +51383,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51111,6 +51450,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51154,6 +51494,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51212,6 +51553,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51284,6 +51626,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51356,6 +51699,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51394,6 +51738,15 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "recursive=" + ((recursive.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "per_page=" + ((per_page.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -51413,16 +51766,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{sha}", sha.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/git/trees/{sha}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "recursive=" - + ((recursive.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&per_page=" - + ((per_page.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/git/trees/{sha}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -51433,6 +51784,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51463,6 +51815,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -51481,14 +51841,14 @@ module Gitea = ("repos/{owner}/{repo}/hooks" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/hooks".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/hooks".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -51499,6 +51859,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51572,12 +51933,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51634,6 +51998,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51706,6 +52071,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51815,12 +52181,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditGitHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditGitHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51846,7 +52215,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetHook - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -51880,6 +52249,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -51905,7 +52275,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeleteHook - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -51950,7 +52320,7 @@ module Gitea = ( owner : string, repo : string, - id : int, + id : int64, body : EditHookOption, ct : System.Threading.CancellationToken option ) @@ -51989,12 +52359,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditHookOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52020,11 +52393,16 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoTestHook - (owner : string, repo : string, id : int, ref : string, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ref : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken + let queryString = + [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -52044,12 +52422,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/hooks/{id}/tests".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "ref=" - + ((ref.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/hooks/{id}/tests".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -52101,6 +52481,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52160,6 +52541,26 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] + [ "labels=" + ((labels.ToString ()) |> System.Uri.EscapeDataString) ] + [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] + [ "type=" + ((type'.ToString ()) |> System.Uri.EscapeDataString) ] + [ "milestones=" + ((milestones.ToString ()) |> System.Uri.EscapeDataString) ] + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + [ "created_by=" + ((created_by.ToString ()) |> System.Uri.EscapeDataString) ] + [ "assigned_by=" + ((assigned_by.ToString ()) |> System.Uri.EscapeDataString) ] + [ + "mentioned_by=" + ((mentioned_by.ToString ()) |> System.Uri.EscapeDataString) + ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -52178,34 +52579,14 @@ module Gitea = ("repos/{owner}/{repo}/issues" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/issues".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "state=" - + ((state.ToString ()) |> System.Uri.EscapeDataString) - + "&labels=" - + ((labels.ToString ()) |> System.Uri.EscapeDataString) - + "&q=" - + ((q.ToString ()) |> System.Uri.EscapeDataString) - + "&type=" - + ((type'.ToString ()) |> System.Uri.EscapeDataString) - + "&milestones=" - + ((milestones.ToString ()) |> System.Uri.EscapeDataString) - + "&since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString) - + "&created_by=" - + ((created_by.ToString ()) |> System.Uri.EscapeDataString) - + "&assigned_by=" - + ((assigned_by.ToString ()) |> System.Uri.EscapeDataString) - + "&mentioned_by=" - + ((mentioned_by.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/issues".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -52216,6 +52597,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52289,12 +52671,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52333,6 +52718,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -52351,18 +52746,14 @@ module Gitea = ("repos/{owner}/{repo}/issues/comments" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/issues/comments".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/issues/comments".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -52373,6 +52764,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52411,7 +52803,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteComment - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52453,7 +52845,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueListIssueCommentAttachments - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52487,6 +52879,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52528,8 +52921,8 @@ module Gitea = ( owner : string, repo : string, - id : int, - attachment_id : int, + id : int64, + attachment_id : int64, ct : System.Threading.CancellationToken option ) = @@ -52569,6 +52962,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52597,8 +52991,8 @@ module Gitea = ( owner : string, repo : string, - id : int, - attachment_id : int, + id : int64, + attachment_id : int64, ct : System.Threading.CancellationToken option ) = @@ -52649,8 +53043,8 @@ module Gitea = ( owner : string, repo : string, - id : int, - attachment_id : int, + id : int64, + attachment_id : int64, body : EditAttachmentOptions, ct : System.Threading.CancellationToken option ) @@ -52693,12 +53087,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52724,7 +53121,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetCommentReactions - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52758,6 +53155,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52799,7 +53197,7 @@ module Gitea = ( owner : string, repo : string, - id : int, + id : int64, content : EditReactionOption, ct : System.Threading.CancellationToken option ) @@ -52838,11 +53236,13 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -52852,7 +53252,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetIssue - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52886,6 +53286,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -52911,7 +53312,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDelete - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -52956,7 +53357,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : EditIssueOption, ct : System.Threading.CancellationToken option ) @@ -52995,12 +53396,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditIssueOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53026,7 +53430,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueListIssueAttachments - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53060,6 +53464,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53101,8 +53506,8 @@ module Gitea = ( owner : string, repo : string, - index : int, - attachment_id : int, + index : int64, + attachment_id : int64, ct : System.Threading.CancellationToken option ) = @@ -53142,6 +53547,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53170,8 +53576,8 @@ module Gitea = ( owner : string, repo : string, - index : int, - attachment_id : int, + index : int64, + attachment_id : int64, ct : System.Threading.CancellationToken option ) = @@ -53222,8 +53628,8 @@ module Gitea = ( owner : string, repo : string, - index : int, - attachment_id : int, + index : int64, + attachment_id : int64, body : EditAttachmentOptions, ct : System.Threading.CancellationToken option ) @@ -53266,12 +53672,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53300,7 +53709,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, since : string, before : string, ct : System.Threading.CancellationToken option @@ -53309,6 +53718,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -53328,14 +53745,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/issues/{index}/comments".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/issues/{index}/comments".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -53346,6 +53763,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53387,7 +53805,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : CreateIssueCommentOption, ct : System.Threading.CancellationToken option ) @@ -53428,12 +53846,15 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateIssueCommentOption.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53459,7 +53880,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteCommentDeprecated - (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53505,7 +53926,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : EditDeadlineOption, ct : System.Threading.CancellationToken option ) @@ -53544,12 +53965,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditDeadlineOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditDeadlineOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53575,7 +53999,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetLabels - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53609,6 +54033,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53650,7 +54075,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : IssueLabelsOption, ct : System.Threading.CancellationToken option ) @@ -53689,12 +54114,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53733,7 +54161,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueClearLabels - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -53778,7 +54206,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : IssueLabelsOption, ct : System.Threading.CancellationToken option ) @@ -53817,12 +54245,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> IssueLabelsOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53861,7 +54292,13 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueRemoveLabel - (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) + ( + owner : string, + repo : string, + index : int64, + id : int64, + ct : System.Threading.CancellationToken option + ) = async { let! ct = Async.CancellationToken @@ -53907,7 +54344,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -53916,6 +54353,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -53935,14 +54380,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/issues/{index}/reactions".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/issues/{index}/reactions".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -53953,6 +54398,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -53994,7 +54440,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, content : EditReactionOption, ct : System.Threading.CancellationToken option ) @@ -54033,11 +54479,13 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + content |> EditReactionOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -54047,7 +54495,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteStopWatch - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54089,7 +54537,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueStartStopWatch - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54131,7 +54579,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueStopStopWatch - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54176,7 +54624,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -54185,6 +54633,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -54204,14 +54660,16 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/issues/{index}/subscriptions".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if + "repos/{owner}/{repo}/issues/{index}/subscriptions".IndexOf (char 63) >= 0 + then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -54222,6 +54680,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54260,7 +54719,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueCheckSubscription - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54294,6 +54753,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54322,7 +54782,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, since : string, page : int, limit : int, @@ -54333,6 +54793,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -54352,18 +54822,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/issues/{index}/timeline".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/issues/{index}/timeline".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -54374,6 +54840,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54415,7 +54882,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, user : string, since : string, before : string, @@ -54427,6 +54894,17 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "user=" + ((user.ToString ()) |> System.Uri.EscapeDataString) ] + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -54446,20 +54924,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/issues/{index}/times".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "user=" - + ((user.ToString ()) |> System.Uri.EscapeDataString) - + "&since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/issues/{index}/times".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -54470,6 +54942,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54511,7 +54984,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : AddTimeOption, ct : System.Threading.CancellationToken option ) @@ -54550,12 +55023,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> AddTimeOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> AddTimeOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54581,7 +55057,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueResetTime - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54623,7 +55099,13 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteTime - (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) + ( + owner : string, + repo : string, + index : int64, + id : int64, + ct : System.Threading.CancellationToken option + ) = async { let! ct = Async.CancellationToken @@ -54679,6 +55161,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "key_id=" + ((key_id.ToString ()) |> System.Uri.EscapeDataString) ] + [ "fingerprint=" + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -54697,18 +55189,14 @@ module Gitea = ("repos/{owner}/{repo}/keys" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/keys".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "key_id=" - + ((key_id.ToString ()) |> System.Uri.EscapeDataString) - + "&fingerprint=" - + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/keys".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -54719,6 +55207,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54792,12 +55281,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54823,7 +55315,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetKey - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54857,6 +55349,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -54882,7 +55375,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeleteKey - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -54929,6 +55422,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -54947,14 +55448,14 @@ module Gitea = ("repos/{owner}/{repo}/labels" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/labels".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/labels".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -54965,6 +55466,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55038,12 +55540,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55069,7 +55574,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueGetLabel - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -55103,6 +55608,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55128,7 +55634,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.IssueDeleteLabel - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -55173,7 +55679,7 @@ module Gitea = ( owner : string, repo : string, - id : int, + id : int64, body : EditLabelOption, ct : System.Threading.CancellationToken option ) @@ -55212,12 +55718,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditLabelOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55274,6 +55783,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55310,6 +55820,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -55329,12 +55844,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/media/{filepath}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "ref=" - + ((ref.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/media/{filepath}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -55366,6 +55883,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] + [ "name=" + ((name.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -55384,18 +55911,14 @@ module Gitea = ("repos/{owner}/{repo}/milestones" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/milestones".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "state=" - + ((state.ToString ()) |> System.Uri.EscapeDataString) - + "&name=" - + ((name.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/milestones".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -55406,6 +55929,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55484,12 +56008,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55549,6 +56076,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55658,12 +56186,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditMilestoneOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55744,6 +56275,28 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] + + status_types + |> List.map (fun queryParam -> + "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + + subject_type + |> List.map (fun queryParam -> + "subject-type=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -55762,24 +56315,14 @@ module Gitea = ("repos/{owner}/{repo}/notifications" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "all=" - + ((all.ToString ()) |> System.Uri.EscapeDataString) - + "&status-types=" - + ((status_types.ToString ()) |> System.Uri.EscapeDataString) - + "&subject-type=" - + ((subject_type.ToString ()) |> System.Uri.EscapeDataString) - + "&since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -55790,6 +56333,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55841,6 +56385,23 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "all=" + ((all.ToString ()) |> System.Uri.EscapeDataString) ] + + status_types + |> List.map (fun queryParam -> + "status-types=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + + [ "to-status=" + ((to_status.ToString ()) |> System.Uri.EscapeDataString) ] + [ + "last_read_at=" + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString) + ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -55859,18 +56420,14 @@ module Gitea = ("repos/{owner}/{repo}/notifications" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "all=" - + ((all.ToString ()) |> System.Uri.EscapeDataString) - + "&status-types=" - + ((status_types.ToString ()) |> System.Uri.EscapeDataString) - + "&to-status=" - + ((to_status.ToString ()) |> System.Uri.EscapeDataString) - + "&last_read_at=" - + ((last_read_at.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/notifications".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -55881,6 +56438,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -55924,8 +56482,8 @@ module Gitea = repo : string, state : string, sort : string, - milestone : int, - labels : int list, + milestone : int64, + labels : int64 list, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -55934,6 +56492,23 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] + [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] + [ "milestone=" + ((milestone.ToString ()) |> System.Uri.EscapeDataString) ] + + labels + |> List.map (fun queryParam -> + "labels=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -55952,22 +56527,14 @@ module Gitea = ("repos/{owner}/{repo}/pulls" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/pulls".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "state=" - + ((state.ToString ()) |> System.Uri.EscapeDataString) - + "&sort=" - + ((sort.ToString ()) |> System.Uri.EscapeDataString) - + "&milestone=" - + ((milestone.ToString ()) |> System.Uri.EscapeDataString) - + "&labels=" - + ((labels.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/pulls".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -55978,6 +56545,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56056,12 +56624,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreatePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreatePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56087,7 +56658,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetPullRequest - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -56121,6 +56692,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56149,7 +56721,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : EditPullRequestOption, ct : System.Threading.CancellationToken option ) @@ -56188,12 +56760,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditPullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditPullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56222,7 +56797,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, diffType : string, binary : bool, ct : System.Threading.CancellationToken option @@ -56231,6 +56806,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "binary=" + ((binary.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -56251,12 +56831,14 @@ module Gitea = .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace("{index}", index.ToString () |> System.Uri.EscapeDataString) .Replace ("{diffType}", diffType.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/pulls/{index}.{diffType}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "binary=" - + ((binary.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/pulls/{index}.{diffType}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -56267,6 +56849,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56279,7 +56862,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -56288,6 +56871,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -56307,14 +56898,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/pulls/{index}/commits".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/pulls/{index}/commits".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -56325,6 +56916,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56366,7 +56958,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, skip_to : string, whitespace : string, page : int, @@ -56377,6 +56969,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "skip-to=" + ((skip_to.ToString ()) |> System.Uri.EscapeDataString) ] + [ "whitespace=" + ((whitespace.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -56396,18 +56998,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/pulls/{index}/files".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "skip-to=" - + ((skip_to.ToString ()) |> System.Uri.EscapeDataString) - + "&whitespace=" - + ((whitespace.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/pulls/{index}/files".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -56418,6 +57016,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56456,7 +57055,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoPullRequestIsMerged - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -56501,7 +57100,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : MergePullRequestOption, ct : System.Threading.CancellationToken option ) @@ -56540,11 +57139,13 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> MergePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> MergePullRequestOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -56554,7 +57155,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoCancelScheduledAutoMerge - (owner : string, repo : string, index : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, index : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -56599,7 +57200,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : PullReviewRequestOptions, ct : System.Threading.CancellationToken option ) @@ -56640,12 +57241,15 @@ module Gitea = new System.Net.Http.StringContent ( body |> PullReviewRequestOptions.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56687,7 +57291,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : PullReviewRequestOptions, ct : System.Threading.CancellationToken option ) @@ -56728,11 +57332,13 @@ module Gitea = new System.Net.Http.StringContent ( body |> PullReviewRequestOptions.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -56745,7 +57351,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, page : int, limit : int, ct : System.Threading.CancellationToken option @@ -56754,6 +57360,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -56773,14 +57387,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/pulls/{index}/reviews".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/pulls/{index}/reviews".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -56791,6 +57405,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56832,7 +57447,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, body : CreatePullReviewOptions, ct : System.Threading.CancellationToken option ) @@ -56871,12 +57486,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreatePullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreatePullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56902,7 +57520,13 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetPullReview - (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) + ( + owner : string, + repo : string, + index : int64, + id : int64, + ct : System.Threading.CancellationToken option + ) = async { let! ct = Async.CancellationToken @@ -56937,6 +57561,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -56965,8 +57590,8 @@ module Gitea = ( owner : string, repo : string, - index : int, - id : int, + index : int64, + id : int64, body : SubmitPullReviewOptions, ct : System.Threading.CancellationToken option ) @@ -57006,12 +57631,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> SubmitPullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> SubmitPullReviewOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57037,7 +57665,13 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeletePullReview - (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) + ( + owner : string, + repo : string, + index : int64, + id : int64, + ct : System.Threading.CancellationToken option + ) = async { let! ct = Async.CancellationToken @@ -57080,7 +57714,13 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetPullReviewComments - (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) + ( + owner : string, + repo : string, + index : int64, + id : int64, + ct : System.Threading.CancellationToken option + ) = async { let! ct = Async.CancellationToken @@ -57115,6 +57755,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57156,8 +57797,8 @@ module Gitea = ( owner : string, repo : string, - index : int, - id : int, + index : int64, + id : int64, body : DismissPullReviewOptions, ct : System.Threading.CancellationToken option ) @@ -57199,12 +57840,15 @@ module Gitea = new System.Net.Http.StringContent ( body |> DismissPullReviewOptions.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57230,7 +57874,13 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoUnDismissPullReview - (owner : string, repo : string, index : int, id : int, ct : System.Threading.CancellationToken option) + ( + owner : string, + repo : string, + index : int64, + id : int64, + ct : System.Threading.CancellationToken option + ) = async { let! ct = Async.CancellationToken @@ -57265,6 +57915,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57293,7 +57944,7 @@ module Gitea = ( owner : string, repo : string, - index : int, + index : int64, style : string, ct : System.Threading.CancellationToken option ) @@ -57301,6 +57952,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "style=" + ((style.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -57320,12 +57976,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{index}", index.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/pulls/{index}/update".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "style=" - + ((style.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/pulls/{index}/update".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -57349,6 +58007,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -57367,14 +58033,14 @@ module Gitea = ("repos/{owner}/{repo}/push_mirrors" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/push_mirrors".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/push_mirrors".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -57385,6 +58051,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57463,12 +58130,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreatePushMirrorOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreatePushMirrorOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57569,6 +58239,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57647,6 +58318,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "ref=" + ((ref.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -57666,12 +58342,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{filepath}", filepath.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/raw/{filepath}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "ref=" - + ((ref.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/raw/{filepath}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -57704,6 +58382,17 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "draft=" + ((draft.ToString ()) |> System.Uri.EscapeDataString) ] + [ "pre-release=" + ((pre_release.ToString ()) |> System.Uri.EscapeDataString) ] + [ "per_page=" + ((per_page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -57722,20 +58411,14 @@ module Gitea = ("repos/{owner}/{repo}/releases" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/releases".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "draft=" - + ((draft.ToString ()) |> System.Uri.EscapeDataString) - + "&pre-release=" - + ((pre_release.ToString ()) |> System.Uri.EscapeDataString) - + "&per_page=" - + ((per_page.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/releases".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -57746,6 +58429,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57824,12 +58508,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57888,6 +58575,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -57947,6 +58635,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58014,7 +58703,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoGetRelease - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -58048,6 +58737,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58073,7 +58763,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoDeleteRelease - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -58118,7 +58808,7 @@ module Gitea = ( owner : string, repo : string, - id : int, + id : int64, body : EditReleaseOption, ct : System.Threading.CancellationToken option ) @@ -58157,12 +58847,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditReleaseOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58188,7 +58881,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.RepoListReleaseAttachments - (owner : string, repo : string, id : int, ct : System.Threading.CancellationToken option) + (owner : string, repo : string, id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -58222,6 +58915,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58263,8 +58957,8 @@ module Gitea = ( owner : string, repo : string, - id : int, - attachment_id : int, + id : int64, + attachment_id : int64, ct : System.Threading.CancellationToken option ) = @@ -58304,6 +58998,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58332,8 +59027,8 @@ module Gitea = ( owner : string, repo : string, - id : int, - attachment_id : int, + id : int64, + attachment_id : int64, ct : System.Threading.CancellationToken option ) = @@ -58384,8 +59079,8 @@ module Gitea = ( owner : string, repo : string, - id : int, - attachment_id : int, + id : int64, + attachment_id : int64, body : EditAttachmentOptions, ct : System.Threading.CancellationToken option ) @@ -58428,12 +59123,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditAttachmentOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58490,6 +59188,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58559,6 +59258,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58573,6 +59273,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -58591,14 +59299,14 @@ module Gitea = ("repos/{owner}/{repo}/stargazers" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/stargazers".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/stargazers".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -58609,6 +59317,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58661,6 +59370,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "sort=" + ((sort.ToString ()) |> System.Uri.EscapeDataString) ] + [ "state=" + ((state.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -58680,18 +59399,14 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{sha}", sha.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/statuses/{sha}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "sort=" - + ((sort.ToString ()) |> System.Uri.EscapeDataString) - + "&state=" - + ((state.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/statuses/{sha}".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -58702,6 +59417,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58782,12 +59498,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateStatusOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateStatusOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58818,6 +59537,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -58836,14 +59563,14 @@ module Gitea = ("repos/{owner}/{repo}/subscribers" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/subscribers".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/subscribers".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -58854,6 +59581,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -58925,6 +59653,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59024,6 +59753,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59054,6 +59784,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -59072,14 +59810,14 @@ module Gitea = ("repos/{owner}/{repo}/tags" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/tags".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/tags".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -59090,6 +59828,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59163,12 +59902,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateTagOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateTagOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59228,6 +59970,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59326,6 +60069,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59398,6 +60142,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59521,6 +60266,17 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "user=" + ((user.ToString ()) |> System.Uri.EscapeDataString) ] + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -59539,20 +60295,14 @@ module Gitea = ("repos/{owner}/{repo}/times" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/times".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "user=" - + ((user.ToString ()) |> System.Uri.EscapeDataString) - + "&since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/times".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -59563,6 +60313,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59635,6 +60386,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59678,6 +60430,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -59696,14 +60456,14 @@ module Gitea = ("repos/{owner}/{repo}/topics" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/topics".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/topics".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -59714,6 +60474,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59774,11 +60535,13 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> RepoTopicOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> RepoTopicOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -59912,12 +60675,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> TransferRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> TransferRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -59976,6 +60742,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60034,6 +60801,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60099,12 +60867,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60164,6 +60935,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60273,12 +61045,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateWikiPageOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60309,6 +61084,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -60327,14 +61110,14 @@ module Gitea = ("repos/{owner}/{repo}/wiki/pages" .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace ("{repo}", repo.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/wiki/pages".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "repos/{owner}/{repo}/wiki/pages".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -60345,6 +61128,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60394,6 +61178,11 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -60413,12 +61202,16 @@ module Gitea = .Replace("{owner}", owner.ToString () |> System.Uri.EscapeDataString) .Replace("{repo}", repo.ToString () |> System.Uri.EscapeDataString) .Replace ("{pageName}", pageName.ToString () |> System.Uri.EscapeDataString) - + (if "repos/{owner}/{repo}/wiki/revisions/{pageName}".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString)), + ((if + "repos/{owner}/{repo}/wiki/revisions/{pageName}".IndexOf (char 63) >= 0 + then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -60429,6 +61222,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60500,12 +61294,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> GenerateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> GenerateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60530,7 +61327,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.RepoGetByID (id : int, ct : System.Threading.CancellationToken option) = + member _.RepoGetByID (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60560,6 +61357,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60611,6 +61409,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60662,6 +61461,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60713,6 +61513,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60764,6 +61565,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60815,6 +61617,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60823,7 +61626,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgGetTeam (id : int, ct : System.Threading.CancellationToken option) = + member _.OrgGetTeam (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60853,6 +61656,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60877,7 +61681,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgDeleteTeam (id : int, ct : System.Threading.CancellationToken option) = + member _.OrgDeleteTeam (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -60946,12 +61750,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> EditTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> EditTeamOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -60977,11 +61784,19 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgListTeamMembers - (id : int, page : int, limit : int, ct : System.Threading.CancellationToken option) + (id : int64, page : int, limit : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -60998,14 +61813,14 @@ module Gitea = ), System.Uri ( ("teams/{id}/members".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if "teams/{id}/members".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "teams/{id}/members".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -61016,6 +61831,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61053,7 +61869,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgListTeamMember (id : int, username : string, ct : System.Threading.CancellationToken option) = + member _.OrgListTeamMember (id : int64, username : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61085,6 +61901,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61109,7 +61926,9 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgRemoveTeamMember (id : int, username : string, ct : System.Threading.CancellationToken option) = + member _.OrgRemoveTeamMember + (id : int64, username : string, ct : System.Threading.CancellationToken option) + = async { let! ct = Async.CancellationToken @@ -61148,7 +61967,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.OrgAddTeamMember (id : int, username : string, ct : System.Threading.CancellationToken option) = + member _.OrgAddTeamMember (id : int64, username : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61188,11 +62007,19 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgListTeamRepos - (id : int, page : int, limit : int, ct : System.Threading.CancellationToken option) + (id : int64, page : int, limit : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -61209,14 +62036,14 @@ module Gitea = ), System.Uri ( ("teams/{id}/repos".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString) - + (if "teams/{id}/repos".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "teams/{id}/repos".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -61227,6 +62054,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61265,7 +62093,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgListTeamRepo - (id : int, org : string, repo : string, ct : System.Threading.CancellationToken option) + (id : int64, org : string, repo : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61299,6 +62127,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61324,7 +62153,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgRemoveTeamRepository - (id : int, org : string, repo : string, ct : System.Threading.CancellationToken option) + (id : int64, org : string, repo : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61366,7 +62195,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.OrgAddTeamRepository - (id : int, org : string, repo : string, ct : System.Threading.CancellationToken option) + (id : int64, org : string, repo : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61411,6 +62240,15 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -61427,13 +62265,10 @@ module Gitea = ), System.Uri ( ("topics/search" - + (if "topics/search".IndexOf (char 63) >= 0 then "&" else "?") - + "q=" - + ((q.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "topics/search".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -61444,6 +62279,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61508,6 +62344,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61538,6 +62375,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -61554,14 +62399,14 @@ module Gitea = ), System.Uri ( ("user/applications/oauth2" - + (if "user/applications/oauth2".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "user/applications/oauth2".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -61572,6 +62417,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61642,12 +62488,15 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateOAuth2ApplicationOptions.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61672,7 +62521,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserGetOAuth2Application (id : int, ct : System.Threading.CancellationToken option) = + member _.UserGetOAuth2Application (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61703,6 +62552,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61727,7 +62577,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserDeleteOAuth2Application (id : int, ct : System.Threading.CancellationToken option) = + member _.UserDeleteOAuth2Application (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61766,7 +62616,7 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.UserUpdateOAuth2Application - (id : int, body : CreateOAuth2ApplicationOptions, ct : System.Threading.CancellationToken option) + (id : int64, body : CreateOAuth2ApplicationOptions, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -61802,12 +62652,15 @@ module Gitea = new System.Net.Http.StringContent ( body |> CreateOAuth2ApplicationOptions.toJsonNode - |> (fun node -> node.ToJsonString ()), - null, - "application/json" + |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61859,6 +62712,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61925,12 +62779,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -61997,11 +62854,13 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> DeleteEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> DeleteEmailOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -62016,6 +62875,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -62032,11 +62899,10 @@ module Gitea = ), System.Uri ( ("user/followers" - + (if "user/followers".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/followers".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -62047,6 +62913,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62090,6 +62957,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -62106,11 +62981,10 @@ module Gitea = ), System.Uri ( ("user/following" - + (if "user/following".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/following".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -62121,6 +62995,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62299,6 +63174,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62307,7 +63183,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserCurrentDeleteGPGKey (id : int, ct : System.Threading.CancellationToken option) = + member _.UserCurrentDeleteGPGKey (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -62350,6 +63226,15 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "fingerprint=" + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -62366,13 +63251,10 @@ module Gitea = ), System.Uri ( ("user/keys" - + (if "user/keys".IndexOf (char 63) >= 0 then "&" else "?") - + "fingerprint=" - + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/keys".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -62383,6 +63265,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62449,12 +63332,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateKeyOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62479,7 +63365,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserCurrentGetKey (id : int, ct : System.Threading.CancellationToken option) = + member _.UserCurrentGetKey (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -62509,6 +63395,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62533,7 +63420,7 @@ module Gitea = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.UserCurrentDeleteKey (id : int, ct : System.Threading.CancellationToken option) = + member _.UserCurrentDeleteKey (id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -62574,6 +63461,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -62590,11 +63485,10 @@ module Gitea = ), System.Uri ( ("user/orgs" - + (if "user/orgs".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/orgs".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -62605,6 +63499,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62646,6 +63541,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -62662,11 +63565,10 @@ module Gitea = ), System.Uri ( ("user/repos" - + (if "user/repos".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/repos".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -62677,6 +63579,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62743,12 +63646,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateRepoOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62800,6 +63706,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62866,12 +63773,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> UserSettingsOptions.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> UserSettingsOptions.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -62913,6 +63823,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -62929,11 +63847,10 @@ module Gitea = ), System.Uri ( ("user/starred" - + (if "user/starred".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/starred".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -62944,6 +63861,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63108,6 +64026,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63124,14 +64050,14 @@ module Gitea = ), System.Uri ( ("user/stopwatches" - + (if "user/stopwatches".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "user/stopwatches".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -63142,6 +64068,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63185,6 +64112,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63201,14 +64136,14 @@ module Gitea = ), System.Uri ( ("user/subscriptions" - + (if "user/subscriptions".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "user/subscriptions".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -63219,6 +64154,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63260,6 +64196,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63276,11 +64220,10 @@ module Gitea = ), System.Uri ( ("user/teams" - + (if "user/teams".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/teams".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -63291,6 +64234,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63340,6 +64284,16 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + [ "since=" + ((since.ToString ()) |> System.Uri.EscapeDataString) ] + [ "before=" + ((before.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63356,15 +64310,10 @@ module Gitea = ), System.Uri ( ("user/times" - + (if "user/times".IndexOf (char 63) >= 0 then "&" else "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString) - + "&since=" - + ((since.ToString ()) |> System.Uri.EscapeDataString) - + "&before=" - + ((before.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "user/times".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -63375,6 +64324,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63413,11 +64363,21 @@ module Gitea = |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) member _.UserSearch - (q : string, uid : int, page : int, limit : int, ct : System.Threading.CancellationToken option) + (q : string, uid : int64, page : int, limit : int, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "q=" + ((q.ToString ()) |> System.Uri.EscapeDataString) ] + [ "uid=" + ((uid.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63434,15 +64394,10 @@ module Gitea = ), System.Uri ( ("users/search" - + (if "users/search".IndexOf (char 63) >= 0 then "&" else "?") - + "q=" - + ((q.ToString ()) |> System.Uri.EscapeDataString) - + "&uid=" - + ((uid.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + + (if queryString = "" then + "" + else + ((if "users/search".IndexOf (char 63) >= 0 then "&" else "?") + queryString))), System.UriKind.Relative ) ) @@ -63453,6 +64408,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63508,6 +64464,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63538,6 +64495,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63555,14 +64520,14 @@ module Gitea = System.Uri ( ("users/{username}/followers" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/followers".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/followers".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -63573,6 +64538,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63616,6 +64582,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63633,14 +64607,14 @@ module Gitea = System.Uri ( ("users/{username}/following" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/following".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/following".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -63651,6 +64625,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63760,6 +64735,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63809,6 +64785,15 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "fingerprint=" + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) ] + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63826,16 +64811,14 @@ module Gitea = System.Uri ( ("users/{username}/keys" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/keys".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "fingerprint=" - + ((fingerprint.ToString ()) |> System.Uri.EscapeDataString) - + "&page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/keys".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -63846,6 +64829,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63889,6 +64873,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -63906,14 +64898,14 @@ module Gitea = System.Uri ( ("users/{username}/orgs" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/orgs".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/orgs".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -63924,6 +64916,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -63995,6 +64988,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64025,6 +65019,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -64042,14 +65044,14 @@ module Gitea = System.Uri ( ("users/{username}/repos" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/repos".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/repos".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -64060,6 +65062,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64103,6 +65106,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -64120,14 +65131,14 @@ module Gitea = System.Uri ( ("users/{username}/starred" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/starred".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/starred".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -64138,6 +65149,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64181,6 +65193,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -64198,14 +65218,14 @@ module Gitea = System.Uri ( ("users/{username}/subscriptions" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/subscriptions".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/subscriptions".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -64216,6 +65236,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64259,6 +65280,14 @@ module Gitea = async { let! ct = Async.CancellationToken + let queryString = + [ + [ "page=" + ((page.ToString ()) |> System.Uri.EscapeDataString) ] + [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] + ] + |> List.concat + |> String.concat "&" + let uri = System.Uri ( System.Uri ( @@ -64276,14 +65305,14 @@ module Gitea = System.Uri ( ("users/{username}/tokens" .Replace ("{username}", username.ToString () |> System.Uri.EscapeDataString) - + (if "users/{username}/tokens".IndexOf (char 63) >= 0 then - "&" + + (if queryString = "" then + "" else - "?") - + "page=" - + ((page.ToString ()) |> System.Uri.EscapeDataString) - + "&limit=" - + ((limit.ToString ()) |> System.Uri.EscapeDataString)), + ((if "users/{username}/tokens".IndexOf (char 63) >= 0 then + "&" + else + "?") + + queryString))), System.UriKind.Relative ) ) @@ -64294,6 +65323,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64366,12 +65396,15 @@ module Gitea = let queryParams = new System.Net.Http.StringContent ( - body |> CreateAccessTokenOption.toJsonNode |> (fun node -> node.ToJsonString ()), - null, - "application/json" + body |> CreateAccessTokenOption.toJsonNode |> (fun node -> node.ToJsonString ()) ) + do + queryParams.Headers.ContentType <- + System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") + do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -64464,6 +65497,7 @@ module Gitea = RequestUri = uri ) + do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs index fb16e07f..4bb96db4 100644 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Generator.fs @@ -524,6 +524,23 @@ module TestOpenApi3Generator = |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema) |> shouldEqual true + [] + let ``Mutually recursive allOf components produce a diagnostic instead of recursing forever`` () = + let composedWith name = + jsonObject [ "allOf", jsonArray [ reference name ] ] + + let pathItem = standardPathItem (responseWithSchema (reference "A")) [] [] + + let source = + document "3.0.3" [ "A", composedWith "B" ; "B", composedWith "A" ] "/things" pathItem + + match OpenApiClientGenerator.parseAndPlan config source with + | Ok _ -> failwith "Planning unexpectedly accepted mutually recursive allOf components" + | Error diagnostics -> + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSchema) + |> shouldEqual true + [] let ``Dangling references always produce a located diagnostic`` () = let property (PositiveInt suffix) = @@ -1364,6 +1381,83 @@ module TestOpenApi3Generator = |> _.ReturnType |> shouldEqual (OpenApiPlannedType.Named definition.FSharpName) + [] + let ``Equivalent additionalProperties forms share their generated dictionary type`` () = + let schema additionalProperties = + jsonObject [ "type", jsonString "object" ; "additionalProperties", additionalProperties ] + + let pathItem = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString "getThing" + "responses", + jsonObject + [ + "200", responseWithSchema (schema (jsonBool true)) + "201", responseWithSchema (schema (jsonObject [])) + ] + ] + ] + + let actual = document "3.0.3" [] "/things" pathItem |> plan + let definition = actual.Types |> List.exactlyOne + + definition.AdditionalProperties + |> shouldEqual (Some (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode)) + + actual.Operations + |> List.exactlyOne + |> _.ReturnType + |> shouldEqual (OpenApiPlannedType.Named definition.FSharpName) + + [] + let ``AllOf repeated properties compare their canonical generated type rather than source syntax`` () = + let payload = + jsonObject + [ + "type", jsonString "object" + "required", jsonArray [ jsonString "id" ] + "properties", jsonObject [ "id", schemaForScalar GeneratedScalar.Int64 false ] + ] + + let branch propertySchema = + jsonObject + [ + "type", jsonString "object" + "properties", jsonObject [ "payload", propertySchema ] + ] + + let parent = + jsonObject + [ + "allOf", + jsonArray + [ + branch (payload.DeepClone ()) + branch (jsonObject [ "allOf", jsonArray [ payload.DeepClone () ] ]) + ] + ] + + let pathItem = standardPathItem (responseWithSchema (reference "Parent")) [] [] + let actual = document "3.0.3" [ "Parent", parent ] "/things" pathItem |> plan + + let parentType = + actual.Types |> List.find (fun definition -> definition.SourceName = "Parent") + + let payloadField = parentType.Fields |> List.exactlyOne + + payloadField.JsonName |> shouldEqual "payload" + + match payloadField.Type with + | OpenApiPlannedType.Optional (OpenApiPlannedType.Named payloadTypeName) -> + actual.Types + |> List.exists (fun definition -> definition.FSharpName = payloadTypeName) + |> shouldEqual true + | unexpected -> failwith $"Expected an optional generated payload type, got %A{unexpected}" + [] let ``Anonymous object deduplication keeps incompatible field types distinct`` () = let schema scalar = diff --git a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs index 0df7cfac..d3b3926b 100644 --- a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs @@ -118,19 +118,74 @@ module internal OpenApiClientGenerator = Location : string } - type private AdditionalProperties = + type private SchemaReference = + { + Name : string + Location : string + } + + type private CanonicalSchema = + { + Location : string + Description : string option + Nullable : bool + Shape : CanonicalSchemaShape + } + + and private CanonicalSchemaShape = + | Reference of SchemaReference + | Any + | Primitive of OpenApiPrimitive + | Array of CanonicalSchema option + | Object of DirectObjectShape + | AllOf of + outerAllowsNull : bool * + hasSiblingObjectKeywords : bool * + allBranchesValid : bool * + branches : CanonicalSchema list + | UnsupportedNumber of format : string option + | UnsupportedType of typeName : string + | Invalid + + and private DirectObjectShape = + { + Properties : Map + Required : Set + AdditionalProperties : AdditionalProperties + } + + and private AdditionalProperties = | Any | Forbidden - | Typed of LocatedObject + | Typed of CanonicalSchema type private ObjectShape = { Description : string option - Properties : Map + Properties : Map Required : Set AdditionalProperties : AdditionalProperties } + type private SchemaIdentity = + | Json + | Primitive of OpenApiPrimitive + | Named of componentName : string + | List of SchemaIdentity + | Optional of SchemaIdentity + | Object of ObjectShapeIdentity + + and private ObjectShapeIdentity = + { + Properties : Map + Required : Set + AdditionalProperties : AdditionalPropertiesIdentity + } + + and private AdditionalPropertiesIdentity = + | Forbidden + | Value of SchemaIdentity + type private ResolvedParameterLocation = | Path | Query @@ -142,7 +197,7 @@ module internal OpenApiClientGenerator = Name : string Location : ResolvedParameterLocation Required : bool - Schema : LocatedObject + Schema : CanonicalSchema SourceLocation : string } @@ -198,1446 +253,1441 @@ module internal OpenApiClientGenerator = let private sanitiseParameterName (value : string) : string = (Ident.createSanitisedParamName value).idText - let rec private canonicalJson (node : JsonNode) : string = - if isNull node then - "null" - else - match node with - | :? JsonObject as value -> - value - |> Seq.map (fun (KeyValue (name, child)) -> - let name = JsonSerializer.Serialize name - $"%s{name}:%s{canonicalJson child}" - ) - |> Seq.sort - |> String.concat "," - |> fun contents -> "{" + contents + "}" - | :? JsonArray as value -> - value - |> Seq.map canonicalJson - |> String.concat "," - |> fun contents -> $"[%s{contents}]" - | value -> value.ToJsonString () - - /// A canonical description of the F# type shape which this generator emits for a schema. - /// OpenAPI annotations and validation constraints are intentionally absent: until the generated - /// type represents them, they cannot make two generated record definitions distinct. - let rec private schemaShapeKey (includeTopLevelNullable : bool) (node : JsonNode) : string = - let quoted (value : string) = JsonSerializer.Serialize value - - let tryNode (node : JsonObject) (name : string) = - match node.TryGetPropertyValue name with - | true, value when not (isNull value) -> Some value - | _ -> None - - let tryStringValue (node : JsonNode) = - try - Some (node.GetValue ()) - with - | :? InvalidOperationException - | :? FormatException -> None - - let tryBoolValue (node : JsonNode) = - try - Some (node.GetValue ()) - with - | :? InvalidOperationException - | :? FormatException -> None - - match node with - | :? JsonObject as value -> - match tryNode value "$ref" |> Option.bind tryStringValue with - | Some reference -> - let schemaPrefix = "#/components/schemas/" - - let reference = - if reference.StartsWith (schemaPrefix, StringComparison.Ordinal) then - reference.Substring schemaPrefix.Length - |> Uri.UnescapeDataString - |> fun value -> value.Replace ("~1", "/", StringComparison.Ordinal) - |> fun value -> value.Replace ("~0", "~", StringComparison.Ordinal) - |> fun value -> schemaPrefix + value - else - reference - - $"ref(%s{quoted reference})" - | None -> - let typeName = tryNode value "type" |> Option.bind tryStringValue - - let isObject = - typeName = Some "object" - || (typeName.IsNone - && (value.ContainsKey "properties" - || value.ContainsKey "required" - || value.ContainsKey "additionalProperties" - || value.ContainsKey "allOf")) - - let nullable = - includeTopLevelNullable - && ((tryNode value "nullable" |> Option.bind tryBoolValue = Some true) - || (typeName.IsNone && not isObject)) - - let core = - if isObject && value.ContainsKey "allOf" then - match tryNode value "allOf" with - | Some (:? JsonArray as branches) -> - branches - |> Seq.map (schemaShapeKey true) - |> Seq.sort - |> String.concat "," - |> fun branches -> $"allOf[%s{branches}]" - | Some invalid -> $"invalidAllOf(%s{canonicalJson invalid})" - | None -> "invalidAllOf(null)" - elif isObject then - let properties = - match tryNode value "properties" with - | Some (:? JsonObject as properties) -> - properties - |> Seq.map (fun (KeyValue (name, schema)) -> - let schema = if isNull schema then "json" else schemaShapeKey true schema - - $"%s{quoted name}:%s{schema}" - ) - |> Seq.sort - |> String.concat "," - | Some invalid -> $"invalid(%s{canonicalJson invalid})" - | None -> "" - - let required = - match tryNode value "required" with - | Some (:? JsonArray as required) -> - required - |> Seq.map (fun item -> - if isNull item then - "null" - else - match tryStringValue item with - | Some item -> quoted item - | None -> canonicalJson item - ) - |> Seq.distinct - |> Seq.sort - |> String.concat "," - | Some invalid -> $"invalid(%s{canonicalJson invalid})" - | None -> "" - - let additionalProperties = - match tryNode value "additionalProperties" with - | None -> "any" - | Some (:? JsonObject as schema) -> $"typed(%s{schemaShapeKey true schema})" - | Some other -> - match tryBoolValue other with - | Some true -> "any" - | Some false -> "forbidden" - | None -> $"invalid(%s{canonicalJson other})" - - $"object(properties=(%s{properties});required=[%s{required}];additional=%s{additionalProperties})" - else - match typeName with - | None -> "json" - | Some "string" -> - match tryNode value "format" |> Option.bind tryStringValue with - | Some "date" -> "date" - | Some "date-time" -> "date-time" - | Some "uuid" -> "guid" - | _ -> "string" - | Some "boolean" -> "bool" - | Some "integer" -> - match tryNode value "format" |> Option.bind tryStringValue with - | Some "int32" -> "int32" - | Some "int64" -> "int64" - | _ -> "bigint" - | Some "number" -> - match tryNode value "format" |> Option.bind tryStringValue with - | Some "float" -> "float32" - | Some "double" -> "float" - | Some "decimal" -> "decimal" - | Some format -> $"unsupported-number(%s{quoted format})" - | None -> "unsupported-number(unformatted)" - | Some "array" -> - match tryNode value "items" with - | Some items -> $"list(%s{schemaShapeKey true items})" - | None -> "list(json)" - | Some other -> $"unsupported(%s{quoted other})" - - if nullable then $"optional(%s{core})" else core - | invalid -> $"invalid(%s{canonicalJson invalid})" - - let private objectShapeKey (shape : ObjectShape) : string = - let quoted (value : string) = JsonSerializer.Serialize value - - let properties = - shape.Properties - |> Map.toSeq - |> Seq.map (fun (name, schema) -> - let schema = - match schema with - | None -> "optional(json)" - | Some schema -> schemaShapeKey true schema.Value - - $"%s{quoted name}:%s{schema}" - ) - |> String.concat "," - - let required = shape.Required |> Seq.map quoted |> String.concat "," - - let additionalProperties = - match shape.AdditionalProperties with - | AdditionalProperties.Any -> "any" - | AdditionalProperties.Forbidden -> "forbidden" - | AdditionalProperties.Typed schema -> $"typed(%s{schemaShapeKey true schema.Value})" - - $"object(properties=(%s{properties});required=[%s{required}];additional=%s{additionalProperties})" + let private report + (diagnostics : ResizeArray) + (code : OpenApiGenerationDiagnosticCode) + (location : string) + (message : string) + = + diagnostics.Add (diagnostic code location message) - let private parseDocument - (parameters : Map) - (root : JsonObject) - : Result + let private tryProperty + (diagnostics : ResizeArray) + (location : string) + (node : JsonObject) + (name : string) + : JsonNode option = - let diagnostics = ResizeArray () + let propertyLocation = $"%s{location}/%s{pointerToken name}" - let report code location message = - diagnostics.Add (diagnostic code location message) + match node.TryGetPropertyValue name with + | false, _ -> None + | true, value when isNull value -> + report diagnostics InvalidDocument propertyLocation "An optional property cannot be null." + None + | true, value -> Some value - let tryProperty (location : string) (node : JsonObject) (name : string) : JsonNode option = - let propertyLocation = $"%s{location}/%s{pointerToken name}" + let private tryString + (diagnostics : ResizeArray) + (location : string) + (node : JsonNode) + : string option + = + try + Some (node.GetValue ()) + with + | :? InvalidOperationException + | :? FormatException -> + report diagnostics InvalidDocument location "Expected a JSON string." + None - match node.TryGetPropertyValue name with - | false, _ -> None - | true, value when isNull value -> - report InvalidDocument propertyLocation "An optional property cannot be null." - None - | true, value -> Some value - - let tryString (location : string) (node : JsonNode) : string option = - try - Some (node.GetValue ()) - with - | :? InvalidOperationException - | :? FormatException -> - report InvalidDocument location "Expected a JSON string." - None + let private optionalString diagnostics location (node : JsonObject) name : string option = + tryProperty diagnostics location node name + |> Option.bind (tryString diagnostics ($"%s{location}/%s{pointerToken name}")) - let optionalString (location : string) (node : JsonObject) (name : string) : string option = - tryProperty location node name - |> Option.bind (tryString ($"%s{location}/%s{pointerToken name}")) + let private requiredString diagnostics location (node : JsonObject) name : string option = + let propertyLocation = $"%s{location}/%s{pointerToken name}" - let requiredString (location : string) (node : JsonObject) (name : string) : string option = - let propertyLocation = $"%s{location}/%s{pointerToken name}" + match node.TryGetPropertyValue name with + | false, _ -> + report diagnostics InvalidDocument propertyLocation "A required string property is missing." + None + | true, value when isNull value -> + report diagnostics InvalidDocument propertyLocation "A required string property cannot be null." + None + | true, value -> tryString diagnostics propertyLocation value - match node.TryGetPropertyValue name with - | false, _ -> - report InvalidDocument propertyLocation "A required string property is missing." - None - | true, value when isNull value -> - report InvalidDocument propertyLocation "A required string property cannot be null." - None - | true, value -> tryString propertyLocation value - - let tryBool (location : string) (node : JsonNode) : bool option = - try - Some (node.GetValue ()) - with - | :? InvalidOperationException - | :? FormatException -> - report InvalidDocument location "Expected a JSON boolean." - None + let private tryBool + (diagnostics : ResizeArray) + (location : string) + (node : JsonNode) + : bool option + = + try + Some (node.GetValue ()) + with + | :? InvalidOperationException + | :? FormatException -> + report diagnostics InvalidDocument location "Expected a JSON boolean." + None - let optionalBool (location : string) (node : JsonObject) (name : string) : bool option = - tryProperty location node name - |> Option.bind (tryBool ($"%s{location}/%s{pointerToken name}")) + let private optionalBool diagnostics location (node : JsonObject) name : bool option = + tryProperty diagnostics location node name + |> Option.bind (tryBool diagnostics ($"%s{location}/%s{pointerToken name}")) - let tryObject (location : string) (node : JsonNode) : LocatedObject option = - match node with - | :? JsonObject as value -> + let private tryObject + (diagnostics : ResizeArray) + (location : string) + (node : JsonNode) + : LocatedObject option + = + match node with + | :? JsonObject as value -> + Some { Value = value Location = location } - |> Some - | _ -> - report InvalidDocument location "Expected a JSON object." - None + | _ -> + report diagnostics InvalidDocument location "Expected a JSON object." + None - let optionalObject (location : string) (node : JsonObject) (name : string) : LocatedObject option = - tryProperty location node name - |> Option.bind (tryObject ($"%s{location}/%s{pointerToken name}")) + let private optionalObject diagnostics location (node : JsonObject) name : LocatedObject option = + tryProperty diagnostics location node name + |> Option.bind (tryObject diagnostics ($"%s{location}/%s{pointerToken name}")) - let tryArray (location : string) (node : JsonNode) : JsonArray option = - match node with - | :? JsonArray as value -> Some value - | _ -> - report InvalidDocument location "Expected a JSON array." - None + let private tryArray + (diagnostics : ResizeArray) + (location : string) + (node : JsonNode) + : JsonArray option + = + match node with + | :? JsonArray as value -> Some value + | _ -> + report diagnostics InvalidDocument location "Expected a JSON array." + None - let optionalArray (location : string) (node : JsonObject) (name : string) : JsonArray option = - tryProperty location node name - |> Option.bind (tryArray ($"%s{location}/%s{pointerToken name}")) + let private optionalArray diagnostics location (node : JsonObject) name : JsonArray option = + tryProperty diagnostics location node name + |> Option.bind (tryArray diagnostics ($"%s{location}/%s{pointerToken name}")) - let objectMap (location : string) (node : JsonObject) : Map = - node - |> Seq.choose (fun (KeyValue (name, value)) -> - tryObject ($"%s{location}/%s{pointerToken name}") value - |> Option.map (fun value -> name, value) - ) - |> Map.ofSeq + let private objectMap diagnostics location (node : JsonObject) : Map = + node + |> Seq.choose (fun (KeyValue (name, value)) -> + tryObject diagnostics ($"%s{location}/%s{pointerToken name}") value + |> Option.map (fun value -> name, value) + ) + |> Map.ofSeq - let componentMap (components : LocatedObject option) (name : string) : Map = - match - components - |> Option.bind (fun value -> optionalObject value.Location value.Value name) - with - | None -> Map.empty - | Some values -> objectMap values.Location values.Value - - let decodePointerToken - (code : OpenApiGenerationDiagnosticCode) - (location : string) - (value : string) - : string option - = - let value = Uri.UnescapeDataString value - - if Regex.IsMatch (value, "~(?:[^01]|$)") then - report code location $"Reference token '%s{value}' contains an invalid JSON Pointer escape." - None - else - let value = value.Replace ("~1", "/", StringComparison.Ordinal) - value.Replace ("~0", "~", StringComparison.Ordinal) |> Some - - let referenceName - (code : OpenApiGenerationDiagnosticCode) - (expectedPrefix : string) - (referenceLocation : string) - (reference : string) - : string option - = - if reference.StartsWith (expectedPrefix, StringComparison.Ordinal) then - reference.Substring expectedPrefix.Length - |> decodePointerToken code referenceLocation - else - report - code - referenceLocation - $"Only local references below '%s{expectedPrefix}' are supported; got '%s{reference}'." + let private componentMap diagnostics (components : LocatedObject option) name : Map = + match + components + |> Option.bind (fun value -> optionalObject diagnostics value.Location value.Value name) + with + | None -> Map.empty + | Some values -> objectMap diagnostics values.Location values.Value - None + let private decodePointerToken diagnostics code location (value : string) : string option = + let value = Uri.UnescapeDataString value - let version = requiredString "#" root "openapi" + if Regex.IsMatch (value, "~(?:[^01]|$)") then + report diagnostics code location $"Reference token '%s{value}' contains an invalid JSON Pointer escape." + None + else + let value = value.Replace ("~1", "/", StringComparison.Ordinal) + value.Replace ("~0", "~", StringComparison.Ordinal) |> Some - match version with - | Some value -> - let parts = value.Split '.' + let private referenceName diagnostics code expectedPrefix referenceLocation (reference : string) : string option = + if reference.StartsWith (expectedPrefix, StringComparison.Ordinal) then + reference.Substring expectedPrefix.Length + |> decodePointerToken diagnostics code referenceLocation + else + report + diagnostics + code + referenceLocation + $"Only local references below '%s{expectedPrefix}' are supported; got '%s{reference}'." - if parts.Length < 2 || parts.[0] <> "3" || parts.[1] <> "0" then - report UnsupportedVersion "#/openapi" $"Expected an OpenAPI 3.0.x document, but got '%s{value}'." - | None -> () + None - let parameters = normaliseParameters parameters + let rec private analyzeSchema + (diagnostics : ResizeArray) + (cache : Dictionary) + (schema : LocatedObject) + : CanonicalSchema + = + match cache.TryGetValue schema.Location with + | true, analyzed -> analyzed + | false, _ -> + let reference = optionalString diagnostics schema.Location schema.Value "$ref" + + let analyzed = + match reference with + | Some reference -> + let referenceLocation = $"%s{schema.Location}/$ref" + + let shape = + referenceName + diagnostics + UnresolvedReference + "#/components/schemas/" + referenceLocation + reference + |> Option.map (fun name -> + CanonicalSchemaShape.Reference + { + Name = name + Location = referenceLocation + } + ) + |> Option.defaultValue CanonicalSchemaShape.Invalid - let className = - match Map.tryFind "CLASSNAME" parameters with - | Some value when not (String.IsNullOrWhiteSpace value) -> value - | _ -> - report InvalidDocument "#/$parameters/ClassName" "The ClassName Myriad parameter is required." - "GeneratedClient" + { + Location = schema.Location + Description = None + Nullable = false + Shape = shape + } + | None -> + let description = + optionalString diagnostics schema.Location schema.Value "description" - if sanitiseTypeName className <> className then - report - InvalidDocument - "#/$parameters/ClassName" - "ClassName must already be a valid PascalCase F# identifier." + let nullable = + optionalBool diagnostics schema.Location schema.Value "nullable" + |> Option.defaultValue false - let createMock = - match Map.tryFind "GENERATEMOCKVISIBILITY" parameters with - | None -> None - | Some value -> - match value.ToLowerInvariant () with - | "internal" -> Some true - | "public" -> Some false - | _ -> - report - InvalidDocument - "#/$parameters/GenerateMockVisibility" - "GenerateMockVisibility must be 'internal' or 'public'." + let typeName = optionalString diagnostics schema.Location schema.Value "type" + let format = optionalString diagnostics schema.Location schema.Value "format" - None + let unsupportedKeywords = + [ "oneOf" ; "anyOf" ; "not" ; "discriminator" ] + |> List.filter schema.Value.ContainsKey - let info = optionalObject "#" root "info" + if not unsupportedKeywords.IsEmpty then + let keywordList = String.concat ", " unsupportedKeywords - let description = - info - |> Option.bind (fun value -> optionalString value.Location value.Value "description") + report + diagnostics + UnsupportedSchema + schema.Location + $"Unsupported shape-changing schema keyword(s): %s{keywordList}." + + match + optionalBool diagnostics schema.Location schema.Value "readOnly", + optionalBool diagnostics schema.Location schema.Value "writeOnly" + with + | Some true, _ + | _, Some true -> + report + diagnostics + UnsupportedSchema + schema.Location + "readOnly/writeOnly schemas require separate request and response projections." + | _ -> () - match info with - | None -> report InvalidDocument "#/info" "The OpenAPI info object is required." - | Some value -> requiredString value.Location value.Value "title" |> ignore + let hasObjectKeywords = + schema.Value.ContainsKey "properties" + || schema.Value.ContainsKey "required" + || schema.Value.ContainsKey "additionalProperties" + || schema.Value.ContainsKey "allOf" - let components = optionalObject "#" root "components" - let schemaComponents = componentMap components "schemas" - let parameterComponents = componentMap components "parameters" - let requestBodyComponents = componentMap components "requestBodies" - let responseComponents = componentMap components "responses" + match typeName with + | Some value when value <> "object" && hasObjectKeywords -> + report + diagnostics + UnsupportedSchema + ($"%s{schema.Location}/type") + $"Schema type '%s{value}' contradicts its object-shape keywords." + | _ -> () - let rawReference (schema : LocatedObject) : (string * string) option = - optionalString schema.Location schema.Value "$ref" - |> Option.map (fun value -> $"%s{schema.Location}/$ref", value) - - let rec isObjectLike (visited : Set) (schema : LocatedObject) : bool = - match rawReference schema with - | Some (location, reference) -> - match referenceName UnsupportedSchema "#/components/schemas/" location reference with - | None -> false - | Some name when Set.contains name visited -> false - | Some name -> - match Map.tryFind name schemaComponents with - | None -> false - | Some target -> isObjectLike (Set.add name visited) target - | None -> - match optionalString schema.Location schema.Value "type" with - | Some "object" -> true - | Some _ -> false - | None -> - schema.Value.ContainsKey "allOf" - || schema.Value.ContainsKey "properties" - || schema.Value.ContainsKey "required" - || schema.Value.ContainsKey "additionalProperties" + let isObject = typeName = Some "object" || (typeName.IsNone && hasObjectKeywords) - let usedTypeNames = HashSet (StringComparer.Ordinal) + // Parse every nested schema occurrence once, even if contradictory keywords mean that + // the occurrence cannot contribute to the generated type. Diagnostics must not depend on + // which planning branch happens to consume the canonical schema. + let properties : Map = + match optionalObject diagnostics schema.Location schema.Value "properties" with + | None -> Map.empty + | Some properties -> + properties.Value + |> Seq.choose (fun (KeyValue (name, value)) -> + tryObject diagnostics ($"%s{properties.Location}/%s{pointerToken name}") value + |> Option.map (fun value -> name, Some (analyzeSchema diagnostics cache value)) + ) + |> Map.ofSeq - for reservedTypeName in - [ - className - "I" + className - "System" - "RestEase" - "WoofWare" - "GenerateMockAttribute" - "HttpClientAttribute" - "JsonParseAttribute" - "JsonSerializeAttribute" - ] do - usedTypeNames.Add reservedTypeName |> ignore + let required = + match optionalArray diagnostics schema.Location schema.Value "required" with + | None -> Set.empty + | Some values -> + values + |> Seq.mapi (fun index value -> + tryString diagnostics ($"%s{schema.Location}/required/%i{index}") value + ) + |> Seq.choose id + |> Set.ofSeq - let objectComponentNames = - schemaComponents - |> Map.toList - |> List.choose (fun (name, schema) -> if isObjectLike Set.empty schema then Some name else None) + let additionalProperties : AdditionalProperties = + match tryProperty diagnostics schema.Location schema.Value "additionalProperties" with + | None -> AdditionalProperties.Any + | Some (:? JsonObject as value) -> + { + Value = value + Location = $"%s{schema.Location}/additionalProperties" + } + |> analyzeSchema diagnostics cache + |> AdditionalProperties.Typed + | Some value -> + match tryBool diagnostics ($"%s{schema.Location}/additionalProperties") value with + | Some true -> AdditionalProperties.Any + | Some false -> AdditionalProperties.Forbidden + | None -> AdditionalProperties.Any - let componentTypeNames = - objectComponentNames - |> List.map (fun sourceName -> - let fsharpName = - allocateUniqueName usedTypeNames "GeneratedType" sanitiseTypeName sourceName + let items = + optionalObject diagnostics schema.Location schema.Value "items" + |> Option.map (analyzeSchema diagnostics cache) + + let allOf = + optionalArray diagnostics schema.Location schema.Value "allOf" + |> Option.map (fun values -> + let branches = + values + |> Seq.mapi (fun index value -> + tryObject diagnostics ($"%s{schema.Location}/allOf/%i{index}") value + |> Option.map (analyzeSchema diagnostics cache) + ) + |> Seq.toList - sourceName, fsharpName - ) - |> Map.ofList + branches, values.Count + ) - let definitions = ResizeArray () + let directObject : DirectObjectShape = + { + Properties = properties + Required = required + AdditionalProperties = additionalProperties + } - let liftedObjectTypes = - System.Collections.Generic.Dictionary (StringComparer.Ordinal) - - let rec schemaNullableInner (visited : Set) (schema : LocatedObject) : bool = - match rawReference schema with - | Some (location, reference) -> - match referenceName UnresolvedReference "#/components/schemas/" location reference with - | None -> false - | Some name when Set.contains name visited -> false - | Some name -> - match Map.tryFind name schemaComponents with - | None -> false - | Some target -> schemaNullableInner (Set.add name visited) target - | None -> - optionalBool schema.Location schema.Value "nullable" - |> Option.defaultValue false - - let schemaNullable (schema : LocatedObject) : bool = schemaNullableInner Set.empty schema - - let rec schemaAllowsNullInner (visited : Set) (schema : LocatedObject) : bool = - match rawReference schema with - | Some (location, reference) -> - match referenceName UnresolvedReference "#/components/schemas/" location reference with - | None -> false - | Some name when Set.contains name visited -> false - | Some name -> - match Map.tryFind name schemaComponents with - | None -> false - | Some target -> schemaAllowsNullInner (Set.add name visited) target - | None -> - match optionalArray schema.Location schema.Value "allOf" with - | Some branches -> - let outerAllowsNull = - match optionalString schema.Location schema.Value "type" with - | None -> true - | Some _ -> schemaNullable schema - - let branchNullability = - branches - |> Seq.mapi (fun index branch -> - tryObject ($"%s{schema.Location}/allOf/%i{index}") branch - |> Option.map (schemaAllowsNullInner visited) - ) - |> Seq.toList + let shape = + if isObject && schema.Value.ContainsKey "allOf" then + match allOf with + | None -> CanonicalSchemaShape.Object directObject + | Some (branches, branchCount) -> + let parsedBranches = branches |> List.choose id + let allBranchesValid = parsedBranches.Length = branchCount + + let hasSiblingObjectKeywords = + schema.Value.ContainsKey "properties" + || schema.Value.ContainsKey "required" + || schema.Value.ContainsKey "additionalProperties" + + CanonicalSchemaShape.AllOf ( + typeName.IsNone || nullable, + hasSiblingObjectKeywords, + allBranchesValid, + parsedBranches + ) + elif isObject then + CanonicalSchemaShape.Object directObject + else + match typeName with + | None -> CanonicalSchemaShape.Any + | Some "string" -> + match format with + | Some "date" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Date + | Some "date-time" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.DateTime + | Some "uuid" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Guid + | _ -> CanonicalSchemaShape.Primitive OpenApiPrimitive.String + | Some "boolean" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Boolean + | Some "integer" -> + match format with + | Some "int32" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Int32 + | Some "int64" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Int64 + | _ -> CanonicalSchemaShape.Primitive OpenApiPrimitive.BigInteger + | Some "number" -> + match format with + | Some "float" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Float32 + | Some "double" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Float + | Some "decimal" -> CanonicalSchemaShape.Primitive OpenApiPrimitive.Decimal + | format -> CanonicalSchemaShape.UnsupportedNumber format + | Some "array" -> CanonicalSchemaShape.Array items + | Some other -> CanonicalSchemaShape.UnsupportedType other - outerAllowsNull - && branchNullability.Length = branches.Count - && (branchNullability |> List.forall (Option.defaultValue false)) - | None -> - if not (schema.Value.ContainsKey "type") && not (isObjectLike Set.empty schema) then - // An unconstrained OpenAPI 3.0 Schema Object accepts every JSON value, including null. - true - else - schemaNullable schema + { + Location = schema.Location + Description = description + Nullable = nullable + Shape = shape + } - let schemaAllowsNull (schema : LocatedObject) : bool = schemaAllowsNullInner Set.empty schema + cache.Add (schema.Location, analyzed) + analyzed + + type private SchemaResolutionContext = + { + Diagnostics : ResizeArray + Components : Map + } + + let private trySchemaTarget + (context : SchemaResolutionContext) + (reportMissing : bool) + (reference : SchemaReference) + : CanonicalSchema option + = + match Map.tryFind reference.Name context.Components with + | Some target -> Some target + | None -> + if reportMissing then + report + context.Diagnostics + UnresolvedReference + reference.Location + $"Schema component '%s{reference.Name}' does not exist." - let reportedUnsupportedSchemaKeywords = HashSet (StringComparer.Ordinal) + None - let validateSchemaKeywords (schema : LocatedObject) = - let unsupportedKeywords = - [ "oneOf" ; "anyOf" ; "not" ; "discriminator" ] - |> List.filter schema.Value.ContainsKey + let rec private resolveSchemaReferences + (context : SchemaResolutionContext) + (reportFailures : bool) + (visited : Set) + (schema : CanonicalSchema) + : (Set * CanonicalSchema) option + = + match schema.Shape with + | CanonicalSchemaShape.Reference reference when Set.contains reference.Name visited -> + if reportFailures then + report + context.Diagnostics + UnsupportedSchema + reference.Location + $"Schema reference cycle involving '%s{reference.Name}' is unsupported." - if not unsupportedKeywords.IsEmpty then - let keywordKey = String.concat "," unsupportedKeywords - let reportKey = $"%s{schema.Location}|%s{keywordKey}" + None + | CanonicalSchemaShape.Reference reference -> + trySchemaTarget context reportFailures reference + |> Option.bind (resolveSchemaReferences context reportFailures (Set.add reference.Name visited)) + | _ -> Some (visited, schema) + + let private schemaIsObjectLike (context : SchemaResolutionContext) (schema : CanonicalSchema) : bool = + match resolveSchemaReferences context false Set.empty schema with + | Some (_, + { + Shape = CanonicalSchemaShape.Object _ + }) + | Some (_, + { + Shape = CanonicalSchemaShape.AllOf _ + }) -> true + | _ -> false + + let rec private schemaAllowsNullInner + (context : SchemaResolutionContext) + (visited : Set) + (schema : CanonicalSchema) + : bool + = + match resolveSchemaReferences context false visited schema with + | None -> false + | Some (visited, resolved) -> + match resolved.Shape with + | CanonicalSchemaShape.Any -> true + | CanonicalSchemaShape.AllOf (outerAllowsNull, _, allBranchesValid, branches) -> + outerAllowsNull + && allBranchesValid + && (branches |> List.forall (schemaAllowsNullInner context visited)) + | _ -> resolved.Nullable + + let private schemaAllowsNull (context : SchemaResolutionContext) (schema : CanonicalSchema) : bool = + schemaAllowsNullInner context Set.empty schema + + type private SchemaPlanningContext = + { + Resolution : SchemaResolutionContext + UsedTypeNames : HashSet + ComponentTypeNames : Map + Definitions : ResizeArray + LiftedObjectTypes : Dictionary + } - if reportedUnsupportedSchemaKeywords.Add reportKey then - let unsupportedKeywords = String.concat ", " unsupportedKeywords + let private emptyObjectShape description : ObjectShape = + { + Description = description + Properties = Map.empty + Required = Set.empty + AdditionalProperties = AdditionalProperties.Any + } + let rec private typeForSchema + (context : SchemaPlanningContext) + (aliasStack : Set) + (suggestedName : string) + (schema : CanonicalSchema) + : OpenApiPlannedType + = + match schema.Shape with + | CanonicalSchemaShape.Reference reference when Map.containsKey reference.Name context.ComponentTypeNames -> + match trySchemaTarget context.Resolution true reference with + | Some target -> + let typeName = context.ComponentTypeNames.[reference.Name] + let result = OpenApiPlannedType.Named typeName + + if schemaAllowsNull context.Resolution target then + OpenApiPlannedType.Optional result + else + result + | None -> OpenApiPlannedType.JsonNode + | CanonicalSchemaShape.Reference _ -> + match resolveSchemaReferences context.Resolution true aliasStack schema with + | None -> OpenApiPlannedType.JsonNode + | Some (aliasStack, target) -> typeForSchema context aliasStack suggestedName target + | shape -> + let baseType = + match shape with + | CanonicalSchemaShape.Any -> OpenApiPlannedType.JsonNode + | CanonicalSchemaShape.Primitive primitive -> OpenApiPlannedType.Primitive primitive + | CanonicalSchemaShape.Array None -> report + context.Resolution.Diagnostics UnsupportedSchema - schema.Location - $"Unsupported shape-changing schema keyword(s): %s{unsupportedKeywords}." - - match - optionalBool schema.Location schema.Value "readOnly", - optionalBool schema.Location schema.Value "writeOnly" - with - | Some true, _ - | _, Some true -> - let reportKey = $"%s{schema.Location}|readOnly/writeOnly" - - if reportedUnsupportedSchemaKeywords.Add reportKey then + ($"%s{schema.Location}/items") + "Array schemas must specify items." + + OpenApiPlannedType.List OpenApiPlannedType.JsonNode + | CanonicalSchemaShape.Array (Some items) -> + typeForSchema context aliasStack ($"%s{suggestedName}Item") items + |> OpenApiPlannedType.List + | CanonicalSchemaShape.Object _ + | CanonicalSchemaShape.AllOf _ -> liftObject context suggestedName schema + | CanonicalSchemaShape.UnsupportedNumber format -> report + context.Resolution.Diagnostics UnsupportedSchema - schema.Location - "readOnly/writeOnly schemas require separate request and response projections." - | _ -> () - - let hasObjectKeywords = - schema.Value.ContainsKey "properties" - || schema.Value.ContainsKey "required" - || schema.Value.ContainsKey "additionalProperties" - || schema.Value.ContainsKey "allOf" - - match optionalString schema.Location schema.Value "type" with - | Some value when value <> "object" && hasObjectKeywords -> - let reportKey = $"%s{schema.Location}|contradictory-type" + ($"%s{schema.Location}/format") + (match format with + | None -> "Unformatted JSON numbers have no lossless built-in F# representation." + | Some format -> $"Number format '%s{format}' has no lossless built-in F# representation.") - if reportedUnsupportedSchemaKeywords.Add reportKey then + OpenApiPlannedType.JsonNode + | CanonicalSchemaShape.UnsupportedType value -> report + context.Resolution.Diagnostics UnsupportedSchema ($"%s{schema.Location}/type") - $"Schema type '%s{value}' contradicts its object-shape keywords." - | _ -> () + $"Schema type '%s{value}' is unsupported." - let validatedSchemaLocations = HashSet (StringComparer.Ordinal) + OpenApiPlannedType.JsonNode + | CanonicalSchemaShape.Invalid + | CanonicalSchemaShape.Reference _ -> OpenApiPlannedType.JsonNode - let rec validateSchemaTree (schema : LocatedObject) = - if validatedSchemaLocations.Add schema.Location then - match rawReference schema with - | Some _ -> () - | None -> - validateSchemaKeywords schema - optionalString schema.Location schema.Value "format" |> ignore - optionalString schema.Location schema.Value "description" |> ignore - optionalBool schema.Location schema.Value "nullable" |> ignore - - match optionalObject schema.Location schema.Value "properties" with - | None -> () - | Some properties -> - for KeyValue (name, value) in properties.Value do - tryObject ($"%s{properties.Location}/%s{pointerToken name}") value - |> Option.iter validateSchemaTree - - match optionalArray schema.Location schema.Value "required" with - | None -> () - | Some required -> - required - |> Seq.iteri (fun index value -> - tryString ($"%s{schema.Location}/required/%i{index}") value |> ignore - ) + if schemaAllowsNull context.Resolution schema then + OpenApiPlannedType.Optional baseType + else + baseType - match optionalObject schema.Location schema.Value "items" with - | None -> () - | Some items -> validateSchemaTree items + and private liftObject + (context : SchemaPlanningContext) + (suggestedName : string) + (schema : CanonicalSchema) + : OpenApiPlannedType + = + let shape = collectObjectShape context Set.empty schema + let identity = objectIdentity context shape - match tryProperty schema.Location schema.Value "additionalProperties" with - | None -> () - | Some (:? JsonObject as value) -> - validateSchemaTree - { - Value = value - Location = $"%s{schema.Location}/additionalProperties" - } - | Some value -> tryBool ($"%s{schema.Location}/additionalProperties") value |> ignore - - match optionalArray schema.Location schema.Value "allOf" with - | None -> () - | Some branches -> - branches - |> Seq.iteri (fun index value -> - tryObject ($"%s{schema.Location}/allOf/%i{index}") value - |> Option.iter validateSchemaTree - ) + match context.LiftedObjectTypes.TryGetValue identity with + | true, typeName -> OpenApiPlannedType.Named typeName + | false, _ -> + let typeName = + allocateUniqueName context.UsedTypeNames "AnonymousType" sanitiseTypeName suggestedName - for KeyValue (_, schema) in schemaComponents do - validateSchemaTree schema - - let rec typeForSchema - (aliasStack : Set) - (suggestedName : string) - (schema : LocatedObject) - : OpenApiPlannedType - = - validateSchemaTree schema - - match rawReference schema with - | Some (location, reference) -> - match referenceName UnresolvedReference "#/components/schemas/" location reference with - | None -> OpenApiPlannedType.JsonNode - | Some name -> - match Map.tryFind name schemaComponents with - | None -> - report UnresolvedReference location $"Schema component '%s{name}' does not exist." - OpenApiPlannedType.JsonNode - | Some target -> - match Map.tryFind name componentTypeNames with - | Some typeName -> - let result = OpenApiPlannedType.Named typeName - - if schemaAllowsNull target then - OpenApiPlannedType.Optional result - else - result - | None when Set.contains name aliasStack -> + context.LiftedObjectTypes.Add (identity, typeName) + + buildDefinition context suggestedName schema.Location typeName shape + |> context.Definitions.Add + + OpenApiPlannedType.Named typeName + + and private buildDefinition + (context : SchemaPlanningContext) + sourceName + sourceLocation + typeName + (shape : ObjectShape) + : OpenApiPlannedTypeDefinition + = + let allProperties = + (shape.Properties, shape.Required) + ||> Set.fold (fun properties requiredName -> + if Map.containsKey requiredName properties then + properties + else + Map.add requiredName None properties + ) + + if + allProperties.IsEmpty + && shape.AdditionalProperties = AdditionalProperties.Forbidden + then + report + context.Resolution.Diagnostics + UnsupportedSchema + sourceLocation + "A closed object with no properties has no faithful non-null F# record representation." + + let usedFieldNames = HashSet (StringComparer.Ordinal) + + if shape.AdditionalProperties <> AdditionalProperties.Forbidden then + usedFieldNames.Add "AdditionalProperties" |> ignore + + let fields = + allProperties + |> Map.toList + |> List.map (fun (jsonName, propertySchema) -> + let required = Set.contains jsonName shape.Required + let fsharpName = allocateUniqueName usedFieldNames "Field" sanitiseTypeName jsonName + + let fieldType = + match propertySchema with + | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode + | Some propertySchema -> + let allowsNull = schemaAllowsNull context.Resolution propertySchema + + if allowsNull && not required then report + context.Resolution.Diagnostics UnsupportedSchema - location - $"Non-object schema reference cycle involving '%s{name}' is unsupported." + propertySchema.Location + "An optional property whose schema allows null has three wire states (missing, null, value), which this generated API does not conflate." - OpenApiPlannedType.JsonNode - | None -> typeForSchema (Set.add name aliasStack) suggestedName target - | None -> - validateSchemaKeywords schema + let result = + typeForSchema context Set.empty ($"%s{typeName}%s{fsharpName}") propertySchema - let baseType = - if isObjectLike Set.empty schema then - liftObject suggestedName schema - else - match optionalString schema.Location schema.Value "type" with - | None -> OpenApiPlannedType.JsonNode - | Some "string" -> - match optionalString schema.Location schema.Value "format" with - | Some "date" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Date - | Some "date-time" -> OpenApiPlannedType.Primitive OpenApiPrimitive.DateTime - | Some "uuid" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Guid - | _ -> OpenApiPlannedType.Primitive OpenApiPrimitive.String - | Some "boolean" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Boolean - | Some "integer" -> - match optionalString schema.Location schema.Value "format" with - | Some "int32" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Int32 - | Some "int64" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Int64 - | _ -> OpenApiPlannedType.Primitive OpenApiPrimitive.BigInteger - | Some "number" -> - match optionalString schema.Location schema.Value "format" with - | Some "float" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Float32 - | Some "double" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Float - | Some "decimal" -> OpenApiPlannedType.Primitive OpenApiPrimitive.Decimal - | format -> - report - UnsupportedSchema - ($"%s{schema.Location}/format") - (match format with - | None -> "Unformatted JSON numbers have no lossless built-in F# representation." - | Some format -> - $"Number format '%s{format}' has no lossless built-in F# representation.") - - OpenApiPlannedType.JsonNode - | Some "array" -> - match optionalObject schema.Location schema.Value "items" with - | None -> + if required || allowsNull then + result + else + OpenApiPlannedType.Optional result + + { + JsonName = jsonName + FSharpName = fsharpName + Type = fieldType + Required = required + } + ) + + let additionalProperties = + match shape.AdditionalProperties with + | AdditionalProperties.Forbidden -> None + | AdditionalProperties.Any -> Some (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) + | AdditionalProperties.Typed schema -> + typeForSchema context Set.empty ($"%s{typeName}AdditionalProperty") schema + |> Some + + { + SourceName = sourceName + FSharpName = typeName + Description = shape.Description + Fields = fields + AdditionalProperties = additionalProperties + } + + and private collectObjectShape + (context : SchemaPlanningContext) + (compositionStack : Set) + (schema : CanonicalSchema) + : ObjectShape + = + match resolveSchemaReferences context.Resolution true compositionStack schema with + | None -> emptyObjectShape None + | Some (compositionStack, resolved) -> + match resolved.Shape with + | CanonicalSchemaShape.Object shape -> + { + Description = resolved.Description + Properties = shape.Properties + Required = shape.Required + AdditionalProperties = shape.AdditionalProperties + } + | CanonicalSchemaShape.AllOf (_, hasSiblingObjectKeywords, _, branches) -> + if hasSiblingObjectKeywords then + report + context.Resolution.Diagnostics + UnsupportedSchema + resolved.Location + "An allOf schema with sibling object-shape keywords is not currently supported." + + let shapes = + branches + |> List.map (fun branch -> + if not (schemaIsObjectLike context.Resolution branch) then + report + context.Resolution.Diagnostics + UnsupportedSchema + branch.Location + "Only object-shaped allOf branches can be represented as an F# record." + + collectObjectShape context compositionStack branch + ) + + let merge (left : ObjectShape) (right : ObjectShape) : ObjectShape = + let ensureNoForbiddenIntroductions (constrained : ObjectShape) (other : ObjectShape) = + match constrained.AdditionalProperties with + | AdditionalProperties.Any -> () + | AdditionalProperties.Forbidden + | AdditionalProperties.Typed _ -> + let introduced = + Set.difference + (other.Properties |> Map.toSeq |> Seq.map fst |> Set.ofSeq) + (constrained.Properties |> Map.toSeq |> Seq.map fst |> Set.ofSeq) + + if not introduced.IsEmpty then report + context.Resolution.Diagnostics UnsupportedSchema - ($"%s{schema.Location}/items") - "Array schemas must specify items." + resolved.Location + "allOf cannot merge fields introduced outside a branch with constrained additionalProperties." - OpenApiPlannedType.List OpenApiPlannedType.JsonNode - | Some items -> - typeForSchema aliasStack ($"%s{suggestedName}Item") items - |> OpenApiPlannedType.List - | Some value -> + ensureNoForbiddenIntroductions left right + ensureNoForbiddenIntroductions right left + + let properties = + (left.Properties, right.Properties) + ||> Map.fold (fun current name propertySchema -> + match Map.tryFind name current, propertySchema with + | None, _ -> Map.add name propertySchema current + | Some None, Some value -> Map.add name (Some value) current + | Some None, None + | Some (Some _), None -> current + | Some (Some existing), Some value -> + if + schemaIdentity context Set.empty existing + <> schemaIdentity context Set.empty value + then + report + context.Resolution.Diagnostics + UnsupportedSchema + value.Location + $"allOf gives property '%s{name}' incompatible schemas." + + current + ) + + let additionalProperties = + match left.AdditionalProperties, right.AdditionalProperties with + | AdditionalProperties.Any, value + | value, AdditionalProperties.Any -> value + | AdditionalProperties.Forbidden, AdditionalProperties.Forbidden -> + AdditionalProperties.Forbidden + | AdditionalProperties.Typed left, AdditionalProperties.Typed right when + schemaIdentity context Set.empty left = schemaIdentity context Set.empty right + -> + AdditionalProperties.Typed left + | _ -> report + context.Resolution.Diagnostics UnsupportedSchema - ($"%s{schema.Location}/type") - $"Schema type '%s{value}' is unsupported." + resolved.Location + "allOf branches have incompatible additionalProperties constraints." - OpenApiPlannedType.JsonNode + AdditionalProperties.Forbidden - if schemaAllowsNull schema then - OpenApiPlannedType.Optional baseType - else - baseType - - and liftObject (suggestedName : string) (schema : LocatedObject) : OpenApiPlannedType = - // Planning every occurrence preserves diagnostics even when its emitted definition is shared. - let shape = collectObjectShape Set.empty schema - // Nullability and annotations wrap or document each use; the flattened record shape is shared. - let key = objectShapeKey shape - - match liftedObjectTypes.TryGetValue key with - | true, typeName -> OpenApiPlannedType.Named typeName - | false, _ -> - let typeName = - allocateUniqueName usedTypeNames "AnonymousType" sanitiseTypeName suggestedName - - liftedObjectTypes.Add (key, typeName) - buildDefinition suggestedName schema.Location typeName shape |> definitions.Add - OpenApiPlannedType.Named typeName - - and buildDefinition - (sourceName : string) - (sourceLocation : string) - (typeName : string) - (shape : ObjectShape) - : OpenApiPlannedTypeDefinition - = - let allProperties = - (shape.Properties, shape.Required) - ||> Set.fold (fun properties requiredName -> - if Map.containsKey requiredName properties then - properties - else - Map.add requiredName None properties - ) + { + Description = None + Properties = properties + Required = Set.union left.Required right.Required + AdditionalProperties = additionalProperties + } - if - allProperties.IsEmpty - && shape.AdditionalProperties = AdditionalProperties.Forbidden - then + match shapes with + | [] -> emptyObjectShape resolved.Description + | head :: tail -> + { List.fold merge head tail with + Description = resolved.Description + } + | _ -> report + context.Resolution.Diagnostics UnsupportedSchema - sourceLocation - "A closed object with no properties has no faithful non-null F# record representation." + resolved.Location + "Expected an object-shaped schema." - let usedFieldNames = HashSet (StringComparer.Ordinal) + emptyObjectShape resolved.Description - if shape.AdditionalProperties <> AdditionalProperties.Forbidden then - usedFieldNames.Add "AdditionalProperties" |> ignore + and private schemaIdentity + (context : SchemaPlanningContext) + (aliasStack : Set) + (schema : CanonicalSchema) + : SchemaIdentity + = + match schema.Shape with + | CanonicalSchemaShape.Reference reference when Map.containsKey reference.Name context.ComponentTypeNames -> + match trySchemaTarget context.Resolution false reference with + | None -> SchemaIdentity.Json + | Some target -> + let core = SchemaIdentity.Named reference.Name + + if schemaAllowsNull context.Resolution target then + SchemaIdentity.Optional core + else + core + | CanonicalSchemaShape.Reference _ -> + match resolveSchemaReferences context.Resolution false aliasStack schema with + | None -> SchemaIdentity.Json + | Some (aliasStack, target) -> schemaIdentity context aliasStack target + | shape -> + let core = + match shape with + | CanonicalSchemaShape.Any -> SchemaIdentity.Json + | CanonicalSchemaShape.Primitive primitive -> SchemaIdentity.Primitive primitive + | CanonicalSchemaShape.Array None -> SchemaIdentity.List SchemaIdentity.Json + | CanonicalSchemaShape.Array (Some items) -> + SchemaIdentity.List (schemaIdentity context aliasStack items) + | CanonicalSchemaShape.Object _ + | CanonicalSchemaShape.AllOf _ -> + collectObjectShape context Set.empty schema + |> objectIdentity context + |> SchemaIdentity.Object + | CanonicalSchemaShape.UnsupportedNumber _ + | CanonicalSchemaShape.UnsupportedType _ + | CanonicalSchemaShape.Invalid + | CanonicalSchemaShape.Reference _ -> SchemaIdentity.Json + + if schemaAllowsNull context.Resolution schema then + SchemaIdentity.Optional core + else + core + + and private objectIdentity (context : SchemaPlanningContext) (shape : ObjectShape) : ObjectShapeIdentity = + let allProperties = + (shape.Properties, shape.Required) + ||> Set.fold (fun properties requiredName -> + if Map.containsKey requiredName properties then + properties + else + Map.add requiredName None properties + ) - let fields = - allProperties - |> Map.toList - |> List.map (fun (jsonName, propertySchema) -> - let required = Set.contains jsonName shape.Required + let properties = + allProperties + |> Map.map (fun _ schema -> + match schema with + | None -> SchemaIdentity.Optional SchemaIdentity.Json + | Some schema -> schemaIdentity context Set.empty schema + ) - let fsharpName = allocateUniqueName usedFieldNames "Field" sanitiseTypeName jsonName + let additionalProperties = + match shape.AdditionalProperties with + | AdditionalProperties.Forbidden -> AdditionalPropertiesIdentity.Forbidden + | AdditionalProperties.Any -> + SchemaIdentity.Optional SchemaIdentity.Json + |> AdditionalPropertiesIdentity.Value + | AdditionalProperties.Typed schema -> + schemaIdentity context Set.empty schema |> AdditionalPropertiesIdentity.Value - let fieldType = - match propertySchema with - | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode - | Some propertySchema -> - let allowsNull = schemaAllowsNull propertySchema + { + Properties = properties + Required = shape.Required + AdditionalProperties = additionalProperties + } - if allowsNull && not required then - report - UnsupportedSchema - propertySchema.Location - "An optional property whose schema allows null has three wire states (missing, null, value), which this generated API does not conflate." + let private addComponentDefinition + (context : SchemaPlanningContext) + (sourceName : string) + (schema : CanonicalSchema) + : unit + = + let shape = collectObjectShape context (Set.singleton sourceName) schema + let typeName = context.ComponentTypeNames.[sourceName] + + buildDefinition context sourceName schema.Location typeName shape + |> context.Definitions.Add + + let rec private resolveComponentReference + (diagnostics : ResizeArray) + (diagnosticCode : OpenApiGenerationDiagnosticCode) + (prefix : string) + (components : Map) + (visited : Set) + (value : LocatedObject) + : LocatedObject option + = + match optionalString diagnostics value.Location value.Value "$ref" with + | None -> Some value + | Some reference -> + let location = $"%s{value.Location}/$ref" - let result = typeForSchema Set.empty ($"%s{typeName}%s{fsharpName}") propertySchema + match referenceName diagnostics diagnosticCode prefix location reference with + | None -> None + | Some name when Set.contains name visited -> + report diagnostics diagnosticCode location $"Reference cycle involving '%s{name}' is unsupported here." + None + | Some name -> + match Map.tryFind name components with + | None -> + report diagnostics diagnosticCode location $"Component '%s{name}' does not exist." + None + | Some target -> + resolveComponentReference diagnostics diagnosticCode prefix components (Set.add name visited) target - if required || allowsNull then - result - else - OpenApiPlannedType.Optional result + let private parseServerBase + (diagnostics : ResizeArray) + (root : JsonObject) + : OpenApiServerBase + = + let report = report diagnostics + let optionalArray = optionalArray diagnostics + let tryObject = tryObject diagnostics + let requiredString = requiredString diagnostics + let optionalObject = optionalObject diagnostics + let objectMap = objectMap diagnostics + + match optionalArray "#" root "servers" with + | None -> OpenApiServerBase.BasePath "/" + | Some servers when servers.Count = 0 -> OpenApiServerBase.BasePath "/" + | Some servers -> + if servers.Count > 1 then + report + UnsupportedOperation + "#/servers" + "Only the first document-level server is supported; additional server entries would be ignored." - { - JsonName = jsonName - FSharpName = fsharpName - Type = fieldType - Required = required - } - ) + match tryObject "#/servers/0" servers.[0] with + | None -> OpenApiServerBase.BasePath "/" + | Some server -> + let mutable url = + requiredString server.Location server.Value "url" |> Option.defaultValue "/" - let additionalProperties = - match shape.AdditionalProperties with - | AdditionalProperties.Forbidden -> None - | AdditionalProperties.Any -> Some (OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode) - | AdditionalProperties.Typed schema -> - typeForSchema Set.empty ($"%s{typeName}AdditionalProperty") schema |> Some + let variables = + match optionalObject server.Location server.Value "variables" with + | None -> Map.empty + | Some variables -> objectMap variables.Location variables.Value - { - SourceName = sourceName - FSharpName = typeName - Description = shape.Description - Fields = fields - AdditionalProperties = additionalProperties - } + for found in Regex.Matches (url, "\\{([^{}]+)\\}") |> Seq.cast do + let variableName = found.Groups.[1].Value - and collectObjectShape (compositionStack : Set) (schema : LocatedObject) : ObjectShape = - match rawReference schema with - | Some (location, reference) -> - match referenceName UnresolvedReference "#/components/schemas/" location reference with - | None -> emptyObjectShape None - | Some name when Set.contains name compositionStack -> - report UnsupportedSchema location $"Object composition cycle involving '%s{name}' is unsupported." - emptyObjectShape None - | Some name -> - match Map.tryFind name schemaComponents with + match Map.tryFind variableName variables with | None -> - report UnresolvedReference location $"Schema component '%s{name}' does not exist." - emptyObjectShape None - | Some target -> collectObjectShape (Set.add name compositionStack) target - | None -> - validateSchemaKeywords schema - - match optionalArray schema.Location schema.Value "allOf" with - | Some branches -> - let shapes = - branches - |> Seq.mapi (fun index node -> - tryObject ($"%s{schema.Location}/allOf/%i{index}") node - |> Option.map (fun branch -> - if not (isObjectLike Set.empty branch) then - report - UnsupportedSchema - branch.Location - "Only object-shaped allOf branches can be represented as an F# record." + report + InvalidDocument + ($"%s{server.Location}/url") + $"Server variable '%s{variableName}' has no definition." + | Some variable -> + match requiredString variable.Location variable.Value "default" with + | None -> () + | Some value -> url <- url.Replace (found.Value, value, StringComparison.Ordinal) - collectObjectShape compositionStack branch - ) - ) - |> Seq.choose id - |> Seq.toList + match Uri.TryCreate (url, UriKind.Absolute) with + | true, _ -> OpenApiServerBase.BaseAddress url + | false, _ -> OpenApiServerBase.BasePath url - if - schema.Value.ContainsKey "properties" - || schema.Value.ContainsKey "required" - || schema.Value.ContainsKey "additionalProperties" - then + type private OperationPlanningContext = + { + Diagnostics : ResizeArray + SchemaCache : Dictionary + SchemaPlanning : SchemaPlanningContext + ParameterComponents : Map + RequestBodyComponents : Map + ResponseComponents : Map + } + + let private parseParameter (context : OperationPlanningContext) (value : LocatedObject) : ResolvedParameter option = + let diagnostics = context.Diagnostics + let report = report diagnostics + let requiredString = requiredString diagnostics + let optionalString = optionalString diagnostics + let optionalBool = optionalBool diagnostics + let optionalObject = optionalObject diagnostics + + resolveComponentReference + diagnostics + UnresolvedReference + "#/components/parameters/" + context.ParameterComponents + Set.empty + value + |> Option.bind (fun value -> + let name = requiredString value.Location value.Value "name" + + let location = + requiredString value.Location value.Value "in" + |> Option.bind (fun location -> + match location with + | "path" -> Some ResolvedParameterLocation.Path + | "query" -> Some ResolvedParameterLocation.Query + | "header" -> Some ResolvedParameterLocation.Header + | "cookie" -> Some ResolvedParameterLocation.Cookie + | other -> report - UnsupportedSchema - schema.Location - "An allOf schema with sibling object-shape keywords is not currently supported." - - let merge (left : ObjectShape) (right : ObjectShape) : ObjectShape = - let ensureNoForbiddenIntroductions (constrained : ObjectShape) (other : ObjectShape) = - match constrained.AdditionalProperties with - | AdditionalProperties.Any -> () - | AdditionalProperties.Forbidden - | AdditionalProperties.Typed _ -> - let introduced = - Set.difference - (other.Properties |> Map.toSeq |> Seq.map fst |> Set.ofSeq) - (constrained.Properties |> Map.toSeq |> Seq.map fst |> Set.ofSeq) - - if not introduced.IsEmpty then - report - UnsupportedSchema - schema.Location - "allOf cannot merge fields introduced outside a branch with constrained additionalProperties." - - ensureNoForbiddenIntroductions left right - ensureNoForbiddenIntroductions right left - - let properties = - (left.Properties, right.Properties) - ||> Map.fold (fun current name schema -> - match Map.tryFind name current, schema with - | None, _ -> Map.add name schema current - | Some None, Some value -> Map.add name (Some value) current - | Some None, None -> current - | Some (Some _), None -> current - | Some (Some existing), Some value -> - if schemaShapeKey true existing.Value <> schemaShapeKey true value.Value then - report - UnsupportedSchema - value.Location - $"allOf gives property '%s{name}' incompatible schemas." + UnsupportedParameter + ($"%s{value.Location}/in") + $"Parameter location '%s{other}' is unsupported." - current - ) + None + ) - let additionalProperties = - match left.AdditionalProperties, right.AdditionalProperties with - | AdditionalProperties.Any, value - | value, AdditionalProperties.Any -> value - | AdditionalProperties.Forbidden, AdditionalProperties.Forbidden -> - AdditionalProperties.Forbidden - | AdditionalProperties.Typed left, AdditionalProperties.Typed right when - schemaShapeKey true left.Value = schemaShapeKey true right.Value - -> - AdditionalProperties.Typed left - | _ -> - report - UnsupportedSchema - schema.Location - "allOf branches have incompatible additionalProperties constraints." + let schema = + optionalObject value.Location value.Value "schema" + |> Option.map (analyzeSchema diagnostics context.SchemaCache) - AdditionalProperties.Forbidden + let hasSchema = value.Value.ContainsKey "schema" + let hasContent = value.Value.ContainsKey "content" - { - Description = None - Properties = properties - Required = Set.union left.Required right.Required - AdditionalProperties = additionalProperties - } + if hasContent then + report + UnsupportedParameter + ($"%s{value.Location}/content") + "Content-based parameters are not supported." - let description = optionalString schema.Location schema.Value "description" + if not hasSchema && not hasContent then + report InvalidDocument value.Location "A parameter must contain exactly one of schema or content." - match shapes with - | [] -> emptyObjectShape description - | head :: tail -> - { List.fold merge head tail with - Description = description - } - | None -> - let properties = - match optionalObject schema.Location schema.Value "properties" with - | None -> Map.empty - | Some properties -> - properties.Value - |> Seq.choose (fun (KeyValue (name, value)) -> - tryObject ($"%s{properties.Location}/%s{pointerToken name}") value - |> Option.map (fun value -> name, Some value) - ) - |> Map.ofSeq + if hasSchema && schema.IsNone then + report + InvalidDocument + ($"%s{value.Location}/schema") + "A parameter schema must be a non-null JSON object." + + match name, location, schema with + | Some name, Some location, Some schema -> + let required = + optionalBool value.Location value.Value "required" |> Option.defaultValue false + + match location with + | ResolvedParameterLocation.Path when not required -> + report UnsupportedParameter value.Location "Path parameters must specify required: true." + | ResolvedParameterLocation.Query when not (Regex.IsMatch (name, "^[A-Za-z0-9._~-]+$")) -> + report + UnsupportedParameter + ($"%s{value.Location}/name") + "Query parameter names must contain only RFC 3986 unreserved characters." + | ResolvedParameterLocation.Header + | ResolvedParameterLocation.Cookie -> + report + UnsupportedParameter + value.Location + "Header and cookie parameters are not representable by the generated HTTP client." + | _ -> () - let required = - match optionalArray schema.Location schema.Value "required" with - | None -> Set.empty - | Some values -> - values - |> Seq.mapi (fun index value -> tryString ($"%s{schema.Location}/required/%i{index}") value) - |> Seq.choose id - |> Set.ofSeq + let expectedStyle = + match location with + | ResolvedParameterLocation.Path -> Some "simple" + | ResolvedParameterLocation.Query -> Some "form" + | _ -> None - let additionalProperties = - match tryProperty schema.Location schema.Value "additionalProperties" with - | None -> AdditionalProperties.Any - | Some (:? JsonObject as value) -> - AdditionalProperties.Typed - { - Value = value - Location = $"%s{schema.Location}/additionalProperties" - } - | Some value -> - match tryBool ($"%s{schema.Location}/additionalProperties") value with - | Some true -> AdditionalProperties.Any - | Some false -> AdditionalProperties.Forbidden - | None -> AdditionalProperties.Any + match expectedStyle, optionalString value.Location value.Value "style" with + | Some expected, Some actual when actual <> expected -> + report + UnsupportedParameter + ($"%s{value.Location}/style") + $"Only the default '%s{expected}' parameter style is supported." + | _ -> () - { - Description = optionalString schema.Location schema.Value "description" - Properties = properties - Required = required - AdditionalProperties = additionalProperties - } + match optionalBool value.Location value.Value "allowReserved" with + | Some true -> + report + UnsupportedParameter + ($"%s{value.Location}/allowReserved") + "allowReserved parameters require a different URI-escaping strategy." + | _ -> () - and emptyObjectShape (description : string option) : ObjectShape = - { - Description = description - Properties = Map.empty - Required = Set.empty - AdditionalProperties = AdditionalProperties.Any - } + { + Name = name + Location = location + Required = required + Schema = schema + SourceLocation = value.Location + } + |> Some + | _ -> None + ) - for sourceName in objectComponentNames do - let schema = schemaComponents.[sourceName] - let shape = collectObjectShape (Set.singleton sourceName) schema - let typeName = componentTypeNames.[sourceName] - buildDefinition sourceName schema.Location typeName shape |> definitions.Add - - let rec resolveComponentReference - (diagnosticCode : OpenApiGenerationDiagnosticCode) - (prefix : string) - (components : Map) - (visited : Set) - (value : LocatedObject) - : LocatedObject option - = - match rawReference value with - | None -> Some value - | Some (location, reference) -> - match referenceName diagnosticCode prefix location reference with - | None -> None - | Some name when Set.contains name visited -> - report diagnosticCode location $"Reference cycle involving '%s{name}' is unsupported here." - None - | Some name -> - match Map.tryFind name components with - | None -> - report diagnosticCode location $"Component '%s{name}' does not exist." - None - | Some target -> - resolveComponentReference diagnosticCode prefix components (Set.add name visited) target - - let parseParameter (value : LocatedObject) : ResolvedParameter option = - resolveComponentReference UnresolvedReference "#/components/parameters/" parameterComponents Set.empty value - |> Option.bind (fun value -> - let name = requiredString value.Location value.Value "name" - - let location = - requiredString value.Location value.Value "in" - |> Option.bind (fun location -> - match location with - | "path" -> Some ResolvedParameterLocation.Path - | "query" -> Some ResolvedParameterLocation.Query - | "header" -> Some ResolvedParameterLocation.Header - | "cookie" -> Some ResolvedParameterLocation.Cookie - | other -> - report - UnsupportedParameter - ($"%s{value.Location}/in") - $"Parameter location '%s{other}' is unsupported." + let private parseParameterList + (context : OperationPlanningContext) + (owner : LocatedObject) + : ResolvedParameter list + = + let diagnostics = context.Diagnostics + let report = report diagnostics + let optionalArray = optionalArray diagnostics + let tryObject = tryObject diagnostics + + match optionalArray owner.Location owner.Value "parameters" with + | None -> [] + | Some values -> + let parsed = + values + |> Seq.mapi (fun index value -> + tryObject ($"%s{owner.Location}/parameters/%i{index}") value + |> Option.bind (parseParameter context) + ) + |> Seq.choose id + |> Seq.toList + + parsed + |> List.groupBy (fun parameter -> parameter.Name, parameter.Location) + |> List.iter (fun ((name, _), values) -> + if values.Length > 1 then + report InvalidDocument owner.Location $"Parameter '%s{name}' is duplicated at the same location." + ) + + parsed + + let private mergeParameters + (inherited : ResolvedParameter list) + (operation : ResolvedParameter list) + : ResolvedParameter list + = + let overrides = + operation + |> List.map (fun parameter -> (parameter.Name, parameter.Location), parameter) + |> Map + + [ + for parameter in inherited do + match Map.tryFind (parameter.Name, parameter.Location) overrides with + | Some replacement -> yield replacement + | None -> yield parameter + + let inheritedKeys = + inherited + |> List.map (fun parameter -> parameter.Name, parameter.Location) + |> Set + + for parameter in operation do + if not (Set.contains (parameter.Name, parameter.Location) inheritedKeys) then + yield parameter + ] - None - ) + let private mediaTypeWithoutParameters (name : string) : string = + match name.IndexOf ';' with + | -1 -> name.Trim () + | separator -> (name.Substring (0, separator)).Trim () - let schema = optionalObject value.Location value.Value "schema" - let hasSchema = value.Value.ContainsKey "schema" - let hasContent = value.Value.ContainsKey "content" + let private mediaTypeEquals (expected : string) (actual : string) : bool = + (mediaTypeWithoutParameters actual).Equals (expected, StringComparison.OrdinalIgnoreCase) - if hasContent then - report - UnsupportedParameter - ($"%s{value.Location}/content") - "Content-based parameters are not supported." + let private selectMedia + (context : OperationPlanningContext) + (purpose : string) + (content : LocatedObject) + : (string * CanonicalSchema option) option + = + let diagnostics = context.Diagnostics + let report = report diagnostics + let tryObject = tryObject diagnostics + let optionalObject = optionalObject diagnostics + + let rank (name : string) = + let name = mediaTypeWithoutParameters name + + if name.Equals ("application/json", StringComparison.OrdinalIgnoreCase) then + 0 + elif name.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) then + 1 + elif name.Equals ("text/plain", StringComparison.OrdinalIgnoreCase) then + 2 + elif name.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) then + 3 + else + 100 - if not hasSchema && not hasContent then - report InvalidDocument value.Location "A parameter must contain exactly one of schema or content." + let candidates = + content.Value + |> Seq.choose (fun (KeyValue (name, node)) -> + let rank = rank name - if hasSchema && schema.IsNone then - report - InvalidDocument - ($"%s{value.Location}/schema") - "A parameter schema must be a non-null JSON object." + if rank = 100 then + None + else + tryObject ($"%s{content.Location}/%s{pointerToken name}") node + |> Option.map (fun media -> rank, name, media) + ) + |> Seq.sortBy (fun (rank, name, _) -> rank, name) + |> Seq.toList - match name, location, schema with - | Some name, Some location, Some schema -> - let required = - optionalBool value.Location value.Value "required" |> Option.defaultValue false + match candidates with + | [] -> + let keys = + content.Value + |> Seq.map (fun (KeyValue (name, _)) -> name) + |> Seq.sort + |> String.concat "', '" + |> fun value -> + if String.IsNullOrEmpty value then + "(none)" + else + $"'%s{value}'" - match location with - | ResolvedParameterLocation.Path when not required -> - report UnsupportedParameter value.Location "Path parameters must specify required: true." - | ResolvedParameterLocation.Query when not (Regex.IsMatch (name, "^[A-Za-z0-9._~-]+$")) -> - report - UnsupportedParameter - ($"%s{value.Location}/name") - "Query parameter names must contain only RFC 3986 unreserved characters." - | ResolvedParameterLocation.Header - | ResolvedParameterLocation.Cookie -> - report - UnsupportedParameter - value.Location - "Header and cookie parameters are not representable by the generated HTTP client." - | _ -> () + report + UnsupportedOperation + content.Location + $"No supported media type was found for %s{purpose}. Content keys: %s{keys}." - let expectedStyle = - match location with - | ResolvedParameterLocation.Path -> Some "simple" - | ResolvedParameterLocation.Query -> Some "form" - | _ -> None + None + | (_, selectedName, selected) :: _ -> + let selectedSchema = + optionalObject selected.Location selected.Value "schema" + |> Option.map (analyzeSchema diagnostics context.SchemaCache) - match expectedStyle, optionalString value.Location value.Value "style" with - | Some expected, Some actual when actual <> expected -> - report - UnsupportedParameter - ($"%s{value.Location}/style") - $"Only the default '%s{expected}' parameter style is supported." - | _ -> () + Some (mediaTypeWithoutParameters selectedName, selectedSchema) - match optionalBool value.Location value.Value "allowReserved" with - | Some true -> - report - UnsupportedParameter - ($"%s{value.Location}/allowReserved") - "allowReserved parameters require a different URI-escaping strategy." - | _ -> () + let rec private isJsonStringType (plannedType : OpenApiPlannedType) : bool = + match plannedType with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> true + | OpenApiPlannedType.Optional inner -> isJsonStringType inner + | _ -> false - { - Name = name - Location = location - Required = required - Schema = schema - SourceLocation = value.Location - } - |> Some - | _ -> None - ) + let private isJsonMediaType (mediaType : string) : bool = + let mediaType = mediaTypeWithoutParameters mediaType - let parseParameterList (owner : LocatedObject) : ResolvedParameter list = - match optionalArray owner.Location owner.Value "parameters" with - | None -> [] - | Some values -> - let parsed = - values - |> Seq.mapi (fun index value -> - tryObject ($"%s{owner.Location}/parameters/%i{index}") value - |> Option.bind parseParameter - ) - |> Seq.choose id - |> Seq.toList + mediaType.Equals ("application/json", StringComparison.OrdinalIgnoreCase) + || mediaType.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) - parsed - |> List.groupBy (fun parameter -> parameter.Name, parameter.Location) - |> List.iter (fun ((name, _), values) -> - if values.Length > 1 then - report - InvalidDocument - owner.Location - $"Parameter '%s{name}' is duplicated at the same location." - ) + let private responseShape + (context : OperationPlanningContext) + (operationName : string) + (value : LocatedObject) + : OpenApiPlannedType * string option + = + let diagnostics = context.Diagnostics + let report = report diagnostics + let optionalObject = optionalObject diagnostics + + let value = + resolveComponentReference + diagnostics + UnresolvedReference + "#/components/responses/" + context.ResponseComponents + Set.empty + value - parsed + match value with + | None -> OpenApiPlannedType.JsonNode, None + | Some value -> + match optionalObject value.Location value.Value "content" with + | None -> OpenApiPlannedType.Unit, None + | Some content when content.Value.Count = 0 -> OpenApiPlannedType.Unit, None + | Some content -> + match selectMedia context "a response" content with + | None -> OpenApiPlannedType.JsonNode, None + | Some (mediaType, schema) -> + let result = + if mediaTypeEquals "application/octet-stream" mediaType then + match schema with + | None -> () + | Some schema -> + match + typeForSchema + context.SchemaPlanning + Set.empty + ($"%s{operationName}BinaryResponse") + schema + with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () + | _ -> + report + UnsupportedOperation + schema.Location + "application/octet-stream responses require a non-null string/binary schema." - let mergeParameters - (inherited : ResolvedParameter list) - (operation : ResolvedParameter list) - : ResolvedParameter list - = - let overrides = - operation - |> List.map (fun parameter -> (parameter.Name, parameter.Location), parameter) - |> Map + OpenApiPlannedType.Stream + elif mediaTypeEquals "text/plain" mediaType then + match schema with + | None -> () + | Some schema -> + match + typeForSchema + context.SchemaPlanning + Set.empty + ($"%s{operationName}TextResponse") + schema + with + | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () + | _ -> + report + UnsupportedOperation + schema.Location + "text/plain responses require a non-null string schema." - [ - for parameter in inherited do - match Map.tryFind (parameter.Name, parameter.Location) overrides with - | Some replacement -> yield replacement - | None -> yield parameter - - let inheritedKeys = - inherited - |> List.map (fun parameter -> parameter.Name, parameter.Location) - |> Set - - for parameter in operation do - if not (Set.contains (parameter.Name, parameter.Location) inheritedKeys) then - yield parameter - ] + OpenApiPlannedType.Primitive OpenApiPrimitive.String + else + match schema with + | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode + | Some schema -> + typeForSchema context.SchemaPlanning Set.empty ($"%s{operationName}Response") schema - let mediaTypeWithoutParameters (name : string) : string = - match name.IndexOf ';' with - | -1 -> name.Trim () - | separator -> (name.Substring (0, separator)).Trim () - - let mediaTypeEquals (expected : string) (actual : string) : bool = - (mediaTypeWithoutParameters actual).Equals (expected, StringComparison.OrdinalIgnoreCase) - - let selectMedia (purpose : string) (content : LocatedObject) : (string * LocatedObject option) option = - let rank (name : string) = - let name = mediaTypeWithoutParameters name - - if name.Equals ("application/json", StringComparison.OrdinalIgnoreCase) then - 0 - elif name.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) then - 1 - elif name.Equals ("text/plain", StringComparison.OrdinalIgnoreCase) then - 2 - elif name.Equals ("application/octet-stream", StringComparison.OrdinalIgnoreCase) then - 3 - else - 100 + if isJsonMediaType mediaType && isJsonStringType result then + report + UnsupportedOperation + content.Location + "JSON string responses need JSON unquoting, which the generated HTTP shell cannot distinguish from text/plain." - let candidates = - content.Value - |> Seq.choose (fun (KeyValue (name, node)) -> - let rank = rank name + result, Some mediaType - if rank = 100 then - None + let private successfulResponses + (context : OperationPlanningContext) + (operationName : string) + (responses : LocatedObject) + : OpenApiPlannedType * string option + = + let diagnostics = context.Diagnostics + let report = report diagnostics + let tryObject = tryObject diagnostics + + let declaredSuccesses = + responses.Value + |> Seq.choose (fun (KeyValue (status, node)) -> + let successful = + if status.Equals ("2XX", StringComparison.OrdinalIgnoreCase) then + true else - tryObject ($"%s{content.Location}/%s{pointerToken name}") node - |> Option.map (fun media -> rank, name, media) - ) - |> Seq.sortBy (fun (rank, name, _) -> rank, name) - |> Seq.toList + match Int32.TryParse status with + | true, value -> 200 <= value && value < 300 + | false, _ -> false - match candidates with - | [] -> - let keys = - content.Value - |> Seq.map (fun (KeyValue (name, _)) -> name) - |> Seq.sort - |> String.concat "', '" - |> fun value -> - if String.IsNullOrEmpty value then - "(none)" - else - $"'%s{value}'" + if successful then + tryObject ($"%s{responses.Location}/%s{pointerToken status}") node + |> Option.map (fun response -> status, response) + else + None + ) + |> Seq.sortBy fst + |> Seq.toList - report - UnsupportedOperation - content.Location - $"No supported media type was found for %s{purpose}. Content keys: %s{keys}." + let rangeCoversEverySuccess = + declaredSuccesses + |> List.exists (fun (status, _) -> status.Equals ("2XX", StringComparison.OrdinalIgnoreCase)) - None - | (_, selectedName, selected) :: _ -> - let selectedSchema = optionalObject selected.Location selected.Value "schema" - Some (mediaTypeWithoutParameters selectedName, selectedSchema) + let candidates = + if rangeCoversEverySuccess then + declaredSuccesses + else + match responses.Value.TryGetPropertyValue "default" with + | false, _ -> declaredSuccesses + | true, value -> + match tryObject ($"%s{responses.Location}/default") value with + | None -> declaredSuccesses + | Some response -> declaredSuccesses @ [ "default", response ] + + match candidates with + | [] -> + report + AmbiguousSuccessResponse + responses.Location + "At least one exact 2xx, 2XX, or default response is required to describe success." - let rec isJsonStringType (plannedType : OpenApiPlannedType) : bool = - match plannedType with - | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> true - | OpenApiPlannedType.Optional inner -> isJsonStringType inner - | _ -> false + OpenApiPlannedType.Unit, None + | (_, first) :: rest -> + let firstShape = responseShape context operationName first + + for status, response in rest do + let otherShape = responseShape context operationName response - let isJsonMediaType (mediaType : string) : bool = - let mediaType = mediaTypeWithoutParameters mediaType + if otherShape <> firstShape then + report + AmbiguousSuccessResponse + ($"%s{responses.Location}/%s{pointerToken status}") + "All possible successful responses must have the same body type and media type." - mediaType.Equals ("application/json", StringComparison.OrdinalIgnoreCase) - || mediaType.EndsWith ("+json", StringComparison.OrdinalIgnoreCase) + firstShape - let responseShape (operationName : string) (value : LocatedObject) : OpenApiPlannedType * string option = - let value = + let private requestBodyParameter + (context : OperationPlanningContext) + (operationName : string) + (operation : LocatedObject) + : (OpenApiPlannedParameter * string) option + = + let diagnostics = context.Diagnostics + let report = report diagnostics + let optionalBool = optionalBool diagnostics + let optionalObject = optionalObject diagnostics + + match optionalObject operation.Location operation.Value "requestBody" with + | None -> None + | Some body -> + let body = resolveComponentReference + diagnostics UnresolvedReference - "#/components/responses/" - responseComponents + "#/components/requestBodies/" + context.RequestBodyComponents Set.empty - value + body - match value with - | None -> OpenApiPlannedType.JsonNode, None - | Some value -> - match optionalObject value.Location value.Value "content" with - | None -> OpenApiPlannedType.Unit, None - | Some content when content.Value.Count = 0 -> OpenApiPlannedType.Unit, None + body + |> Option.bind (fun body -> + let required = + optionalBool body.Location body.Value "required" |> Option.defaultValue false + + if not required then + report + UnsupportedOperation + body.Location + "Optional request bodies cannot be represented without conflating omission and JSON null." + + match optionalObject body.Location body.Value "content" with + | None -> + report InvalidDocument ($"%s{body.Location}/content") "Request bodies require content." + None | Some content -> - match selectMedia "a response" content with - | None -> OpenApiPlannedType.JsonNode, None - | Some (mediaType, schema) -> - let result = + selectMedia context "a request body" content + |> Option.map (fun (mediaType, schema) -> + let plannedType = if mediaTypeEquals "application/octet-stream" mediaType then - match schema with - | None -> () - | Some schema -> - match typeForSchema Set.empty ($"%s{operationName}BinaryResponse") schema with - | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () - | _ -> - report - UnsupportedOperation - schema.Location - "application/octet-stream responses require a non-null string/binary schema." - OpenApiPlannedType.Stream elif mediaTypeEquals "text/plain" mediaType then match schema with | None -> () | Some schema -> - match typeForSchema Set.empty ($"%s{operationName}TextResponse") schema with + match + typeForSchema + context.SchemaPlanning + Set.empty + ($"%s{operationName}TextRequest") + schema + with | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () | _ -> report UnsupportedOperation schema.Location - "text/plain responses require a non-null string schema." + "text/plain request bodies require a non-null string schema." OpenApiPlannedType.Primitive OpenApiPrimitive.String else match schema with | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode - | Some schema -> typeForSchema Set.empty ($"%s{operationName}Response") schema + | Some schema -> + typeForSchema + context.SchemaPlanning + Set.empty + ($"%s{operationName}Request") + schema - if isJsonMediaType mediaType && isJsonStringType result then + if mediaTypeEquals "application/octet-stream" mediaType then report UnsupportedOperation content.Location - "JSON string responses need JSON unquoting, which the generated HTTP shell cannot distinguish from text/plain." - - result, Some mediaType - - let successfulResponses (operationName : string) (responses : LocatedObject) = - let declaredSuccesses = - responses.Value - |> Seq.choose (fun (KeyValue (status, node)) -> - let successful = - if status.Equals ("2XX", StringComparison.OrdinalIgnoreCase) then - true - else - match Int32.TryParse status with - | true, value -> 200 <= value && value < 300 - | false, _ -> false - - if successful then - tryObject ($"%s{responses.Location}/%s{pointerToken status}") node - |> Option.map (fun response -> status, response) - else - None - ) - |> Seq.sortBy fst - |> Seq.toList - - let rangeCoversEverySuccess = - declaredSuccesses - |> List.exists (fun (status, _) -> status.Equals ("2XX", StringComparison.OrdinalIgnoreCase)) - - let candidates = - if rangeCoversEverySuccess then - declaredSuccesses - else - match responses.Value.TryGetPropertyValue "default" with - | false, _ -> declaredSuccesses - | true, value -> - match tryObject ($"%s{responses.Location}/default") value with - | None -> declaredSuccesses - | Some response -> declaredSuccesses @ [ "default", response ] - - match candidates with - | [] -> - report - AmbiguousSuccessResponse - responses.Location - "At least one exact 2xx, 2XX, or default response is required to describe success." - - OpenApiPlannedType.Unit, None - | (_, first) :: rest -> - let firstShape = responseShape operationName first - - for status, response in rest do - let otherShape = responseShape operationName response - - if otherShape <> firstShape then - report - AmbiguousSuccessResponse - ($"%s{responses.Location}/%s{pointerToken status}") - "All possible successful responses must have the same body type and media type." - - firstShape - - let requestBodyParameter - (operationName : string) - (operation : LocatedObject) - : (OpenApiPlannedParameter * string) option - = - match optionalObject operation.Location operation.Value "requestBody" with - | None -> None - | Some body -> - let body = - resolveComponentReference - UnresolvedReference - "#/components/requestBodies/" - requestBodyComponents - Set.empty - body - - body - |> Option.bind (fun body -> - let required = - optionalBool body.Location body.Value "required" |> Option.defaultValue false - - if not required then - report - UnsupportedOperation - body.Location - "Optional request bodies cannot be represented without conflating omission and JSON null." - - match optionalObject body.Location body.Value "content" with - | None -> - report InvalidDocument ($"%s{body.Location}/content") "Request bodies require content." - None - | Some content -> - selectMedia "a request body" content - |> Option.map (fun (mediaType, schema) -> - let plannedType = - if mediaTypeEquals "application/octet-stream" mediaType then - OpenApiPlannedType.Stream - elif mediaTypeEquals "text/plain" mediaType then - match schema with - | None -> () - | Some schema -> - match typeForSchema Set.empty ($"%s{operationName}TextRequest") schema with - | OpenApiPlannedType.Primitive OpenApiPrimitive.String -> () - | _ -> - report - UnsupportedOperation - schema.Location - "text/plain request bodies require a non-null string schema." - - OpenApiPlannedType.Primitive OpenApiPrimitive.String - else - match schema with - | None -> OpenApiPlannedType.Optional OpenApiPlannedType.JsonNode - | Some schema -> typeForSchema Set.empty ($"%s{operationName}Request") schema - - if mediaTypeEquals "application/octet-stream" mediaType then - report - UnsupportedOperation - content.Location - "Binary request content types are not emitted correctly by the generated HTTP shell." - - if isJsonMediaType mediaType && isJsonStringType plannedType then - report - UnsupportedOperation - content.Location - "JSON string request bodies need JSON quoting, which the generated HTTP shell cannot distinguish from text/plain." - - { - WireName = "body" - FSharpName = "body" - Location = OpenApiParameterLocation.Body - Type = plannedType - Required = required - }, - mediaType - ) - ) - - let parseServerBase () : OpenApiServerBase = - match optionalArray "#" root "servers" with - | None -> OpenApiServerBase.BasePath "/" - | Some servers when servers.Count = 0 -> OpenApiServerBase.BasePath "/" - | Some servers -> - if servers.Count > 1 then - report - UnsupportedOperation - "#/servers" - "Only the first document-level server is supported; additional server entries would be ignored." - - match tryObject "#/servers/0" servers.[0] with - | None -> OpenApiServerBase.BasePath "/" - | Some server -> - let mutable url = - requiredString server.Location server.Value "url" |> Option.defaultValue "/" - - let variables = - match optionalObject server.Location server.Value "variables" with - | None -> Map.empty - | Some variables -> objectMap variables.Location variables.Value - - for found in Regex.Matches (url, "\\{([^{}]+)\\}") |> Seq.cast do - let variableName = found.Groups.[1].Value + "Binary request content types are not emitted correctly by the generated HTTP shell." - match Map.tryFind variableName variables with - | None -> + if isJsonMediaType mediaType && isJsonStringType plannedType then report - InvalidDocument - ($"%s{server.Location}/url") - $"Server variable '%s{variableName}' has no definition." - | Some variable -> - match requiredString variable.Location variable.Value "default" with - | None -> () - | Some value -> url <- url.Replace (found.Value, value, StringComparison.Ordinal) + UnsupportedOperation + content.Location + "JSON string request bodies need JSON quoting, which the generated HTTP shell cannot distinguish from text/plain." + + { + WireName = "body" + FSharpName = "body" + Location = OpenApiParameterLocation.Body + Type = plannedType + Required = required + }, + mediaType + ) + ) - match Uri.TryCreate (url, UriKind.Absolute) with - | true, _ -> OpenApiServerBase.BaseAddress url - | false, _ -> OpenApiServerBase.BasePath url + let private planOperations (context : OperationPlanningContext) (root : JsonObject) : OpenApiPlannedOperation list = + let diagnostics = context.Diagnostics + let report = report diagnostics + let optionalString = optionalString diagnostics + let optionalObject = optionalObject diagnostics + let optionalArray = optionalArray diagnostics + let tryObject = tryObject diagnostics + let schemaResolution = context.SchemaPlanning.Resolution + let typeForSchema = typeForSchema context.SchemaPlanning let paths = optionalObject "#" root "paths" let operations = ResizeArray () @@ -1693,7 +1743,7 @@ module internal OpenApiClientGenerator = "Path-specific servers are unsupported." | _ -> () - let inheritedParameters = parseParameterList pathItem + let inheritedParameters = parseParameterList context pathItem for httpMethod, operation in methodEntries pathItem do match optionalArray operation.Location operation.Value "servers" with @@ -1718,7 +1768,7 @@ module internal OpenApiClientGenerator = allocateUniqueName usedMethodNames "Operation" sanitiseTypeName operationId let mergedParameters = - parseParameterList operation |> mergeParameters inheritedParameters + parseParameterList context operation |> mergeParameters inheritedParameters let templateNames = Regex.Matches (path, "\\{([^{}]+)\\}") @@ -1774,7 +1824,7 @@ module internal OpenApiClientGenerator = ($"%s{operationFSharpName}%s{parameterFSharpName}") parameter.Schema - if schemaAllowsNull parameter.Schema then + if schemaAllowsNull schemaResolution parameter.Schema then report UnsupportedParameter parameter.Schema.Location @@ -1808,7 +1858,7 @@ module internal OpenApiClientGenerator = ) ) - let body = requestBodyParameter operationFSharpName operation + let body = requestBodyParameter context operationFSharpName operation let plannedParameters = match body with @@ -1826,7 +1876,7 @@ module internal OpenApiClientGenerator = "Operations require responses." OpenApiPlannedType.Unit, None - | Some responses -> successfulResponses operationFSharpName responses + | Some responses -> successfulResponses context operationFSharpName responses operations.Add { @@ -1845,6 +1895,15 @@ module internal OpenApiClientGenerator = RequestContentType = body |> Option.map snd } + operations |> Seq.sortBy _.FSharpName |> Seq.toList + + let private orderDefinitions + (diagnostics : ResizeArray) + (definitions : OpenApiPlannedTypeDefinition seq) + : OpenApiPlannedTypeDefinition list + = + let report = report diagnostics + let rec namedDependencies (plannedType : OpenApiPlannedType) : Set = match plannedType with | OpenApiPlannedType.Named name -> Set.singleton name @@ -1902,15 +1961,160 @@ module internal OpenApiClientGenerator = for name in definitionsByName |> Map.toList |> List.map fst do visitDefinition name + orderedDefinitions |> Seq.toList + + let private parseDocument + (parameters : Map) + (root : JsonObject) + : Result + = + let diagnostics = ResizeArray () + let report = report diagnostics + let optionalString = optionalString diagnostics + let requiredString = requiredString diagnostics + let optionalObject = optionalObject diagnostics + let componentMap = componentMap diagnostics + + let version = requiredString "#" root "openapi" + + match version with + | Some value -> + let parts = value.Split '.' + + if parts.Length < 2 || parts.[0] <> "3" || parts.[1] <> "0" then + report UnsupportedVersion "#/openapi" $"Expected an OpenAPI 3.0.x document, but got '%s{value}'." + | None -> () + + let parameters = normaliseParameters parameters + + let className = + match Map.tryFind "CLASSNAME" parameters with + | Some value when not (String.IsNullOrWhiteSpace value) -> value + | _ -> + report InvalidDocument "#/$parameters/ClassName" "The ClassName Myriad parameter is required." + "GeneratedClient" + + if sanitiseTypeName className <> className then + report + InvalidDocument + "#/$parameters/ClassName" + "ClassName must already be a valid PascalCase F# identifier." + + let createMock = + match Map.tryFind "GENERATEMOCKVISIBILITY" parameters with + | None -> None + | Some value -> + match value.ToLowerInvariant () with + | "internal" -> Some true + | "public" -> Some false + | _ -> + report + InvalidDocument + "#/$parameters/GenerateMockVisibility" + "GenerateMockVisibility must be 'internal' or 'public'." + + None + + let info = optionalObject "#" root "info" + + let description = + info + |> Option.bind (fun value -> optionalString value.Location value.Value "description") + + match info with + | None -> report InvalidDocument "#/info" "The OpenAPI info object is required." + | Some value -> requiredString value.Location value.Value "title" |> ignore + + let components = optionalObject "#" root "components" + let schemaCache = Dictionary (StringComparer.Ordinal) + + let schemaComponents = + componentMap components "schemas" + |> Map.map (fun _ -> analyzeSchema diagnostics schemaCache) + + let parameterComponents = componentMap components "parameters" + let requestBodyComponents = componentMap components "requestBodies" + let responseComponents = componentMap components "responses" + + let schemaResolution = + { + Diagnostics = diagnostics + Components = schemaComponents + } + + let usedTypeNames = HashSet (StringComparer.Ordinal) + + for reservedTypeName in + [ + className + "I" + className + "System" + "RestEase" + "WoofWare" + "GenerateMockAttribute" + "HttpClientAttribute" + "JsonParseAttribute" + "JsonSerializeAttribute" + ] do + usedTypeNames.Add reservedTypeName |> ignore + + let objectComponentNames = + schemaComponents + |> Map.toList + |> List.choose (fun (name, schema) -> + if schemaIsObjectLike schemaResolution schema then + Some name + else + None + ) + + let componentTypeNames = + objectComponentNames + |> List.map (fun sourceName -> + let fsharpName = + allocateUniqueName usedTypeNames "GeneratedType" sanitiseTypeName sourceName + + sourceName, fsharpName + ) + |> Map.ofList + + let definitions = ResizeArray () + + let schemaPlanning = + { + Resolution = schemaResolution + UsedTypeNames = usedTypeNames + ComponentTypeNames = componentTypeNames + Definitions = definitions + LiftedObjectTypes = Dictionary () + } + + for sourceName in objectComponentNames do + addComponentDefinition schemaPlanning sourceName schemaComponents.[sourceName] + + let operationPlanning = + { + Diagnostics = diagnostics + SchemaCache = schemaCache + SchemaPlanning = schemaPlanning + ParameterComponents = parameterComponents + RequestBodyComponents = requestBodyComponents + ResponseComponents = responseComponents + } + + let serverBase = parseServerBase diagnostics root + let operations = planOperations operationPlanning root + let orderedDefinitions = orderDefinitions diagnostics definitions + let plan = { Namespace = className InterfaceName = "I" + className Description = description CreateMock = createMock - ServerBase = parseServerBase () - Types = orderedDefinitions |> Seq.toList - Operations = operations |> Seq.sortBy _.FSharpName |> Seq.toList + ServerBase = serverBase + Types = orderedDefinitions + Operations = operations } if diagnostics.Count = 0 then From 6a1668e78c470cc444ae41f8dbcef88c1bda9089 Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:20:18 +0100 Subject: [PATCH 5/9] Cover the petstore's optional query parameter end-to-end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The petstore spec's `limit` on GET /pets is `required: false`, so the generator plans it as `int option` — but nothing exercised ListPets at runtime, so the broken encoding it previously produced (`limit=Some%2825%29`, and a NullReferenceException on None) went unnoticed. Regenerating on top of the option-aware query encoding fixes the emitted client; this pins the behaviour with a test. Co-Authored-By: Claude Opus 4.8 --- ConsumePlugin/Generated2OpenApiPetstore.fs | 8 ++++++- .../TestSwagger/TestOpenApi3Client.fs | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/ConsumePlugin/Generated2OpenApiPetstore.fs b/ConsumePlugin/Generated2OpenApiPetstore.fs index d98c45f5..11cb139b 100644 --- a/ConsumePlugin/Generated2OpenApiPetstore.fs +++ b/ConsumePlugin/Generated2OpenApiPetstore.fs @@ -1105,7 +1105,13 @@ module OpenApiPetstore = let! ct = Async.CancellationToken let queryString = - [ [ "limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString) ] ] + [ + limit + |> Option.map (fun queryParam -> + "limit=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString) + ) + |> Option.toList + ] |> List.concat |> String.concat "&" diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs index 2fb97e60..4328a344 100644 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs @@ -231,3 +231,26 @@ module TestOpenApi3Client = let third = Pet.toJsonNode parsed JsonNode.DeepEquals (first, second) |> shouldEqual true JsonNode.DeepEquals (second, third) |> shouldEqual true + + [] + [] + let ``Optional query parameters are omitted from the URL when absent`` (supplied : bool) = + task { + let expectedUri = + if supplied then + "https://api.example.test/v1/public/pets?limit=25" + else + "https://api.example.test/v1/public/pets" + + let handler (message : HttpRequestMessage) = + async { + message.RequestUri.ToString () |> shouldEqual expectedUri + return response HttpStatusCode.OK (Some "[]") + } + + use httpClient = HttpClientMock.makeNoUri handler + let client = OpenApiPetstore.make httpClient + + let! pets = client.ListPets (if supplied then Some 25 else None) + pets |> shouldBeEmpty + } From 69fc0161842a31bdc9d8ca8f98b80906168e78f9 Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Sat, 25 Jul 2026 15:59:46 +0100 Subject: [PATCH 6/9] Hmm --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9bc346d6..01012cc6 100644 --- a/README.md +++ b/README.md @@ -351,8 +351,8 @@ so that the following manoeuvre will result in a generated mock: ### OpenAPI 3.0 -The existing `swagger-client` generator detects the document version from the root `swagger` or `openapi` field, so OpenAPI 3.0 uses the same project configuration and preserves the Swagger 2.0 entry point. -OpenAPI 3.1 is rejected explicitly rather than being interpreted with 3.0 schema semantics. +The generator detects the document version from the root `swagger` or `openapi` field, so OpenAPI 3.0 uses the same project configuration as Swagger 2.0. +OpenAPI 3.1 is rejected at build time. The OpenAPI 3.0 path supports: @@ -366,7 +366,7 @@ The OpenAPI 3.0 path supports: The planner fails with a located diagnostic for structural constructs which the generated HTTP/JSON layer cannot represent. This currently includes OpenAPI 3.1, external references, `oneOf`/`anyOf`/`not`, optional-and-nullable three-state values, mutually recursive groups of records, header/cookie parameters, non-default parameter styles, optional or binary request bodies, and operations whose possible successful responses have incompatible body shapes. -This is a typed client generator, not a complete OpenAPI validator or policy engine: +This is only a typed client generator, not a complete OpenAPI validator or policy engine: * schema validation keywords such as `enum`, patterns, and numeric bounds are not enforced by the generated F# types; * security requirements and schemes do not add authentication automatically: configure the caller-supplied `HttpClient` instead; From 5703dd1da1ce75f0d4f7e30da2383a8d9c2a4acd Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Sat, 25 Jul 2026 17:26:41 +0100 Subject: [PATCH 7/9] OpenAPI 3.0: apply security requirements The OpenAPI 3.0 planner ignored `security` and `components.securitySchemes` entirely, so a document which required authentication silently generated a client which sent none. Each security scheme an operation requires now becomes an abstract property on the generated interface, and hence a `unit -> string` argument of `make` which is called afresh on every request needing that credential. Each operation sends exactly the credentials its own requirement asks for: `security: []` sends none and doesn't even ask for them, and a requirement naming several schemes sends all of them. Where an operation offers alternatives, the first satisfiable one is applied, and which one that is is visible in the generated source; the new `SecuritySchemes` Myriad parameter restricts the choice. An operation with no satisfiable requirement is now a build failure rather than a silently unauthenticated client. Supported schemes are the header-carried ones: `apiKey` in a header, `http` of any scheme, and `oauth2`/`openIdConnect`, for which the caller supplies the `Authorization` header value. No token flow is performed. Expressing this needed a way to set a header on only some of an interface's members, so this also adds `[]` to the `HttpClient` generator: the named property still becomes a `unit -> _` argument of `make`, but only the members which name it call it. `[]` on a property continues to apply to every member. The property may be named by a literal or by `nameof Unchecked.defaultof.TheProperty`. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 11 + ConsumePlugin/Generated2OpenApiPetstore.fs | 42 +- ConsumePlugin/GeneratedOpenApiPetstore.fs | 19 + ConsumePlugin/GeneratedRestClient.fs | 139 +++++ ConsumePlugin/RestApiExample.fs | 28 + ConsumePlugin/openapi-petstore.json | 47 +- README.md | 50 +- .../Attributes.fs | 14 + .../SurfaceBaseline.txt | 2 + .../version.json | 2 +- .../TestHttpClient/TestPerEndpointHeader.fs | 100 ++++ .../TestSwagger/TestOpenApi3Client.fs | 93 +++- .../TestSwagger/TestOpenApi3Security.fs | 495 ++++++++++++++++++ .../WoofWare.Myriad.Plugins.Test.fsproj | 2 + .../HttpClientGenerator.fs | 88 +++- .../OpenApiClientGenerator.fs | 405 +++++++++++++- 16 files changed, 1504 insertions(+), 33 deletions(-) create mode 100644 WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs create mode 100644 WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs diff --git a/CHANGELOG.md b/CHANGELOG.md index b9128c68..b1c2b3dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ The `swagger-client` generator now accepts OpenAPI 3.0 JSON documents as well as It generates DTO records and a chained `HttpClient` interface from component schemas, paths, parameters, request bodies, responses, and root server definitions. Unsupported or structurally ambiguous OpenAPI constructs fail with structured, JSON-pointer-located diagnostics; unconstrained JSON values preserve `null`, and unbounded integers use `BigInteger`. +The OpenAPI 3.0 generator now applies `security` requirements, rather than ignoring them. +Each security scheme an operation requires becomes a `unit -> string` argument of the generated `make`, evaluated afresh per request, and each operation sends exactly the credentials its own requirement asks for (an operation with `security: []` sends none). +Supported schemes are the header-carried ones: `apiKey` in a header, `http` of any scheme, and `oauth2`/`openIdConnect` (for which you supply the `Authorization` header value; no token flow is performed). +Where an operation offers alternative requirements, the first satisfiable one is used; the new `SecuritySchemes` Myriad parameter restricts which schemes may be chosen. +An operation with no satisfiable requirement is now a build failure rather than a silently unauthenticated client. + +Adds the `[]` attribute for the `HttpClient` generator, which sets a header on one member's requests, taking its value from a property of the same interface. +(`[]` on a property continues to set its header on every member's requests.) +The property may be named either by a string literal or by `nameof Unchecked.defaultof.TheProperty`. +This is how the OpenAPI generator expresses per-operation security requirements. + # WoofWare.Myriad.Plugins 10.3.1 The `ArgParserGenerator` now supports positional args together with arbitrary discriminated-union args. diff --git a/ConsumePlugin/Generated2OpenApiPetstore.fs b/ConsumePlugin/Generated2OpenApiPetstore.fs index 11cb139b..5a62a085 100644 --- a/ConsumePlugin/Generated2OpenApiPetstore.fs +++ b/ConsumePlugin/Generated2OpenApiPetstore.fs @@ -718,10 +718,18 @@ open WoofWare.Myriad.Plugins /// Module for constructing a REST client. [] module OpenApiPetstore = - /// Create a REST client. - let make (client : System.Net.Http.HttpClient) : IOpenApiPetstore = + /// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties. + let make + (apiKeyAuth : unit -> string) + (bearerAuth : unit -> string) + (client : System.Net.Http.HttpClient) + : IOpenApiPetstore + = { new IOpenApiPetstore with - member _.CreatePet (body : NewPet, ct : System.Threading.CancellationToken option) = + member _.ApiKeyAuth : string = apiKeyAuth () + member _.BearerAuth : string = bearerAuth () + + member this.CreatePet (body : NewPet, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -749,6 +757,8 @@ module OpenApiPetstore = System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) + do httpMessage.Headers.Add ("Authorization", this.BearerAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -774,7 +784,7 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.DeletePet (pet_id : int64, ct : System.Threading.CancellationToken option) = + member this.DeletePet (pet_id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -795,6 +805,7 @@ module OpenApiPetstore = RequestUri = uri ) + do httpMessage.Headers.Add ("Authorization", this.BearerAuth.ToString ()) let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () use response = response @@ -802,7 +813,7 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.Download (ct : System.Threading.CancellationToken option) = + member this.Download (ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -820,6 +831,7 @@ module OpenApiPetstore = RequestUri = uri ) + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "application/octet-stream") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -828,7 +840,7 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.Echo (body : string, ct : System.Threading.CancellationToken option) = + member this.Echo (body : string, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -853,6 +865,7 @@ module OpenApiPetstore = System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("text/plain; charset=utf-8") do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "text/plain") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -862,7 +875,7 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.EchoAnything + member this.EchoAnything (body : System.Text.Json.Nodes.JsonNode option, ct : System.Threading.CancellationToken option) = async { @@ -898,6 +911,7 @@ module OpenApiPetstore = System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -917,7 +931,9 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.EchoCounter (body : System.Numerics.BigInteger, ct : System.Threading.CancellationToken option) = + member this.EchoCounter + (body : System.Numerics.BigInteger, ct : System.Threading.CancellationToken option) + = async { let! ct = Async.CancellationToken @@ -949,6 +965,7 @@ module OpenApiPetstore = System.Net.Http.Headers.MediaTypeHeaderValue.Parse ("application/json; charset=utf-8") do httpMessage.Content <- queryParams + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -979,7 +996,7 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.GetCounter (ct : System.Threading.CancellationToken option) = + member this.GetCounter (ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -997,6 +1014,7 @@ module OpenApiPetstore = RequestUri = uri ) + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -1027,7 +1045,7 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.GetPet (pet_id : int64, ct : System.Threading.CancellationToken option) = + member this.GetPet (pet_id : int64, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -1048,6 +1066,7 @@ module OpenApiPetstore = RequestUri = uri ) + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () @@ -1100,7 +1119,7 @@ module OpenApiPetstore = } |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) - member _.ListPets (limit : int option, ct : System.Threading.CancellationToken option) = + member this.ListPets (limit : int option, ct : System.Threading.CancellationToken option) = async { let! ct = Async.CancellationToken @@ -1136,6 +1155,7 @@ module OpenApiPetstore = RequestUri = uri ) + do httpMessage.Headers.Add ("X-API-Key", this.ApiKeyAuth.ToString ()) do httpMessage.Headers.Add ("Accept", "application/json") let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let response = response.EnsureSuccessStatusCode () diff --git a/ConsumePlugin/GeneratedOpenApiPetstore.fs b/ConsumePlugin/GeneratedOpenApiPetstore.fs index e55e3117..cf47875b 100644 --- a/ConsumePlugin/GeneratedOpenApiPetstore.fs +++ b/ConsumePlugin/GeneratedOpenApiPetstore.fs @@ -85,15 +85,27 @@ type Pet = /// A compact OpenAPI 3 fixture used to compile the generated client. [] type IOpenApiPetstore = + /// The value of the 'X-API-Key' header, which carries the API key of the 'apiKeyAuth' security scheme. + /// This function is called afresh on every request which requires this scheme, so it can return a token that has since been refreshed. + /// Key issued from the pet store console. + abstract ApiKeyAuth : string + /// The complete value of the 'Authorization' header for the 'bearerAuth' security scheme, which is HTTP authentication scheme 'Bearer'. + /// The value must include the scheme name: for example, "Bearer <credentials>". + /// This function is called afresh on every request which requires this scheme, so it can return a token that has since been refreshed. + abstract BearerAuth : string + /// Invoke the 'createPet' OpenAPI operation. [] [] [] + [] + [] abstract CreatePet : [] body : NewPet * ?ct : System.Threading.CancellationToken -> Pet System.Threading.Tasks.Task /// Invoke the 'deletePet' OpenAPI operation. [] + [] abstract DeletePet : [] pet_id : int64 * ?ct : System.Threading.CancellationToken -> unit System.Threading.Tasks.Task @@ -101,12 +113,14 @@ type IOpenApiPetstore = /// Invoke the 'download' OpenAPI operation. [] [] + [] abstract Download : ?ct : System.Threading.CancellationToken -> System.IO.Stream System.Threading.Tasks.Task /// Invoke the 'echo' OpenAPI operation. [] [] [] + [] abstract Echo : [] body : string * ?ct : System.Threading.CancellationToken -> string System.Threading.Tasks.Task @@ -114,6 +128,7 @@ type IOpenApiPetstore = [] [] [] + [] abstract EchoAnything : [] body : System.Text.Json.Nodes.JsonNode option * ?ct : System.Threading.CancellationToken -> System.Text.Json.Nodes.JsonNode option System.Threading.Tasks.Task @@ -122,6 +137,7 @@ type IOpenApiPetstore = [] [] [] + [] abstract EchoCounter : [] body : System.Numerics.BigInteger * ?ct : System.Threading.CancellationToken -> System.Numerics.BigInteger System.Threading.Tasks.Task @@ -129,12 +145,14 @@ type IOpenApiPetstore = /// Invoke the 'getCounter' OpenAPI operation. [] [] + [] abstract GetCounter : ?ct : System.Threading.CancellationToken -> System.Numerics.BigInteger System.Threading.Tasks.Task /// Invoke the 'getPet' OpenAPI operation. [] [] + [] abstract GetPet : [] pet_id : int64 * ?ct : System.Threading.CancellationToken -> Pet System.Threading.Tasks.Task @@ -147,6 +165,7 @@ type IOpenApiPetstore = /// Invoke the 'listPets' OpenAPI operation. [] [] + [] abstract ListPets : [] limit : int option * ?ct : System.Threading.CancellationToken -> Pet list System.Threading.Tasks.Task diff --git a/ConsumePlugin/GeneratedRestClient.fs b/ConsumePlugin/GeneratedRestClient.fs index 4cbe83f9..e8c29160 100644 --- a/ConsumePlugin/GeneratedRestClient.fs +++ b/ConsumePlugin/GeneratedRestClient.fs @@ -1989,6 +1989,145 @@ open System.Net open System.Net.Http open RestEase +/// Module for constructing a REST client. +[] +module ApiWithPerEndpointHeaders = + /// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties. + let make + (bearerToken : unit -> string) + (apiKey : unit -> int) + (ubiquitous : unit -> string) + (client : System.Net.Http.HttpClient) + : IApiWithPerEndpointHeaders + = + { new IApiWithPerEndpointHeaders with + member _.BearerToken : string = bearerToken () + member _.ApiKey : int = apiKey () + member _.Ubiquitous : string = ubiquitous () + + member this.Authorized (parameter : string, ct : CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> + raise ( + System.ArgumentNullException ( + nameof (client.BaseAddress), + "No base address was supplied on the type, and no BaseAddress was on the HttpClient." + ) + ) + | v -> v), + System.Uri ( + "authorized/{param}" + .Replace ("{param}", parameter.ToString () |> System.Uri.EscapeDataString), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("X-Everywhere", this.Ubiquitous.ToString ()) + do httpMessage.Headers.Add ("Authorization", this.BearerToken.ToString ()) + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member this.Both (parameter : string, ct : CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> + raise ( + System.ArgumentNullException ( + nameof (client.BaseAddress), + "No base address was supplied on the type, and no BaseAddress was on the HttpClient." + ) + ) + | v -> v), + System.Uri ( + "both/{param}".Replace ("{param}", parameter.ToString () |> System.Uri.EscapeDataString), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("X-Everywhere", this.Ubiquitous.ToString ()) + do httpMessage.Headers.Add ("Authorization", this.BearerToken.ToString ()) + do httpMessage.Headers.Add ("X-Api-Key", this.ApiKey.ToString ()) + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + + member this.Anonymous (parameter : string, ct : CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client.BaseAddress with + | null -> + raise ( + System.ArgumentNullException ( + nameof (client.BaseAddress), + "No base address was supplied on the type, and no BaseAddress was on the HttpClient." + ) + ) + | v -> v), + System.Uri ( + "anonymous/{param}" + .Replace ("{param}", parameter.ToString () |> System.Uri.EscapeDataString), + System.UriKind.Relative + ) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("X-Everywhere", this.Ubiquitous.ToString ()) + let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + } +namespace PureGym + +open System +open System.Threading +open System.Threading.Tasks +open System.IO +open System.Net +open System.Net.Http +open RestEase + /// Module for constructing a REST client. [] module ClientWithJsonBody = diff --git a/ConsumePlugin/RestApiExample.fs b/ConsumePlugin/RestApiExample.fs index 4f7f28fc..6d6bc344 100644 --- a/ConsumePlugin/RestApiExample.fs +++ b/ConsumePlugin/RestApiExample.fs @@ -211,6 +211,34 @@ type IApiWithHeaders2 = abstract GetPathParam : [] parameter : string * ?ct : CancellationToken -> Task +/// Different endpoints require different credentials, and one requires none at all: exactly the shape +/// OpenAPI security requirements take. +[] +type IApiWithPerEndpointHeaders = + abstract BearerToken : string + + abstract ApiKey : int + + /// Stamps a header onto every endpoint, to prove the two mechanisms compose. + [
] + abstract Ubiquitous : string + + // The property may be named by a literal, or (so that renaming it is a compile error rather than + // a header which silently stops being sent) by `nameof`, which is what the OpenAPI generator emits. + [] + [] + abstract Authorized : [] parameter : string * ?ct : CancellationToken -> Task + + [] + [.BearerToken)>] + [.ApiKey)>] + abstract Both : [] parameter : string * ?ct : CancellationToken -> Task + + [] + abstract Anonymous : [] parameter : string * ?ct : CancellationToken -> Task + [] type IClientWithJsonBody = // As a POST request of a JSON-serialised body, we automatically set Content-Type: application/json. diff --git a/ConsumePlugin/openapi-petstore.json b/ConsumePlugin/openapi-petstore.json index 27f0c3e4..6706c1d7 100644 --- a/ConsumePlugin/openapi-petstore.json +++ b/ConsumePlugin/openapi-petstore.json @@ -55,7 +55,13 @@ "201": { "$ref": "#/components/responses/PetResponse" } - } + }, + "security": [ + { + "apiKeyAuth": [], + "bearerAuth": [] + } + ] } }, "/pets/{pet-id}": { @@ -78,7 +84,15 @@ "204": { "description": "Deleted" } - } + }, + "security": [ + { + "legacyQueryKey": [] + }, + { + "bearerAuth": [] + } + ] } }, "/status": { @@ -95,7 +109,8 @@ } } } - } + }, + "security": [] } }, "/download": { @@ -323,6 +338,30 @@ } } } + }, + "securitySchemes": { + "apiKeyAuth": { + "type": "apiKey", + "name": "X-API-Key", + "in": "header", + "description": "Key issued from the pet store console." + }, + "bearerAuth": { + "type": "http", + "scheme": "Bearer", + "bearerFormat": "JWT" + }, + "legacyQueryKey": { + "type": "apiKey", + "name": "api_key", + "in": "query", + "description": "Deprecated: this client cannot carry a key in the query string." + } + } + }, + "security": [ + { + "apiKeyAuth": [] } - } + ] } diff --git a/README.md b/README.md index 01012cc6..5250afc0 100644 --- a/README.md +++ b/README.md @@ -360,16 +360,49 @@ The OpenAPI 3.0 path supports: * primitive schemas and formats, arrays, objects, required properties, `nullable`, `additionalProperties`, compatible object `allOf` intersections, and self-recursive records; * inherited and operation-level path/query parameters, with operation-level overrides; * JSON and plain-text request bodies, successful JSON/plain-text/binary responses, and no-content responses; -* root server URLs, including expansion of server-variable defaults; and +* root server URLs, including expansion of server-variable defaults; +* root and operation-level `security` requirements, for header-carried security schemes; and * deterministic sanitisation and collision handling for generated F# identifiers. The planner fails with a located diagnostic for structural constructs which the generated HTTP/JSON layer cannot represent. This currently includes OpenAPI 3.1, external references, `oneOf`/`anyOf`/`not`, optional-and-nullable three-state values, mutually recursive groups of records, header/cookie parameters, non-default parameter styles, optional or binary request bodies, and operations whose possible successful responses have incompatible body shapes. +#### Security requirements + +Each security scheme some operation requires becomes an abstract property on the generated interface, +and hence a `unit -> string` argument of the generated `make`, which is called afresh on every request +that needs that credential (so a token can be refreshed between calls). +Each operation sends exactly the credentials its own `security` demands: an operation with `security: []` +sends none and doesn't even ask for them, and one whose requirement names several schemes sends all of them. +An operation's `security` replaces the root's rather than adding to it, as the specification says. + +Supported schemes are the ones whose credential is a request header whose entire value the caller supplies: +`apiKey` with `in: header`, `http` with any scheme (the value must include the scheme name, e.g. `"Bearer eyJ…"`), +and `oauth2`/`openIdConnect` (which supply the `Authorization` header value: the generated client runs no +token flow of its own, so you remain responsible for acquiring and refreshing tokens). +`apiKey` with `in: query` or `in: cookie` is not supported. + +Where an operation offers *alternative* requirements, the first one the generated client can satisfy is +applied, and which one that is is visible in the generated source. +To choose a different one, restrict the schemes with the `SecuritySchemes` Myriad parameter, which takes a +comma-separated list of scheme names: + +```xml + + Petstore + bearerAuth,apiKeyAuth + +``` + +An operation with no satisfiable requirement is a build failure, rather than a client which silently +issues unauthenticated requests. +If you would rather authenticate the `HttpClient` yourself (with a `DelegatingHandler`, say), the way to +say so is `security: []`, or to remove the security schemes from the document you generate from. + This is only a typed client generator, not a complete OpenAPI validator or policy engine: * schema validation keywords such as `enum`, patterns, and numeric bounds are not enforced by the generated F# types; -* security requirements and schemes do not add authentication automatically: configure the caller-supplied `HttpClient` instead; +* OAuth 2.0 and OpenID Connect flows, scopes, and token endpoints are not implemented: the generated client sends the `Authorization` header value you give it and nothing more; * the existing JSON codecs represent both an absent optional field and an explicit JSON `null` as `None`, and likewise cannot distinguish a missing required-nullable field from `null` (schemas which require all three states are rejected); and * optional query parameters are emitted as `option` arguments, with wire-level omission delegated to the chained `HttpClient` generator. @@ -502,6 +535,19 @@ The motivating example is again ahead-of-time compilation: we wish to avoid the * Variable and constant header values are supported: see [the definition of `IApiWithHeaders`](./ConsumePlugin/RestApiExample.fs). +* A `[
]` property sets its header on *every* request. To set one on only some of them, + declare a property with no `[
]` attribute and name it from the members which want it: + `[]`. + The property still becomes a `unit -> _` argument of `make`, re-evaluated per request, but it is + only called by the members which name it. + You can name the property with `nameof` instead of a literal, so that renaming it is a compile + error rather than a header which silently stops being sent; since `nameof` needs an instance for a + non-static member, the spelling is + `[.BearerToken)>]`. + (The OpenAPI generator emits the literal form: Fantomas cannot print that chain from a generated + syntax tree, and there both sides come from the same string in any case.) + See [the definition of `IApiWithPerEndpointHeaders`](./ConsumePlugin/RestApiExample.fs); + this is what the OpenAPI generator emits for per-operation security requirements. ### Limitations diff --git a/WoofWare.Myriad.Plugins.Attributes/Attributes.fs b/WoofWare.Myriad.Plugins.Attributes/Attributes.fs index 53b7a587..ec361be4 100644 --- a/WoofWare.Myriad.Plugins.Attributes/Attributes.fs +++ b/WoofWare.Myriad.Plugins.Attributes/Attributes.fs @@ -95,6 +95,20 @@ type HttpClientAttribute (isExtensionMethod : bool) = /// Shorthand for the "isExtensionMethod = false" constructor; see documentation there for details. new () = HttpClientAttribute HttpClientAttribute.DefaultIsExtensionMethod +/// Attribute indicating that this interface member sets the given header on its own requests, +/// taking the value from the named parameterless property of the same interface (which the +/// "create HTTP client" generator turns into a `unit -> _` argument, re-evaluated on every request). +/// +/// This differs from `[]` on a property, which sets its header on *every* +/// member's requests: this attribute applies the header only to the members which name the property. +/// It is how the OpenAPI generator expresses per-operation security requirements, where two +/// operations of the same API may require different credentials, or none at all. +/// +/// The named property must exist on the same interface, and must not itself carry a +/// `[]` attribute (which would apply it everywhere anyway). +type HeaderFromPropertyAttribute (header : string, propertyName : string) = + inherit Attribute () + /// Attribute indicating a DU type to which the "create catamorphism" Myriad /// generator should apply during build. /// Supply the `typeName` for the name of the record type we will generate, which contains diff --git a/WoofWare.Myriad.Plugins.Attributes/SurfaceBaseline.txt b/WoofWare.Myriad.Plugins.Attributes/SurfaceBaseline.txt index e6e082e7..907d9015 100644 --- a/WoofWare.Myriad.Plugins.Attributes/SurfaceBaseline.txt +++ b/WoofWare.Myriad.Plugins.Attributes/SurfaceBaseline.txt @@ -27,6 +27,8 @@ WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: bool WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: unit WoofWare.Myriad.Plugins.GenerateMockAttribute.DefaultIsInternal [static property]: [read-only] bool WoofWare.Myriad.Plugins.GenerateMockAttribute.get_DefaultIsInternal [static method]: unit -> bool +WoofWare.Myriad.Plugins.HeaderFromPropertyAttribute inherit System.Attribute +WoofWare.Myriad.Plugins.HeaderFromPropertyAttribute..ctor [constructor]: (string, string) WoofWare.Myriad.Plugins.HttpClientAttribute inherit System.Attribute WoofWare.Myriad.Plugins.HttpClientAttribute..ctor [constructor]: bool WoofWare.Myriad.Plugins.HttpClientAttribute..ctor [constructor]: unit diff --git a/WoofWare.Myriad.Plugins.Attributes/version.json b/WoofWare.Myriad.Plugins.Attributes/version.json index 3f1d2288..c2da8b91 100644 --- a/WoofWare.Myriad.Plugins.Attributes/version.json +++ b/WoofWare.Myriad.Plugins.Attributes/version.json @@ -1,5 +1,5 @@ { - "version": "3.8", + "version": "3.9", "publicReleaseRefSpec": [ "^refs/heads/main$" ], diff --git a/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs b/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs new file mode 100644 index 00000000..9a8dd1e8 --- /dev/null +++ b/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs @@ -0,0 +1,100 @@ +namespace WoofWare.Myriad.Plugins.Test + +open System +open System.Net +open System.Net.Http +open System.Threading +open NUnit.Framework +open FsUnitTyped +open PureGym + +/// Headers whose values come from an interface property, but which are stamped only onto the +/// endpoints that ask for them. This is how per-operation OpenAPI security requirements are +/// expressed: two endpoints of the same API may need different credentials, or none. +[] +module TestPerEndpointHeader = + + /// Echoes the request's headers back, one per line, so the test can assert on them. + let private echoHeaders (message : HttpRequestMessage) : HttpResponseMessage Async = + async { + let headers = + [ + for h in message.Headers do + yield $"%s{h.Key}: %s{Seq.exactlyOne h.Value}" + ] + |> List.sort + |> String.concat "\n" + + let resp = new HttpResponseMessage (HttpStatusCode.OK) + resp.Content <- new StringContent (headers) + return resp + } + + let private makeApi (client : HttpClient) (bearerReads : int ref) (apiKeyReads : int ref) = + let bearerToken () = + Interlocked.Increment bearerReads |> ignore + "token-value" + + let apiKey () = + Interlocked.Increment apiKeyReads |> ignore + 42 + + ApiWithPerEndpointHeaders.make bearerToken apiKey (fun () -> "everywhere") client + + [] + let ``An endpoint gets only the credentials it asks for`` () = + use client = HttpClientMock.make (Uri "https://example.com") echoHeaders + let bearerReads = ref 0 + let apiKeyReads = ref 0 + let api = makeApi client bearerReads apiKeyReads + + api.Authorized("param").Result.Split "\n" + |> shouldEqual [| "Authorization: token-value" ; "X-Everywhere: everywhere" |] + + bearerReads.Value |> shouldEqual 1 + apiKeyReads.Value |> shouldEqual 0 + + [] + let ``An endpoint requiring several credentials gets all of them`` () = + use client = HttpClientMock.make (Uri "https://example.com") echoHeaders + let bearerReads = ref 0 + let apiKeyReads = ref 0 + let api = makeApi client bearerReads apiKeyReads + + api.Both("param").Result.Split "\n" + |> shouldEqual + [| + "Authorization: token-value" + "X-Api-Key: 42" + "X-Everywhere: everywhere" + |] + + bearerReads.Value |> shouldEqual 1 + apiKeyReads.Value |> shouldEqual 1 + + [] + let ``An endpoint requiring no credentials is not sent any`` () = + use client = HttpClientMock.make (Uri "https://example.com") echoHeaders + let bearerReads = ref 0 + let apiKeyReads = ref 0 + let api = makeApi client bearerReads apiKeyReads + + api.Anonymous("param").Result.Split "\n" + |> shouldEqual [| "X-Everywhere: everywhere" |] + + // The credentials aren't merely omitted from the request: they're never even asked for, + // so a caller who has no credentials at all can still call this endpoint. + bearerReads.Value |> shouldEqual 0 + apiKeyReads.Value |> shouldEqual 0 + + [] + let ``Credentials are re-read on every request`` () = + use client = HttpClientMock.make (Uri "https://example.com") echoHeaders + let bearerReads = ref 0 + let apiKeyReads = ref 0 + let api = makeApi client bearerReads apiKeyReads + + for _ in 1..3 do + api.Authorized("param").Result |> ignore + + bearerReads.Value |> shouldEqual 3 diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs index 4328a344..dc6358e3 100644 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Client.fs @@ -7,6 +7,7 @@ open System.Net open System.Net.Http open System.Numerics open System.Text.Json.Nodes +open System.Threading open FsUnitTyped open NUnit.Framework open OpenApiPetstore @@ -14,6 +15,26 @@ open OpenApiPetstore [] module TestOpenApi3Client = + /// The security schemes of the petstore document, whose credentials the generated client demands + /// of us before it will issue any request that needs them. + let private credentials () = + let apiKeyReads = ref 0 + let bearerReads = ref 0 + + let client (httpClient : HttpClient) = + OpenApiPetstore.make + (fun () -> + Interlocked.Increment apiKeyReads |> ignore + "api-key-value" + ) + (fun () -> + Interlocked.Increment bearerReads |> ignore + "Bearer token-value" + ) + httpClient + + client, apiKeyReads, bearerReads + let private response (status : HttpStatusCode) (body : string option) = let result = new HttpResponseMessage (status) @@ -118,7 +139,8 @@ module TestOpenApi3Client = } use httpClient = HttpClientMock.makeNoUri handler - let client = OpenApiPetstore.make httpClient + let make, _, _ = credentials () + let client = make httpClient let! fetched = client.GetPet 42L fetched.Id |> shouldEqual 42L @@ -249,8 +271,75 @@ module TestOpenApi3Client = } use httpClient = HttpClientMock.makeNoUri handler - let client = OpenApiPetstore.make httpClient + let make, _, _ = credentials () + let client = make httpClient let! pets = client.ListPets (if supplied then Some 25 else None) pets |> shouldBeEmpty } + + /// The document's security requirements, as they reach the wire: the root requirement applies + /// everywhere it isn't overridden, `security: []` suppresses it, an operation naming two schemes + /// sends both, and the query-carried key we can't represent is passed over for the bearer token. + [] + let ``Each operation sends exactly the credentials its security requirement asks for`` () = + task { + let observed = ResizeArray () + + let handler (message : HttpRequestMessage) = + async { + let credentialHeaders = + [ + for header in message.Headers do + if header.Key = "X-API-Key" || header.Key = "Authorization" then + yield header.Key, Seq.exactlyOne header.Value + ] + |> List.sortBy fst + + observed.Add (message.RequestUri.AbsolutePath, credentialHeaders) + + match message.Method.Method with + | "DELETE" -> return response HttpStatusCode.NoContent None + | "POST" -> return response HttpStatusCode.Created (Some """{"id":43,"name":"Ada"}""") + | _ when message.RequestUri.AbsolutePath.EndsWith ("status", StringComparison.Ordinal) -> + return response HttpStatusCode.OK (Some "healthy") + | _ -> return response HttpStatusCode.OK (Some """{"id":42,"name":"Ada"}""") + } + + use httpClient = HttpClientMock.makeNoUri handler + let make, apiKeyReads, bearerReads = credentials () + let client = make httpClient + + let! _ = client.GetPet 42L + + let! _ = + client.CreatePet + { + AdditionalProperties = Dictionary () + Name = "Ada" + Tag = None + } + + do! client.DeletePet 43L + let! _ = client.GetStatus () + + observed + |> List.ofSeq + |> shouldEqual + [ + // The root requirement: the API key alone. + "/v1/public/pets/42", [ "X-API-Key", "api-key-value" ] + // Two schemes in one requirement: both credentials go. + "/v1/public/pets", [ "Authorization", "Bearer token-value" ; "X-API-Key", "api-key-value" ] + // Alternatives: the legacy query-string key is unrepresentable, so we take the bearer. + "/v1/public/pets/43", [ "Authorization", "Bearer token-value" ] + // security: [] really does mean "send nothing". + "/v1/public/status", [] + ] + + // A caller who has no bearer token can still call every operation which doesn't need one: + // the credential is fetched only where the document requires it, not merely dropped from + // the request afterwards. + apiKeyReads.Value |> shouldEqual 2 + bearerReads.Value |> shouldEqual 2 + } diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs new file mode 100644 index 00000000..a8cc624a --- /dev/null +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs @@ -0,0 +1,495 @@ +namespace WoofWare.Myriad.Plugins.Test + +open System +open System.Text.Json.Nodes +open FsCheck +open FsCheck.FSharp +open FsUnitTyped +open NUnit.Framework +open WoofWare.Myriad.Plugins + +/// The OpenAPI planner's treatment of `security` and `components.securitySchemes`: which credentials +/// each operation sends, and which documents it refuses rather than silently authenticating nothing. +[] +module TestOpenApi3Security = + + let private jsonString (value : string) : JsonNode = JsonValue.Create value + + let private jsonObject (properties : (string * JsonNode) list) : JsonNode = + let result = JsonObject () + + for name, value in properties do + result.Add (name, value) + + result :> JsonNode + + let private jsonArray (values : JsonNode list) : JsonNode = + JsonArray (values |> List.toArray) :> JsonNode + + let private apiKeyHeaderScheme (headerName : string) : JsonNode = + jsonObject + [ + "type", jsonString "apiKey" + "name", jsonString headerName + "in", jsonString "header" + ] + + let private apiKeyElsewhereScheme (location : string) : JsonNode = + jsonObject + [ + "type", jsonString "apiKey" + "name", jsonString "key" + "in", jsonString location + ] + + let private httpScheme (scheme : string) : JsonNode = + jsonObject [ "type", jsonString "http" ; "scheme", jsonString scheme ] + + let private oauth2Scheme () : JsonNode = + jsonObject + [ + "type", jsonString "oauth2" + "flows", + jsonObject + [ + "clientCredentials", + jsonObject + [ + "tokenUrl", jsonString "https://example.test/token" + "scopes", jsonObject [ "read", jsonString "Read things" ] + ] + ] + ] + + let private openIdConnectScheme () : JsonNode = + jsonObject + [ + "type", jsonString "openIdConnect" + "openIdConnectUrl", jsonString "https://example.test/.well-known/openid-configuration" + ] + + /// One alternative of a `security` array: all of these schemes together. + let private requirement (schemes : string list) : JsonNode = + jsonObject (schemes |> List.map (fun scheme -> scheme, jsonArray [])) + + /// A document whose operations are named by their path, so a test can look up an operation's + /// plan by name. `operations` gives each operation's `security` array, if it declares one. + let private securityDocument + (schemes : (string * JsonNode) list) + (rootSecurity : JsonNode list option) + (operations : (string * JsonNode list option) list) + : string + = + let pathItem (name : string) (security : JsonNode list option) = + jsonObject + [ + "get", + jsonObject + [ + "operationId", jsonString name + "responses", jsonObject [ "200", jsonObject [ "description", jsonString "success" ] ] + match security with + | None -> () + | Some security -> "security", jsonArray security + ] + ] + + jsonObject + [ + "openapi", jsonString "3.0.3" + "info", jsonObject [ "title", jsonString "Generated API" ; "version", jsonString "1.0.0" ] + "servers", jsonArray [ jsonObject [ "url", jsonString "/api/v1" ] ] + "paths", + jsonObject ( + operations + |> List.map (fun (name, security) -> $"/%s{name}", pathItem name security) + ) + "components", jsonObject [ "securitySchemes", jsonObject schemes ] + match rootSecurity with + | None -> () + | Some security -> "security", jsonArray security + ] + |> _.ToJsonString() + + let private config = Map [ "CLASSNAME", "GeneratedClient" ] + + let private plan (parameters : Map) (source : string) : OpenApiClientPlan = + match OpenApiClientGenerator.parseAndPlan parameters source with + | Ok value -> value + | Error diagnostics -> + diagnostics + |> List.map (fun diagnostic -> $"%s{diagnostic.Location}: %s{diagnostic.Message}") + |> String.concat Environment.NewLine + |> failwith + + let private diagnostics (parameters : Map) (source : string) : OpenApiGenerationDiagnostic list = + match OpenApiClientGenerator.parseAndPlan parameters source with + | Ok _ -> failwith "Planning unexpectedly succeeded" + | Error diagnostics -> diagnostics + + /// The operation whose path was `/name`, by the F# name the planner gave it. + let private operation (plan : OpenApiClientPlan) (name : string) : OpenApiPlannedOperation = + plan.Operations + |> List.filter (fun operation -> operation.Path = $"/%s{name}") + |> List.exactlyOne + + [] + let ``A root security requirement is applied to every operation`` () = + let source = + securityDocument + [ "bearerAuth", httpScheme "bearer" ] + (Some [ requirement [ "bearerAuth" ] ]) + [ "first", None ; "second", None ] + + let plan = plan config source + + for name in [ "first" ; "second" ] do + (operation plan name).Security |> shouldEqual [ "bearerAuth" ] + + let credential = plan.Credentials.["bearerAuth"] + credential.HeaderName |> shouldEqual "Authorization" + credential.Kind |> shouldEqual (OpenApiSecuritySchemeKind.Http "bearer") + credential.FSharpName |> shouldEqual "BearerAuth" + + [] + let ``An operation's security replaces the root's, and an empty one demands no credentials`` () = + let source = + securityDocument + [ + "bearerAuth", httpScheme "bearer" + "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" + ] + (Some [ requirement [ "bearerAuth" ] ]) + [ + "inherited", None + "overridden", Some [ requirement [ "apiKeyAuth" ] ] + "public", Some [] + ] + + let plan = plan config source + + (operation plan "inherited").Security |> shouldEqual [ "bearerAuth" ] + (operation plan "overridden").Security |> shouldEqual [ "apiKeyAuth" ] + (operation plan "public").Security |> shouldEqual [] + + plan.Credentials.["apiKeyAuth"].HeaderName |> shouldEqual "X-API-Key" + + plan.Credentials.["apiKeyAuth"].Kind + |> shouldEqual OpenApiSecuritySchemeKind.ApiKey + + [] + let ``A requirement naming several schemes sends all of their credentials`` () = + let source = + securityDocument + [ + "bearerAuth", httpScheme "bearer" + "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" + ] + None + [ "both", Some [ requirement [ "apiKeyAuth" ; "bearerAuth" ] ] ] + + let plan = plan config source + + (operation plan "both").Security |> shouldEqual [ "apiKeyAuth" ; "bearerAuth" ] + + plan.Credentials |> Map.count |> shouldEqual 2 + + [] + let ``Only the schemes some operation uses become credentials the caller must supply`` () = + let source = + securityDocument + [ + "used", httpScheme "bearer" + "unused", apiKeyHeaderScheme "X-Unused" + "alsoUnrepresentable", apiKeyElsewhereScheme "query" + ] + None + [ "thing", Some [ requirement [ "used" ] ] ] + + let plan = plan config source + + plan.Credentials |> Map.toList |> List.map fst |> shouldEqual [ "used" ] + + [] + let ``OAuth2 and OpenID Connect credentials are carried, but no flow is performed`` () = + let source = + securityDocument + [ "oauth", oauth2Scheme () ; "oidc", openIdConnectScheme () ] + None + [ + "oauthThing", Some [ requirement [ "oauth" ] ] + "oidcThing", Some [ requirement [ "oidc" ] ] + ] + + let plan = plan config source + + plan.Credentials.["oauth"].Kind |> shouldEqual OpenApiSecuritySchemeKind.OAuth2 + + plan.Credentials.["oauth"].HeaderName |> shouldEqual "Authorization" + + plan.Credentials.["oidc"].Kind + |> shouldEqual OpenApiSecuritySchemeKind.OpenIdConnect + + [] + let ``The first representable alternative is the one applied`` () = + let source = + securityDocument + [ + "queryKey", apiKeyElsewhereScheme "query" + "bearerAuth", httpScheme "bearer" + "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" + ] + None + [ + "thing", + Some + [ + requirement [ "queryKey" ] + requirement [ "bearerAuth" ] + requirement [ "apiKeyAuth" ] + ] + ] + + let plan = plan config source + + (operation plan "thing").Security |> shouldEqual [ "bearerAuth" ] + + [] + let ``An operation whose alternatives include the empty requirement first sends nothing`` () = + let source = + securityDocument + [ "bearerAuth", httpScheme "bearer" ] + None + [ "thing", Some [ requirement [] ; requirement [ "bearerAuth" ] ] ] + + let plan = plan config source + + (operation plan "thing").Security |> shouldEqual [] + plan.Credentials |> shouldEqual Map.empty + + [] + let ``An unsatisfiable security requirement fails the build rather than authenticating nothing`` () = + for location in [ "query" ; "cookie" ] do + let source = + securityDocument + [ "key", apiKeyElsewhereScheme location ] + None + [ "thing", Some [ requirement [ "key" ] ] ] + + diagnostics config source + |> List.filter (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity) + |> List.map _.Location + |> shouldEqual [ "#/paths/~1thing/get/security" ] + + [] + let ``A root security requirement we cannot satisfy fails every operation which inherits it`` () = + let source = + securityDocument + [ "key", apiKeyElsewhereScheme "query" ] + (Some [ requirement [ "key" ] ]) + [ "thing", None ; "public", Some [] ] + + let diagnostics = diagnostics config source + + diagnostics + |> List.filter (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity) + |> List.length + |> shouldEqual 1 + + [] + let ``A requirement naming an undefined scheme is a dangling reference`` () = + let source = + securityDocument + [ "bearerAuth", httpScheme "bearer" ] + None + [ "thing", Some [ requirement [ "nonexistent" ] ] ] + + diagnostics config source + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnresolvedReference) + |> shouldEqual true + + [] + let ``A security scheme of unknown type is rejected`` () = + let source = + securityDocument + [ "weird", jsonObject [ "type", jsonString "magic" ] ] + None + [ "thing", Some [ requirement [ "weird" ] ] ] + + let diagnostics = diagnostics config source + + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.InvalidDocument) + |> shouldEqual true + + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity) + |> shouldEqual true + + [] + let ``The SecuritySchemes parameter chooses between alternatives`` () = + let source = + securityDocument + [ + "bearerAuth", httpScheme "bearer" + "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" + ] + None + [ + "thing", Some [ requirement [ "bearerAuth" ] ; requirement [ "apiKeyAuth" ] ] + ] + + let restricted = plan (config |> Map.add "SECURITYSCHEMES" "apiKeyAuth") source + + (operation restricted "thing").Security |> shouldEqual [ "apiKeyAuth" ] + + // Without the restriction we'd have taken the document's first alternative. + (operation (plan config source) "thing").Security + |> shouldEqual [ "bearerAuth" ] + + [] + let ``The SecuritySchemes parameter cannot silently exclude every alternative`` () = + let source = + securityDocument + [ "bearerAuth", httpScheme "bearer" ] + None + [ "thing", Some [ requirement [ "bearerAuth" ] ] ] + + diagnostics (config |> Map.add "SECURITYSCHEMES" "apiKeyAuth") source + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity) + |> shouldEqual true + + [] + let ``A SecuritySchemes parameter naming an undefined scheme is rejected`` () = + let source = + securityDocument + [ "bearerAuth", httpScheme "bearer" ] + None + [ "thing", Some [ requirement [ "bearerAuth" ] ] ] + + diagnostics (config |> Map.add "SECURITYSCHEMES" "bearerAuth, typo") source + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.InvalidDocument + && diagnostic.Location.Contains ("SecuritySchemes", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``Credential property names do not collide with operation names`` () = + // The scheme and the operation sanitise to the same F# identifier, and both are members of + // the same interface. + let source = + securityDocument [ "thing", httpScheme "bearer" ] None [ "thing", Some [ requirement [ "thing" ] ] ] + + let plan = plan config source + + (operation plan "thing").FSharpName |> shouldEqual "Thing" + plan.Credentials.["thing"].FSharpName |> shouldEqual "Thing2" + + type private GeneratedSchemeKind = + | Bearer + | ApiKeyHeader + | OAuth2 + | ApiKeyQuery + | ApiKeyCookie + + /// A scheme as the generated document declares it, paired with whether the planner can carry it. + type private GeneratedScheme = + { + Name : string + Json : JsonNode + Representable : bool + } + + let private generatedScheme (index : int) (kind : GeneratedSchemeKind) : GeneratedScheme = + let json, representable = + match kind with + | Bearer -> httpScheme "bearer", true + | ApiKeyHeader -> apiKeyHeaderScheme $"X-Key-%i{index}", true + | OAuth2 -> oauth2Scheme (), true + | ApiKeyQuery -> apiKeyElsewhereScheme "query", false + | ApiKeyCookie -> apiKeyElsewhereScheme "cookie", false + + { + Name = $"scheme%i{index}" + Json = json + Representable = representable + } + + /// A document's schemes, plus one operation's alternatives as indices into them. + let private securityCase : Gen = + gen { + let! schemeCount = Gen.choose (1, 4) + + let! kinds = + Gen.listOfLength + schemeCount + (Gen.elements [ Bearer ; ApiKeyHeader ; OAuth2 ; ApiKeyQuery ; ApiKeyCookie ]) + + let schemes = kinds |> List.mapi generatedScheme + + let alternative = + gen { + let! size = Gen.choose (0, 2) + let! indices = Gen.listOfLength size (Gen.choose (0, schemeCount - 1)) + // A requirement is a JSON object, so it cannot name the same scheme twice. + return List.distinct indices + } + + let! alternativeCount = Gen.choose (0, 4) + let! alternatives = Gen.listOfLength alternativeCount alternative + return schemes, alternatives + } + + [] + let ``The applied requirement is always the document's first satisfiable alternative`` () = + let property (schemes : GeneratedScheme list, alternatives : int list list) = + let representable = + schemes + |> List.mapi (fun index scheme -> index, scheme.Representable) + |> Map.ofList + + // The oracle: the first alternative all of whose schemes we can carry. An absent + // alternative list is not a failure; it means "this operation needs no credentials". + let expected = + if List.isEmpty alternatives then + Some [] + else + alternatives + |> List.tryFind (fun alternative -> alternative |> List.forall (fun index -> representable.[index])) + |> Option.map (fun alternative -> + alternative + |> List.map (fun index -> schemes.[index].Name) + |> List.distinct + |> List.sort + ) + + let source = + securityDocument + (schemes |> List.map (fun scheme -> scheme.Name, scheme.Json)) + None + [ + "thing", + Some ( + alternatives + |> List.map (fun alternative -> + alternative |> List.map (fun index -> schemes.[index].Name) |> requirement + ) + ) + ] + + match OpenApiClientGenerator.parseAndPlan config source, expected with + | Ok plan, Some expected -> + (operation plan "thing").Security = expected + && (plan.Credentials |> Map.toList |> List.map fst) = List.distinct expected + | Error diagnostics, None -> + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity) + | Ok plan, None -> + let sent = (operation plan "thing").Security + failwith $"Planning accepted an unsatisfiable requirement, sending %+A{sent}" + | Error diagnostics, Some expected -> + failwith + $"Planning rejected a satisfiable requirement %+A{expected}: %+A{diagnostics |> List.map _.Message}" + + Check.QuickThrowOnFailure (Prop.forAll (Arb.fromGen securityCase) property) diff --git a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj index 5d7adeff..c054dac9 100644 --- a/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj +++ b/WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj @@ -26,6 +26,7 @@ + @@ -56,6 +57,7 @@ + diff --git a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs index 4e912166..7c96ff3e 100644 --- a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs @@ -64,6 +64,10 @@ module internal HttpClientGenerator = /// Headers which apply *only* to this endpoint. /// For example, SynConst "Authorization" and SynConst "token BLAH". Headers : (SynExpr * SynExpr) list + /// Headers which apply *only* to this endpoint, whose values come from a property of the + /// interface (and so are re-evaluated on every request). + /// For example, SynConst "Authorization" and the identifier `BearerToken`. + PropertyHeaders : (SynExpr * Ident) list } /// Allocate an identifier based on `desired` that does not clash with any name in `taken`. @@ -206,6 +210,42 @@ module internal HttpClientGenerator = | _ -> None ) + /// The property a HeaderFromProperty attribute names. The compiler only ever sees a string here, + /// but the source may spell it either as a literal or, so that a rename is a compile error rather + /// than a silent breakage, as `nameof Unchecked.defaultof.TheProperty` (F#'s `nameof` + /// requires an instance for a non-static member, hence the dance). We read the syntax, not the + /// evaluated constant, so we take the last identifier of whatever `nameof` was applied to. + let private propertyNameOfAttributeArg (expr : SynExpr) : string = + match SynExpr.stripOptionalParen expr with + | SynExpr.Const (SynConst.String (property, SynStringKind.Regular, _), _) -> property + | SynExpr.App (_, _, SynExpr.Ident funcName, arg, _) when funcName.idText = "nameof" -> + match SynExpr.stripOptionalParen arg with + | SynExpr.DotGet (_, _, SynLongIdent (path, _, _), _) + | SynExpr.LongIdent (_, SynLongIdent (path, _, _), _, _) when not path.IsEmpty -> (List.last path).idText + | arg -> failwith $"Expected `nameof` to be applied to a property access, but got: %+A{arg}" + | expr -> + failwith + $"Expected the property in a HeaderFromProperty attribute to be a string literal or a `nameof`, but got: %+A{expr}" + + /// Get the (header name, name of the property supplying its value) pairs associated with the + /// HeaderFromProperty attributes within the list. + let extractHeaderFromPropertyInformation (attrs : SynAttribute list) : (SynExpr * string) list = + attrs + |> List.choose (fun attr -> + match SynLongIdent.toString attr.TypeName with + | "HeaderFromProperty" + | "HeaderFromPropertyAttribute" + | "WoofWare.Myriad.Plugins.HeaderFromProperty" + | "WoofWare.Myriad.Plugins.HeaderFromPropertyAttribute" -> + match attr.ArgExpr with + | SynExpr.Paren (SynExpr.Tuple (_, [ header ; property ], _, _), _, _, _) -> + Some (SynExpr.stripOptionalParen header, propertyNameOfAttributeArg property) + | e -> + failwith + $"Expected HeaderFromProperty attributes to be of the form [], but got: %+A{e}" + | _ -> None + ) + let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool = attrs |> List.exists (fun attr -> @@ -785,7 +825,7 @@ module internal HttpClientGenerator = ) let setVariableHeaders = - variableHeaders + variableHeaders @ info.PropertyHeaders |> List.map (fun (headerName, callToGetValue) -> [ headerName @@ -899,7 +939,10 @@ module internal HttpClientGenerator = |> SynExpr.startAsTask cancellationTokenArg let thisIdent = - if variableHeaders.IsEmpty then "_" else "this" + if variableHeaders.IsEmpty && info.PropertyHeaders.IsEmpty then + "_" + else + "this" |> Ident.create let args = args |> List.map snd |> SynPat.tuple |> List.singleton @@ -1028,24 +1071,37 @@ module internal HttpClientGenerator = let properties = interfaceType.Properties |> List.map (fun pi -> + // A property with no Header attribute supplies no header of its own; it's addressable + // by the members which name it in a HeaderFromProperty attribute. let headerInfo = match extractHeaderInformation pi.Attributes with - | [ [ x ] ] -> x + | [ [ x ] ] -> Some x | [ _ ] -> failwith - "Expected exactly one Header parameter on the member, with exactly one arg; got one Header parameter with non-1-many args" - | [] -> - failwith - "Expected exactly one Header parameter on the member, with exactly one arg; got no Header parameters" + "Expected at most one Header parameter on the member, with exactly one arg; got one Header parameter with non-1-many args" + | [] -> None | _ -> failwith - "Expected exactly one Header parameter on the member, with exactly one arg; got multiple Header parameters" + "Expected at most one Header parameter on the member, with exactly one arg; got multiple Header parameters" headerInfo, pi ) + /// The properties which a member may name in a HeaderFromProperty attribute: that is, all + /// the properties which don't already stamp their header onto every request. + let addressableProperties = + properties + |> List.choose (fun (header, pi) -> + match header with + | Some _ -> None + | None -> Some (pi.Identifier.idText, pi.Identifier) + ) + |> Map.ofList + let nonPropertyMembers = - let properties = properties |> List.map (fun (header, pi) -> header, pi.Identifier) + let properties = + properties + |> List.choose (fun (header, pi) -> header |> Option.map (fun header -> header, pi.Identifier)) interfaceType.Members |> List.map (fun mem -> @@ -1061,6 +1117,19 @@ module internal HttpClientGenerator = $"Expected Header attribute on member %s{mem.Identifier.idText} to have exactly two arguments." ) + let propertyHeaders = + extractHeaderFromPropertyInformation mem.Attributes + |> List.map (fun (headerName, propertyName) -> + match Map.tryFind propertyName addressableProperties with + | Some identifier -> headerName, identifier + | None -> + let available = + addressableProperties |> Map.toList |> List.map fst |> String.concat ", " + + failwith + $"Member %s{mem.Identifier.idText} takes a header from property '%s{propertyName}', but the interface has no such property without a Header attribute of its own. Available: [%s{available}]" + ) + let shouldEnsureSuccess = not (shouldAllowAnyStatusCode mem.Attributes) let returnType = @@ -1102,6 +1171,7 @@ module internal HttpClientGenerator = BasePath = basePath Accessibility = mem.Accessibility Headers = specificHeaders + PropertyHeaders = propertyHeaders } ) |> List.map (constructMember constantHeaders properties) diff --git a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs index d3b3926b..2e4c93d5 100644 --- a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs @@ -19,6 +19,7 @@ type internal OpenApiGenerationDiagnosticCode = | UnsupportedSchema | UnsupportedParameter | UnsupportedOperation + | UnsupportedSecurity | AmbiguousSuccessResponse type internal OpenApiGenerationDiagnostic = @@ -81,6 +82,33 @@ type internal OpenApiPlannedParameter = Required : bool } +/// The kind of an OpenAPI security scheme. Every kind we support is carried in a request header +/// whose entire value the caller supplies; we perform no token acquisition of any sort. +type internal OpenApiSecuritySchemeKind = + /// `type: apiKey`, `in: header`. + | ApiKey + /// `type: http`; the argument is the `scheme`, e.g. "bearer" or "basic". The credential is the + /// whole `Authorization` header value, scheme name and all. + | Http of scheme : string + /// `type: oauth2`. We run no OAuth flow: the caller supplies an `Authorization` header value. + | OAuth2 + /// `type: openIdConnect`. As for `oauth2`, the caller supplies an `Authorization` header value. + | OpenIdConnect + +/// A credential which the generated client requires its caller to supply, because some operation's +/// security requirement asks for it. +type internal OpenApiPlannedCredential = + { + /// The name under which this scheme appears in `components.securitySchemes`. + SchemeName : string + /// The property on the generated interface which supplies this credential. + FSharpName : string + /// The header whose entire value this credential is. + HeaderName : string + Kind : OpenApiSecuritySchemeKind + Description : string option + } + type internal OpenApiPlannedOperation = { OperationId : string @@ -92,6 +120,9 @@ type internal OpenApiPlannedOperation = ReturnType : OpenApiPlannedType Accept : string option RequestContentType : string option + /// The security schemes whose credentials this operation sends, by `SchemeName`. Empty when + /// the operation requires no credentials. Every entry is a key of the plan's `Credentials`. + Security : string list } type internal OpenApiServerBase = @@ -107,6 +138,9 @@ type internal OpenApiClientPlan = ServerBase : OpenApiServerBase Types : OpenApiPlannedTypeDefinition list Operations : OpenApiPlannedOperation list + /// The credentials the generated client's operations require, keyed by scheme name. Only the + /// schemes some operation actually uses appear here. + Credentials : Map } [] @@ -1171,6 +1205,199 @@ module internal OpenApiClientGenerator = | true, _ -> OpenApiServerBase.BaseAddress url | false, _ -> OpenApiServerBase.BasePath url + /// A security scheme from `components.securitySchemes`, as far as the generated client is + /// concerned: either a header whose entire value the caller supplies, or a reason we can't + /// carry it at all. + type private SecurityScheme = + | Representable of headerName : string * kind : OpenApiSecuritySchemeKind * description : string option + | Unrepresentable of reason : string + + /// One entry of a `security` array: the schemes which must *all* be satisfied together, sorted + /// for determinism. The empty list is the OpenAPI empty requirement `{}`, i.e. "no credentials". + type private SecurityRequirement = + { + Schemes : string list + Location : string + } + + /// The `security` of an operation or of the document root: an ordered list of alternatives, any + /// one of which suffices. `None` means the key was absent (so the root's value is inherited); + /// `Some []` means it was present and empty, which explicitly demands no credentials. + type private SecurityRequirements = SecurityRequirement list option + + let private parseSecuritySchemes + (diagnostics : ResizeArray) + (components : LocatedObject option) + : Map + = + let report = report diagnostics + let requiredString = requiredString diagnostics + let optionalString = optionalString diagnostics + let optionalObject = optionalObject diagnostics + + let declared = componentMap diagnostics components "securitySchemes" + + declared + |> Map.map (fun _ scheme -> + match + resolveComponentReference + diagnostics + UnresolvedReference + "#/components/securitySchemes/" + declared + Set.empty + scheme + with + | None -> SecurityScheme.Unrepresentable "the security scheme's reference could not be resolved" + | Some scheme -> + + let description = optionalString scheme.Location scheme.Value "description" + + match requiredString scheme.Location scheme.Value "type" with + | None -> SecurityScheme.Unrepresentable "the security scheme has no type" + | Some "apiKey" -> + let name = requiredString scheme.Location scheme.Value "name" + + match requiredString scheme.Location scheme.Value "in" with + | None -> SecurityScheme.Unrepresentable "the apiKey security scheme does not say where the key goes" + | Some "header" -> + match name with + | None -> SecurityScheme.Unrepresentable "the apiKey security scheme names no header" + | Some name -> SecurityScheme.Representable (name, OpenApiSecuritySchemeKind.ApiKey, description) + | Some ("query" | "cookie" as location) -> + SecurityScheme.Unrepresentable + $"apiKey credentials carried in the %s{location} are not representable by the generated HTTP client, which can only set headers" + | Some other -> + report + InvalidDocument + ($"%s{scheme.Location}/in") + $"An apiKey security scheme's 'in' must be one of header, query, or cookie, but got '%s{other}'." + + SecurityScheme.Unrepresentable + $"the apiKey security scheme has an unrecognised location '%s{other}'" + | Some "http" -> + match requiredString scheme.Location scheme.Value "scheme" with + | None -> SecurityScheme.Unrepresentable "the http security scheme names no authentication scheme" + | Some httpScheme -> + SecurityScheme.Representable ( + "Authorization", + OpenApiSecuritySchemeKind.Http httpScheme, + description + ) + | Some "oauth2" -> + match optionalObject scheme.Location scheme.Value "flows" with + | None -> + report InvalidDocument scheme.Location "An oauth2 security scheme must have a 'flows' object." + SecurityScheme.Unrepresentable "the oauth2 security scheme has no flows" + | Some _ -> + SecurityScheme.Representable ("Authorization", OpenApiSecuritySchemeKind.OAuth2, description) + | Some "openIdConnect" -> + match requiredString scheme.Location scheme.Value "openIdConnectUrl" with + | None -> SecurityScheme.Unrepresentable "the openIdConnect security scheme has no discovery URL" + | Some _ -> + SecurityScheme.Representable ( + "Authorization", + OpenApiSecuritySchemeKind.OpenIdConnect, + description + ) + | Some other -> + report + InvalidDocument + ($"%s{scheme.Location}/type") + $"Security scheme type '%s{other}' is not one of apiKey, http, oauth2, openIdConnect." + + SecurityScheme.Unrepresentable $"'%s{other}' is not a security scheme type defined by OpenAPI 3.0" + ) + + /// Parse the `security` of a document root or an operation. Scheme names which no security + /// scheme defines are a document error, and are reported here however the requirement is later + /// used: a dangling reference is a bug in the document even if we don't happen to need it. + let private parseSecurityRequirements + (diagnostics : ResizeArray) + (schemes : Map) + (owner : LocatedObject) + : SecurityRequirements + = + let report = report diagnostics + let optionalArray = optionalArray diagnostics + let tryObject = tryObject diagnostics + let tryArray = tryArray diagnostics + + match optionalArray owner.Location owner.Value "security" with + | None -> None + | Some requirements -> + + let location = $"%s{owner.Location}/security" + + requirements + |> Seq.mapi (fun index requirement -> + let location = $"%s{location}/%i{index}" + + match tryObject location requirement with + | None -> None + | Some requirement -> + let schemeNames = + requirement.Value + |> Seq.map (fun (KeyValue (name, scopes)) -> name, scopes) + |> Seq.sortBy fst + |> Seq.toList + + for name, scopes in schemeNames do + let schemeLocation = $"%s{location}/%s{pointerToken name}" + // The scopes carry no information the generated client can act on, but a + // non-array here means the document doesn't say what it thinks it says. + tryArray schemeLocation scopes |> ignore + + if not (Map.containsKey name schemes) then + report + UnresolvedReference + schemeLocation + $"Security requirement names scheme '%s{name}', which no security scheme defines." + + { + Schemes = schemeNames |> List.map fst + Location = location + } + |> Some + ) + |> Seq.toList + |> List.choose id + |> Some + + /// Choose the credentials an operation sends: the first alternative, in document order, all of + /// whose schemes we can represent and the caller permitted. `Ok []` means "send none", which is + /// what an absent or empty `security` demands. `Error` lists why each alternative was rejected. + let private selectSecurityRequirement + (permitted : Set option) + (schemes : Map) + (alternatives : SecurityRequirement list) + : Result + = + let rejection (schemeName : string) : string option = + match Map.tryFind schemeName schemes with + | None -> Some $"'%s{schemeName}' is not defined by any security scheme" + | Some (SecurityScheme.Unrepresentable reason) -> Some $"'%s{schemeName}' is unsupported: %s{reason}" + | Some (SecurityScheme.Representable _) -> + match permitted with + | Some permitted when not (Set.contains schemeName permitted) -> + Some $"'%s{schemeName}' was not listed in the SecuritySchemes Myriad parameter" + | _ -> None + + let rec go (rejections : (string * string) list) (alternatives : SecurityRequirement list) = + match alternatives with + | [] -> Error (List.rev rejections) + | alternative :: rest -> + match alternative.Schemes |> List.choose rejection with + | [] -> Ok alternative.Schemes + | reasons -> go ((alternative.Location, String.concat "; " reasons) :: rejections) rest + + // No alternatives at all is not a failure to satisfy anything: it is the statement that this + // operation needs no credentials. + if List.isEmpty alternatives then + Ok [] + else + go [] alternatives + type private OperationPlanningContext = { Diagnostics : ResizeArray @@ -1179,6 +1406,13 @@ module internal OpenApiClientGenerator = ParameterComponents : Map RequestBodyComponents : Map ResponseComponents : Map + SecuritySchemes : Map + /// The schemes the caller is willing to have the generated client use, if they restricted + /// them; `None` permits every scheme the document defines. + PermittedSecuritySchemes : Set option + /// Names already taken by members of the generated interface. Shared with the credential + /// properties, which live in the same scope as the operation methods. + UsedMemberNames : HashSet } let private parseParameter (context : OperationPlanningContext) (value : LocatedObject) : ResolvedParameter option = @@ -1692,7 +1926,17 @@ module internal OpenApiClientGenerator = let paths = optionalObject "#" root "paths" let operations = ResizeArray () let usedOperationIds = HashSet (StringComparer.Ordinal) - let usedMethodNames = HashSet (StringComparer.Ordinal) + let usedMethodNames = context.UsedMemberNames + + let rootSecurity = + parseSecurityRequirements + diagnostics + context.SecuritySchemes + { + Location = "#" + Value = root + } + |> Option.defaultValue [] let methodEntries (pathItem : LocatedObject) = [ @@ -1767,6 +2011,33 @@ module internal OpenApiClientGenerator = let operationFSharpName = allocateUniqueName usedMethodNames "Operation" sanitiseTypeName operationId + // An operation's own `security` replaces the root's entirely, including when it + // is present and empty (which demands that we send no credentials at all). + let security = + let alternatives = + parseSecurityRequirements diagnostics context.SecuritySchemes operation + |> Option.defaultValue rootSecurity + + match + selectSecurityRequirement + context.PermittedSecuritySchemes + context.SecuritySchemes + alternatives + with + | Ok schemes -> schemes + | Error rejections -> + let rejections = + rejections + |> List.map (fun (location, reason) -> $"%s{location}: %s{reason}") + |> String.concat Environment.NewLine + + report + UnsupportedSecurity + ($"%s{operation.Location}/security") + $"No security requirement of this operation can be satisfied by the generated client, so it would silently issue unauthenticated requests.%s{Environment.NewLine}%s{rejections}" + + [] + let mergedParameters = parseParameterList context operation |> mergeParameters inheritedParameters @@ -1893,6 +2164,7 @@ module internal OpenApiClientGenerator = ReturnType = returnType Accept = accept RequestContentType = body |> Option.map snd + Security = security } operations |> Seq.sortBy _.FSharpName |> Seq.toList @@ -2015,6 +2287,19 @@ module internal OpenApiClientGenerator = None + // Restricting the schemes is how a caller resolves an operation's *alternative* security + // requirements at generation time: we take the first alternative the caller permitted, so + // the choice is visible in the generated source rather than made at runtime. + let permittedSecuritySchemes = + match Map.tryFind "SECURITYSCHEMES" parameters with + | None -> None + | Some value -> + value.Split ',' + |> Seq.map _.Trim() + |> Seq.filter (fun value -> not (String.IsNullOrWhiteSpace value)) + |> Set.ofSeq + |> Some + let info = optionalObject "#" root "info" let description = @@ -2035,6 +2320,17 @@ module internal OpenApiClientGenerator = let parameterComponents = componentMap components "parameters" let requestBodyComponents = componentMap components "requestBodies" let responseComponents = componentMap components "responses" + let securitySchemes = parseSecuritySchemes diagnostics components + + match permittedSecuritySchemes with + | None -> () + | Some permitted -> + for name in permitted do + if not (Map.containsKey name securitySchemes) then + report + InvalidDocument + "#/$parameters/SecuritySchemes" + $"The SecuritySchemes Myriad parameter names '%s{name}', which the document does not define." let schemaResolution = { @@ -2092,6 +2388,8 @@ module internal OpenApiClientGenerator = for sourceName in objectComponentNames do addComponentDefinition schemaPlanning sourceName schemaComponents.[sourceName] + let usedMemberNames = HashSet (StringComparer.Ordinal) + let operationPlanning = { Diagnostics = diagnostics @@ -2100,12 +2398,40 @@ module internal OpenApiClientGenerator = ParameterComponents = parameterComponents RequestBodyComponents = requestBodyComponents ResponseComponents = responseComponents + SecuritySchemes = securitySchemes + PermittedSecuritySchemes = permittedSecuritySchemes + UsedMemberNames = usedMemberNames } let serverBase = parseServerBase diagnostics root let operations = planOperations operationPlanning root let orderedDefinitions = orderDefinitions diagnostics definitions + // Only the schemes some operation actually sends become credentials the caller must supply. + let credentials = + operations + |> List.collect _.Security + |> Set.ofList + |> Seq.map (fun schemeName -> + match Map.tryFind schemeName securitySchemes with + | Some (SecurityScheme.Representable (headerName, kind, schemeDescription)) -> + let credential = + { + SchemeName = schemeName + FSharpName = + allocateUniqueName usedMemberNames "SecurityScheme" sanitiseTypeName schemeName + HeaderName = headerName + Kind = kind + Description = schemeDescription + } + + schemeName, credential + | _ -> + // selectSecurityRequirement only ever returns representable schemes. + failwith $"Logic error: security scheme '%s{schemeName}' was selected but is not representable." + ) + |> Map.ofSeq + let plan = { Namespace = className @@ -2115,6 +2441,7 @@ module internal OpenApiClientGenerator = ServerBase = serverBase Types = orderedDefinitions Operations = operations + Credentials = credentials } if diagnostics.Count = 0 then @@ -2232,7 +2559,58 @@ module internal OpenApiClientGenerator = fields |> SynTypeDefnRepr.record |> SynTypeDefn.create componentInfo - let private renderOperation (operation : OpenApiPlannedOperation) : SynMemberDefn = + /// The documentation of the property through which the caller supplies one credential. It has to + /// say exactly what string the client will send, because we send it verbatim. + let private credentialDoc (credential : OpenApiPlannedCredential) : string list = + [ + match credential.Kind with + | OpenApiSecuritySchemeKind.ApiKey -> + yield + $"The value of the '%s{credential.HeaderName}' header, which carries the API key of the '%s{credential.SchemeName}' security scheme." + | OpenApiSecuritySchemeKind.Http scheme -> + yield + $"The complete value of the '%s{credential.HeaderName}' header for the '%s{credential.SchemeName}' security scheme, which is HTTP authentication scheme '%s{scheme}'." + + yield $"The value must include the scheme name: for example, \"%s{scheme} <credentials>\"." + | OpenApiSecuritySchemeKind.OAuth2 + | OpenApiSecuritySchemeKind.OpenIdConnect -> + let kind = + match credential.Kind with + | OpenApiSecuritySchemeKind.OpenIdConnect -> "OpenID Connect" + | _ -> "OAuth 2.0" + + yield + $"The complete value of the '%s{credential.HeaderName}' header for the '%s{credential.SchemeName}' security scheme, which is %s{kind}." + + yield + "This client runs no token flow of its own: it sends exactly the value you return, so you must acquire and refresh the token yourself (the value is usually \"Bearer <access token>\")." + + yield + "This function is called afresh on every request which requires this scheme, so it can return a token that has since been refreshed." + + match credential.Description with + | None -> () + | Some description -> yield description + ] + + let private renderCredential (credential : OpenApiPlannedCredential) : SynMemberDefn = + SynType.string + |> SynMemberDefn.abstractMember + [] + (SynIdent.createS credential.FSharpName) + None + SynValInfo.empty + // PreXmlDoc.create' emits each line verbatim, where PreXmlDoc.create inserts the space + // after the slashes for you. + (credentialDoc credential + |> List.map (fun line -> " " + line) + |> PreXmlDoc.create') + + let private renderOperation + (credentials : Map) + (operation : OpenApiPlannedOperation) + : SynMemberDefn + = let cancellationToken = SynType.signatureParamOfType [] @@ -2308,6 +2686,23 @@ module internal OpenApiClientGenerator = SynAttribute.create (SynLongIdent.createS' [ "RestEase" ; "Header" ]) (SynExpr.tuple [ SynExpr.CreateConst "Content-Type" ; SynExpr.CreateConst mediaType ]) + + // The property is named by a literal rather than the `nameof` the attribute also + // accepts: the only spelling F# accepts for a non-static member is the unbroken chain + // `nameof Unchecked.defaultof.Prop`, which Fantomas cannot print from an AST + // whose ranges are synthetic. Both sides of this correspondence are generated from the + // same string anyway, so there is nothing here for `nameof` to catch. + for schemeName in operation.Security do + let credential = credentials.[schemeName] + + yield + SynAttribute.create + (SynLongIdent.createS' [ "WoofWare" ; "Myriad" ; "Plugins" ; "HeaderFromProperty" ]) + (SynExpr.tuple + [ + SynExpr.CreateConst credential.HeaderName + SynExpr.CreateConst credential.FSharpName + ]) ] renderType operation.ReturnType @@ -2327,8 +2722,10 @@ module internal OpenApiClientGenerator = plan.Types |> List.map renderRecord |> SynModuleDecl.createTypes let interfaceType = - plan.Operations - |> List.map renderOperation + // Credential properties come first, so that the generated `make` takes them before its + // HttpClient and in an order that doesn't shift when operations are added. + (plan.Credentials |> Map.toList |> List.map (snd >> renderCredential)) + @ (plan.Operations |> List.map (renderOperation plan.Credentials)) |> SynTypeDefnRepr.interfaceType |> SynTypeDefn.create ( let attributes = From 0fb7c2c1d3698cc0095647ca7a0eb9746e5c5540 Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Sat, 25 Jul 2026 18:06:50 +0100 Subject: [PATCH 8/9] Address review of the OpenAPI 3.0 security work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs found by a Codex review of 5703dd1, both of which would have produced a broken client from a valid document. An interface property whose name lowercases to `client` collided with the HttpClient argument the generator adds to `make`, so a security scheme named "client" produced `let make (client : unit -> string) (client : HttpClient)`, which doesn't compile. The HttpClient generator now names its own argument around the properties, as it already did for the `queryString` binding. Two schemes in one requirement could demand the same header — an `http` scheme alongside an `oauth2` one, say, both of which carry `Authorization`. Each is individually representable, so we selected the requirement and then emitted two `Headers.Add ("Authorization", _)` calls, which throws on every request. Such an alternative is now unsatisfiable, so a later alternative can be chosen instead, or the build fails. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 2 + ConsumePlugin/GeneratedRestClient.fs | 51 +++++++++++ ConsumePlugin/RestApiExample.fs | 10 +++ .../TestHttpClient/TestPerEndpointHeader.fs | 10 +++ .../TestSwagger/TestOpenApi3Security.fs | 84 +++++++++++++++---- .../HttpClientGenerator.fs | 21 +++-- .../OpenApiClientGenerator.fs | 30 ++++++- 7 files changed, 185 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1c2b3dc..d15282fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Supported schemes are the header-carried ones: `apiKey` in a header, `http` of a Where an operation offers alternative requirements, the first satisfiable one is used; the new `SecuritySchemes` Myriad parameter restricts which schemes may be chosen. An operation with no satisfiable requirement is now a build failure rather than a silently unauthenticated client. +Fixes a latent bug in the `HttpClient` generator: an interface property named `Client` collided with the `HttpClient` argument of the generated `make`, so the generated source did not compile. + Adds the `[]` attribute for the `HttpClient` generator, which sets a header on one member's requests, taking its value from a property of the same interface. (`[]` on a property continues to set its header on every member's requests.) The property may be named either by a string literal or by `nameof Unchecked.defaultof.TheProperty`. diff --git a/ConsumePlugin/GeneratedRestClient.fs b/ConsumePlugin/GeneratedRestClient.fs index e8c29160..2351fca7 100644 --- a/ConsumePlugin/GeneratedRestClient.fs +++ b/ConsumePlugin/GeneratedRestClient.fs @@ -2128,6 +2128,57 @@ open System.Net open System.Net.Http open RestEase +/// Module for constructing a REST client. +[] +module ApiWithClientProperty = + /// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties. + let make (client : unit -> string) (client1 : System.Net.Http.HttpClient) : IApiWithClientProperty = + { new IApiWithClientProperty with + member _.Client : string = client () + + member this.Get (ct : CancellationToken option) = + async { + let! ct = Async.CancellationToken + + let uri = + System.Uri ( + (match client1.BaseAddress with + | null -> + raise ( + System.ArgumentNullException ( + nameof (client1.BaseAddress), + "No base address was supplied on the type, and no BaseAddress was on the HttpClient." + ) + ) + | v -> v), + System.Uri ("endpoint", System.UriKind.Relative) + ) + + use httpMessage = + new System.Net.Http.HttpRequestMessage ( + Method = System.Net.Http.HttpMethod.Get, + RequestUri = uri + ) + + do httpMessage.Headers.Add ("X-Client", this.Client.ToString ()) + let! response = client1.SendAsync (httpMessage, ct) |> Async.AwaitTask + let response = response.EnsureSuccessStatusCode () + use response = response + let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask + return responseString + } + |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) + } +namespace PureGym + +open System +open System.Threading +open System.Threading.Tasks +open System.IO +open System.Net +open System.Net.Http +open RestEase + /// Module for constructing a REST client. [] module ClientWithJsonBody = diff --git a/ConsumePlugin/RestApiExample.fs b/ConsumePlugin/RestApiExample.fs index 6d6bc344..d121d373 100644 --- a/ConsumePlugin/RestApiExample.fs +++ b/ConsumePlugin/RestApiExample.fs @@ -239,6 +239,16 @@ type IApiWithPerEndpointHeaders = [] abstract Anonymous : [] parameter : string * ?ct : CancellationToken -> Task +/// Regression test: the generated `make` takes one argument per property plus an HttpClient of its +/// own, so a property named `Client` would collide with it and fail to compile. +[] +type IApiWithClientProperty = + [
] + abstract Client : string + + [] + abstract Get : ?ct : CancellationToken -> Task + [] type IClientWithJsonBody = // As a POST request of a JSON-serialised body, we automatically set Content-Type: application/json. diff --git a/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs b/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs index 9a8dd1e8..7d9f2666 100644 --- a/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs +++ b/WoofWare.Myriad.Plugins.Test/TestHttpClient/TestPerEndpointHeader.fs @@ -98,3 +98,13 @@ module TestPerEndpointHeader = api.Authorized("param").Result |> ignore bearerReads.Value |> shouldEqual 3 + + /// The generated `make` takes one argument per property and an HttpClient of its own; a property + /// named `Client` claims the name the HttpClient would otherwise have had, so the generator has + /// to rename its own argument. If it didn't, the generated source wouldn't compile at all. + [] + let ``A property named Client does not collide with the generated HttpClient argument`` () = + use client = HttpClientMock.make (Uri "https://example.com") echoHeaders + let api = ApiWithClientProperty.make (fun () -> "clash") client + + api.Get().Result.Split "\n" |> shouldEqual [| "X-Client: clash" |] diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs index a8cc624a..2ec6e725 100644 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs @@ -267,6 +267,54 @@ module TestOpenApi3Security = (operation plan "thing").Security |> shouldEqual [] plan.Credentials |> shouldEqual Map.empty + // A single request cannot carry two Authorization values: HttpRequestHeaders.Add throws. An + // alternative demanding both would generate a client that failed on every call. + [] + let ``Schemes which compete for one header cannot be satisfied together`` () = + let source = + securityDocument + [ "bearerAuth", httpScheme "bearer" ; "oauth", oauth2Scheme () ] + None + [ "thing", Some [ requirement [ "bearerAuth" ; "oauth" ] ] ] + + diagnostics config source + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity + && diagnostic.Message.Contains ("'Authorization' header", StringComparison.Ordinal) + ) + |> shouldEqual true + + [] + let ``A header collision doesn't stop a later alternative being chosen`` () = + let source = + securityDocument + [ + "bearerAuth", httpScheme "bearer" + "oauth", oauth2Scheme () + "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" + ] + None + [ + "thing", Some [ requirement [ "bearerAuth" ; "oauth" ] ; requirement [ "apiKeyAuth" ] ] + ] + + (operation (plan config source) "thing").Security + |> shouldEqual [ "apiKeyAuth" ] + + [] + let ``Schemes with distinct headers can be satisfied together`` () = + let source = + securityDocument + [ + "bearerAuth", httpScheme "bearer" + "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" + ] + None + [ "thing", Some [ requirement [ "bearerAuth" ; "apiKeyAuth" ] ] ] + + (operation (plan config source) "thing").Security + |> shouldEqual [ "apiKeyAuth" ; "bearerAuth" ] + [] let ``An unsatisfiable security requirement fails the build rather than authenticating nothing`` () = for location in [ "query" ; "cookie" ] do @@ -393,27 +441,28 @@ module TestOpenApi3Security = | ApiKeyQuery | ApiKeyCookie - /// A scheme as the generated document declares it, paired with whether the planner can carry it. + /// A scheme as the generated document declares it, paired with the header it would occupy + /// (`None` if the planner can't carry it at all). type private GeneratedScheme = { Name : string Json : JsonNode - Representable : bool + Header : string option } let private generatedScheme (index : int) (kind : GeneratedSchemeKind) : GeneratedScheme = - let json, representable = + let json, header = match kind with - | Bearer -> httpScheme "bearer", true - | ApiKeyHeader -> apiKeyHeaderScheme $"X-Key-%i{index}", true - | OAuth2 -> oauth2Scheme (), true - | ApiKeyQuery -> apiKeyElsewhereScheme "query", false - | ApiKeyCookie -> apiKeyElsewhereScheme "cookie", false + | Bearer -> httpScheme "bearer", Some "Authorization" + | ApiKeyHeader -> apiKeyHeaderScheme $"X-Key-%i{index}", Some $"X-Key-%i{index}" + | OAuth2 -> oauth2Scheme (), Some "Authorization" + | ApiKeyQuery -> apiKeyElsewhereScheme "query", None + | ApiKeyCookie -> apiKeyElsewhereScheme "cookie", None { Name = $"scheme%i{index}" Json = json - Representable = representable + Header = header } /// A document's schemes, plus one operation's alternatives as indices into them. @@ -444,19 +493,22 @@ module TestOpenApi3Security = [] let ``The applied requirement is always the document's first satisfiable alternative`` () = let property (schemes : GeneratedScheme list, alternatives : int list list) = - let representable = - schemes - |> List.mapi (fun index scheme -> index, scheme.Representable) - |> Map.ofList + // The oracle: the first alternative all of whose schemes we can carry, and no two of + // whose schemes want the same header (one request can't carry two Authorization values). + // An absent alternative list is not a failure; it means "this operation needs no + // credentials". + let satisfiable (alternative : int list) = + let headers = alternative |> List.map (fun index -> schemes.[index].Header) + + List.forall Option.isSome headers + && List.length (List.distinct headers) = List.length headers - // The oracle: the first alternative all of whose schemes we can carry. An absent - // alternative list is not a failure; it means "this operation needs no credentials". let expected = if List.isEmpty alternatives then Some [] else alternatives - |> List.tryFind (fun alternative -> alternative |> List.forall (fun index -> representable.[index])) + |> List.tryFind satisfiable |> Option.map (fun alternative -> alternative |> List.map (fun index -> schemes.[index].Name) diff --git a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs index 7c96ff3e..f6b60013 100644 --- a/WoofWare.Myriad.Plugins/HttpClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/HttpClientGenerator.fs @@ -259,7 +259,10 @@ module internal HttpClientGenerator = /// constantHeaders are a list of (headerName, headerValue) /// variableHeaders are a list of (headerName, selfPropertyToGetValueOf) + /// `clientName` is the name we gave the HttpClient argument of the generated `make`; it isn't + /// always "client", because an interface property may already have claimed that name. let constructMember + (clientName : string) (constantHeaders : (SynExpr * SynExpr) list) (variableHeaders : (SynExpr * Ident) list) (info : MemberInfo) @@ -471,7 +474,7 @@ module internal HttpClientGenerator = let requestUri = let uriIdent = SynExpr.createLongIdent [ "System" ; "Uri" ] - let baseAddress = SynExpr.createLongIdent [ "client" ; "BaseAddress" ] + let baseAddress = SynExpr.createLongIdent [ clientName ; "BaseAddress" ] let baseAddress = [ @@ -891,7 +894,7 @@ module internal HttpClientGenerator = "response", SynExpr.awaitTask ( SynExpr.applyFunction - (SynExpr.createLongIdent [ "client" ; "SendAsync" ]) + (SynExpr.createLongIdent [ clientName ; "SendAsync" ]) (SynExpr.tuple [ SynExpr.createIdent "httpMessage" ; SynExpr.createIdent "ct" ]) ) ) @@ -1087,6 +1090,14 @@ module internal HttpClientGenerator = headerInfo, pi ) + // Every property becomes a `unit -> _` argument of `make`, named by lowercasing it; the + // HttpClient argument we add alongside them must not collide with any of those. + let clientName = + properties + |> List.map (fun (_, pi) -> (Ident.lowerFirstLetter pi.Identifier).idText) + |> Set.ofList + |> freshName "client" + /// The properties which a member may name in a HeaderFromProperty attribute: that is, all /// the properties which don't already stamp their header onto every request. let addressableProperties = @@ -1174,7 +1185,7 @@ module internal HttpClientGenerator = PropertyHeaders = propertyHeaders } ) - |> List.map (constructMember constantHeaders properties) + |> List.map (constructMember clientName constantHeaders properties) let propertyMembers = properties @@ -1218,7 +1229,7 @@ module internal HttpClientGenerator = ) let clientCreationArg = - SynPat.named "client" + SynPat.named clientName |> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpClient" ]) let xmlDoc = @@ -1228,8 +1239,6 @@ module internal HttpClientGenerator = "Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties." |> PreXmlDoc.create - let functionName = Ident.create "client" - let pattern = SynLongIdent.createS "make" let returnInfo = SynType.createLongIdent interfaceType.Name diff --git a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs index 2e4c93d5..b45e3d95 100644 --- a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs @@ -1383,12 +1383,40 @@ module internal OpenApiClientGenerator = Some $"'%s{schemeName}' was not listed in the SecuritySchemes Myriad parameter" | _ -> None + /// Schemes which must be satisfied *together* must each contribute a distinct header: a + /// single request cannot carry two `Authorization` values (the BCL throws when you try), so + /// a requirement pairing, say, an http scheme with an oauth2 one is not one we can send. + let collidingHeaders (alternativeSchemes : string list) : string option = + let collisions = + alternativeSchemes + |> List.choose (fun schemeName -> + match Map.tryFind schemeName schemes with + | Some (SecurityScheme.Representable (headerName, _, _)) -> Some (headerName, schemeName) + | _ -> None + ) + |> List.groupBy fst + |> List.filter (fun (_, users) -> List.length users > 1) + + match collisions with + | [] -> None + | collisions -> + collisions + |> List.map (fun (headerName, users) -> + let users = users |> List.map snd |> String.concat " and " + $"%s{users} would all have to set the '%s{headerName}' header, which can only carry one value" + ) + |> String.concat "; " + |> Some + let rec go (rejections : (string * string) list) (alternatives : SecurityRequirement list) = match alternatives with | [] -> Error (List.rev rejections) | alternative :: rest -> match alternative.Schemes |> List.choose rejection with - | [] -> Ok alternative.Schemes + | [] -> + match collidingHeaders alternative.Schemes with + | None -> Ok alternative.Schemes + | Some reason -> go ((alternative.Location, reason) :: rejections) rest | reasons -> go ((alternative.Location, String.concat "; " reasons) :: rejections) rest // No alternatives at all is not a failure to satisfy anything: it is the statement that this From 77623887aac7d3531e73a8f32dc55ae73ece3d5f Mon Sep 17 00:00:00 2001 From: Smaug123 <3138005+Smaug123@users.noreply.github.com> Date: Sat, 25 Jul 2026 18:20:50 +0100 Subject: [PATCH 9/9] OpenAPI 3.0: refuse to guess between security alternatives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Taking the first satisfiable alternative meant that a document offering several — as real specs commonly do — silently chose an authentication method on the caller's behalf. Gitea's Swagger spec is the motivating example: it offers seven alternatives on every endpoint, four of which we can carry, so "first wins" would conscript every consumer into HTTP Basic. A document lists its alternatives in no particular order, so document order is not a preference. Exactly one alternative must now be satisfiable; several is an AmbiguousSecurity diagnostic naming the candidates, and the caller says which they want with the SecuritySchemes parameter. This matches the Swagger 2.0 generator. The empty requirement {} counts as a candidate like any other: an operation offering both "no credentials" and a real scheme is a genuine choice, and sending nothing is exactly the silently-unauthenticated client this all exists to prevent. Setting SecuritySchemes empty takes that alternative wherever the document offers it. Alternatives naming the same schemes are deduplicated first, since a repeated alternative is one choice rather than two. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 2 +- README.md | 13 ++- .../TestSwagger/TestOpenApi3Security.fs | 94 ++++++++++++++----- .../OpenApiClientGenerator.fs | 76 +++++++++++---- 4 files changed, 140 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d15282fa..7c815bdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Unsupported or structurally ambiguous OpenAPI constructs fail with structured, J The OpenAPI 3.0 generator now applies `security` requirements, rather than ignoring them. Each security scheme an operation requires becomes a `unit -> string` argument of the generated `make`, evaluated afresh per request, and each operation sends exactly the credentials its own requirement asks for (an operation with `security: []` sends none). Supported schemes are the header-carried ones: `apiKey` in a header, `http` of any scheme, and `oauth2`/`openIdConnect` (for which you supply the `Authorization` header value; no token flow is performed). -Where an operation offers alternative requirements, the first satisfiable one is used; the new `SecuritySchemes` Myriad parameter restricts which schemes may be chosen. +Where an operation can be authenticated in more than one way, the generator refuses to guess: name the one you want in the new `SecuritySchemes` Myriad parameter (or set it empty to send no credentials wherever the document permits that). An operation with no satisfiable requirement is now a build failure rather than a silently unauthenticated client. Fixes a latent bug in the `HttpClient` generator: an interface property named `Client` collided with the `HttpClient` argument of the generated `make`, so the generated source did not compile. diff --git a/README.md b/README.md index 5250afc0..8d6906cd 100644 --- a/README.md +++ b/README.md @@ -382,10 +382,11 @@ and `oauth2`/`openIdConnect` (which supply the `Authorization` header value: the token flow of its own, so you remain responsible for acquiring and refreshing tokens). `apiKey` with `in: query` or `in: cookie` is not supported. -Where an operation offers *alternative* requirements, the first one the generated client can satisfy is -applied, and which one that is is visible in the generated source. -To choose a different one, restrict the schemes with the `SecuritySchemes` Myriad parameter, which takes a -comma-separated list of scheme names: +Where an operation can be authenticated in more than one way, the generator **refuses to guess**, because +a document lists its alternatives in no particular order, and choosing between them chooses how you +authenticate. +Say which you want with the `SecuritySchemes` Myriad parameter, which takes a comma-separated list of +scheme names: ```xml @@ -394,6 +395,10 @@ comma-separated list of scheme names: ``` +This includes the case where one of the alternatives is the empty requirement `{}`, i.e. "no credentials": +sending nothing is a choice too, and a silently unauthenticated client is exactly what this is here to +prevent. Set `SecuritySchemes` to the empty string to take that alternative wherever the document offers it. + An operation with no satisfiable requirement is a build failure, rather than a client which silently issues unauthenticated requests. If you would rather authenticate the `HttpClient` yourself (with a `DelegatingHandler`, say), the way to diff --git a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs index 2ec6e725..e6876a1c 100644 --- a/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs +++ b/WoofWare.Myriad.Plugins.Test/TestSwagger/TestOpenApi3Security.fs @@ -231,13 +231,13 @@ module TestOpenApi3Security = |> shouldEqual OpenApiSecuritySchemeKind.OpenIdConnect [] - let ``The first representable alternative is the one applied`` () = + let ``The one satisfiable alternative is applied, whatever its position`` () = let source = securityDocument [ "queryKey", apiKeyElsewhereScheme "query" + "cookieKey", apiKeyElsewhereScheme "cookie" "bearerAuth", httpScheme "bearer" - "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" ] None [ @@ -246,7 +246,7 @@ module TestOpenApi3Security = [ requirement [ "queryKey" ] requirement [ "bearerAuth" ] - requirement [ "apiKeyAuth" ] + requirement [ "cookieKey" ] ] ] @@ -254,15 +254,57 @@ module TestOpenApi3Security = (operation plan "thing").Security |> shouldEqual [ "bearerAuth" ] + // Document order is not a preference: a spec which says an operation accepts any of several + // credentials is not saying which one *you* should send, and picking for you would silently + // choose how you authenticate. [] - let ``An operation whose alternatives include the empty requirement first sends nothing`` () = + let ``Several satisfiable alternatives are ambiguous rather than guessed between`` () = + let source = + securityDocument + [ + "bearerAuth", httpScheme "bearer" + "apiKeyAuth", apiKeyHeaderScheme "X-API-Key" + ] + None + [ + "thing", Some [ requirement [ "bearerAuth" ] ; requirement [ "apiKeyAuth" ] ] + ] + + diagnostics config source + |> List.filter (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.AmbiguousSecurity) + |> List.map _.Location + |> shouldEqual [ "#/paths/~1thing/get/security" ] + + /// An operation offering both "no credentials" and a real scheme is a genuine choice too: + /// sending nothing is exactly the silently-unauthenticated client this all exists to prevent. + [] + let ``An alternative demanding no credentials does not win by default`` () = let source = securityDocument [ "bearerAuth", httpScheme "bearer" ] None [ "thing", Some [ requirement [] ; requirement [ "bearerAuth" ] ] ] - let plan = plan config source + let diagnostics = diagnostics config source + + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.AmbiguousSecurity) + |> shouldEqual true + + // The message has to say how to ask for the unauthenticated one, since it has no name. + diagnostics + |> List.exists (fun diagnostic -> diagnostic.Message.Contains ("(no credentials)", StringComparison.Ordinal)) + |> shouldEqual true + + [] + let ``An empty SecuritySchemes parameter selects the unauthenticated alternative`` () = + let source = + securityDocument + [ "bearerAuth", httpScheme "bearer" ] + None + [ "thing", Some [ requirement [] ; requirement [ "bearerAuth" ] ] ] + + let plan = plan (config |> Map.add "SECURITYSCHEMES" "") source (operation plan "thing").Security |> shouldEqual [] plan.Credentials |> shouldEqual Map.empty @@ -391,9 +433,10 @@ module TestOpenApi3Security = (operation restricted "thing").Security |> shouldEqual [ "apiKeyAuth" ] - // Without the restriction we'd have taken the document's first alternative. - (operation (plan config source) "thing").Security - |> shouldEqual [ "bearerAuth" ] + // Without the restriction, this document doesn't say which to use, so it doesn't generate. + diagnostics config source + |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.AmbiguousSecurity) + |> shouldEqual true [] let ``The SecuritySchemes parameter cannot silently exclude every alternative`` () = @@ -491,30 +534,32 @@ module TestOpenApi3Security = } [] - let ``The applied requirement is always the document's first satisfiable alternative`` () = + let ``The applied requirement is always the document's unique satisfiable alternative`` () = let property (schemes : GeneratedScheme list, alternatives : int list list) = - // The oracle: the first alternative all of whose schemes we can carry, and no two of - // whose schemes want the same header (one request can't carry two Authorization values). - // An absent alternative list is not a failure; it means "this operation needs no - // credentials". + // An alternative works if we can carry every scheme it names, and no two of them want + // the same header (one request can't carry two Authorization values). let satisfiable (alternative : int list) = let headers = alternative |> List.map (fun index -> schemes.[index].Header) List.forall Option.isSome headers && List.length (List.distinct headers) = List.length headers + let schemeNames (alternative : int list) = + alternative + |> List.map (fun index -> schemes.[index].Name) + |> List.distinct + |> List.sort + + // The oracle: the operation generates exactly when one distinct alternative works. An + // absent alternative list is not a failure; it means "this operation needs no + // credentials". let expected = if List.isEmpty alternatives then Some [] else - alternatives - |> List.tryFind satisfiable - |> Option.map (fun alternative -> - alternative - |> List.map (fun index -> schemes.[index].Name) - |> List.distinct - |> List.sort - ) + match alternatives |> List.filter satisfiable |> List.map schemeNames |> List.distinct with + | [ chosen ] -> Some chosen + | _ -> None let source = securityDocument @@ -536,10 +581,13 @@ module TestOpenApi3Security = && (plan.Credentials |> Map.toList |> List.map fst) = List.distinct expected | Error diagnostics, None -> diagnostics - |> List.exists (fun diagnostic -> diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity) + |> List.exists (fun diagnostic -> + diagnostic.Code = OpenApiGenerationDiagnosticCode.UnsupportedSecurity + || diagnostic.Code = OpenApiGenerationDiagnosticCode.AmbiguousSecurity + ) | Ok plan, None -> let sent = (operation plan "thing").Security - failwith $"Planning accepted an unsatisfiable requirement, sending %+A{sent}" + failwith $"Planning chose credentials %+A{sent} where the document did not say to" | Error diagnostics, Some expected -> failwith $"Planning rejected a satisfiable requirement %+A{expected}: %+A{diagnostics |> List.map _.Message}" diff --git a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs index b45e3d95..7764fca7 100644 --- a/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs +++ b/WoofWare.Myriad.Plugins/OpenApiClientGenerator.fs @@ -20,6 +20,7 @@ type internal OpenApiGenerationDiagnosticCode = | UnsupportedParameter | UnsupportedOperation | UnsupportedSecurity + | AmbiguousSecurity | AmbiguousSuccessResponse type internal OpenApiGenerationDiagnostic = @@ -1364,14 +1365,26 @@ module internal OpenApiClientGenerator = |> List.choose id |> Some - /// Choose the credentials an operation sends: the first alternative, in document order, all of - /// whose schemes we can represent and the caller permitted. `Ok []` means "send none", which is - /// what an absent or empty `security` demands. `Error` lists why each alternative was rejected. + /// Why an operation's security requirement could not be met. + type private SecuritySelectionFailure = + /// No alternative can be satisfied, so the client could only issue unauthenticated requests. + /// Each entry is a requirement's location and why it was rejected. + | Unsatisfiable of rejections : (string * string) list + /// Several alternatives could be satisfied, and the document says nothing about which the + /// caller would prefer. Each entry is a candidate's location and the schemes it names. + | Ambiguous of candidates : (string * string list) list + + /// Choose the credentials an operation sends. `Ok []` means "send none", which is what an absent + /// or empty `security` demands. + /// + /// Exactly one alternative must be satisfiable. *Several* is an error rather than a guess: a + /// document lists its alternatives in no particular order, so choosing between them would choose + /// how the caller authenticates. They say which they want with the SecuritySchemes parameter. let private selectSecurityRequirement (permitted : Set option) (schemes : Map) (alternatives : SecurityRequirement list) - : Result + : Result = let rejection (schemeName : string) : string option = match Map.tryFind schemeName schemes with @@ -1408,23 +1421,33 @@ module internal OpenApiClientGenerator = |> String.concat "; " |> Some - let rec go (rejections : (string * string) list) (alternatives : SecurityRequirement list) = - match alternatives with - | [] -> Error (List.rev rejections) - | alternative :: rest -> - match alternative.Schemes |> List.choose rejection with - | [] -> - match collidingHeaders alternative.Schemes with - | None -> Ok alternative.Schemes - | Some reason -> go ((alternative.Location, reason) :: rejections) rest - | reasons -> go ((alternative.Location, String.concat "; " reasons) :: rejections) rest - // No alternatives at all is not a failure to satisfy anything: it is the statement that this // operation needs no credentials. if List.isEmpty alternatives then Ok [] else - go [] alternatives + + let satisfiable, rejected = + alternatives + |> List.map (fun alternative -> + match alternative.Schemes |> List.choose rejection with + | [] -> + match collidingHeaders alternative.Schemes with + | None -> Choice1Of2 alternative + | Some reason -> Choice2Of2 (alternative.Location, reason) + | reasons -> Choice2Of2 (alternative.Location, String.concat "; " reasons) + ) + |> List.partitionChoice + + // Two alternatives naming the same schemes are the same choice, not a choice between two. + match satisfiable |> List.distinctBy _.Schemes with + | [ chosen ] -> Ok chosen.Schemes + | [] -> Error (SecuritySelectionFailure.Unsatisfiable rejected) + | candidates -> + candidates + |> List.map (fun candidate -> candidate.Location, candidate.Schemes) + |> SecuritySelectionFailure.Ambiguous + |> Error type private OperationPlanningContext = { @@ -2053,7 +2076,7 @@ module internal OpenApiClientGenerator = alternatives with | Ok schemes -> schemes - | Error rejections -> + | Error (SecuritySelectionFailure.Unsatisfiable rejections) -> let rejections = rejections |> List.map (fun (location, reason) -> $"%s{location}: %s{reason}") @@ -2065,6 +2088,25 @@ module internal OpenApiClientGenerator = $"No security requirement of this operation can be satisfied by the generated client, so it would silently issue unauthenticated requests.%s{Environment.NewLine}%s{rejections}" [] + | Error (SecuritySelectionFailure.Ambiguous candidates) -> + let candidates = + candidates + |> List.map (fun (location, schemes) -> + let schemes = + match schemes with + | [] -> "(no credentials)" + | schemes -> String.concat " + " schemes + + $"%s{location}: %s{schemes}" + ) + |> String.concat Environment.NewLine + + report + AmbiguousSecurity + ($"%s{operation.Location}/security") + $"This operation can be authenticated in more than one way, and choosing between them would choose how you authenticate. Name the scheme you want in the SecuritySchemes Myriad parameter (comma-separated; leave it empty to send no credentials wherever the document permits that).%s{Environment.NewLine}%s{candidates}" + + [] let mergedParameters = parseParameterList context operation |> mergeParameters inheritedParameters