@@ -6,6 +6,7 @@ open System.IO
66open System.Reflection
77open System.Text .Json
88open System.Text .Json .Serialization
9+ open Microsoft.FSharp .Reflection
910open FSharpLint.Framework
1011open FSharpLint.Framework .Rules
1112open FSharpLint.Framework .HintParser
@@ -17,6 +18,40 @@ let SettingsFileName = "fsharplint.json"
1718exception ConfigurationException of string
1819
1920module 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
3066module IgnoreFiles =
300336type ConventionsConfig =
301337 { recursiveAsyncFunction: EnabledConfig option
302338 avoidTooShortNames: EnabledConfig option
339+ indexerAccessorStyleConsistency: RuleConfig < IndexerAccessorStyleConsistency .Config > option
303340 redundantNewKeyword: EnabledConfig option
304341 favourStaticEmptyFields: EnabledConfig option
305342 asyncExceptionWithoutReturn: EnabledConfig option
346383 this.binding |> Option.map ( fun config -> config.Flatten()) |> Option.toArray |> Array.concat
347384 this.suggestUseAutoProperty |> Option.bind ( constructRuleIfEnabled SuggestUseAutoProperty.rule) |> Option.toArray
348385 this.ensureTailCallDiagnosticsInRecursiveFunctions |> Option.bind ( constructRuleIfEnabled EnsureTailCallDiagnosticsInRecursiveFunctions.rule) |> Option.toArray
386+ this.indexerAccessorStyleConsistency |> Option.bind ( constructRuleWithConfig IndexerAccessorStyleConsistency.rule) |> Option.toArray
349387 |]
350388
351389type TypographyConfig =
@@ -403,6 +441,7 @@ type Configuration =
403441 PatternMatchExpressionIndentation: EnabledConfig option
404442 RecursiveAsyncFunction: EnabledConfig option
405443 AvoidTooShortNames: EnabledConfig option
444+ IndexerAccessorStyleConsistency: RuleConfig < IndexerAccessorStyleConsistency .Config > option
406445 RedundantNewKeyword: EnabledConfig option
407446 FavourNonMutablePropertyInitialization: EnabledConfig option
408447 FavourReRaise: EnabledConfig option
498537 PatternMatchExpressionIndentation = None
499538 RecursiveAsyncFunction = None
500539 AvoidTooShortNames = None
540+ IndexerAccessorStyleConsistency = None
501541 RedundantNewKeyword = None
502542 FavourNonMutablePropertyInitialization = None
503543 FavourReRaise = None
@@ -693,6 +733,7 @@ let flattenConfig (config:Configuration) =
693733 config.PatternMatchExpressionIndentation |> Option.bind ( constructRuleIfEnabled PatternMatchExpressionIndentation.rule)
694734 config.RecursiveAsyncFunction |> Option.bind ( constructRuleIfEnabled RecursiveAsyncFunction.rule)
695735 config.AvoidTooShortNames |> Option.bind ( constructRuleIfEnabled AvoidTooShortNames.rule)
736+ config.IndexerAccessorStyleConsistency |> Option.bind ( constructRuleWithConfig IndexerAccessorStyleConsistency.rule)
696737 config.RedundantNewKeyword |> Option.bind ( constructRuleIfEnabled RedundantNewKeyword.rule)
697738 config.FavourNonMutablePropertyInitialization |> Option.bind ( constructRuleIfEnabled FavourNonMutablePropertyInitialization.rule)
698739 config.FavourReRaise |> Option.bind ( constructRuleIfEnabled FavourReRaise.rule)
0 commit comments