Skip to content

Commit 1133967

Browse files
authored
Merge pull request #13 from dawedawe/quote_bugfix
bring fixes and changes from fsi port back here
2 parents 9784f17 + 4aa3a60 commit 1133967

File tree

4 files changed

+150
-151
lines changed

4 files changed

+150
-151
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [1.0.2] - 2024-05-18
4+
5+
### Fixed
6+
7+
* Fixed support for expressions with quotes, for example `h shouldn't`.
8+
39
## [1.0.1] - 2024-01-25
410

511
### Fixed

src/Fsih.Tests/Tests.fs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,22 @@ let ``fetching and parsing docs works for expressions`` ((expr, fullName): (Expr
3939
let doc = Quoted.tryGetDocumentation expr
4040

4141
match doc with
42-
| None -> Assert.False(true, sprintf "no docs for %s" fullName)
43-
| Some d -> Assert.Equal(fullName, d.FullName)
42+
| ValueNone -> Assert.False(true, sprintf "no docs for %s" fullName)
43+
| ValueSome d -> Assert.Equal(fullName, d.FullName)
4444

4545
[<Fact>]
4646
let ``full info is as expected for Seq.splitInto`` () =
4747
let doc = Quoted.tryGetDocumentation <@ Seq.splitInto @>
4848

4949
match doc with
50-
| Some { Summary = summary
51-
Remarks = Some remarks
52-
Parameters = parameters
53-
Returns = Some returns
54-
Exceptions = exceptions
55-
Examples = examples
56-
FullName = fullName
57-
Assembly = assembly } ->
50+
| ValueSome { Summary = summary
51+
Remarks = Some remarks
52+
Parameters = parameters
53+
Returns = Some returns
54+
Exceptions = exceptions
55+
Examples = examples
56+
FullName = fullName
57+
Assembly = assembly } ->
5858
Assert.Equal("Splits the input sequence into at most count chunks.", summary)
5959

6060
Assert.Equal(
@@ -83,48 +83,48 @@ let ``full info is as expected for Seq.splitInto`` () =
8383
Assert.Equal("Microsoft.FSharp.Collections.SeqModule.splitInto", fullName)
8484
Assert.Equal("FSharp.Core.dll", assembly)
8585

86-
| Some _ -> Assert.False(true, "unexpected help")
87-
| None -> Assert.False(true, "no docs for Seq.splitInto")
86+
| ValueSome _ -> Assert.False(true, "unexpected help")
87+
| ValueNone -> Assert.False(true, "no docs for Seq.splitInto")
8888

8989
[<Fact>]
9090
let ``returns is as expected for HashIdentity.FromFunctions`` () =
9191
let doc = Quoted.tryGetDocumentation <@ HashIdentity.FromFunctions @>
9292

9393
match doc with
94-
| Some { Returns = Some returns } ->
94+
| ValueSome { Returns = Some returns } ->
9595
Assert.Equal(
9696
"An object implementing System.Collections.Generic.IEqualityComparer using the given functions.",
9797
returns
9898
)
99-
| Some _ -> Assert.False(true, "unexpected help")
100-
| None -> Assert.False(true, "no docs for HashIdentity.FromFunctions")
99+
| ValueSome _ -> Assert.False(true, "unexpected help")
100+
| ValueNone -> Assert.False(true, "no docs for HashIdentity.FromFunctions")
101101

102102
[<Fact>]
103103
let ``remarks is as expected for List.reduce`` () =
104104
let doc = Quoted.tryGetDocumentation <@ List.reduce @>
105105

106106
match doc with
107-
| Some { Remarks = Some remarks } -> Assert.Equal("Raises System.ArgumentException if list is empty", remarks)
108-
| Some _ -> Assert.False(true, "unexpected help")
109-
| None -> Assert.False(true, "no docs for List.reduce")
107+
| ValueSome { Remarks = Some remarks } -> Assert.Equal("Raises System.ArgumentException if list is empty", remarks)
108+
| ValueSome _ -> Assert.False(true, "unexpected help")
109+
| ValueNone -> Assert.False(true, "no docs for List.reduce")
110110

111111
[<Fact>]
112112
let ``summary is as expected for Array.sortDescending`` () =
113113
let doc = Quoted.tryGetDocumentation <@ Array.sortDescending @>
114114

115115
match doc with
116-
| Some { Summary = summary } ->
116+
| ValueSome { Summary = summary } ->
117117
Assert.Equal(
118118
"Sorts the elements of an array, in descending order, returning a new array. Elements are compared using Microsoft.FSharp.Core.Operators.compare.",
119119
summary
120120
)
121-
| None -> Assert.False(true, "no docs for Array.sortDescending")
121+
| ValueNone -> Assert.False(true, "no docs for Array.sortDescending")
122122

123123
[<Fact>]
124124
let ``ReflectedDefinition works as expected`` () =
125125
let docReflected = TryGetDocumentation(id)
126126
let docQuoted = Quoted.tryGetDocumentation <@ id @>
127127

128128
match docReflected, docQuoted with
129-
| Some r, Some q -> Assert.True((r = q))
129+
| ValueSome r, ValueSome q -> Assert.True((r = q))
130130
| _ -> Assert.False(true, "no docs for id")

src/Fsih/Parser.fs

Lines changed: 97 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,27 @@ let trimDotNet (s: string) =
6868
// WTF, seems like we loose inner xml (example content) if we cache an XmlDocument
6969
let xmlDocCache = Collections.Generic.Dictionary<string, string>()
7070

71-
let getXmlDocument xmlPath =
71+
let tryGetXmlDocument xmlPath =
7272
#if DEBUG
73-
printfn $"xml file: %s{xmlPath}"
73+
printfn $"trying xml file: %s{xmlPath}"
7474
#endif
75-
match xmlDocCache.TryGetValue(xmlPath) with
76-
| true, value ->
77-
let xmlDocument = XmlDocument()
78-
xmlDocument.LoadXml(value)
79-
xmlDocument
80-
| _ ->
81-
let rawXml = File.ReadAllText(xmlPath)
82-
let xmlDocument = XmlDocument()
83-
xmlDocument.LoadXml(rawXml)
84-
xmlDocCache.Add(xmlPath, rawXml)
85-
xmlDocument
75+
try
76+
match xmlDocCache.TryGetValue(xmlPath) with
77+
| true, value ->
78+
let xmlDocument = XmlDocument()
79+
xmlDocument.LoadXml(value)
80+
Some xmlDocument
81+
| _ ->
82+
let rawXml = System.IO.File.ReadAllText(xmlPath)
83+
let xmlDocument = XmlDocument()
84+
xmlDocument.LoadXml(rawXml)
85+
xmlDocCache.Add(xmlPath, rawXml)
86+
Some xmlDocument
87+
with _ ->
88+
#if DEBUG
89+
printfn $"xml file not found: {xmlPath}"
90+
#endif
91+
None
8692

8793
let getTexts (node: Xml.XmlNode) =
8894
seq {
@@ -101,93 +107,91 @@ let getTexts (node: Xml.XmlNode) =
101107
}
102108
|> String.concat ""
103109

104-
let helpText (xmlPath: string) (assembly: string) (modName: string) (implName: string) (sourceName: string) =
110+
let tryMkHelp
111+
(xmlDocument: XmlDocument option)
112+
(assembly: string)
113+
(modName: string)
114+
(implName: string)
115+
(sourceName: string)
116+
=
105117
let sourceName = sourceName.Replace('.', '#') // for .ctor
106118
let implName = implName.Replace('.', '#') // for .ctor
107119
let xmlName = $"{modName}.{implName}"
108-
let xmlDocument = getXmlDocument xmlPath
109120

110-
let node =
111-
let toTry =
112-
[ $"""/doc/members/member[contains(@name, ":{xmlName}`")]"""
113-
$"""/doc/members/member[contains(@name, ":{xmlName}(")]"""
114-
$"""/doc/members/member[contains(@name, ":{xmlName}")]""" ]
121+
let toTry =
122+
[ $"""/doc/members/member[contains(@name, ":{xmlName}`")]"""
123+
$"""/doc/members/member[contains(@name, ":{xmlName}(")]"""
124+
$"""/doc/members/member[contains(@name, ":{xmlName}")]""" ]
115125

126+
xmlDocument
127+
|> Option.bind (fun xmlDocument ->
116128
seq {
117129
for t in toTry do
118-
#if DEBUG
119-
printfn "trying xpath: %s" t
120-
#endif
121130
let node = xmlDocument.SelectSingleNode(t)
122131
if not (isNull node) then Some node else None
123132
}
124-
|> Seq.tryPick id
125-
126-
match node with
127-
| None ->
128-
#if DEBUG
129-
printfn $"// No node found for {xmlName}"
130-
#endif
131-
None
132-
| Some n ->
133-
let summary =
134-
n.SelectSingleNode("summary")
135-
|> Option.ofObj
136-
|> Option.map getTexts
137-
|> Option.map cleanupXmlContent
138-
139-
let remarks =
140-
n.SelectSingleNode("remarks")
141-
|> Option.ofObj
142-
|> Option.map getTexts
143-
|> Option.map cleanupXmlContent
144-
145-
let parameters =
146-
n.SelectNodes("param")
147-
|> Seq.cast<XmlNode>
148-
|> Seq.map (fun n -> n.Attributes.GetNamedItem("name").Value.Trim(), n.InnerText.Trim())
149-
|> List.ofSeq
150-
151-
let returns =
152-
n.SelectSingleNode("returns")
153-
|> Option.ofObj
154-
|> Option.map (fun n -> getTexts(n).Trim())
155-
156-
let exceptions =
157-
n.SelectNodes("exception")
158-
|> Seq.cast<XmlNode>
159-
|> Seq.map (fun n ->
160-
let exType = n.Attributes.GetNamedItem("cref").Value
161-
let idx = exType.IndexOf(':')
162-
let exType = if idx >= 0 then exType.Substring(idx + 1) else exType
163-
exType.Trim(), n.InnerText.Trim())
164-
|> List.ofSeq
165-
166-
let examples =
167-
n.SelectNodes("example")
168-
|> Seq.cast<XmlNode>
169-
|> Seq.map (fun n ->
170-
let codeNode = n.SelectSingleNode("code")
171-
172-
let code =
173-
if isNull codeNode then
174-
""
175-
else
176-
n.RemoveChild(codeNode) |> ignore
177-
cleanupXmlContent codeNode.InnerText
178-
179-
code, cleanupXmlContent n.InnerText)
180-
|> List.ofSeq
181-
182-
match summary with
183-
| Some s ->
184-
{ Summary = s
185-
Remarks = remarks
186-
Parameters = parameters
187-
Returns = returns
188-
Exceptions = exceptions
189-
Examples = examples
190-
FullName = $"{modName}.{sourceName}" // the long ident as users see it
191-
Assembly = assembly }
192-
|> Some
193-
| None -> None
133+
|> Seq.tryPick id)
134+
|> function
135+
| None -> ValueNone
136+
| Some n ->
137+
let summary =
138+
n.SelectSingleNode("summary")
139+
|> Option.ofObj
140+
|> Option.map getTexts
141+
|> Option.map cleanupXmlContent
142+
143+
let remarks =
144+
n.SelectSingleNode("remarks")
145+
|> Option.ofObj
146+
|> Option.map getTexts
147+
|> Option.map cleanupXmlContent
148+
149+
let parameters =
150+
n.SelectNodes("param")
151+
|> Seq.cast<XmlNode>
152+
|> Seq.map (fun n -> n.Attributes.GetNamedItem("name").Value.Trim(), n.InnerText.Trim())
153+
|> List.ofSeq
154+
155+
let returns =
156+
n.SelectSingleNode("returns")
157+
|> Option.ofObj
158+
|> Option.map (fun n -> getTexts(n).Trim())
159+
160+
let exceptions =
161+
n.SelectNodes("exception")
162+
|> Seq.cast<XmlNode>
163+
|> Seq.map (fun n ->
164+
let exType = n.Attributes.GetNamedItem("cref").Value
165+
let idx = exType.IndexOf(':')
166+
let exType = if idx >= 0 then exType.Substring(idx + 1) else exType
167+
exType.Trim(), n.InnerText.Trim())
168+
|> List.ofSeq
169+
170+
let examples =
171+
n.SelectNodes("example")
172+
|> Seq.cast<XmlNode>
173+
|> Seq.map (fun n ->
174+
let codeNode = n.SelectSingleNode("code")
175+
176+
let code =
177+
if isNull codeNode then
178+
""
179+
else
180+
n.RemoveChild(codeNode) |> ignore
181+
cleanupXmlContent codeNode.InnerText
182+
183+
code, cleanupXmlContent n.InnerText)
184+
|> List.ofSeq
185+
186+
match summary with
187+
| Some s ->
188+
{ Summary = s
189+
Remarks = remarks
190+
Parameters = parameters
191+
Returns = returns
192+
Exceptions = exceptions
193+
Examples = examples
194+
FullName = $"{modName}.{sourceName}" // the long ident as users see it
195+
Assembly = assembly }
196+
|> ValueSome
197+
| None -> ValueNone

0 commit comments

Comments
 (0)