From 30cb7e140145406527af5c51aeb03d04e1325f2c Mon Sep 17 00:00:00 2001 From: hong4rc Date: Sun, 12 Jul 2026 11:38:08 +0700 Subject: [PATCH] fix: Recognize setext headings whose first line starts with # A line like `#1 Goals` or `#hashtag` followed by a setext underline was rendered as a paragraph plus `
` instead of a heading. A line only starts an ATX heading when the `#`s are followed by whitespace or EOL, so these are paragraph text and the underline makes a setext heading. The lheading ATX-interrupt check was bare ` {0,3}#{1,6}`, missing the `(?:\s|$)` that the paragraph and ATX heading rules already require. --- src/rules.ts | 4 ++-- test/specs/new/lheading_hash_prefix.html | 3 +++ test/specs/new/lheading_hash_prefix.md | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 test/specs/new/lheading_hash_prefix.html create mode 100644 test/specs/new/lheading_hash_prefix.md diff --git a/src/rules.ts b/src/rules.ts index cdbbeadb93..8fe4e24316 100644 --- a/src/rules.ts +++ b/src/rules.ts @@ -115,7 +115,7 @@ const lheading = edit(lheadingCore) .replace(/blockCode/g, /(?: {4}| {0,3}\t)/) // indented code blocks can interrupt .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt - .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt + .replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/) // ATX heading can interrupt .replace(/html/g, / {0,3}<[^\n>]+>\n/) // block html can interrupt .replace(/\|table/g, '') // table not in commonmark .getRegex(); @@ -124,7 +124,7 @@ const lheadingGfm = edit(lheadingCore) .replace(/blockCode/g, /(?: {4}| {0,3}\t)/) // indented code blocks can interrupt .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt - .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt + .replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/) // ATX heading can interrupt .replace(/html/g, / {0,3}<[^\n>]+>\n/) // block html can interrupt .replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/) // table can interrupt .getRegex(); diff --git a/test/specs/new/lheading_hash_prefix.html b/test/specs/new/lheading_hash_prefix.html new file mode 100644 index 0000000000..b5c5ec34aa --- /dev/null +++ b/test/specs/new/lheading_hash_prefix.html @@ -0,0 +1,3 @@ +

#1 Goals

+

#hashtag

+

####### seven

diff --git a/test/specs/new/lheading_hash_prefix.md b/test/specs/new/lheading_hash_prefix.md new file mode 100644 index 0000000000..4d88c47bf3 --- /dev/null +++ b/test/specs/new/lheading_hash_prefix.md @@ -0,0 +1,8 @@ +#1 Goals +--------- + +#hashtag +=== + +####### seven +=== \ No newline at end of file