repomatic.site_anchors module

Same-page fragment links, checked against the anchors the build produced.

A literal ](#fragment) is the one cross-reference nothing resolves. A :ref: or :doc: role goes through Sphinx, which reports a missing target under nitpicky; a raw fragment is copied into the HTML untouched, so a slug that never existed ships as a link that looks fine and lands nowhere. The build stays green because it was never asked a question.

Caution

A Markdown link checker cannot stand in for this, because it has to guess the slug. Measured against lychee 0.24.2 on the heading ## The pages.dev hostname`: myst-parser builds``the-pages-dev-hostname`, lychee’s GitHub-style slugger wants the-pagesdev-hostname, and each reports the other as broken. That disagreement is why this repository excludes intra-docs fragments from lychee altogether, which left the class with no coverage at all until a #the-pagesdev-hostname link shipped against a the-pages-dev-hostname anchor.

The built page is the only authority, so that is what this reads. Fragments come from the Markdown source rather than from the rendered HTML, which is what keeps the check to what an author actually wrote: a theme’s own footnote backrefs and header permalinks never enter, so there is no denylist to keep.

repomatic.site_anchors.ANCHOR_ATTRIBUTES = frozenset({'id', 'name'})

HTML attributes a browser will scroll a fragment to.

repomatic.site_anchors.DEFAULT_BUILD_DIR = PosixPath('docs/_build')

Where the Sphinx builders in this project’s workflows write the site.

repomatic.site_anchors.DEFAULT_DOCS_DIR = PosixPath('docs')

Conventional root of a Sphinx source tree.

repomatic.site_anchors.FENCE_RE = re.compile('^\\s*(?:`{3,}|~{3,})')

Opening or closing line of a fenced code block.

An authored same-page link, ](#fragment).

Anchored on the ](# sequence, which is what makes it same-page: a link to another document carries a path before its # and is Sphinx’s problem, not this one.

repomatic.site_anchors.INLINE_CODE_RE = re.compile('(?P<ticks>`+)(?:.|\\n)*?(?P=ticks)')

An inline code span, of any backtick width.

repomatic.site_anchors.MARKDOWN_SUFFIX = '.md'

Extension of the sources scanned for authored links.

class repomatic.site_anchors.MissingAnchor(source, fragment, page)[source]

Bases: object

One authored fragment with no anchor to land on.

source: Path

Markdown file that wrote the link.

fragment: str

The fragment as authored, without its #.

page: Path

Built page the fragment was looked for in.

property message: str

The finding as a single reportable line.

class repomatic.site_anchors.AnchorReport(missing=<factory>, unbuilt=<factory>, checked=0)[source]

Bases: object

What one sweep over a docs tree found.

missing: list[MissingAnchor]

Every authored fragment that resolves to nothing.

unbuilt: list[Path]

Sources with no built page, so with nothing to check against.

A page left out of every toctree, or a fragment file meant only to be included by another, lands here. Reported rather than failed: the build is what decides which sources become pages, and it is not this check’s place to second-guess it.

checked: int = 0

How many authored fragments were resolved against a built page.

repomatic.site_anchors.page_anchors(html)[source]

Every fragment a built page can be scrolled to.

Parameters:

html (str) – Full source of one built page.

Return type:

set[str]

Returns:

The id and name values it carries.

repomatic.site_anchors.strip_code(text)[source]

Blank out every code span and fenced block of a Markdown source.

A fence showing ](#example) documents a link rather than making one, and checking it would fail a page for its own example. Lines are replaced rather than deleted so a reported line number still points at the source.

Parameters:

text (str) – Markdown source.

Return type:

str

Returns:

The same text with code content emptied.

repomatic.site_anchors.authored_fragments(text)[source]

Every same-page fragment a Markdown source links to.

Parameters:

text (str) – Markdown source.

Return type:

list[str]

Returns:

Fragments without their #, in source order, duplicates kept out.

repomatic.site_anchors.built_page(source, docs_dir, build_dir)[source]

Locate the page a Markdown source was rendered into.

Both Sphinx HTML builders are covered by trying each layout in turn: html writes {name}.html, dirhtml writes {name}/index.html. Probing rather than reading [tool.repomatic] sphinx.builder keeps the check honest about the tree in front of it, and correct for a caller pointed at a directory some other builder wrote.

Parameters:
  • source (Path) – The Markdown file.

  • docs_dir (Path) – Root the source tree is relative to.

  • build_dir (Path) – Root of the rendered site.

Return type:

Path | None

Returns:

The built page, or None when the source produced none.

repomatic.site_anchors.markdown_sources(docs_dir, build_dir)[source]

Every authored Markdown source under a docs tree.

Skips the rendered site, which commonly sits inside the source tree, and every underscore-prefixed directory, Sphinx’s own convention for the static and template folders that hold no authored prose.

Parameters:
  • docs_dir (Path) – Root of the documentation sources.

  • build_dir (Path) – Root of the rendered site, excluded when nested.

Return type:

Iterator[Path]

Returns:

The sources, in path order.

repomatic.site_anchors.check_anchors(docs_dir, build_dir)[source]

Resolve every authored fragment against the page it was built into.

Parameters:
  • docs_dir (Path) – Root of the documentation sources.

  • build_dir (Path) – Root of the rendered site.

Return type:

AnchorReport

Returns:

What the sweep found.