diff --git a/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs b/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs index 4fce415..527dd95 100644 --- a/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs +++ b/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs @@ -5,6 +5,8 @@ open System.Reflection open Microsoft.OpenApi.Reader open ProviderImplementation.ProvidedTypes open Microsoft.FSharp.Core.CompilerServices +open Microsoft.FSharp.Quotations +open Microsoft.FSharp.Reflection open Swagger open SwaggerProvider.Internal open SwaggerProvider.Internal.v3.Compilers @@ -28,6 +30,14 @@ type public OpenApiClientTypeProvider(cfg: TypeProviderConfig) as this = // check we contain a copy of runtime files, and are not referencing the runtime DLL do assert (typeof.Assembly.GetName().Name = asm.GetName().Name) + let buildStringListExpr(items: string list) : Expr = + let cases = FSharpType.GetUnionCases typeof + let nilCase = cases |> Array.find(fun c -> c.Name = "Empty") + let consCase = cases |> Array.find(fun c -> c.Name = "Cons") + let nil = Expr.NewUnionCase(nilCase, []) + + List.foldBack (fun (s: string) acc -> Expr.NewUnionCase(consCase, [ Expr.Value(s, typeof); acc ])) items nil + let myParamType = let t = ProvidedTypeDefinition(asm, ns, "OpenApiClientProvider", Some typeof, isErased = false) @@ -103,6 +113,11 @@ type public OpenApiClientTypeProvider(cfg: TypeProviderConfig) as this = |> Seq.map(fun e -> $"%s{e.Message} @ %s{e.Pointer}") |> String.concat "\n") + let parseErrors = + diagnostic.Errors + |> Seq.map(fun e -> $"%s{e.Message} @ %s{e.Pointer}") + |> Seq.toList + let defCompiler = DefinitionCompiler(schema, preferNullable) let opCompiler = @@ -118,6 +133,19 @@ type public OpenApiClientTypeProvider(cfg: TypeProviderConfig) as this = ty.AddXmlDoc("OpenAPI Provider for " + schemaPathRaw) ty.AddMembers tys + + let errProp = + ProvidedProperty( + "SchemaReaderErrors", + typeof, + isStatic = true, + getterCode = fun _ -> buildStringListExpr parseErrors + ) + + errProp.AddXmlDoc + "List of OpenAPI parse errors tolerated by this provider instance. Non-empty only when IgnoreParseErrors=true and the schema has validation issues." + + ty.AddMember errProp tempAsm.AddTypes [ ty ] ty diff --git a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj index feb8be6..ecb8b27 100644 --- a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj +++ b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj @@ -28,6 +28,7 @@ + diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.SchemaReaderErrors.Tests.fs b/tests/SwaggerProvider.ProviderTests/v3/Swagger.SchemaReaderErrors.Tests.fs new file mode 100644 index 0000000..f889558 --- /dev/null +++ b/tests/SwaggerProvider.ProviderTests/v3/Swagger.SchemaReaderErrors.Tests.fs @@ -0,0 +1,33 @@ +module Swagger.SchemaReaderErrors.Tests + +open SwaggerProvider +open Xunit +open FsUnitTyped + +[] +let ValidSchema = __SOURCE_DIRECTORY__ + "/../Schemas/v3/petstore.yaml" + +[] +let SchemaWithErrors = + __SOURCE_DIRECTORY__ + + "/../Schemas/v3/nullable-parameter-issue261.json" + +type ValidApi = OpenApiClientProvider + +type ApiWithErrors = OpenApiClientProvider + +[] +let ``SchemaReaderErrors is empty for a valid schema``() = + ValidApi.SchemaReaderErrors |> shouldEqual [] + +[] +let ``SchemaReaderErrors is non-empty when IgnoreParseErrors=true and schema has validation errors``() = + ApiWithErrors.SchemaReaderErrors |> List.isEmpty |> shouldEqual false + +[] +let ``SchemaReaderErrors entries contain message and pointer``() = + let errors = ApiWithErrors.SchemaReaderErrors + errors |> List.isEmpty |> shouldEqual false + + for entry in errors do + entry.Contains(" @ ") |> shouldEqual true