Skip to content

Rewrite the markdown parser to follow CommonMark - #35

Merged
noha merged 2 commits into
mainfrom
feature/commonmark-core
Sep 11, 2026
Merged

noha merged 2 commits into
mainfrom
feature/commonmark-core

Conversation

@noha

@noha noha commented Sep 11, 2026

Copy link
Copy Markdown
Owner

The parser recognised a fixed set of constructs line by line, which left out most of the syntax the spec defines and got several of the covered cases wrong - inline code appeared verbatim in the output, single asterisks were not emphasis, and blockquotes and list items could hold only inline text.

It now follows the two phase strategy CommonMark describes. FOBlockParser reads the source line by line and keeps a stack of open container blocks, asking each block polymorphically whether it continues (#continueOn:), what it may contain (#canContain:) and whether it takes raw lines. FOInlineParser then turns the text of the leaf blocks into inline nodes, using a delimiter stack for emphasis and a bracket stack for links, so emphasis nests and link text is parsed.

New syntax: inline code, setext headings, thematic breaks, backslash escapes, HTML entities, hard and soft line breaks, autolinks, inline raw HTML, link reference definitions, reference links, loose and tight lists, ordered lists with a start number, and blockquotes and list items holding arbitrary blocks.

FOHTMLRenderVisitor now produces the HTML the spec asks for, newlines included, and percent encodes link destinations. Because every block now ends with a newline, the four Foliage-Core tests that asserted rendered pages verbatim were adjusted. The two Foliage additions are kept and covered by tests:
language=x alongside the plain x info string, and HTML attributes after an
image destination.

Measured against the 655 examples of the CommonMark 0.31.2 specification, all
of which pass. FOCommonMarkSpecTest keeps 65 of them in the repository as a
standing regression net. The GFM extensions (tables, task lists, strikethrough,
extended autolinks) are not implemented yet.

Two behaviour changes show up in existing blog sources: a code fence must now be
closed by a fence at least as long as the one that opened it, and a ** run
between a letter and punctuation no longer opens emphasis.

noha and others added 2 commits September 12, 2026 00:00
The parser recognised a fixed set of constructs line by line, which left out
most of the syntax the spec defines and got several of the covered cases wrong -
inline code appeared verbatim in the output, *single asterisks* were not
emphasis, and blockquotes and list items could hold only inline text.

It now follows the two phase strategy CommonMark describes. FOBlockParser reads
the source line by line and keeps a stack of open container blocks, asking each
block polymorphically whether it continues (#continueOn:), what it may contain
(#canContain:) and whether it takes raw lines. FOInlineParser then turns the
text of the leaf blocks into inline nodes, using a delimiter stack for emphasis
and a bracket stack for links, so emphasis nests and link text is parsed.

New syntax: inline code, setext headings, thematic breaks, backslash escapes,
HTML entities, hard and soft line breaks, autolinks, inline raw HTML, link
reference definitions, reference links, loose and tight lists, ordered lists
with a start number, and blockquotes and list items holding arbitrary blocks.

FOHTMLRenderVisitor now produces the HTML the spec asks for, newlines included,
and percent encodes link destinations. Because every block now ends with a
newline, the four Foliage-Core tests that asserted rendered pages verbatim were
adjusted. The two Foliage additions are kept and covered by tests:
```language=x alongside the plain ```x info string, and HTML attributes after an
image destination.

Measured against the 655 examples of the CommonMark 0.31.2 specification, all
of which pass. FOCommonMarkSpecTest keeps 65 of them in the repository as a
standing regression net. The GFM extensions (tables, task lists, strikethrough,
extended autolinks) are not implemented yet.

Two behaviour changes show up in existing blog sources: a code fence must now be
closed by a fence at least as long as the one that opened it, and a ** run
between a letter and punctuation no longer opens emphasis.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every block now ends with a newline, which the four series tests asserting
rendered output did not expect.

testAbstractPrefersHandWrittenDataFileOverAutoDerivedOne was already failing on
main: "Add a per-post series teaser box, render series text as HTML" changed
#abstract to render HTML and updated FOSeriesTest, but left this one expecting
the plain source text. It now expects the same HTML the other series tests do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@noha
noha force-pushed the feature/commonmark-core branch from ec15c91 to 09d7e1b Compare September 11, 2026 22:02
@noha
noha merged commit b730f66 into main Sep 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant