From 3d42486a024b308e65ba7cd9a8e4adb2c21d8f7e Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 29 Sep 2022 14:08:07 +0200 Subject: [PATCH 1/4] Resolve markdown links in html code. --- .../MarkdownUtils.fs | 33 ++++++++++++++- tests/FSharp.Markdown.Tests/Markdown.fs | 42 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs index 9e7bf9828..716d88ae1 100644 --- a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs +++ b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs @@ -5,6 +5,8 @@ namespace rec FSharp.Formatting.Markdown open System.Collections.Generic +open System.Linq +open System.Xml.Linq open FSharp.Formatting.Templating module internal MarkdownUtils = @@ -315,7 +317,36 @@ module internal MarkdownUtils = ) | OtherBlock (lines: (string * MarkdownRange) list, range) -> OtherBlock(lines |> List.map (fun (line, range) -> (mapText f line, range)), range) - | InlineHtmlBlock (code, count, range) -> InlineHtmlBlock(mapText f code, count, range) + | InlineHtmlBlock (code, count, range) -> + try + let fText, _, fLink = f + + if code.StartsWith("{code}") + // ends-with is XPath 2.0 only, https://stackoverflow.com/questions/1525299/xpath-and-xslt-2-0-for-net + let attributes = + match System.Xml.XPath.Extensions.XPathEvaluate(element, "//*/@*[contains(., '.md')]") with + | :? System.Collections.IEnumerable as enumerable -> + enumerable |> Enumerable.Cast |> Seq.toArray + | _ -> Array.empty + + if Array.isEmpty attributes then + InlineHtmlBlock(fText code, count, range) + else + for attribute in attributes do + if attribute.Value.EndsWith(".md") then + attribute.SetValue(fLink attribute.Value) + + let html = element.Elements() |> Seq.map string |> String.concat "" |> fText + InlineHtmlBlock(html, count, range) + with ex -> + InlineHtmlBlock(mapText f code, count, range) // NOTE: substitutions are not currently applied to embedded LiterateParagraph which are in any case eliminated // before substitutions are applied. diff --git a/tests/FSharp.Markdown.Tests/Markdown.fs b/tests/FSharp.Markdown.Tests/Markdown.fs index 5239ddd0e..293d91b9a 100644 --- a/tests/FSharp.Markdown.Tests/Markdown.fs +++ b/tests/FSharp.Markdown.Tests/Markdown.fs @@ -981,3 +981,45 @@ let ``Do not close emphasis if second * is preceded by punctuation and followed let doc2 = "*(*foo*)*" let actual2 = "

(foo)

\r\n" |> properNewLines Markdown.ToHtml doc2 |> shouldEqual actual2 + +[] +let ``Replace relative markdown file in anchor href attribute`` () = + let doc = "my link" + let mdlinkResolver _ = Some "./other-file.html" + let actual = "my link\r\n" + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual + +[] +let ``Replace relative markdown file in multiple anchors`` () = + let doc = "link onelink two" + let mdlinkResolver _ = Some "./other-file.html" + let actual = "link onelink two\r\n" + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual + +[] +let ``Replace relative markdown file in multiple attributes`` () = + let doc = "d" + let mdlinkResolver _ = Some "./other-file.html" + let actual = "d\r\n" + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual + +[] +let ``Replace relative markdown file in custom attribute`` () = + let doc = "" + let mdlinkResolver _ = Some "./other-file.html" + let actual = "\r\n" + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual + +[] +let ``Don't replace links in generated code block`` () = + let doc = "
content
" + let mdlinkResolver _ = failwith "should not be reached!" + let actual = "
content
\r\n" + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual + +[] +let ``Don't replace links in generated code block in table`` () = + let doc = "content
" + let mdlinkResolver _ = failwith "should not be reached!" + let actual = "content
\r\n" + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual From 265557dee6c953782bf8c7510f7dbab044dc3822 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 29 Sep 2022 14:12:16 +0200 Subject: [PATCH 2/4] Add release notes. --- RELEASE_NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e2368f99a..6c13a89c0 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,7 @@ +## 16.2.0 + +* Resolve markdown links in raw html [#769](https://github.com/fsprojects/FSharp.Formatting/issues/769) + ## 16.1.1 * [Fix arguments naming and escape operator name in usageHtml](https://github.com/fsprojects/FSharp.Formatting/pull/765/) From 3a54eb07698db3e7e68d0eb3ea5ead17159a273f Mon Sep 17 00:00:00 2001 From: nojaf Date: Sun, 2 Oct 2022 15:21:18 +0200 Subject: [PATCH 3/4] Use `|> properNewLines` helper in tests. --- tests/FSharp.Markdown.Tests/Markdown.fs | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/FSharp.Markdown.Tests/Markdown.fs b/tests/FSharp.Markdown.Tests/Markdown.fs index 293d91b9a..7899d29b9 100644 --- a/tests/FSharp.Markdown.Tests/Markdown.fs +++ b/tests/FSharp.Markdown.Tests/Markdown.fs @@ -986,40 +986,56 @@ let ``Do not close emphasis if second * is preceded by punctuation and followed let ``Replace relative markdown file in anchor href attribute`` () = let doc = "my link" let mdlinkResolver _ = Some "./other-file.html" - let actual = "my link\r\n" + + let actual = + "my link\r\n" + |> properNewLines + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual [] let ``Replace relative markdown file in multiple anchors`` () = let doc = "link onelink two" let mdlinkResolver _ = Some "./other-file.html" - let actual = "link onelink two\r\n" + + let actual = + "link onelink two\r\n" + |> properNewLines + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual [] let ``Replace relative markdown file in multiple attributes`` () = let doc = "d" let mdlinkResolver _ = Some "./other-file.html" - let actual = "d\r\n" + let actual = "d\r\n" |> properNewLines Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual [] let ``Replace relative markdown file in custom attribute`` () = let doc = "" let mdlinkResolver _ = Some "./other-file.html" - let actual = "\r\n" + + let actual = + "\r\n" + |> properNewLines + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual [] let ``Don't replace links in generated code block`` () = let doc = "
content
" let mdlinkResolver _ = failwith "should not be reached!" - let actual = "
content
\r\n" + let actual = "
content
\r\n" |> properNewLines Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual [] let ``Don't replace links in generated code block in table`` () = let doc = "content
" let mdlinkResolver _ = failwith "should not be reached!" - let actual = "content
\r\n" + + let actual = + "content
\r\n" + |> properNewLines + Markdown.ToHtml(doc, mdlinkResolver = mdlinkResolver) |> shouldEqual actual From 26891c390210cb2e69f4e904ddb947cf5d565067 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 11 Oct 2022 17:39:58 +0200 Subject: [PATCH 4/4] Map code content when it is code block. --- src/FSharp.Formatting.Markdown/MarkdownUtils.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs index 716d88ae1..a6c5f529a 100644 --- a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs +++ b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs @@ -324,7 +324,7 @@ module internal MarkdownUtils = if code.StartsWith("