mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-19 03:49:50 -05:00
Three defects, all in the site machinery rather than the prose, all visible on the first page anyone opens. `r"\1=\""` is not an escaped quote. In a raw string that backslash is a character, so every `src="docs/…"` the README hook rewrote came out as `src=\"helixscreen-print-status.webp"` and the browser asked for a file whose name began with a quote. Both screenshots on the front page 404'd. `- [x]` is python-markdown's plain list syntax unless pymdownx.tasklist is enabled, so the Status checkboxes -- the list this project leads with, and the thing a reader decides on -- rendered as the literal text `[x]`. Enabled, with custom_checkbox so they get the theme's own mark. The checklists in is-this-for-you.md and after-the-flash.md were the same bug. And mkdocs rewrites markdown links but not raw HTML attributes, which is invisible until a page with an `<img>` in it is not the front page: with directory URLs, is-this-for-you.md is served from /is-this-for-you/, one level below the image it names. The hook now rewrites relative src/href in raw HTML too, prefixing `../` per level of the page's own URL, so an `<img>` works from wherever the page ends up -- and it points at a file that must exist, so a typo stays a broken link the build can still catch. Found by serving the site and looking at it, which is the only way any of these three surface: --strict validates markdown links, and every one of these was in HTML or in text it had no reason to read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S3XZh4SqPdXAowVndz6tMr
92 lines
3.7 KiB
Python
92 lines
3.7 KiB
Python
"""Two jobs, both about keeping one source of truth.
|
|
|
|
`on_pre_build` publishes README.md as the site's front page. The README is the
|
|
project's front door on GitHub and has to stay that; a hand-copied
|
|
docs/index.md would be a second front page, free to drift from the first, so
|
|
the build generates index.md on every run and .gitignore keeps it out of the
|
|
tree.
|
|
|
|
`on_page_markdown` rewrites the links that point out of docs/ -- at
|
|
`../payload/klipper/extras/ff_tool.py` and friends -- into GitHub URLs. Those
|
|
links are written relative because that is what works when the page is read in
|
|
the repo, which is where a contributor reads it; on the site they would 404.
|
|
Rewriting them here means nobody has to remember two link styles, and a link
|
|
whose target does not exist at all is still left alone, so mkdocs --strict can
|
|
fail the build over it.
|
|
"""
|
|
|
|
import pathlib
|
|
import re
|
|
|
|
REPO = "https://github.com/Klipper4FlashForge/firmware"
|
|
BRANCH = "master"
|
|
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
DOCS = ROOT / "docs"
|
|
|
|
# A markdown link target that is not absolute, an anchor, or a mail address.
|
|
LINK = re.compile(r"\]\((?!https?:|#|mailto:)([^)\s]+)\)")
|
|
# The same, for a raw HTML attribute: mkdocs rewrites markdown links but not
|
|
# these, and with directory URLs a page sits one level below its own images.
|
|
ATTR = re.compile(r'\b(src|href)="(?!https?:|#|mailto:|/|\.\./)([^"]+)"')
|
|
|
|
|
|
def on_pre_build(config, **kwargs):
|
|
text = (ROOT / "README.md").read_text(encoding="utf-8")
|
|
# The README's paths are relative to the repo root, the site's to docs/:
|
|
# resolve from the root first, so `gcode/` and `docs/notes/` become GitHub
|
|
# URLs, then strip the prefix from what is left, which is the site itself.
|
|
text = _rewrite_links(text, ROOT)
|
|
text = re.sub(r"\]\(docs/", "](", text)
|
|
text = re.sub(r'(src|href)="docs/', r'\1="', text)
|
|
index = DOCS / "index.md"
|
|
# Only write on a real change: `mkdocs serve` watches docs/, and touching
|
|
# index.md every build would rebuild forever.
|
|
if not index.exists() or index.read_text(encoding="utf-8") != text:
|
|
index.write_text(text, encoding="utf-8")
|
|
|
|
|
|
def on_page_markdown(markdown, page, **kwargs):
|
|
markdown = _rewrite_links(markdown, (DOCS / page.file.src_path).parent)
|
|
return _rewrite_html_paths(markdown, page)
|
|
|
|
|
|
def _rewrite_html_paths(markdown, page):
|
|
"""Point a raw <img src="x.jpg"> at the file, from wherever the page is.
|
|
|
|
`page.url` is "" for the front page and "is-this-for-you/" for a page one
|
|
level down, so the number of slashes in it is how far the image is above
|
|
the reader.
|
|
"""
|
|
up = "../" * page.url.count("/")
|
|
here = (DOCS / page.file.src_path).parent
|
|
|
|
def rewrite(match):
|
|
attr, target = match.group(1), match.group(2)
|
|
if not (here / target).exists():
|
|
return match.group(0)
|
|
return f'{attr}="{up}{target}"'
|
|
|
|
return ATTR.sub(rewrite, markdown)
|
|
|
|
|
|
def _rewrite_links(markdown, here):
|
|
def rewrite(match):
|
|
target = match.group(1)
|
|
path, _, fragment = target.partition("#")
|
|
if not path:
|
|
return match.group(0)
|
|
resolved = (here / path).resolve()
|
|
try:
|
|
relative = resolved.relative_to(ROOT)
|
|
except ValueError:
|
|
return match.group(0) # outside the repo; not ours to fix
|
|
if not resolved.exists():
|
|
return match.group(0) # broken: let --strict say so
|
|
if resolved.is_file() and DOCS in resolved.parents:
|
|
return match.group(0) # a page or an image; mkdocs has it
|
|
kind = "tree" if resolved.is_dir() else "blob"
|
|
suffix = f"#{fragment}" if fragment else ""
|
|
return f"]({REPO}/{kind}/{BRANCH}/{relative}{suffix})"
|
|
|
|
return LINK.sub(rewrite, markdown)
|