mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-20 23:11:46 +02:00
fix(governance): retain malformed link follow-ups
This commit is contained in:
@@ -9,6 +9,7 @@ INLINE_LINK_START_RE = re.compile(r"\[[^\]\n]*\]\(")
|
||||
REFERENCE_DEFINITION_RE = re.compile(
|
||||
r"""(?mx)
|
||||
^\ {0,3}\[(?P<label>[^\]\n]+)\]:[\t\ ]*
|
||||
(?:\r?\n[\t\ ]+)?
|
||||
(?P<target><[^>\n]+>|[^\t\ \n]+)
|
||||
(?:[\t\ ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\([^()]*\)))?
|
||||
[\t\ ]*$
|
||||
@@ -75,19 +76,21 @@ def without_inline_code(text: str) -> str:
|
||||
|
||||
def inline_link_targets(text: str) -> list[str]:
|
||||
targets: list[str] = []
|
||||
for match in INLINE_LINK_START_RE.finditer(text):
|
||||
matches = list(INLINE_LINK_START_RE.finditer(text))
|
||||
for index, match in enumerate(matches):
|
||||
start = match.end()
|
||||
next_start = (
|
||||
matches[index + 1].start() if index + 1 < len(matches) else len(text)
|
||||
)
|
||||
if start < len(text) and text[start] == "<":
|
||||
end = text.find(">", start + 1)
|
||||
end = text.find(">", start + 1, next_start)
|
||||
if end != -1:
|
||||
targets.append(text[start : end + 1])
|
||||
continue
|
||||
break
|
||||
continue
|
||||
depth = 0
|
||||
quote: str | None = None
|
||||
escaped = False
|
||||
closed = False
|
||||
for end in range(start, len(text)):
|
||||
for end in range(start, next_start):
|
||||
character = text[end]
|
||||
if quote is not None:
|
||||
if escaped:
|
||||
@@ -105,11 +108,8 @@ def inline_link_targets(text: str) -> list[str]:
|
||||
elif character == ")":
|
||||
if depth == 0:
|
||||
targets.append(text[start:end])
|
||||
closed = True
|
||||
break
|
||||
depth -= 1
|
||||
if not closed:
|
||||
break
|
||||
return targets
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ INLINE_LINK_START_RE = re.compile(r"\[[^\]\n]*\]\(")
|
||||
REFERENCE_DEFINITION_RE = re.compile(
|
||||
r"""(?mx)
|
||||
^\ {0,3}\[(?P<label>[^\]\n]+)\]:[\t\ ]*
|
||||
(?:\r?\n[\t\ ]+)?
|
||||
(?P<target><[^>\n]+>|[^\t\ \n]+)
|
||||
(?:[\t\ ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\([^()]*\)))?
|
||||
[\t\ ]*$
|
||||
@@ -75,19 +76,21 @@ def without_inline_code(text: str) -> str:
|
||||
|
||||
def inline_link_targets(text: str) -> list[str]:
|
||||
targets: list[str] = []
|
||||
for match in INLINE_LINK_START_RE.finditer(text):
|
||||
matches = list(INLINE_LINK_START_RE.finditer(text))
|
||||
for index, match in enumerate(matches):
|
||||
start = match.end()
|
||||
next_start = (
|
||||
matches[index + 1].start() if index + 1 < len(matches) else len(text)
|
||||
)
|
||||
if start < len(text) and text[start] == "<":
|
||||
end = text.find(">", start + 1)
|
||||
end = text.find(">", start + 1, next_start)
|
||||
if end != -1:
|
||||
targets.append(text[start : end + 1])
|
||||
continue
|
||||
break
|
||||
continue
|
||||
depth = 0
|
||||
quote: str | None = None
|
||||
escaped = False
|
||||
closed = False
|
||||
for end in range(start, len(text)):
|
||||
for end in range(start, next_start):
|
||||
character = text[end]
|
||||
if quote is not None:
|
||||
if escaped:
|
||||
@@ -105,11 +108,8 @@ def inline_link_targets(text: str) -> list[str]:
|
||||
elif character == ")":
|
||||
if depth == 0:
|
||||
targets.append(text[start:end])
|
||||
closed = True
|
||||
break
|
||||
depth -= 1
|
||||
if not closed:
|
||||
break
|
||||
return targets
|
||||
|
||||
|
||||
|
||||
@@ -220,6 +220,19 @@ def test_artifact_scope_handles_many_unclosed_inline_links_linearly(
|
||||
assert result.returncode == 0, result.stdout
|
||||
|
||||
|
||||
@pytest.mark.parametrize("prefix", ("<unterminated ", "unterminated "))
|
||||
def test_artifact_scope_checks_link_after_unclosed_destination(
|
||||
project: Path, prefix: str
|
||||
) -> None:
|
||||
(project / "index.md").write_text(
|
||||
f"[broken]({prefix}[missing](missing-guide.md)\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
result = run_audit(project, "artifacts")
|
||||
assert result.returncode == 1
|
||||
assert "Broken Markdown link: 'index.md' -> 'missing-guide.md'" in result.stdout
|
||||
|
||||
|
||||
def test_artifact_scope_ignores_links_inside_code_examples(project: Path) -> None:
|
||||
(project / "guide.md").write_text(
|
||||
"`[inline](missing-inline.md)`\n\n```md\n[fenced](missing-fenced.md)\n```\n",
|
||||
@@ -276,6 +289,17 @@ def test_artifact_scope_checks_reference_style_markdown_links(
|
||||
assert "missing-guide.md" in result.stdout
|
||||
|
||||
|
||||
def test_artifact_scope_checks_continuation_line_reference_target(
|
||||
project: Path,
|
||||
) -> None:
|
||||
(project / "index.md").write_text(
|
||||
"[docs]\n\n[docs]:\n missing-guide.md\n", encoding="utf-8"
|
||||
)
|
||||
result = run_audit(project, "artifacts")
|
||||
assert result.returncode == 1
|
||||
assert "Broken Markdown link: 'index.md' -> 'missing-guide.md'" in result.stdout
|
||||
|
||||
|
||||
def test_adr_scope_requires_every_file_in_index(project: Path) -> None:
|
||||
adr_dir = project / "docs" / "adr"
|
||||
adr_dir.mkdir(parents=True)
|
||||
|
||||
Reference in New Issue
Block a user