Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 64a3c0f

Browse files
facelessuserwaylan
authored andcommitted
Fix HTML handling of </>
Fixes #1528
1 parent f2b9fd1 commit 64a3c0f

File tree

6 files changed

+66
-0
lines changed

6 files changed

+66
-0
lines changed

‎docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the [Contributing Guide](contributing.md) for details.
1414
### Fixed
1515

1616
* Fixed dropped content in `md_in_html` (#1526).
17+
* Fixed HTML handling corner case that prevented some content from not being rendered (#1528).
1718

1819
## [3.8.0] - 2025年04月09日
1920

‎markdown/htmlparser.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
spec.loader.exec_module(htmlparser)
4242
sys.modules['htmlparser'] = htmlparser
4343

44+
# This is a hack. We are sneaking in `</>` so we can capture it without the HTML parser
45+
# throwing it away. When we see it, we will process it as data.
46+
htmlparser.starttagopen = re.compile('<[a-zA-Z]|</>')
47+
4448
# Monkeypatch `HTMLParser` to only accept `?>` to close Processing Instructions.
4549
htmlparser.piclose = re.compile(r'\?>')
4650
# Monkeypatch `HTMLParser` to only recognize entity references with a closing semicolon.
@@ -297,6 +301,11 @@ def get_starttag_text(self) -> str:
297301
return self.__starttag_text
298302

299303
def parse_starttag(self, i: int) -> int: # pragma: no cover
304+
# Treat `</>` as normal data as it is not a real tag.
305+
if self.rawdata[i:i + 3] == '</>':
306+
self.handle_data(self.rawdata[i:i + 3])
307+
return i + 3
308+
300309
self.__starttag_text = None
301310
endpos = self.check_for_whole_start_tag(i)
302311
if endpos < 0:

‎tests/test_syntax/blocks/test_html_blocks.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,3 +1643,21 @@ def test_placeholder_in_source(self):
16431643
placeholder = md.htmlStash.get_placeholder(md.htmlStash.html_counter + 1)
16441644
result = md.postprocessors['raw_html'].run(placeholder)
16451645
self.assertEqual(placeholder, result)
1646+
1647+
def test_noname_tag(self):
1648+
self.assertMarkdownRenders(
1649+
self.dedent(
1650+
"""
1651+
<div>
1652+
</>
1653+
</div>
1654+
"""
1655+
),
1656+
self.dedent(
1657+
"""
1658+
<div>
1659+
</>
1660+
</div>
1661+
"""
1662+
)
1663+
)

‎tests/test_syntax/extensions/test_md_in_html.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,24 @@ def test_trailing_content_after_tag_in_md_block(self):
15381538
extensions=['md_in_html']
15391539
)
15401540

1541+
def test_noname_tag(self):
1542+
self.assertMarkdownRenders(
1543+
self.dedent(
1544+
"""
1545+
<div markdown>
1546+
</>
1547+
</div>
1548+
"""
1549+
),
1550+
self.dedent(
1551+
"""
1552+
<div>
1553+
<p>&lt;/&gt;</p>
1554+
</div>
1555+
"""
1556+
)
1557+
)
1558+
15411559

15421560
def load_tests(loader, tests, pattern):
15431561
""" Ensure `TestHTMLBlocks` doesn't get run twice by excluding it here. """

‎tests/test_syntax/inline/test_code.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,20 @@ def test_code_html(self):
6262
"""
6363
)
6464
)
65+
66+
def test_noname_tag(self):
67+
# Browsers ignore `</>`, but a Markdown parser should not, and should treat it as data
68+
# but not a tag.
69+
70+
self.assertMarkdownRenders(
71+
self.dedent(
72+
"""
73+
`</>`
74+
"""
75+
),
76+
self.dedent(
77+
"""
78+
<p><code>&lt;/&gt;</code></p>
79+
"""
80+
)
81+
)

‎tests/test_syntax/inline/test_raw_html.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ def test_inline_html_angle_brackets(self):
3131

3232
def test_inline_html_backslashes(self):
3333
self.assertMarkdownRenders('<img src="..\\..\\foo.png">', '<p><img src="..\\..\\foo.png"></p>')
34+
35+
def test_noname_tag(self):
36+
self.assertMarkdownRenders('<span></></span>', '<p><span>&lt;/&gt;</span></p>')

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /