#r "System.Xml.Linq.dll" open System.IO open System.Xml.Linq open System.Text.RegularExpressions //Script will read all old rules entries from Settings.StyleCop file //they will be merged with existing rules in FxCop.ruleset (generated by Visual Studio) let oldRulesFile = "Settings.StyleCop" let newRulesFile = "FxCop.ruleset" //https://github.com/StyleCop/StyleCop/raw/master/Project/Docs/Rules/Index.hhk //used for Id <-> Name maping let allRulesIndexFile = "Index.hhk" type RuleAction = Warning | Error | Hidden | Info | None override this.ToString() = sprintf "%A" this type Rule = { Id : string; Name: string; Action: RuleAction } override this.ToString() = sprintf "%s: %s" this.Id this.Name let defaultAction = None let stringToRule str = match str with | "Warning" -> Warning | "Error" -> Error | "Hidden" -> Hidden | "Info" -> Info | _ -> None let xelement name children = XElement(XName.Get name, (Seq.cast children:XObject seq)) let xattribute name value = XAttribute(XName.Get name, value) :> XObject let allRules = File.ReadAllText allRulesIndexFile |> fun input -> Regex.Matches(input, """(\w\w\d+): (\w+)""") |> Seq.cast |> Seq.map (fun x -> { Id = x.Groups.[1].Value; Name = x.Groups.[2].Value; Action = defaultAction }) let allRulesMap = Map.ofSeq <| Seq.map (fun rule -> (rule.Name, rule)) allRules let oldRules = File.ReadAllText oldRulesFile |> XDocument.Parse |> fun xml -> xml.Descendants(XName.Get("Rule")) |> Seq.map (fun el -> { Id = null; Name = el.Attribute(XName.Get("Name")).Value; Action = defaultAction }) let document = XDocument.Parse <| File.ReadAllText newRulesFile let root = document.Root; let styleCopNode = root.Descendants(XName.Get "Rules") |> Seq.filter (fun x -> x.Attribute(XName.Get "AnalyzerId").Value = "StyleCop.Analyzers") |> Seq.cast |> Seq.tryHead let mutable existingRules = match styleCopNode with | Some node -> node.Remove() |> ignore //remove to replace later with the new one node.Descendants(XName.Get "Rule") |> Seq.map (fun x -> { Id = x.Attribute(XName.Get "Id").Value; Action = stringToRule (x.Attribute(XName.Get "Action").Value); Name = null }) | _ -> Seq.empty let mutable matched = List.Empty let mutable notMatched = List.Empty for rule in oldRules do match allRulesMap |> Map.tryFind rule.Name with | Some x -> matched <- List.append matched [{x with Action = rule.Action}] | _ -> notMatched <- List.append notMatched [rule] |> ignore existingRules |> Seq.filter (fun rule -> Option.isNone <| List.tryFind (fun x -> x.Id = rule.Id) matched) |> Seq.append matched |> Seq.map (fun rule -> xelement "Rule" [ xattribute "Id" rule.Id; xattribute "Action" (string rule.Action) ]) |> Seq.cast |> Seq.append [ xattribute "AnalyzerId" "StyleCop.Analyzers"; xattribute "RuleNamespace" "StyleCop.Analyzers" ] |> xelement "Rules" |> root.Add document.Save(newRulesFile) printfn "Not matched: %d" notMatched.Length