fix(docs-governance): read HTML comments and code spans in one pass, as CommonMark does

Code spans were blanked before comments, so a code span could swallow a comment's closer and the comment then hid a real link after it. Comments and code spans are now read left to right, whichever opens first. An escaped \<!-- is text, and a comment becomes an opaque run of NUL characters rather than spaces, so a reference definition can no longer start across it.
This commit is contained in:
L4XB committed 2026-10-23 01:54:04 +02:00
1 parent 72229119a3
commit bf38bfcae2
5 files changed
+102 -73

No files matched your search

@@ -49,10 +49,36 @@ def without_fenced_code(text: str) -> str:
return "".join(output)
def without_inline_code(text: str) -> str:
def _is_escaped(text: str, index: int) -> bool:
backslashes = 0
while index - backslashes > 0 and text[index - backslashes - 1] == "\\":
backslashes += 1
return backslashes % 2 == 1
def without_inline_code_and_html_comments(text: str) -> str:
"""Blank out inline code spans and HTML comments, whichever opens first.
A comment runs from `<!--` to the first `-->` after it (`<!-->` and `<!--->` included). It
becomes an opaque run of NUL characters, so a link or a reference definition cannot continue
through it, as none can through raw HTML. An escaped `\\<!--`, or an opener with no closer,
stays literal text, as in CommonMark.
"""
output: list[str] = []
cursor = 0
comments_can_close = True
while cursor < len(text):
if comments_can_close and text.startswith("<!--", cursor) and not _is_escaped(text, cursor):
closing = text.find("-->", cursor + 2)
if closing != -1:
output.extend(
"\n" if character == "\n" else "\0"
for character in text[cursor : closing + 3]
)
cursor = closing + 3
continue
# -- no closer here means none for any later opener either --
comments_can_close = False
if text[cursor] != "`":
output.append(text[cursor])
cursor += 1
@@ -74,28 +100,6 @@ def without_inline_code(text: str) -> str:
return "".join(output)
def without_html_comments(text: str) -> str:
"""Blank out HTML comments, where link-shaped text is not a link.
A comment runs from `<!--` to the first `-->` after it (`<!-->` and `<!--->` included). An
opener with no closer is left alone, as CommonMark leaves it literal text inline.
"""
output: list[str] = []
cursor = 0
while True:
start = text.find("<!--", cursor)
if start == -1:
break
end = text.find("-->", start + 2)
if end == -1:
break
output.append(text[cursor:start])
output.append(re.sub(r"[^\n]", " ", text[start : end + 3]))
cursor = end + 3
output.append(text[cursor:])
return "".join(output)
def inline_link_targets(text: str) -> list[str]:
targets: list[str] = []
matches = list(INLINE_LINK_START_RE.finditer(text))
@@ -195,7 +199,7 @@ def reference_link_targets(text: str) -> list[str]:
def markdown_link_targets(text: str) -> list[str]:
text = without_html_comments(without_inline_code(without_fenced_code(text)))
text = without_inline_code_and_html_comments(without_fenced_code(text))
return inline_link_targets(text) + reference_link_targets(text)
@@ -10,7 +10,7 @@
"id": "hand-seeded",
"source": "manual-curation-pending-regeneration"
},
"registryDigest": "26e3471f7d97e474b311e1cc45c3d967f5be98fca09f264a8cfd8de33ac1158d",
"registryDigest": "f2a5daa835fd6ed2974e14b3f6118ac640115fd8caf10fd8568f1b8adc9a432b",
"schemaVersion": 1,
"triggers": {
"skill:agent-runtime-gateway-smoke-test": [
@@ -49,10 +49,36 @@ def without_fenced_code(text: str) -> str:
return "".join(output)
def without_inline_code(text: str) -> str:
def _is_escaped(text: str, index: int) -> bool:
backslashes = 0
while index - backslashes > 0 and text[index - backslashes - 1] == "\\":
backslashes += 1
return backslashes % 2 == 1
def without_inline_code_and_html_comments(text: str) -> str:
"""Blank out inline code spans and HTML comments, whichever opens first.
A comment runs from `<!--` to the first `-->` after it (`<!-->` and `<!--->` included). It
becomes an opaque run of NUL characters, so a link or a reference definition cannot continue
through it, as none can through raw HTML. An escaped `\\<!--`, or an opener with no closer,
stays literal text, as in CommonMark.
"""
output: list[str] = []
cursor = 0
comments_can_close = True
while cursor < len(text):
if comments_can_close and text.startswith("<!--", cursor) and not _is_escaped(text, cursor):
closing = text.find("-->", cursor + 2)
if closing != -1:
output.extend(
"\n" if character == "\n" else "\0"
for character in text[cursor : closing + 3]
)
cursor = closing + 3
continue
# -- no closer here means none for any later opener either --
comments_can_close = False
if text[cursor] != "`":
output.append(text[cursor])
cursor += 1
@@ -74,28 +100,6 @@ def without_inline_code(text: str) -> str:
return "".join(output)
def without_html_comments(text: str) -> str:
"""Blank out HTML comments, where link-shaped text is not a link.
A comment runs from `<!--` to the first `-->` after it (`<!-->` and `<!--->` included). An
opener with no closer is left alone, as CommonMark leaves it literal text inline.
"""
output: list[str] = []
cursor = 0
while True:
start = text.find("<!--", cursor)
if start == -1:
break
end = text.find("-->", start + 2)
if end == -1:
break
output.append(text[cursor:start])
output.append(re.sub(r"[^\n]", " ", text[start : end + 3]))
cursor = end + 3
output.append(text[cursor:])
return "".join(output)
def inline_link_targets(text: str) -> list[str]:
targets: list[str] = []
matches = list(INLINE_LINK_START_RE.finditer(text))
@@ -195,7 +199,7 @@ def reference_link_targets(text: str) -> list[str]:
def markdown_link_targets(text: str) -> list[str]:
text = without_html_comments(without_inline_code(without_fenced_code(text)))
text = without_inline_code_and_html_comments(without_fenced_code(text))
return inline_link_targets(text) + reference_link_targets(text)
@@ -49,10 +49,36 @@ def without_fenced_code(text: str) -> str:
return "".join(output)
def without_inline_code(text: str) -> str:
def _is_escaped(text: str, index: int) -> bool:
backslashes = 0
while index - backslashes > 0 and text[index - backslashes - 1] == "\\":
backslashes += 1
return backslashes % 2 == 1
def without_inline_code_and_html_comments(text: str) -> str:
"""Blank out inline code spans and HTML comments, whichever opens first.
A comment runs from `<!--` to the first `-->` after it (`<!-->` and `<!--->` included). It
becomes an opaque run of NUL characters, so a link or a reference definition cannot continue
through it, as none can through raw HTML. An escaped `\\<!--`, or an opener with no closer,
stays literal text, as in CommonMark.
"""
output: list[str] = []
cursor = 0
comments_can_close = True
while cursor < len(text):
if comments_can_close and text.startswith("<!--", cursor) and not _is_escaped(text, cursor):
closing = text.find("-->", cursor + 2)
if closing != -1:
output.extend(
"\n" if character == "\n" else "\0"
for character in text[cursor : closing + 3]
)
cursor = closing + 3
continue
# -- no closer here means none for any later opener either --
comments_can_close = False
if text[cursor] != "`":
output.append(text[cursor])
cursor += 1
@@ -74,28 +100,6 @@ def without_inline_code(text: str) -> str:
return "".join(output)
def without_html_comments(text: str) -> str:
"""Blank out HTML comments, where link-shaped text is not a link.
A comment runs from `<!--` to the first `-->` after it (`<!-->` and `<!--->` included). An
opener with no closer is left alone, as CommonMark leaves it literal text inline.
"""
output: list[str] = []
cursor = 0
while True:
start = text.find("<!--", cursor)
if start == -1:
break
end = text.find("-->", start + 2)
if end == -1:
break
output.append(text[cursor:start])
output.append(re.sub(r"[^\n]", " ", text[start : end + 3]))
cursor = end + 3
output.append(text[cursor:])
return "".join(output)
def inline_link_targets(text: str) -> list[str]:
targets: list[str] = []
matches = list(INLINE_LINK_START_RE.finditer(text))
@@ -195,7 +199,7 @@ def reference_link_targets(text: str) -> list[str]:
def markdown_link_targets(text: str) -> list[str]:
text = without_html_comments(without_inline_code(without_fenced_code(text)))
text = without_inline_code_and_html_comments(without_fenced_code(text))
return inline_link_targets(text) + reference_link_targets(text)
+17
View File
@@ -280,6 +280,23 @@ def test_artifact_scope_ignores_links_inside_html_comments(project: Path) -> Non
assert "Broken Markdown link: 'guide.md' -> 'missing-after.md'" in result.stdout
def test_artifact_scope_reads_html_comments_as_commonmark_does(project: Path) -> None:
(project / "guide.md").write_text(
# -- an escaped opener is text, so the link after it is real --
"Intro \\<!-- [escaped](missing-escaped.md) -->\n\n"
# -- a comment that opens before a code span ends at its own closer --
"<!-- ` --> `sample` [after-code](missing-after-code.md)\n\n"
# -- a comment where a destination must begin does not make a definition --
"[foo]: <!-- note --> missing-definition.md\n\n[foo]\n",
encoding="utf-8",
)
result = run_audit(project, "artifacts")
assert result.returncode == 1
assert "Broken Markdown link: 'guide.md' -> 'missing-escaped.md'" in result.stdout
assert "Broken Markdown link: 'guide.md' -> 'missing-after-code.md'" in result.stdout
assert "missing-definition.md" not in result.stdout
def test_artifact_scope_ignores_title_with_escaped_quotes(project: Path) -> None:
(project / "guide.md").write_text("# Guide\n", encoding="utf-8")
(project / "index.md").write_text(