Skip to content

🐛 FIX: html_block: blank lines inside containers prematurely terminate non-blank-line-terminator sequences - #406

Merged
chrisjsewell merged 7 commits into
executablebooks:masterfrom
binggao1230:fix/html-block-blank-line-in-container
Nov 9, 2026
Merged

chrisjsewell merged 7 commits into
executablebooks:masterfrom
binggao1230:fix/html-block-blank-line-in-container

Conversation

@binggao1230

Copy link
Copy Markdown
Contributor

Problem

HTML blocks started with <!--, <?, <!A, <![CDATA[, or <script>/<pre>/<style>/<textarea> (CommonMark types 1–5) have specific end conditions (-->, ?>, >, ]]>, closing tags). Per CommonMark spec §4.6, these blocks continue until the matching end tag is found, or the last line of the document/container — blank lines inside them do not terminate them.

When such a block appeared inside a container (e.g. a list item), a blank line within the comment caused early termination. The scan loop in html_block checks state.sCount[nextLine] < state.blkIndent to detect container boundaries, but blank lines always have sCount = 0, so any positive blkIndent (set by the list rule) incorrectly fired the guard.

Reproduction (from #377):

from markdown_it import MarkdownIt
md = MarkdownIt()
text = '''1. item

    <!--
    The following code block specifies the full path.

    [1]: <https://example.com>
    -->
    paragraph
'''
print(md.render(text))

Before this fix, --> was escaped as --&gt; inside a paragraph (comment prematurely closed at the blank line).

Fix

One-character addition: skip the sCount < blkIndent guard when the line is blank (state.isEmpty(nextLine)). Blank lines in sequences 6–7 (end condition ^$) still terminate correctly because an empty lineText matches ^$ through the existing end-condition check.

Test

New fixture in commonmark_extras.md covering the exact case from #377.

This pull request was prepared with the assistance of AI, under my direction and review.

…n-blank-line-terminator sequences

HTML blocks started with `<!--`, `<?`, `<!A`, `<![CDATA[`, or `<script>`/`<pre>`/`<style>`/`<textarea>`
(CommonMark types 1–5) have specific end conditions (e.g. `-->`).  Per the CommonMark spec §4.6,
these blocks continue until the matching end tag is found, or until the last line of the document /
container block — blank lines inside them do NOT terminate them.

When such a block appeared inside a container (e.g. a list item) a blank line within the comment
caused `state.sCount[nextLine] < state.blkIndent` to fire and break out of the scan loop early.
Blank lines always have `sCount = 0`, so any positive `blkIndent` would trigger the break even
though the blank line was still part of the containing list item.

Fix: skip the `sCount < blkIndent` guard for blank lines (`state.isEmpty(nextLine)`).
Blank lines that belong to a blank-line-terminator sequence (types 6–7, end condition `^$`) still
terminate correctly because an empty `lineText` matches `^$` via the end-condition check.

Fixes executablebooks#377.

chrisjsewell commented Sep 17, 2026 •

Copy link
Copy Markdown
Member

Thanks @binggao1230, and apologies for the slow response. I agree the fix is right against the CommonMark spec: a blank line inside a list item does not end the container, so a type 1–5 HTML block should continue to its real end condition, and the reference implementation renders the #377 example as a comment.

The blocker is that this port deliberately mirrors the JavaScript markdown-it, and markdown-it 14.1.1 produces byte-identical output to markdown-it-py for this input (with html: true). The same guard, state.sCount[nextLine] < state.blkIndent, is in upstream html_block.mjs, so this is an upstream bug rather than a porting error, and it was raised there as markdown-it/markdown-it#1144. Diverging here would mean the two implementations disagree on HTML block termination, which tends to come back to us as bug reports from projects that rely on parity.

So I would rather not merge this ahead of upstream. The change is a one-liner, and your fixture translates directly, so would you be willing to open the equivalent pull request against markdown-it/markdown-it, referencing #1144? As soon as it lands there we will port it here, crediting you. I will leave this PR open in the meantime so it is not lost.

@binggao1230

Copy link
Copy Markdown
Contributor Author

Thanks for the careful parity check. It turns out markdown-it/markdown-it#1155 already fixed #1144 and was merged as 68cfb8c on May 22; current markdown-it master contains its endsOnBlankLine guard. Version 14.1.1 predates that merge, which explains the byte-identical release behavior. I'll rebase this PR and align it with the upstream implementation and its list/blockquote fixtures.

Resolve the commonmark_extras.md conflict with executablebooks#409 by keeping both
sides: master's two image-description fixtures, then this PR's.
Match markdown-it 68cfb8c (markdown-it#1155, released in 14.2.0):
compute whether the block type ends on a blank line once, and only
skip the outdent break for blank lines when it does not. Behaviour is
unchanged (types 6/7 already stopped at the blank line via their `^$`
end condition); the shape just mirrors upstream for future syncs.

A single combined condition replaces upstream's nested `if`, which
ruff's SIM102 rejects.
Copy both fixtures verbatim from markdown-it 68cfb8c
(test/fixtures/markdown-it/commonmark_extras.txt), the list-item case
and the blockquote case, so this file keeps mirroring upstream. They
replace the executablebooks#377 fixture, which was the same list-item case in
different words.

The list-item fixture fails with master's html_block.py; the
blockquote one already passes there and guards against regressions.
Two markdown-it-py fixtures for executablebooks#377 in issue-fixes.md (so
commonmark_extras.md stays a mirror of upstream). They cover the other
half of the outdent guard: a comment in a list item must still end at
the next list item after a blank line, and at an outdented non-blank
line. Upstream's #1144 fixtures only cover the blank-line half.
Expected output is identical to markdown-it 15.0.3.
# Conflicts:
#	tests/test_port/fixtures/commonmark_extras.md
#	tests/test_port/fixtures/issue-fixes.md
@chrisjsewell
chrisjsewell merged commit cb36d3a into executablebooks:master Nov 9, 2026
15 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.

2 participants