diff --git a/overrides/base.html b/overrides/base.html deleted file mode 100644 index 6190791b..00000000 --- a/overrides/base.html +++ /dev/null @@ -1,261 +0,0 @@ -{#- - This file was automatically generated - do not edit --#} -{% import "partials/language.html" as lang with context %} - - - - {% block site_meta %} - - - {% if page.meta and page.meta.description %} - - {% elif config.site_description %} - - {% endif %} - {% if page.meta and page.meta.author %} - - {% elif config.site_author %} - - {% endif %} - {% if page.canonical_url %} - - {% endif %} - {% if page.previous_page %} - - {% endif %} - {% if page.next_page %} - - {% endif %} - {% if config.extra.alternate is iterable %} - {% for alt in config.extra.alternate %} - - {% endfor %} - {% endif %} - {% if "rss" in config.plugins %} - - - {% endif %} - - - - - {% endblock %} - {% block htmltitle %} - {% if page.meta and page.meta.title %} - {{ page.meta.title }} - {{ config.site_name }} - {% elif page.title and not page.is_homepage %} - {{ page.title | striptags }} - {{ config.site_name }} - {% else %} - {{ config.site_name }} - {% endif %} - {% endblock %} - {% block styles %} - - {% if config.theme.palette %} - {% set palette = config.theme.palette %} - - {% endif %} - {% include "partials/icons.html" %} - {% endblock %} - {% block libs %} - {% for script in config.extra.polyfills %} - {{ script | script_tag }} - {% endfor %} - {% endblock %} - {% block fonts %} - {% if config.theme.font != false %} - {% set text = config.theme.font.text | d("Roboto", true) %} - {% set code = config.theme.font.code | d("Roboto Mono", true) %} - - - - {% endif %} - {% endblock %} - {% for path in config.extra_css %} - - {% endfor %} - {% include "partials/javascripts/base.html" %} - {% block analytics %} - {% include "partials/integrations/analytics.html" %} - {% endblock %} - {% block extrahead %}{% endblock %} - - {% set direction = config.theme.direction or lang.t("direction") %} - {% if config.theme.palette %} - {% set palette = config.theme.palette %} - {% if not palette is mapping %} - {% set palette = palette | first %} - {% endif %} - {% set scheme = palette.scheme | d("default", true) %} - {% set primary = palette.primary | d("indigo", true) %} - {% set accent = palette.accent | d("indigo", true) %} - - {% else %} - - {% endif %} - {% set features = config.theme.features or [] %} - - - -
- {% if page.toc | first is defined %} - {% set skip = page.toc | first %} - - {{ lang.t("action.skip") }} - - {% endif %} -
-
- {% if self.announce() %} - - {% endif %} -
- {% if config.extra.version %} - - {% endif %} - {% block header %} - {% include "partials/header.html" %} - {% endblock %} -
- {% block hero %}{% endblock %} - {% block tabs %} - {% if "navigation.tabs.sticky" not in features %} - {% if "navigation.tabs" in features %} - {% include "partials/tabs.html" %} - {% endif %} - {% endif %} - {% endblock %} -
-
- {% block site_nav %} - {% if nav %} - {% if page.meta and page.meta.hide %} - {% set hidden = "hidden" if "navigation" in page.meta.hide %} - {% endif %} - - {% endif %} - {% if "toc.integrate" not in features %} - {% if page.meta and page.meta.hide %} - {% set hidden = "hidden" if "toc" in page.meta.hide %} - {% endif %} - - {% endif %} - {% endblock %} - {% block container %} -
- {% if "navigation.path" in features %} - {% include "partials/path.html" %} - {% endif %} -
- {% block content %} - {% include "partials/content.html" %} - {% endblock %} -
-
- {% endblock %} - {% include "partials/javascripts/content.html" %} -
- {% if "navigation.top" in features %} - {% include "partials/top.html" %} - {% endif %} -
- {% block footer %} - {% include "partials/footer.html" %} - {% endblock %} -
-
-
-
- {% if "navigation.instant.progress" in features %} - {% include "partials/progress.html" %} - {% endif %} - {% if config.extra.consent %} - - {% include "partials/javascripts/consent.html" %} - {% endif %} - {% block config %} - {% set _ = namespace() %} - {% set _.annotate = config.extra.annotate %} - {% set _.tags = config.extra.tags %} - {%- if config.extra.version -%} - {%- set mike = config.plugins.mike -%} - {%- if not mike or mike.config.version_selector -%} - {%- set _.version = config.extra.version -%} - {%- endif -%} - {%- endif -%} - - {% endblock %} - {% block scripts %} - - {% for script in config.extra_javascript %} - {{ script | script_tag }} - {% endfor %} - {% endblock %} - - diff --git a/overrides/main.html b/overrides/main.html index f1ced90e..ede03840 100644 --- a/overrides/main.html +++ b/overrides/main.html @@ -1,2 +1,7 @@ -{# Tab icons are wired in overrides/base.html (site_meta block). #} {% extends "base.html" %} + +{% block site_meta %} + {{ super() }} + + +{% endblock %} diff --git a/scripts/check_html_links.py b/scripts/check_html_links.py index c5d0d6a4..d96afebb 100644 --- a/scripts/check_html_links.py +++ b/scripts/check_html_links.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -"""Verify that MkDocs-built HTML pages link only to existing locations +"""Verify that MkDocs-built HTML pages reference only existing locations in the rendered site. The landing page (docs/index.md → site/index.html) embeds raw HTML with -href attributes. MkDocs strict mode does not validate those links, so this -script walks each href and confirms the target resolves under site/. +links and media references. MkDocs strict mode does not validate those +targets, so this script walks each href/src and confirms the target resolves +under site/. Usage: python scripts/check_html_links.py [SITE_DIR] (default SITE_DIR is ./site, the output of `mkdocs build`) @@ -12,13 +13,24 @@ from __future__ import annotations -import re import sys +from html.parser import HTMLParser from pathlib import Path from urllib.parse import urldefrag, urlparse HTML_PAGES = ("index.html",) -HREF_RE = re.compile(r'href="([^"]+)"') +TARGET_ATTRS = {"href", "src"} + + +class TargetParser(HTMLParser): + def __init__(self) -> None: + super().__init__() + self.targets: list[str] = [] + + def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: + for name, value in attrs: + if name in TARGET_ATTRS and value: + self.targets.append(value) def is_external(href: str) -> bool: @@ -58,9 +70,9 @@ def main() -> int: if not path.exists(): errors.append(f"{page}: not present in {site}") continue - content = path.read_text(encoding="utf-8") - for match in HREF_RE.finditer(content): - href = match.group(1) + parser = TargetParser() + parser.feed(path.read_text(encoding="utf-8")) + for href in parser.targets: if is_external(href): continue ok, msg = resolve(path.parent, site, href)