Skip to content

Commit 06ca9c2

Browse files
webwarrior-wsknocte
authored andcommitted
Core: add JSON converter for simple DUs
Add a JSON converter for discriminated unions that only have cases with no fields. It maps DUs to strings, like JsonStringEnumConverter does it for enums. This fixes the tests for IndexerAccessorStyleConsistency rule (for serializing its config simple DU called IndexerAccessorStyle).
1 parent 7c4d369 commit 06ca9c2

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

src/FSharpLint.Core/Application/Configuration.fs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ open System.IO
66
open System.Reflection
77
open System.Text.Json
88
open System.Text.Json.Serialization
9+
open Microsoft.FSharp.Reflection
910
open FSharpLint.Framework
1011
open FSharpLint.Framework.Rules
1112
open FSharpLint.Framework.HintParser
@@ -17,6 +18,40 @@ let SettingsFileName = "fsharplint.json"
1718
exception ConfigurationException of string
1819

1920
module internal FSharpJsonConverter =
21+
22+
type private SimpleDUConverter<'TDiscriminatedUnion>() =
23+
inherit JsonConverter<'TDiscriminatedUnion>()
24+
25+
let allCases = FSharpType.GetUnionCases typeof<'TDiscriminatedUnion>
26+
27+
override this.Read (reader: byref<Text.Json.Utf8JsonReader>, typeToConvert: Type, options: Text.Json.JsonSerializerOptions): 'TDiscriminatedUnion =
28+
let value = reader.GetString()
29+
match allCases |> Array.tryFind (fun case -> case.Name = value) with
30+
| Some case -> FSharpValue.MakeUnion(case, Array.empty) :?> 'TDiscriminatedUnion
31+
| _ -> failwithf "Unexpected value: %A. Expected one of: %A" value allCases
32+
33+
override this.Write (writer: Text.Json.Utf8JsonWriter, value: 'TDiscriminatedUnion, options: Text.Json.JsonSerializerOptions): unit =
34+
writer.WriteStringValue(value.ToString())
35+
36+
/// JSON converter for discriminated unions that only have cases with no fields.
37+
/// Maps DUs to strings, like JsonStringEnumConverter.
38+
type SimpleDiscriminatedUnionJsonConverter() =
39+
inherit JsonConverterFactory()
40+
41+
override this.CanConvert (typeToConvert: Type): bool =
42+
FSharpType.IsUnion typeToConvert
43+
&& (FSharpType.GetUnionCases typeToConvert |> Array.forall (fun typ -> typ.GetFields().Length = 0))
44+
45+
override this.CreateConverter (typeToConvert: Type, options: JsonSerializerOptions): JsonConverter =
46+
let converterType = typedefof<SimpleDUConverter<_>>
47+
Activator.CreateInstance(
48+
converterType.MakeGenericType(Array.singleton typeToConvert),
49+
BindingFlags.Instance ||| BindingFlags.Public,
50+
binder=null,
51+
args=Array.empty,
52+
culture=null
53+
)
54+
:?> JsonConverter
2055

2156
let jsonOptions =
2257
let options =
@@ -25,6 +60,7 @@ module internal FSharpJsonConverter =
2560
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
2661
)
2762
options.Converters.Add(JsonStringEnumConverter())
63+
options.Converters.Add(SimpleDiscriminatedUnionJsonConverter())
2864
options
2965

3066
module IgnoreFiles =

0 commit comments

Comments
 (0)