14. Page text is Markdown, parsed by a library on both sides#

Date: 2026-10-20 (#71, #102)

Status#

Accepted

Context#

Early rendering and importing used hand-written regexes. They mis-handled tables, code, nested brackets and pathological inputs, and the client and server disagreed about what a link or image was. Search needed plain text from the same parse.

Decision#

  • Both sides use the same grammar: CommonMark plus tables, strikethrough, footnotes, [[slug|label]] page links, raw HTML as text, and a line break kept as one.

  • The PWA renders with markdown-it in a lazy chunk (render.ts); a post-parse pass allows only http(s), mailto, page and in-page links (rel=noopener) and only this server’s images. ```mermaid blocks are drawn by a bundled, separately loaded Mermaid with securityLevel: 'strict', so the CSP does not change.

  • The server uses markdown-it-py (scrap/markdown.py) to produce search text (link/image text, not addresses; code as typed) and for link rewriting, which rewrites links, images and wiki links found by the parse and mapped back to source positions, so code is never touched.

  • Parsers must be linear in the text. Migration 0004 re-indexed every page this way.

  • Search deliberately does not index addresses.

Consequences#

  • Rendering offline works once the chunk is cached; before that, text shows as typed.

  • Two parser implementations must be kept in step, covered by tests and docs.

  • A hand-written URL is found by its link text, not its domain, by choice.