Module

renderers.html

HTML renderer using StringBuilder pattern.

Renders typed AST to HTML with O(n) performance using StringBuilder.

Thread Safety:

All per-render state is encapsulated in RenderContext, created fresh for each render() call. Multiple threads can safely share a single HtmlRenderer instance and call render() concurrently without synchronization.

Single-Pass Heading Decoration: Heading IDs are generated during the AST walk, eliminating the need for regex-based post-processing. TOC data is collected during rendering.

Classes

HeadingInfo 3 ▼
Heading metadata collected during rendering. Used to build TOC without post-render regex scanning.…

Heading metadata collected during rendering.

Used to build TOC without post-render regex scanning. Collected by HtmlRenderer during the AST walk.

Attributes

Name Type Description
level int —
text str —
slug str —
RenderContext 4 ▼
Per-render mutable state. Encapsulates all state that changes during a single render() call. Creat…

Per-render mutable state.

Encapsulates all state that changes during a single render() call. Created fresh for each render, ensuring thread safety when sharing HtmlRenderer instances across threads.

Thread Safety:

Each render() call creates its own RenderContext instance.
No shared mutable state between concurrent renders.

Attributes

Name Type Description
headings list[HeadingInfo] —
seen_slugs set[str] —
footnote_defs dict[str, FootnoteDef] —
footnote_refs list[str] —
HtmlRenderer 20 ▼
Render AST to HTML using StringBuilder pattern. O(n) rendering using StringBuilder for string accu…

Render AST to HTML using StringBuilder pattern.

O(n) rendering using StringBuilder for string accumulation. All per-render state is encapsulated in RenderContext.

Usage:

>>> from patitas.parser import Parser
>>> parser = Parser()
>>> doc = parser.parse("# Hello **World**")
>>> renderer = HtmlRenderer()
>>> html = renderer.render(doc)
'<h1>Hello <strong>World</strong></h1>\n'

Thread Safety:

Multiple threads can safely share a single HtmlRenderer instance.
Each render() call creates an independent RenderContext, ensuring
no shared mutable state between concurrent renders.

Methods

render 1 str ▼
Render document AST to HTML string. **Thread Safety:** Creates independent Ren…
def render(self, node: Document) -> str

Render document AST to HTML string.

Thread Safety: Creates independent RenderContext per call. Safe for concurrent execution from multiple threads.

Parameters
Name Type Description
node —

Document AST root

Returns
str HTML string
get_headings 0 list[HeadingInfo] ▼
Get heading info collected during last render. **Thread Safety:** Uses Context…
def get_headings(self) -> list[HeadingInfo]

Get heading info collected during last render.

Thread Safety: Uses ContextVar to store per-thread/task render context. Safe to call from concurrent threads sharing a single renderer.

Returns
list[HeadingInfo] List of HeadingInfo from the last render() call. Empty if render() hasn't been called.
Internal Methods 18 ▼
__init__ 6 ▼
Initialize renderer.
def __init__(self, source: str = '', *, highlight: bool = False, directive_registry: DirectiveRegistry | None = None, role_registry: RoleRegistry | None = None, text_transformer: Callable[[str], str] | None = None, slugify: Callable[[str], str] | None = None) -> None
Parameters
Name Type Description
source —

Original source buffer for zero-copy extraction

Default:''
highlight —

Enable syntax highlighting for code blocks

Default:False
directive_registry —

Optional registry for custom directive rendering

Default:None
role_registry —

Optional registry for custom role rendering

Default:None
text_transformer —

Optional callback to transform plain text nodes

Default:None
slugify —

Optional custom slugify function for heading IDs

