fix: allow indented lines in setext heading text - #4095
Merged
UziTech merged 1 commit intoSep 21, 2026
Merged
Conversation
CommonMark says the text of a setext heading is what "would be interpreted as a paragraph", and lists the blocks that disqualify a line: code fence, ATX heading, block quote, thematic break, list item, HTML block. Indented code is not on that list, because it cannot interrupt a paragraph; thematic break is on it but was missing from the rule. So `a\n b\n===` produced `<p>a\n b\n===</p>` instead of an `<h1>`, and `a\n***\n===` swallowed the thematic break into the heading. Drop blockCode from the continuation lookahead in lheadingCore (the leading guard still needs it, since an indented line does start a code block there) and add hr, so the list matches the specification.
|
@giaBaoJS is attempting to deploy a commit to the MarkedJS Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Marked version: 18.0.13 (
634f810)Markdown flavor: CommonMark
Description
The setext heading rule refuses to let the heading text span a line that looks like an indented code block, and it lets a thematic break line be swallowed into the heading text. Both come from the same list of interrupters in
lheadingCore.Expectation
CommonMark 0.31.2, section 4.3 Setext headings:
Indented code is deliberately absent from that list, because (4.4 Indented code blocks) an indented code block cannot interrupt a paragraph, and (4.8 Paragraphs) "lines after the first may be indented any amount, since indented code blocks cannot interrupt paragraphs". Thematic break is on the list, but was missing from the rule.
src/Lexer.tsalready says the same thing in words for paragraphs (// An indented code block cannot interrupt a paragraph.), and_paragraphcorrectly omits indented code from its own continuation interrupters.Result
commonmark@0.31.2(already a devDependency here) is the reference:a\n b\n===<p>a\n b\n===</p><h1>a\nb</h1>a\n b\n---<p>a\n b</p>\n<hr><h2>a\nb</h2>a\n\tb\n===<p>a\n\tb\n===</p><h1>a\nb</h1>a\n***\n===<h1>a\n***</h1><p>a</p>\n<hr>\n<p>===</p>What was attempted
src/rules.ts:115uses one placeholder list in two positions:The leading
(?!...)guard is correct and stays: at the start of a block an indented line really does open a code block (Foo\n===is a code block plus a paragraph, and marked already gets that right). Only the continuation lookahead is wrong, soblockCodeis dropped from it andhris added, leaving the two positions with the lists the spec describes.The
hrhalf is not optional. Without it, allowing indented continuation lines exposes the pre-existing gap for thematic breaks on many more inputs, and the change is a net regression; with it, the differential fuzz below is clean.Measurements
Suites, before and after (
node --test):test:specstest:unitThe 4 added spec tests are the two new fixture pairs (gfm and
gfm: false).Conformance, measured by running every example in
test/specs/commonmarkandtest/specs/gfmthrough marked and comparing with the same html-differ the harness uses, rather than reading the completion table (which countsshouldFailannotations and is static):gfm: false)gfm: true)Unchanged: no example in the CommonMark suite covers a setext heading with an indented continuation line, which is why this went unnoticed. The same failing examples fail before and after (32, 33, 503, and 602/608/611/612 under gfm).
Differential fuzz over 220,000 generated block-structure documents (random line sequences drawn from indented lines, tabs, underlines, fences, bullets, quotes, ATX headings, thematic breaks, table rows, html tags), comparing old marked / new marked /
commonmark@0.31.2with the harness's html-differ, across 5 seeds and bothgfm: falseandgfm: true:The handful of remaining documents where both versions differ from the reference differ only on unrelated pre-existing points (link reference definitions,
<br>formatting).Two things worth flagging:
<h1>a\n b</h1>where the reference emits<h1>a\nb</h1>). That is pre-existing and identical to what marked already does for paragraph continuation lines (<p>a\n b</p>), it is whitespace-insignificant in the rendered HTML, and the spec suite's differ treats the two as equal. The fixtures are therefore written withoutrenderExact. Happy to fix the whitespace separately if you want it.blockPedantic.paragraphembedslheadingin its continuation lookahead, so pedantic mode inherits the change.test/specs/original(pedantic) stays 100% green.recheckreportsblock.normal.lheading,block.gfm.lheadingandblock.pedantic.lheadingassafeafter the change.Contributor
Committer
In most cases, this should be a different person than the contributor.