Skip to content

Inline content after a leading HTML comment is not parsed when comment starts the line #951

Description

@josemoliver

Summary

When a line inside a list item (and other non-paragraph block contexts) starts with an HTML comment (<!-- ... -->), everything after the comment on that same line is rendered as literal, un-parsed text instead of receiving normal inline processing. This breaks every inline construct tested — bold, emphasis, inline code, links, and footnote references — not just one specific syntax. It reproduces on the default pipeline with no extensions enabled, so it isn't specific to UseAdvancedExtensions() or the footnote extension.

This appears to contradict CommonMark's own treatment of HTML comments, which are inline-level constructs when they don't occupy an entire block on their own — a comment sharing a line with other content should not suppress inline parsing of the rest of that line.

Environment

  • Markdig NuGet package version: 1.3.2
  • Assembly version reported at runtime (typeof(Markdown).Assembly.GetName().Version): 1.3.0.0
  • Target framework: net10.0 (also reproduces on net8.0/netstandard2.1, per the package's shipped targets — not verified individually, but the parsing code path is shared)
  • OS: Windows 11

Minimal Repro

using Markdig;

var pipeline = new MarkdownPipelineBuilder().Build(); // default pipeline, no extensions

Console.WriteLine(Markdown.ToHtml("1. <!-- c --> **bold**", pipeline));

Actual output:

<ol>
<li><!-- c --> **bold**
</li>
</ol>

Expected output (matching what happens when there's any text before the comment — see "Working control case" below):

<ol>
<li><!-- c --> <strong>bold</strong></li>
</ol>

Additional cases

Working control case — the same comment does not break inline parsing when it isn't the first thing on the line:

Console.WriteLine(Markdown.ToHtml("text <!-- c --> **bold**", pipeline));
<p>text <!-- c --> <strong>bold</strong></p>

Not comment-specific to the extent I first assumed, but comment-specific relative to other inline HTML — other inline HTML constructs starting a line do not trigger the bug; only the comment form does:

Console.WriteLine(Markdown.ToHtml("1. <br/> **bold**", pipeline));            // OK: <li><br/> <strong>bold</strong></li>
Console.WriteLine(Markdown.ToHtml("1. <span>x</span> **bold**", pipeline));   // OK: <li><span>x</span> <strong>bold</strong></li>
Console.WriteLine(Markdown.ToHtml("1. <http://x.com> **bold**", pipeline));   // OK: <li><a href="http://x.com">http://x.com</a> <strong>bold</strong></li>
Console.WriteLine(Markdown.ToHtml("1. <!-- c --> **bold**", pipeline));       // BROKEN: <li><!-- c --> **bold**\n</li>

Not limited to lists — a bare top-level line starting with a comment is also affected, and additionally doesn't even get wrapped in a <p> tag, suggesting Markdig isn't treating the line as a normal paragraph at all once it decides the leading token is an HTML comment:

Console.WriteLine(Markdown.ToHtml("<!-- c --> **bold**", pipeline));
<!-- c --> **bold**

(No <p> wrapper, and **bold** left completely unparsed.)

Reproduces with the footnotes extension too — this is what surfaced the bug for us originally. A footnote reference placed after a leading comment on a list-item line is silently dropped, and — worse — its matching [^label]: ... definition disappears from the output entirely rather than just being left unmatched:

var advPipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();

Console.WriteLine(Markdown.ToHtml(
    "1. <!-- c --> [^1]\n\n[^1]: note text",
    advPipeline));
<ol>
<li><!-- c --> [^1]
</li>
</ol>
<div class="footnotes">
<hr />
<ol>
</ol>
</div>

The [^1] reference is left as literal text, and <div class="footnotes"> renders with an empty <ol> — the definition itself vanishes, it isn't merely left unreferenced. Swapping the order (footnote reference before the comment) works correctly and is our current workaround:

Console.WriteLine(Markdown.ToHtml(
    "1. [^1] <!-- c -->\n\n[^1]: note text",
    advPipeline));
<ol>
<li><a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a> <!-- c --></li>
</ol>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1">
<p>note text<a href="#fnref:1" class="footnote-back-ref">&#8617;</a></p>
</li>
</ol>
</div>

A further downstream consequence for footnotes specifically: because the dropped [^1] reference is never counted, a document with multiple numeric footnote labels renumbers everything after the broken one off-by-one relative to their written labels — e.g. [^3]'s reference silently renders as footnote 2 in the output once [^2] is swallowed by a preceding comment, since Markdig's footnote numbering follows encounter order of successfully-parsed references, not the label text. This can produce a rendered document where a footnote's number doesn't match the definition a reader would expect from its label.

Expected behavior

An HTML comment sharing a line with other Markdown content should be parsed as an inline-level HTML span (per CommonMark's treatment of comments that don't constitute an entire HTML block on their own), and inline parsing of the rest of the line should continue normally afterward — the same as already happens for <br/>, <span>...</span>, and autolinks in the same position.

Suspected cause (not verified against source, offered as a starting point)

The behavior pattern — broken only when the comment is the first token on the line, working fine when preceded by any other inline content — suggests the block parser is classifying a line beginning with <!-- as an HTML block (CommonMark type 2) even when trailing content follows it on the same line, rather than only when the comment's opening line contains nothing else. Once classified that way, the rest of the line appears to be consumed as raw HTML-block content instead of being handed to the inline parser.

Impact

Any Markdown source that places an HTML comment at the start of a list item, blockquote, or other block whose content begins mid-line, followed immediately by any Markdown inline syntax (emphasis, links, code spans, footnote references, etc.), will silently render that trailing syntax as literal text — with no warning or parse error. This is easy to hit by accident (e.g. a comment used as a marker/annotation at the start of a list item followed by real content) and the failure is silent rather than a visible error, making it a difficult class of bug for downstream users to notice without visually diffing rendered output against source.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions