diff --git a/src/dfo_docs/manifest.py b/src/dfo_docs/manifest.py index 83ab1b4..a8fd3ae 100644 --- a/src/dfo_docs/manifest.py +++ b/src/dfo_docs/manifest.py @@ -362,7 +362,7 @@ def _build_source_nav( and recursively for each nested grouping heading inside it. """ landing: str | None = None - if entries and len(entries[0].breadcrumb) == depth and _is_index(entries[0].file): + if _leads_with_landing(entries, depth=depth): landing = _page_id(source_name, _page_slug(entries[0].file)) entries = entries[1:] @@ -416,6 +416,16 @@ def _group_id(key_path: tuple[str, ...]) -> str: return "group:" + "/".join(key_path) +def _leads_with_landing(entries: Sequence[NavEntry], *, depth: int) -> bool: + """Whether `entries`, one nav group's flattened entries at `depth`, open with the + group's own `index.md`, which `_build_source_nav` folds into the group's landing.""" + return ( + bool(entries) + and len(entries[0].breadcrumb) == depth + and _is_index(entries[0].file) + ) + + def _is_index(file: str) -> bool: return PurePosixPath(file).name == "index.md" @@ -433,6 +443,9 @@ def _source_pages( *, corpus_root: Path, ) -> list[Page]: + landing_file = ( + sidecar.nav[0].file if _leads_with_landing(sidecar.nav, depth=0) else None + ) return [ _fetched_page( fetched, @@ -440,7 +453,11 @@ def _source_pages( file=nav_entry.file, slug=_page_slug(nav_entry.file), path_prefix=sidecar.path, - title=nav_entry.title or nav_entry.file, + title=( + sidecar.title + if nav_entry.file == landing_file + else nav_entry.title or nav_entry.file + ), kind=PageKind.PAGE, corpus_root=corpus_root, excluded=sidecar.excluded, diff --git a/tests/docsync/test_pages.py b/tests/docsync/test_pages.py index effcb68..a30fe45 100644 --- a/tests/docsync/test_pages.py +++ b/tests/docsync/test_pages.py @@ -164,7 +164,7 @@ def test_pages_follow_the_nav_with_their_sections_and_titles(tmp_path): assert [(p.page_id, p.section_path, p.title) for p in pages] == [ ("hub", (), "Home"), ("hub/build/share", ("Build",), "Share"), - ("guide", ("Build", "Guide"), "Guide home"), + ("guide", ("Build", "Guide"), "Guide"), ("guide/start", ("Build", "Guide"), "Start"), ("guide/deep", ("Build", "Guide", "Deep"), "Deep"), ("guide/deep/detail", ("Build", "Guide", "Deep"), "Detail"), diff --git a/tests/test_manifest.py b/tests/test_manifest.py index aeba756..1b4e383 100644 --- a/tests/test_manifest.py +++ b/tests/test_manifest.py @@ -509,6 +509,49 @@ def test_mount_group_folds_leading_index_into_page_id_and_path(tmp_path): assert [child.title for child in guides_group.children] == ["Advanced"] +def test_source_index_page_takes_the_source_title_not_its_nav_label(tmp_path): + """A source that labels its landing `Home: index.md` still publishes that page + under the source's title, matching its group; other pages, including a later + top-level `index.md` leaf, keep their nav label.""" + repo = _make_repo(tmp_path, "labelled") + (repo / "mkdocs.yml").write_text( + "site_name: tools/labelled\n" + "title: Labelled Reader\n" + "nav:\n" + " - Home: index.md\n" + " - Changelog: changelog.md\n" + " - Reference: reference/index.md\n" + " - Guides:\n" + " - Home: guides/index.md\n" + " - Advanced: guides/advanced.md\n" + ) + docs = repo / "docs" + (docs / "guides").mkdir(parents=True) + (docs / "reference").mkdir() + for name in ( + "index", + "changelog", + "reference/index", + "guides/index", + "guides/advanced", + ): + (docs / f"{name}.md").write_text(f"# {name}\n") + _commit_all(repo, "init") + source = _sample_source(repo, name="labelled", path="tools/labelled") + fetched = _fetch(source, tmp_path) + hub = HubNode(children=(HubNode(mount="labelled"),)) + + _, pages, _ = _build( + tmp_path, sources={"labelled": source}, hub=hub, fetched=[fetched] + ) + + assert _by_id(pages, "labelled").title == "Labelled Reader" + assert _by_id(pages, "labelled/changelog").title == "Changelog" + # Only the leading index is the landing; a later top-level index is a leaf. + assert _by_id(pages, "labelled/reference").title == "Reference" + assert _by_id(pages, "labelled/guides").title == "Home" + + def test_nav_node_ids_join_to_pages_and_groups_are_opaque(tmp_path): repo = _sample_repo(tmp_path) source = _sample_source(repo, path="tools/sample")