diff --git a/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs b/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs index 4fce415..14f15fd 100644 --- a/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs +++ b/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs @@ -103,7 +103,8 @@ type public OpenApiClientTypeProvider(cfg: TypeProviderConfig) as this = |> Seq.map(fun e -> $"%s{e.Message} @ %s{e.Pointer}") |> String.concat "\n") - let defCompiler = DefinitionCompiler(schema, preferNullable) + let useDateOnly = cfg.SystemRuntimeAssemblyVersion.Major >= 6 + let defCompiler = DefinitionCompiler(schema, preferNullable, useDateOnly) let opCompiler = OperationCompiler(schema, defCompiler, ignoreControllerPrefix, ignoreOperationId, preferAsync) diff --git a/src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs b/src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs index b7940b5..d96d52d 100644 --- a/src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs +++ b/src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs @@ -86,7 +86,8 @@ type public SwaggerTypeProvider(cfg: TypeProviderConfig) as this = let schema = SwaggerParser.parseSchema schemaData - let defCompiler = DefinitionCompiler(schema, preferNullable) + let useDateOnly = cfg.SystemRuntimeAssemblyVersion.Major >= 6 + let defCompiler = DefinitionCompiler(schema, preferNullable, useDateOnly) let opCompiler = OperationCompiler(schema, defCompiler, ignoreControllerPrefix, ignoreOperationId, preferAsync) diff --git a/src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs index fc55346..14231ef 100644 --- a/src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs +++ b/src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs @@ -150,7 +150,7 @@ and NamespaceAbstraction(name: string) = Some ty) /// Object for compiling definitions. -type DefinitionCompiler(schema: SwaggerObject, provideNullable) as this = +type DefinitionCompiler(schema: SwaggerObject, provideNullable, useDateOnly: bool) as this = let definitionToSchemaObject = Map.ofSeq schema.Definitions let definitionToType = Collections.Generic.Dictionary<_, _>() let nsRoot = NamespaceAbstraction("Root") @@ -352,7 +352,16 @@ type DefinitionCompiler(schema: SwaggerObject, provideNullable) as this = | Float -> typeof | Double -> typeof | String -> typeof - | Date + | Date -> + // Use DateOnly only when the target runtime supports it (.NET 6+). + // We check useDateOnly (derived from cfg.SystemRuntimeAssemblyVersion) rather than + // probing the design-time host process, which may differ from the consumer's runtime. + if useDateOnly then + System.Type.GetType("System.DateOnly") + |> Option.ofObj + |> Option.defaultValue typeof + else + typeof | DateTime -> typeof | File -> typeof.MakeArrayType 1 | Enum(_, "string") -> typeof diff --git a/src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs index a2acfde..7b2a918 100644 --- a/src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs +++ b/src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs @@ -165,7 +165,7 @@ and NamespaceAbstraction(name: string) = Some ty) /// Object for compiling definitions. -type DefinitionCompiler(schema: OpenApiDocument, provideNullable) as this = +type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: bool) as this = let pathToSchema = if isNull schema.Components then Map.empty @@ -496,7 +496,16 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable) as this = // for `application/octet-stream` request body // for `multipart/form-data` : https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#considerations-for-file-uploads typeof - | HasFlag JsonSchemaType.String, "date" + | HasFlag JsonSchemaType.String, "date" -> + // Use DateOnly only when the target runtime supports it (.NET 6+). + // We check useDateOnly (derived from cfg.SystemRuntimeAssemblyVersion) rather than + // probing the design-time host process, which may differ from the consumer's runtime. + if useDateOnly then + System.Type.GetType("System.DateOnly") + |> Option.ofObj + |> Option.defaultValue typeof + else + typeof | HasFlag JsonSchemaType.String, "date-time" -> typeof | HasFlag JsonSchemaType.String, "uuid" -> typeof | HasFlag JsonSchemaType.String, _ -> typeof diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.NullableDate.Tests.fs b/tests/SwaggerProvider.ProviderTests/v3/Swagger.NullableDate.Tests.fs index 3d16a48..a1b0f94 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.NullableDate.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/v3/Swagger.NullableDate.Tests.fs @@ -17,7 +17,7 @@ let ``PersonDto should have nullable birthDate property``() = let birthDateProp = personType.GetProperty("BirthDate") birthDateProp |> shouldNotEqual null - // The property should be Option (default) or Nullable (with PreferNullable=true) + // The property should be Option (on .NET 6+) or Option (netstandard2.0) let propType = birthDateProp.PropertyType propType.IsGenericType |> shouldEqual true @@ -29,6 +29,16 @@ let ``PersonDto should have nullable birthDate property``() = hasNullableWrapper |> shouldEqual true +[] +let ``PersonDto birthDate property should be Option on NET6+``() = + let personType = typeof + let birthDateProp = personType.GetProperty("BirthDate") + birthDateProp |> shouldNotEqual null + + // On NET6+, format: date should map to DateOnly wrapped in Option + let propType = birthDateProp.PropertyType + propType |> shouldEqual typeof> + [] let ``PersonDto can deserialize JSON with null birthDate using type provider deserialization``() = // This JSON is from the issue - a person with null birthDate diff --git a/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs b/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs index 6b22c54..5fa9245 100644 --- a/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs +++ b/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs @@ -13,7 +13,7 @@ module V2 = let testSchema schemaStr = let schema = SwaggerParser.parseSchema schemaStr - let defCompiler = DefinitionCompiler(schema, false) + let defCompiler = DefinitionCompiler(schema, false, Environment.Version.Major >= 6) let opCompiler = OperationCompiler(schema, defCompiler, true, false, true) opCompiler.CompileProvidedClients(defCompiler.Namespace) ignore <| defCompiler.Namespace.GetProvidedTypes() @@ -35,7 +35,7 @@ module V3 = |> Seq.map (fun e -> e.Message) |> String.concat ";\n- ")*) try - let defCompiler = DefinitionCompiler(schema, false) + let defCompiler = DefinitionCompiler(schema, false, Environment.Version.Major >= 6) let opCompiler = OperationCompiler(schema, defCompiler, true, false, true) opCompiler.CompileProvidedClients(defCompiler.Namespace) defCompiler.Namespace.GetProvidedTypes()