Skip to content

Commit 88e65f1

Browse files
authored
fix: Update GFM alert regex to disallow content on header line (#252)
* fix: Make github alert parsing case-insensitive Signed-off-by: Frost Ming <me@frostming.com> * fix: Update GFM alert regex to disallow content on header line Signed-off-by: Frost Ming <me@frostming.com> * fix: Bump version to 2.2.2 Signed-off-by: Frost Ming <me@frostming.com>
1 parent e347932 commit 88e65f1

File tree

4 files changed

+33
-10
lines changed

4 files changed

+33
-10
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## v2.2.2(2026-01-05)
2+
3+
### Fixed
4+
5+
- Fix a bug in GFM alert block parsing where alert types were case-sensitive.
6+
- Fix GFM alert regex to disallow content on header line.
7+
18
## v2.2.1(2025-10-13)
29

310
### Changed

marko/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from .block import Document
2424
from .parser import ElementType
2525

26-
__version__ = "2.2.1"
26+
__version__ = "2.2.2"
2727

2828

2929
class SetupDone(Exception):

marko/ext/gfm/elements.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,13 @@ class Alert(block.Quote):
225225

226226
@classmethod
227227
def match(cls, source):
228-
return source.expect_re(r" {,3}>\s*\[\!(WARNING|NOTE|TIP|IMPORTANT|CAUTION)\]")
228+
return source.expect_re(
229+
r"(?im) {,3}>\s*\[\!(WARNING|NOTE|TIP|IMPORTANT|CAUTION)\]\s*$"
230+
)
229231

230232
@classmethod
231233
def parse(cls, source):
232-
alert_type = source.match.group(1)
234+
alert_type = source.match.group(1).upper()
233235
source.next_line(require_prefix=False)
234236
source.consume()
235237
state = cls(alert_type)

tests/test_ext.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import pytest
2+
13
from marko import Markdown
24

35

@@ -106,20 +108,32 @@ def setup_method(self):
106108
self.md_ast = Markdown(renderer=ASTRenderer, extensions=[GFM])
107109
self.md_html = Markdown(extensions=[GFM])
108110

109-
def test_alert_ast(self):
110-
text = "> [!WARNING]\n> Foo bar\n> Bar\n"
111+
@pytest.mark.parametrize(
112+
"alert_type", ["WARNING", "CAUTION", "TIP", "warning", "Caution"]
113+
)
114+
def test_alert_ast(self, alert_type):
115+
text = f"> [!{alert_type}]\n> Foo bar\n> Bar\n"
111116
ast = self.md_ast(text)
112117
admon = ast["children"][0]
113118
assert admon["element"] == "alert"
114-
assert admon["alert_type"] == "WARNING"
119+
assert admon["alert_type"] == alert_type.upper()
115120
inner = admon["children"][0]["children"]
116121
assert inner[0]["children"] == "Foo bar"
117122
assert inner[1]["element"] == "line_break"
118123
assert inner[2]["children"] == "Bar"
119124

120-
def test_alert_html(self):
121-
text = "> [!WARNING]\n> Foo bar\n> Bar\n"
125+
@pytest.mark.parametrize(
126+
"alert_type", ["WARNING", "CAUTION", "TIP", "warning", "Caution"]
127+
)
128+
def test_alert_html(self, alert_type):
129+
text = f"> [!{alert_type}]\n> Foo bar\n> Bar\n"
122130
html = self.md_html(text)
123-
assert '<blockquote class="alert alert-warning">' in html
124-
assert "<p>Warning</p>" in html
131+
assert f'<blockquote class="alert alert-{alert_type.lower()}">' in html
132+
assert f"<p>{alert_type.title()}</p>" in html
125133
assert "<p>Foo bar\nBar</p>" in html
134+
135+
def test_alert_disallow_content_on_header_line(self):
136+
text = "> [!NOTE] This is not allowed.\n> Foo bar\n"
137+
html = self.md_html(text)
138+
# Should be treated as a normal blockquote.
139+
assert "<blockquote>\n<p>[!NOTE] This is not allowed." in html

0 commit comments

Comments
 (0)