Skip to content

Commit 6194c5e

Browse files
fix(lint): don't hide same-stem orphans behind qualified links (#147)
find_orphans added the bare stem of *every* wikilink to the "incoming" set, so a qualified link like `[[concepts/foo]]` also registered the stem `foo`. Any other page that merely shared that stem in a different directory (e.g. `summaries/foo`) was then treated as linked and excluded from orphan detection — a genuine orphan was silently missed. Only add the bare stem when the link itself is a bare stem (no `/`); qualified links register only their full path. Bare `[[foo]]` links still resolve by stem, so a page named `foo` in any directory remains non-orphaned. Adds regression tests for both the qualified-link (orphan now flagged) and bare-link (still matched) cases.
1 parent c92f2e9 commit 6194c5e

2 files changed

Lines changed: 37 additions & 4 deletions

File tree

openkb/lint.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,14 @@ def find_orphans(wiki: Path) -> list[str]:
321321
incoming: set[str] = set()
322322
for links in outgoing.values():
323323
for lnk in links:
324-
incoming.add(lnk.strip().strip("/"))
325-
# Also add stems
326-
for lnk in links:
327-
incoming.add(Path(lnk.strip()).stem)
324+
cleaned = lnk.strip().strip("/")
325+
incoming.add(cleaned)
326+
# Only treat a link as a bare-stem reference when it is itself a
327+
# bare stem. A qualified link like ``concepts/foo`` must not mark a
328+
# same-stem page in another directory (``summaries/foo``) as linked,
329+
# which would hide a genuine orphan.
330+
if "/" not in cleaned:
331+
incoming.add(Path(cleaned).stem)
328332

329333
orphans: list[str] = []
330334
for rel, links in outgoing.items():

tests/test_lint.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,35 @@ def test_empty_wiki_has_no_orphans(self, tmp_path):
114114

115115
assert result == []
116116

117+
def test_qualified_link_does_not_hide_same_stem_orphan(self, tmp_path):
118+
# A qualified link [[concepts/dup]] must not mark a *different* page
119+
# that merely shares the "dup" stem (summaries/dup) as linked — that
120+
# page is a genuine orphan and must still be flagged.
121+
wiki = _make_wiki(tmp_path)
122+
(wiki / "concepts" / "dup.md").write_text("# Linked concept", encoding="utf-8")
123+
(wiki / "summaries" / "linker.md").write_text(
124+
"See [[concepts/dup]]", encoding="utf-8"
125+
)
126+
(wiki / "summaries" / "dup.md").write_text(
127+
"Orphan sharing the 'dup' stem, with no links.", encoding="utf-8"
128+
)
129+
130+
result = find_orphans(wiki)
131+
132+
assert "summaries/dup" in result
133+
assert "concepts/dup" not in result
134+
135+
def test_bare_stem_link_still_matches_same_stem_page(self, tmp_path):
136+
# A bare [[dup]] link (no path) intentionally resolves by stem, so a
137+
# page with that stem is not considered an orphan.
138+
wiki = _make_wiki(tmp_path)
139+
(wiki / "concepts" / "dup.md").write_text("# A concept", encoding="utf-8")
140+
(wiki / "summaries" / "linker.md").write_text("See [[dup]]", encoding="utf-8")
141+
142+
result = find_orphans(wiki)
143+
144+
assert "concepts/dup" not in result
145+
117146

118147
class TestFindMissingEntries:
119148
def test_no_missing_entries(self, tmp_path):

0 commit comments

Comments
 (0)