Default:None
_render_block 3 ▼
Render a block node.
def _render_block(self, block: Block, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
block —
sb —
ctx —
_render_heading 3 ▼
Render heading with ID for anchoring.
def _render_heading(self, heading: Heading, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
heading —
sb —
ctx —
_render_paragraph 3 ▼
Render paragraph.
def _render_paragraph(self, para: Paragraph, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
para —
sb —
ctx —
_render_fenced_code 2 ▼
Render fenced code block.
def _render_fenced_code(self, code: FencedCode, sb: StringBuilder) -> None
Parameters
Name Type Description
code —
sb —
_render_indented_code 2 ▼
Render indented code block.
def _render_indented_code(self, code: IndentedCode, sb: StringBuilder) -> None
Parameters
Name Type Description
code —
sb —
_render_blockquote 3 ▼
Render block quote.
def _render_blockquote(self, quote: BlockQuote, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
quote —
sb —
ctx —
_render_list 3 ▼
Render ordered or unordered list.
def _render_list(self, lst: List, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
lst —
sb —
ctx —
_render_list_item 4 ▼
Render list item. CommonMark: - Tight lists: Single paragraph items render as …
def _render_list_item(self, item: ListItem, sb: StringBuilder, ctx: RenderContext, tight: bool) -> None

Render list item.

CommonMark:

  • Tight lists: Single paragraph items render as text (no

    tags)

  • Loose lists: All paragraphs wrapped in

    tags

Parameters
Name Type Description
item —
sb —
ctx —
tight —
_render_table 3 ▼
Render GFM-style table.
def _render_table(self, table: Table, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
table —
sb —
ctx —
_render_table_row 5 ▼
Render table row.
def _render_table_row(self, row: TableRow, sb: StringBuilder, ctx: RenderContext, is_header: bool, alignments: tuple[str | None, ...]) -> None
Parameters
Name Type Description
row —
sb —
ctx —
is_header —
alignments —
_render_math_block 2 ▼
Render block math.
def _render_math_block(self, math: MathBlock, sb: StringBuilder) -> None
Parameters
Name Type Description
math —
sb —
_render_directive 3 ▼
Render directive block. If a directive registry is configured and has a handle…
def _render_directive(self, directive: Directive[Any], sb: StringBuilder, ctx: RenderContext) -> None

Render directive block.

If a directive registry is configured and has a handler for this directive, delegate to the handler per the DirectiveHandler contract:render(node, rendered_children, sb) -> None. Children are rendered first and passed as a string. Unknown (unregistered) directive names fall back to a generic container.

Handler exceptions are intentionally NOT swallowed: a broken handler must surface loudly rather than silently emit wrong-but-plausible HTML.

Parameters
Name Type Description
directive —
sb —
ctx —
_render_inlines 3 ▼
Render a sequence of inline nodes.
def _render_inlines(self, inlines: tuple[Inline, ...], sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
inlines —
sb —
ctx —
_render_inline 3 ▼
Render an inline node.
def _render_inline(self, inline: Inline, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
inline —
sb —
ctx —
_render_role 2 ▼
Render inline role.
def _render_role(self, role: Role, sb: StringBuilder) -> None
Parameters
Name Type Description
role —
sb —
_collect_footnotes 2 ▼
Collect footnote definitions from document.
def _collect_footnotes(self, doc: Document, ctx: RenderContext) -> None
Parameters
Name Type Description
doc —
ctx —
_render_footnotes_section 2 ▼
Render footnotes section at end of document.
def _render_footnotes_section(self, sb: StringBuilder, ctx: RenderContext) -> None
Parameters
Name Type Description
sb —
ctx —

Functions

html_escape 1 str ▼
Escape HTML special characters. CommonMark-compliant: escapes , &, " but NOT s…
def html_escape(s: str) -> str

Escape HTML special characters.

CommonMark-compliant: escapes <, >, &, " but NOT single quotes. Uses str.translate for speed; fast path when no escaping needed.

Parameters
Name Type Description
s str
Returns
str
_encode_url 1 str ▼
Encode URL for CommonMark compliance. CommonMark requires: 1. Decode HTML enti…
def _encode_url(url: str) -> str

Encode URL for CommonMark compliance.

CommonMark requires:

  1. Decode HTML entities (e.g., ä → ä)
  2. Percent-encode special characters (spaces, backslashes, non-ASCII)

Returns URL safe for href attribute (still needs html_escape for quotes).

Parameters
Name Type Description
url str
Returns
str