-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expose page Markdown at page.md instead of page/index.md #1950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7ec7e11
48d097f
a242092
2f14ec8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| """MkDocs post-build hook: flatten per-page Markdown from ``page/index.md`` to | ||
| ``page.md``. | ||
|
|
||
| Registered via the top-level ``hooks:`` list in ``mkdocs.yml``. Runs after the | ||
| ``mkdocs-llmstxt`` plugin (see the ``event_priority`` on ``on_post_build``). | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
| import re | ||
| from pathlib import Path, PurePosixPath | ||
|
|
||
| import mkdocs.plugins | ||
|
|
||
|
|
||
| def flat_md_target(rel_path: str) -> str | None: | ||
| """Map a generated Markdown file's site-relative path to its flat target. | ||
|
|
||
| Args: | ||
| rel_path: Path of the generated file relative to ``site_dir``, POSIX form. | ||
|
|
||
| Returns: | ||
| The new site-relative path (e.g. ``agents/config.md``), or ``None`` if | ||
| the file must stay in place (root ``index.md`` or a non-``index.md`` file). | ||
| """ | ||
| p = PurePosixPath(rel_path) | ||
| if p.name != "index.md": | ||
| return None | ||
| parent = p.parent | ||
| if parent in (PurePosixPath("."), PurePosixPath("")): | ||
| return None # root site/index.md stays as-is | ||
| return f"{parent.as_posix()}.md" | ||
|
|
||
|
|
||
| def rewrite_index_links(text: str, site_url: str) -> str: | ||
| """Rewrite ``{site_url}/<path>/index.md`` links to ``{site_url}/<path>.md``. | ||
|
|
||
| The bare homepage link ``{site_url}/index.md`` has no intermediate path | ||
| segment and is left unchanged. Scoping to ``site_url`` avoids corrupting | ||
| unrelated URLs that merely contain the substring ``index.md``. | ||
| """ | ||
| base = site_url.rstrip("/") | ||
| pattern = re.compile(re.escape(base) + r"/([^\s)]+?)/index\.md") | ||
| return pattern.sub(lambda m: f"{base}/{m.group(1)}.md", text) | ||
|
|
||
|
|
||
| log = logging.getLogger("mkdocs.hooks.flatten_md") | ||
|
|
||
|
|
||
| @mkdocs.plugins.event_priority(-100) | ||
| def on_post_build(config, **kwargs) -> None: # noqa: ARG001 | ||
| """Rename generated ``index.md`` files to flat ``page.md`` and fix links. | ||
|
|
||
| Priority ``-100`` ensures this runs after the ``mkdocs-llmstxt`` plugin's | ||
| own ``on_post_build`` (lower priority runs later). | ||
| """ | ||
| site_dir = Path(config["site_dir"]) | ||
| site_url = config["site_url"] | ||
|
|
||
| # Pass 1: rename <dir>/index.md -> <dir>.md (root index.md is left alone). | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are restructuring the documentation file serving structure on the fly for the sole purpose of providing a new access method (**/page.md URL pattern). This solution not appropriate to the outcome and will likely create serving and maintenance issues in the future. Since this functionality is purely meant to provide a new access pattern (**/page.md), and since we already provide a markdown output (e.g., https://adk.dev/get-started/index.md ), I recommend you create a extension of the redirect functionality that runs after all configured redirects in mkdoc.yaml to capture requests for the **/page.md URL pattern, such that a request for https://adk.dev/get-started.md is redirected to https://adk.dev/get-started/index.md , without rewriting the existing page source. |
||
| renamed = 0 | ||
| for md_path in list(site_dir.rglob("index.md")): | ||
| rel = md_path.relative_to(site_dir).as_posix() | ||
| target_rel = flat_md_target(rel) | ||
| if target_rel is None: | ||
| continue | ||
| md_path.replace(site_dir / target_rel) | ||
| renamed += 1 | ||
|
|
||
| # Pass 2: rewrite site-internal .../index.md links in all text outputs. | ||
| # Load-bearing assumption: internal .md links are absolute {site_url}/... URLs | ||
| # because mkdocs-llmstxt normalizes them via its _convert_to_absolute_link, so | ||
| # rewrite_index_links only handles absolute links; relative .../index.md links | ||
| # are not expected here. | ||
| rewritten = 0 | ||
| targets = list(site_dir.rglob("*.md")) | ||
| for extra in ("llms.txt", "llms-full.txt"): | ||
| extra_path = site_dir / extra | ||
| if extra_path.exists(): | ||
| targets.append(extra_path) | ||
| for path in targets: | ||
| text = path.read_text(encoding="utf8") | ||
| new_text = rewrite_index_links(text, site_url) | ||
| if new_text != text: | ||
| path.write_text(new_text, encoding="utf8") | ||
| rewritten += 1 | ||
|
|
||
| log.info( | ||
| "flatten_md: renamed %d markdown file(s), rewrote links in %d file(s)", | ||
| renamed, | ||
| rewritten, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| from flatten_md import flat_md_target, on_post_build, rewrite_index_links | ||
|
|
||
| SITE = "https://adk.dev" | ||
|
|
||
|
|
||
| def test_flat_md_target_regular_page(): | ||
| assert flat_md_target("agents/config/index.md") == "agents/config.md" | ||
|
|
||
|
|
||
| def test_flat_md_target_section_index(): | ||
| assert flat_md_target("agents/index.md") == "agents.md" | ||
|
|
||
|
|
||
| def test_flat_md_target_root_index_stays(): | ||
| assert flat_md_target("index.md") is None | ||
|
|
||
|
|
||
| def test_flat_md_target_non_index_ignored(): | ||
| assert flat_md_target("agents/config.md") is None | ||
|
|
||
|
|
||
| def test_rewrite_links_regular_page(): | ||
| text = "[cfg](https://adk.dev/agents/config/index.md)" | ||
| assert rewrite_index_links(text, SITE) == "[cfg](https://adk.dev/agents/config.md)" | ||
|
|
||
|
|
||
| def test_rewrite_links_section_index(): | ||
| text = "See https://adk.dev/agents/index.md for details" | ||
| assert rewrite_index_links(text, SITE) == "See https://adk.dev/agents.md for details" | ||
|
|
||
|
|
||
| def test_rewrite_links_homepage_unchanged(): | ||
| text = "Home: https://adk.dev/index.md" | ||
| assert rewrite_index_links(text, SITE) == "Home: https://adk.dev/index.md" | ||
|
|
||
|
|
||
| def test_rewrite_links_trailing_slash_site_url(): | ||
| text = "https://adk.dev/agents/config/index.md" | ||
| assert rewrite_index_links(text, "https://adk.dev/") == "https://adk.dev/agents/config.md" | ||
|
|
||
|
|
||
| def test_rewrite_links_idempotent(): | ||
| once = rewrite_index_links("https://adk.dev/agents/config/index.md", SITE) | ||
| assert rewrite_index_links(once, SITE) == once | ||
|
|
||
|
|
||
| def _build_fake_site(site_root): | ||
| """Create a realistic post-build site layout under ``site_root``. | ||
|
|
||
| Returns the ``config`` dict expected by ``on_post_build``. | ||
| """ | ||
| (site_root / "agents" / "config").mkdir(parents=True) | ||
| (site_root / "agents" / "config" / "index.md").write_text( | ||
| "[agents](https://adk.dev/agents/index.md)\n" | ||
| "[qs](https://adk.dev/get-started/quickstart/index.md)\n", | ||
| encoding="utf8", | ||
| ) | ||
| (site_root / "agents" / "index.md").write_text( | ||
| "[cfg](https://adk.dev/agents/config/index.md)\n", | ||
| encoding="utf8", | ||
| ) | ||
| (site_root / "index.md").write_text( | ||
| "Home: https://adk.dev/index.md\n", | ||
| encoding="utf8", | ||
| ) | ||
| (site_root / "llms.txt").write_text( | ||
| "- [X](https://adk.dev/agents/config/index.md)\n", | ||
| encoding="utf8", | ||
| ) | ||
| (site_root / "llms-full.txt").write_text( | ||
| "See https://adk.dev/agents/index.md for details\n", | ||
| encoding="utf8", | ||
| ) | ||
| return {"site_dir": str(site_root), "site_url": SITE} | ||
|
|
||
|
|
||
| def test_on_post_build_renames_layout(tmp_path): | ||
| site_root = tmp_path / "site" | ||
| config = _build_fake_site(site_root) | ||
|
|
||
| on_post_build(config) | ||
|
|
||
| # Flat targets exist; original nested index.md files are gone. | ||
| assert (site_root / "agents" / "config.md").exists() | ||
| assert not (site_root / "agents" / "config" / "index.md").exists() | ||
| assert (site_root / "agents.md").exists() | ||
| assert not (site_root / "agents" / "index.md").exists() | ||
|
|
||
| # Root index.md is left in place (not renamed). | ||
| assert (site_root / "index.md").exists() | ||
|
|
||
|
|
||
| def test_on_post_build_rewrites_links(tmp_path): | ||
| site_root = tmp_path / "site" | ||
| config = _build_fake_site(site_root) | ||
|
|
||
| on_post_build(config) | ||
|
|
||
| config_md = (site_root / "agents" / "config.md").read_text(encoding="utf8") | ||
| assert "https://adk.dev/agents.md" in config_md | ||
| assert "https://adk.dev/get-started/quickstart.md" in config_md | ||
| assert "index.md" not in config_md | ||
|
|
||
| agents_md = (site_root / "agents.md").read_text(encoding="utf8") | ||
| assert "https://adk.dev/agents/config.md" in agents_md | ||
| assert "index.md" not in agents_md | ||
|
|
||
| llms = (site_root / "llms.txt").read_text(encoding="utf8") | ||
| assert "https://adk.dev/agents/config.md" in llms | ||
| assert "index.md" not in llms | ||
|
|
||
| llms_full = (site_root / "llms-full.txt").read_text(encoding="utf8") | ||
| assert "https://adk.dev/agents.md" in llms_full | ||
| assert "index.md" not in llms_full | ||
|
|
||
| # Bare homepage link is preserved unchanged. | ||
| root_md = (site_root / "index.md").read_text(encoding="utf8") | ||
| assert root_md == "Home: https://adk.dev/index.md\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewriting the links of the markdown file is unnecessary. The links as provided work just fine, and you are introducing complexity, dependency on this URL re-writing script, and creating potential link failures by doing this. Recommend removing this.