"""Fail the docs build when a page's cross-references did not resolve. Zensical (0.0.48) stays green even under `--strict` on two failure modes MkDocs strict mode aborted on: - An unresolvable `[text][identifier]` cross-reference renders as literal bracket text (mkdocs-autorefs used to warn). The generated API index and the docstring cross-references rely on such references resolving. - A failed `objects.inv` inventory download is logged as an ERROR record and otherwise ignored, silently degrading every link through that inventory (thousands of standard-library links alone) to plain text. Both are caught from the built site itself, so no log-wording change can disarm the check: an unresolved reference leaves a tell-tale bracket sequence in prose text (code blocks legitimately contain `][`, e.g. dict indexing, so only text outside `
`/`` counts), and every inventory
declared in `mkdocs.yml` must contribute at least one resolved reference —
an `autorefs-external` anchor, which hand-authored prose links to the same
host never carry — to the site (an inventory that contributes none is dead
config and fails too).
Offline contributors can skip the inventory check by setting
`DOCS_ALLOW_INVENTORY_FAILURE=1`; CI (`CI=true`) never skips it.
Usage:
python scripts/docs/check_crossrefs.py --site-dir site
"""
from __future__ import annotations
import argparse
import os
import re
import sys
from html.parser import HTMLParser
from pathlib import Path
from urllib.parse import urlsplit
import yaml
ROOT = Path(__file__).parent.parent.parent
# Unresolved cross-reference tell-tales in extracted prose (`\x00` marks a
# skipped code element, see _ProseTextExtractor): the two-part
# `[text][identifier]` reconstruction — the identifier part is always plain
# text, so a code mark inside the second brackets means indexing prose like
# `data[`x`][`y`]`, not a reference — and the shortcut `[`identifier`]` form,
# which extracts as `[\x00]` unless a preceding word character or bracket
# makes it a subscript like `list[`str`]`.
_UNRESOLVED = re.compile(r"\]\[[^\]\s\x00]*\]|(?]*autorefs-external[^>]*>")
class _ProseTextExtractor(HTMLParser):
"""Collect text outside //