diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 772e4712..645ef5d2 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -30,6 +30,9 @@ * Add missing `[]` attribute on `Can include-output-and-it` test so it is executed by the test runner. * Add regression test confirming that types whose name matches their enclosing namespace are correctly included in generated API docs. [#944](https://github.com/fsprojects/FSharp.Formatting/issues/944) * Fix crash (`failwith "tbd - IndirectImage"`) when `Markdown.ToMd` is called on a document containing reference-style images with bracket syntax. The indirect image is now serialised as `![alt](url)` when the reference is resolved, or in bracket notation when it is not. [#1094](https://github.com/fsprojects/FSharp.Formatting/pull/1094) +* Fix `Markdown.ToMd` serialising italic spans with asterisks incorrectly as bold spans. [#1102](https://github.com/fsprojects/FSharp.Formatting/pull/1102) +* Fix `Markdown.ToMd` serialising ordered list items with incorrect numbering and formatting. [#1102](https://github.com/fsprojects/FSharp.Formatting/pull/1102) +* Fix `Markdown.ToMd` not preserving indented code blocks: bare code output was re-parsed as a paragraph. Indented code blocks are now serialised as fenced code blocks, which round-trip correctly. * Fix `Markdown.ToMd` serialising `*emphasis*` (italic) spans as `**...**` (bold) instead of `*...*`. [#1102](https://github.com/fsprojects/FSharp.Formatting/pull/1102) * Fix `Markdown.ToMd` serialising ordered list items with 0-based numbering and no period (e.g. `0 first`) instead of 1-based with a period (e.g. `1. first`). [#1102](https://github.com/fsprojects/FSharp.Formatting/pull/1102) * Fix `HtmlElement` SVG serialisation: `LinearGradient` now renders as `` and `RadialGradient` now renders as `` — both previously emitted the invalid tag ``. diff --git a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs index 20a1479b..ef8dd396 100644 --- a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs +++ b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs @@ -187,15 +187,15 @@ module internal MarkdownUtils = yield String.replicate 3 (string c) yield "" | CodeBlock(code = code; fence = fence; language = language) -> - match fence with - | None -> () - | Some f -> yield f + language + // Indented code blocks (fence = None) are serialised as fenced blocks so + // that the round-trip is valid — raw indented code without a '> ' prefix + // or 4-space indent would be parsed as a paragraph, not a code block. + let f = defaultArg fence "```" + yield f + language yield code - match fence with - | None -> () - | Some f -> yield f + yield f yield "" | ListBlock(Unordered, paragraphsl, _) -> diff --git a/tests/FSharp.Markdown.Tests/Markdown.fs b/tests/FSharp.Markdown.Tests/Markdown.fs index e5cf2b90..99ea859e 100644 --- a/tests/FSharp.Markdown.Tests/Markdown.fs +++ b/tests/FSharp.Markdown.Tests/Markdown.fs @@ -1444,6 +1444,38 @@ let ``ToMd round-trip: indirect image with unresolved reference`` () = result |> should contain "![alt text][unknown-ref]" // -------------------------------------------------------------------------------------- +// ToMd round-trip: indented code block (fence = None) — issue #fix-tomd-indented-codeblock +// -------------------------------------------------------------------------------------- + +[] +let ``ToMd round-trip: indented code block is preserved as a code block`` () = + // An indented code block (4-space indent) is serialised as a fenced block to + // guarantee the round-trip: outputting bare code without any fence would cause + // re-parsing to produce a paragraph instead of a code block. + let input = " let x = 1\n let y = 2" + let doc = Markdown.Parse(input) + // The parser should have produced a CodeBlock, not a Paragraph + let cbs = + doc.Paragraphs + |> List.choose (function + | CodeBlock _ as cb -> Some cb + | _ -> None) + + cbs |> should haveLength 1 + // ToMd should produce a fenced form so the round-trip is valid + let result = Markdown.ToMd(doc, newline = "\n") + result |> should contain "```" + result |> should contain "let x = 1" + result |> should contain "let y = 2" + // The serialised form re-parses to a CodeBlock, not a Paragraph + let doc2 = Markdown.Parse(result) + + doc2.Paragraphs + |> List.choose (function + | CodeBlock _ as cb -> Some cb + | _ -> None) + |> should haveLength 1 + // ToMd: HardLineBreak and HorizontalRule round-trip // --------------------------------------------------------------------------------------