mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-13 23:49:14 +00:00
fix(wiki): keep an article labelled index from overwriting index.md
A god node labelled index() (an ordinary web view) or a community named
after one slugs to "index", so to_wiki wrote its article to index.md and
then replaced it with the catalog; the catalog entry linked back to the
catalog itself. Reserve the index slug in the dedup set, and link the
navigation footer to index.md directly so the label resolver can map an
"index" label to its own deduplicated file.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit aad5e0feab)
This commit is contained in:
1 parent
17b007ab74
commit
efc5a4ded3
2 files changed
+40
-4
No files matched your search
+13
-4
@@ -30,6 +30,12 @@ _SLUG_SUFFIX_RESERVE = 5
|
||||
_UNSAFE_SLUG_CHARS = re.compile(r'[<>:"/\\|?*#%\x00-\x1f\x7f]')
|
||||
|
||||
|
||||
# The navigation footer links the catalog by its fixed filename rather than via
|
||||
# the label resolver, so an article whose own label is "index" resolves to its
|
||||
# own (deduplicated) file instead of the catalog.
|
||||
_INDEX_LINK = "[index](index.md)"
|
||||
|
||||
|
||||
def _safe_filename(name: str, limit: int = 200) -> str:
|
||||
"""Make a label safe for use as a filename across platforms AND as a
|
||||
markdown link destination.
|
||||
@@ -178,7 +184,7 @@ def _community_article(
|
||||
lines.append(f"- {conf}: {n} ({pct}%)")
|
||||
lines.append("")
|
||||
|
||||
lines += ["---", "", f"*Part of the graphify knowledge wiki. See {_md_link('index', resolver)} to navigate.*"]
|
||||
lines += ["---", "", f"*Part of the graphify knowledge wiki. See {_INDEX_LINK} to navigate.*"]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -224,7 +230,7 @@ def _god_node_article(G: nx.Graph, nid: str, labels: dict[int, str], node_commun
|
||||
)
|
||||
lines.append("")
|
||||
|
||||
lines += ["---", "", f"*Part of the graphify knowledge wiki. See {_md_link('index', resolver)} to navigate.*"]
|
||||
lines += ["---", "", f"*Part of the graphify knowledge wiki. See {_INDEX_LINK} to navigate.*"]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -338,7 +344,10 @@ def to_wiki(
|
||||
node_community: dict[str, int] = {n: cid for cid, nodes in communities.items() for n in nodes}
|
||||
|
||||
count = 0
|
||||
used_slugs: set[str] = set()
|
||||
# "index" is reserved for the catalog written below: an article slugged
|
||||
# "index" (a community named after an `index()` hub, an `Index` god node on a
|
||||
# case-insensitive filesystem) would otherwise be overwritten by index.md.
|
||||
used_slugs: set[str] = {"index"}
|
||||
|
||||
# Articles are capped against THIS wiki directory, not just NAME_MAX: on
|
||||
# Windows a 200-char slug under an ordinary graphify-out/wiki/ overruns
|
||||
@@ -368,7 +377,7 @@ def to_wiki(
|
||||
# _md_link renders them as plain text. Communities are slugged before god nodes
|
||||
# (and setdefault keeps the first), preserving the filename-assignment order
|
||||
# the case-collision dedup relies on.
|
||||
resolver: dict[str, str] = {"index": "index"}
|
||||
resolver: dict[str, str] = {}
|
||||
|
||||
community_slugs: dict[int, str] = {}
|
||||
for cid in communities:
|
||||
|
||||
@@ -309,6 +309,33 @@ def test_to_wiki_god_node_label_case_collides_with_community(tmp_path):
|
||||
assert len(set(lowered)) == len(lowered), [p.name for p in articles]
|
||||
|
||||
|
||||
def test_to_wiki_article_labelled_index_does_not_overwrite_index_md(tmp_path):
|
||||
"""index.md is the wiki's reserved entry point. A community whose label slugs
|
||||
to "index" (the default hub labeler names a community after its hub node, so a
|
||||
hub `index()` view or an `Index` class does this) or a god node labelled
|
||||
`index()` must get its own file, not be written to index.md and then
|
||||
overwritten by the catalog - which also made its catalog link point back at
|
||||
the index itself."""
|
||||
G = nx.Graph()
|
||||
G.add_node("n1", label="index()", file_type="code", source_file="views.py")
|
||||
G.add_node("n2", label="render", file_type="code", source_file="views.py")
|
||||
G.add_node("n3", label="Index", file_type="code", source_file="search.py")
|
||||
G.add_node("n4", label="query", file_type="code", source_file="search.py")
|
||||
G.add_edge("n1", "n2", relation="calls", confidence="EXTRACTED", weight=1.0)
|
||||
G.add_edge("n3", "n4", relation="calls", confidence="EXTRACTED", weight=1.0)
|
||||
communities = {0: ["n1", "n2"], 1: ["n3", "n4"]}
|
||||
labels = {0: "index", 1: "Search"}
|
||||
god_nodes = [{"id": "n3", "label": "Index", "degree": 1}]
|
||||
n = to_wiki(G, communities, tmp_path, community_labels=labels, god_nodes_data=god_nodes)
|
||||
articles = [p for p in tmp_path.glob("*.md") if p.stem.lower() != "index"]
|
||||
# every article survives as its own file next to the catalog
|
||||
assert len(articles) == n == 3, sorted(p.name for p in tmp_path.glob("*.md"))
|
||||
index_text = (tmp_path / "index.md").read_text(encoding="utf-8")
|
||||
assert index_text.startswith("# Knowledge Graph Index")
|
||||
# no catalog entry links back to the catalog itself
|
||||
assert "(index.md)" not in index_text, index_text
|
||||
|
||||
|
||||
# Regression tests for portable wiki links - Obsidian [[wikilinks]] break in
|
||||
# every non-Obsidian renderer (VS Code preview, GitHub, GitLab, plain browsers).
|
||||
|
||||
|
||||
Reference in new issue
Block a user