Skip to content

📚 DOCS: freeze the section_ref token shape and make its grammar normative - #169

Merged
chrisjsewell merged 7 commits into
masterfrom
maint/section-ref-api
Nov 10, 2026
Merged

chrisjsewell merged 7 commits into
masterfrom
maint/section-ref-api

Conversation

@chrisjsewell

Copy link
Copy Markdown
Member

Stacked on #168 (the nine-digit bound). Retarget to master once #168 merges.

The section_ref token becomes public API with 0.7.0. MyST-Parser reads it, and other implementations port the grammar
from this plugin, so this PR pins the token shape and states the grammar as rules before the tag.
There is no behaviour change.

  • Token shape: a new test asserts every field of the token:
    type="section_ref", nesting=0, children=None, tag="", attrs={}, markup="§",
    content as written ("§01.02") and meta={"numbers": [1, 2]}.
    The docstring says "The token shape is part of the public API from 0.7.0."
  • Normative grammar (the docstring is rendered through autofunction):
    • ASCII digits only;
    • 1 to 9 digits per level, with a maximal match;
    • a trailing . is not taken;
    • an ASCII letter after the match blocks it, but a non-ASCII letter does not;
    • an over-long level leaves the whole run literal;
    • no reference inside code spans, autolinks, inline math or raw HTML tags (text between two tags is inline text).
  • Escape wording corrected: the old text read as if \§ were a CommonMark escape. It is not, because § is not ASCII
    punctuation: the backslash stays visible and no reference forms. § and § give a literal sign.
  • Alt text: markdown-it-py's renderInlineAsText keeps only text tokens, so in plain HTML a reference disappears
    from image alt text, as inline math does. A renderer should use the token's content.
  • New fixture rows: non-ASCII digits (§١, §3), the two entities, an autolink, and raw HTML.

Checks run:

  • the full suite on CPython 3.12 and on PyPy 3.11;
  • pre-commit run --all-files;
  • sphinx-build -nW --keep-going -b html docs/.

Each new test was checked against a mutant of the behaviour it pins, and each one fails under its mutant.

`§` followed by more than 4300 digits made `int()` raise ValueError
(Python's integer string conversion limit), aborting the whole render.

A level longer than nine digits now makes the rule decline, so the text
renders literally and no shorter prefix is captured. Nine digits keeps
every number below 10**9 (a signed 32-bit int) and far below the
conversion limit, which cannot be configured below 640.
Drop the many-refs timing case: it goes through the valid-reference path
this change does not touch, and on PyPy it mostly measures markdown-it-py's
renderer, whose string concatenation is quadratic there (it failed the 1s
budget, and took about 3s with --cov).

Raise the budget to 3s, which still catches a quadratic scan (tens of
seconds at 200k characters), and drop the redundant timeout marker
(pyproject.toml already sets timeout = 10).

Say in the docstring that leading zeros count towards the nine digits.
The budget catches a scan that does Python-level work per character, or
a backtracking regex. A quadratic scan built from string slices can
still pass it, so the docstring no longer claims every quadratic scan
would take tens of seconds.
Assert every field of the section_ref token (type, nesting, children, tag,
attrs, markup, content and meta) in one test, and say in the plugin
docstring that the token shape is part of the public API from 0.7.0.
State the grammar in the plugin docstring as rules: ASCII digits only,
the ASCII-letter look-ahead (a non-ASCII letter does not block a match),
no trailing dot, the nine-digit bound, the contexts where no reference
forms, and that \§ is not a backslash escape (the backslash stays
visible), with § and § giving a literal sign.

Pin the statements the fixtures did not cover yet with fixture rows:
non-ASCII digits, the two entities, an autolink and raw HTML.

Note that markdown-it-py's renderInlineAsText keeps only text tokens, so
a renderer that wants the reference in image alt text should use the
section_ref token's content.
@codecov

codecov Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.66%. Comparing base (d11bdaf) to head (ae0dab4).
⚠️ Report is 34 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #169      +/-   ##
==========================================
+ Coverage   92.80%   94.66%   +1.86%     
==========================================
  Files          31       40       +9     
  Lines        1835     2325     +490     
==========================================
+ Hits         1703     2201     +498     
+ Misses        132      124       -8     
Flag Coverage Δ
pytests 94.66% <ø> (+1.86%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Base automatically changed from maint/section-ref-digit-limit to master November 10, 2026 14:17
@chrisjsewell
chrisjsewell merged commit 89b1977 into master Nov 10, 2026
12 of 13 checks passed
@chrisjsewell
chrisjsewell deleted the maint/section-ref-api branch November 10, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant