Skip to content

[repo-assist] perf: HtmlDocument.ToString reuses one StringBuilder across all child elements - #1787

Draft
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/perf-htmldoc-shared-sb-2026-07-30-2b6111142ceed6c5
Draft

[repo-assist] perf: HtmlDocument.ToString reuses one StringBuilder across all child elements#1787
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/perf-htmldoc-shared-sb-2026-07-30-2b6111142ceed6c5

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

🤖 This PR was created by Repo Assist, an automated AI assistant.

Summary

HtmlDocument.ToString() previously called element.ToString() for each top-level child element, which:

  1. Created a new StringBuilder internally
  2. Serialised the node tree into it
  3. Extracted the intermediate string
  4. Appended that string to the document-level StringBuilder

For a typical HTML page with <html>, <head>, <body> (3+ root elements), this meant 3 extra string allocations and 3 extra copy passes before the final document string was available.

Fix

Extract the serialisation logic into an internal SerializeTo(sb, indentation, canAddNewLine, insidePre) method on HtmlNode. HtmlDocument.ToString() now passes its own StringBuilder directly, eliminating the intermediate strings.

HtmlNode.ToString() creates a fresh StringBuilder and delegates to SerializeTo — the public API is unchanged.

Benefit

  • Reduces allocations when serialising HtmlDocument values (common in HTML type provider output and scraping pipelines).
  • The savings scale with the number of top-level elements; for a full HTML page with <!DOCTYPE>, <html>, this removes at least 2 intermediate string allocations.

Trade-offs

  • SerializeTo is marked internal — it does not affect the public API.
  • The serialisation logic itself is unchanged; only the entrypoint structure differs.

Test Status

All 3926 tests pass on Linux/net8.0:

  • FSharp.Data.Core.Tests: 3143 passed
  • FSharp.Data.DesignTime.Tests: 489 passed, 1 skipped
  • FSharp.Data.Tests: 292 passed
  • FSharp.Data.Reference.Tests: 2 passed

Generated by 🌈 Repo Assist, see workflow run. Learn more.
Comment /repo-assist to run again

Add this agentic workflow to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@42c2ab5b4e4c9273534c39259b2e0df7f20f07e9

… elements

HtmlDocument.ToString() previously called element.ToString() for each
top-level element, which created a new StringBuilder, serialised the
node into it, extracted the intermediate string, and then appended that
string to the document-level StringBuilder.  For pages with N root
elements this meant N extra string allocations and N extra copy passes.

Fix: extract the serialisation logic into an internal SerializeTo(sb,...)
method on HtmlNode so the document can pass its own StringBuilder
directly.  HtmlNode.ToString() creates the StringBuilder and delegates,
preserving the public API unchanged.

All 3926 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants