|
| 1 | +#I @"../../packages/build/FAKE/tools" |
| 2 | +#r @"FakeLib.dll" |
| 3 | +#r "System.Xml.Linq.dll" |
| 4 | + |
| 5 | +#load @"Paths.fsx" |
| 6 | + |
| 7 | +namespace XmlDocPatcher |
| 8 | + |
| 9 | +open System.Linq |
| 10 | +open System.Text.RegularExpressions |
| 11 | +open System.Xml |
| 12 | +open System.Xml.Linq |
| 13 | +open System.Xml.XPath |
| 14 | + |
| 15 | +open Paths |
| 16 | +open Projects |
| 17 | +open Fake |
| 18 | + |
| 19 | +module InheritDoc = |
| 20 | + |
| 21 | + let private apiName n = Regex.Replace(n, @"^\w\:(.+?)(?:\(.+$|$)", "$1") |
| 22 | + let private relatedInterface n = Regex.Replace(n, @"\.([^.]+\.[^.]+)$", ".I$1") |
| 23 | + let private relatedInterfaceAsync n = (relatedInterface n).Replace("Async", "") |
| 24 | + let private relatedInterfaceDescriptor n = Regex.Replace(n, @"\.([^.]+)Descriptor\.([^.]+)$", ".I$1.$2") |
| 25 | + let private relatedInterfaceDescriptorRequest n = Regex.Replace(n, @"\.([^.]+)Descriptor\.([^.]+)$", ".I$1Request.$2") |
| 26 | + let private relatedInterfaceDescriptorGeneric n = Regex.Replace(n, @"\.([^.]+)Descriptor[^.]+.([^.]+)$", ".I$1.$2") |
| 27 | + let private manualMapping (n : string) = |
| 28 | + //this sucks but untill roslyn gets coderewriting API's this is the best we got without making it |
| 29 | + //a bigger thing than it already is |
| 30 | + match n with |
| 31 | + | n when n.Contains("PutMapping") -> n.Replace("PutMapping", "TypeMapping") |
| 32 | + | _ -> n |
| 33 | + let private relatedApiLookups = [ |
| 34 | + relatedInterface; |
| 35 | + relatedInterfaceAsync; |
| 36 | + relatedInterfaceDescriptor; |
| 37 | + relatedInterfaceDescriptorRequest; |
| 38 | + relatedInterfaceDescriptorGeneric; |
| 39 | + manualMapping |
| 40 | + ]; |
| 41 | + |
| 42 | + let private documentedApis = fun (file : string) -> |
| 43 | + use reader = XmlReader.Create file |
| 44 | + seq { |
| 45 | + while reader.ReadToFollowing("member") do |
| 46 | + let name = apiName(reader.GetAttribute("name")) |
| 47 | + let innerXml = reader.ReadInnerXml().Trim(); |
| 48 | + if (isNotNullOrEmpty innerXml && not (innerXml.Contains("<inheritdoc"))) then |
| 49 | + let xdoc = XDocument.Parse("<x>" + innerXml + "</x>") |
| 50 | + yield (name, xdoc) |
| 51 | + } |> Map.ofSeq |
| 52 | + |
| 53 | + let private patchInheritDoc = fun file -> |
| 54 | + traceFAKE "Rewriting xmldoc: %s" file |
| 55 | + |
| 56 | + let mapOfDocumentedApis = documentedApis file |
| 57 | + |
| 58 | + let findDocumentation (apiElement:string) = |
| 59 | + relatedApiLookups |
| 60 | + |> Seq.map (fun f -> f apiElement) |
| 61 | + |> (Seq.map <| mapOfDocumentedApis.TryFind) |
| 62 | + |> Seq.choose id |
| 63 | + |> Seq.tryHead |
| 64 | + |
| 65 | + let xml = XDocument.Load file |
| 66 | + |
| 67 | + xml.XPathSelectElements("//inheritdoc") |
| 68 | + |> Seq.iter (fun inheritDocElement -> |
| 69 | + let parent =inheritDocElement.Parent |
| 70 | + let name = apiName (parent.Attribute(XName.Get "name").Value) |
| 71 | + let documentation = findDocumentation name |
| 72 | + |
| 73 | + match documentation with |
| 74 | + | Some d -> |
| 75 | + let elements = d.Element(XName.Get("x")).Elements().ToList(); |
| 76 | + inheritDocElement.AddBeforeSelf(elements) |
| 77 | + | _ -> |
| 78 | + //unignore the following to find undocumented/badly inherited methods |
| 79 | + //tracefn "not inherited: %s" apiElement |
| 80 | + ignore() |
| 81 | + ) |
| 82 | + |
| 83 | + use writer = new XmlTextWriter(file,null) |
| 84 | + writer.Formatting <- Formatting.Indented; |
| 85 | + xml.Save(writer); |
| 86 | + |
| 87 | + let patchInheritDocs = fun () -> |
| 88 | + AllPublishableProjectsWithSupportedFrameworks |
| 89 | + |> Seq.map (fun p -> |
| 90 | + let folder = Paths.ProjectOutputFolder p.project p.framework |
| 91 | + folder @@ p.project.Name + ".xml" |
| 92 | + ) |
| 93 | + |> Seq.filter fileExists |
| 94 | + |> Seq.iter patchInheritDoc |
| 95 | + |
0 commit comments