From 59f7875d2ae1dc5070e0e9fbae2e949533669924 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 11:10:02 +0000 Subject: [PATCH 1/2] refactor: extract formatListBlock helper to eliminate ordered/unordered list duplication in MarkdownUtils.fs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- RELEASE_NOTES.md | 3 + .../MarkdownUtils.fs | 76 +++++++------------ 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 8a318b6a..35e55f01 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -2,6 +2,9 @@ ## [Unreleased] +### Changed +* Refactor `Markdown.ToMd` list-block formatting: extract a shared `formatListBlock` helper to eliminate the near-identical code paths for ordered and unordered lists in `MarkdownUtils.fs`. + ### Changed * Compile `Regex` instances to module-level singletons (with `RegexOptions.Compiled`) in `PageContentList`, `HtmlFormatting`, `Formatting`, `Menu`, and `LlmsTxt`. Previously a new, uncompiled `Regex` was constructed on every call (once per page heading, once per HTML page, once per menu item, once per llms.txt entry), incurring repeated JIT overhead. The patterns are now compiled once at module load and reused across all calls. * Replace deprecated `System.Net.WebClient` with `System.Net.Http.HttpClient` in the image downloader used by `--saveimages`. Removes the `#nowarn "44"` suppression. diff --git a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs index 6b784184..ec9e7514 100644 --- a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs +++ b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs @@ -157,6 +157,32 @@ module internal MarkdownUtils = /// Format a MarkdownParagraph let rec formatParagraph (ctx: FormattingContext) paragraph = + // Shared helper for both ordered and unordered list blocks. + // getPrefix receives the 0-based item index and returns the leading string (e.g. "* " or "1. "). + let formatListBlock paragraphsl (getPrefix: int -> string) = + let isTight = + paragraphsl + |> List.forall (function + | [ Span _ ] -> true + | _ -> false) + + [ for (n, paragraphs) in List.indexed paragraphsl do + for (i, paragraph) in List.indexed paragraphs do + let lines: string list = formatParagraph ctx paragraph + let lines = if lines.IsEmpty then [ "" ] else lines + + for (j, line) in List.indexed lines do + if i = 0 && j = 0 then + yield getPrefix n + line + else + yield " " + line + + if not isTight then + yield "" + + if isTight then + yield "" ] + [ match paragraph with | LatexBlock(env, lines, _) -> // Single-line equation blocks are rendered with the compact $$...$$ notation @@ -197,54 +223,8 @@ module internal MarkdownUtils = yield f yield "" - | ListBlock(Unordered, paragraphsl, _) -> - // A tight list has exactly one Span per item (no blank lines between items). - let isTight = - paragraphsl - |> List.forall (function - | [ Span _ ] -> true - | _ -> false) - - for paragraphs in paragraphsl do - for (i, paragraph) in List.indexed paragraphs do - let lines = formatParagraph ctx paragraph - let lines = if lines.IsEmpty then [ "" ] else lines - - for (j, line) in List.indexed lines do - if i = 0 && j = 0 then - yield "* " + line - else - yield " " + line - - if not isTight then - yield "" - - if isTight then - yield "" - | ListBlock(Ordered, paragraphsl, _) -> - // A tight list has exactly one Span per item (no blank lines between items). - let isTight = - paragraphsl - |> List.forall (function - | [ Span _ ] -> true - | _ -> false) - - for (n, paragraphs) in List.indexed paragraphsl do - for (i, paragraph) in List.indexed paragraphs do - let lines = formatParagraph ctx paragraph - let lines = if lines.IsEmpty then [ "" ] else lines - - for (j, line) in List.indexed lines do - if i = 0 && j = 0 then - yield $"%i{n + 1}. " + line - else - yield " " + line - - if not isTight then - yield "" - - if isTight then - yield "" + | ListBlock(Unordered, paragraphsl, _) -> yield! formatListBlock paragraphsl (fun _ -> "* ") + | ListBlock(Ordered, paragraphsl, _) -> yield! formatListBlock paragraphsl (fun n -> $"{n + 1}. ") | TableBlock(headers, alignments, rows, _) -> match headers with From 4e50a8d5a1be756c1aec685739dece8d87a78221 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 20 Apr 2026 11:10:05 +0000 Subject: [PATCH 2/2] ci: trigger checks