Skip to content

✨ sphinx-codelinks: a reference marker can name its own field, and markers match whole words - #2499

Merged
chrisjsewell merged 12 commits into
masterfrom
claude/lucid-hawking-pa89x2-doxygen
Nov 7, 2026
Merged

chrisjsewell merged 12 commits into
masterfrom
claude/lucid-hawking-pa89x2-doxygen

Conversation

@chrisjsewell

@chrisjsewell chrisjsewell commented Nov 7, 2026 •

Copy link
Copy Markdown
Member

What

packages/sphinx-codelinks: a need-ID reference marker can name the field its references go to.
An entry of analyse.need_id_refs.markers is a string, as before (its references go to the project's ref_url_field),
or a table { marker = "\\satisfies", field = "impl_url" } (a dict in conf.py).
So one source tree fills impl_url and test_url on the requirements it references;
field = "" attaches a marker's references nowhere (codelinks analyse still lists them).

[codelinks.projects.app.analyse.need_id_refs]
markers = [
  "@need-ids:",
  { marker = "\\satisfies", field = "impl_url" },
  { marker = "\\verifies", field = "test_url" },
]

Configuration checks, one helper for ref_url_field and every table field, applied where the field can be written
(URL generation on, and the field used: ref_url_field while a plain-string marker exists, or a non-empty table field):
not a URL field, not a need link type, and not the back links of one (verifies_back).
A marker listed twice, in any form, is refused.
Two behaviour changes follow, both in the changelog:
a ref_url_field naming a link type was accepted and is now an error;
a field named after a declared link type's back links used to switch that link type off with warnings only, and is now an error that leaves the link type intact.
One check is relaxed: a ref_url_field equal to a URL field in a project that writes no reference (no plain marker, or URLs off) now loads.

Marker matching. With a field per marker, the old matching misattributed, so it is fixed:

  • a marker's ids end at the next marker on the line: \satisfies REQ_1 \verifies REQ_2 gave \satisfies the ids REQ_1, \verifies, REQ_2, so REQ_2 landed in both fields;
  • a marker ending in a letter, digit or _ matches only where no letter, digit or _ follows: with marker \verifies, \verifiesall REQ_2 gave a reference to all;
  • where several markers match at one position the longest wins, and every match counts (the same marker twice on a line yields both);
  • a letter or digit is any Unicode letter or number (general category L* or N*), or _; the same rule decides the existing reference-line test (nothing alphanumeric before the line's first match).

A line extracts as before when exactly one configured marker occurs in its text, once, and that marker does not end in a letter, digit or _ that a letter, digit or _ directly follows.
Every existing extraction snapshot is unchanged; ten cases are added to the shared corpus tests/data/extraction/need_refs.yaml.
env_version goes from 3 to 4, so the first build after upgrading re-reads every document rather than keep references the old rule extracted.

Docs: the table form and the field checks in components/configuration.rst; "How a marker is found" and a short "Coming from Doxygen" recipe (markers for \satisfies / \verifies, URL generation on, start_sequence = "@@" so a Doxygen @param a, b line is not a one-line need, and what the recipe does not do) in components/analyse.rst; the changelog under Unreleased.

Why

Teams moving from Doxygen write \satisfies and \verifies on documented entities.
They want "where is REQ_1 implemented" and "where is it tested" as two fields on the requirement, and a filter for the requirements no test verifies (type == "req" and not test_url).
Today every marker of a project writes the one ref_url_field, so the only route was two projects over the same tree.
The shared extraction corpus keeps another implementation of the same rules in agreement.

Tests

  • tests/test_need_id_refs_matching.py: every clause of the matching rule (the boundary with _, ASCII and non-ASCII digits and letters, a circled letter or combining mark that is not one, punctuation; the longest marker in either configuration order; no overlap; ids ending at the next match; */ removed from the last segment only; the same marker twice; the reference-line test), and that a one-occurrence line extracts as the old rule did.
  • Ten shared corpus cases with their snapshots (need_refs-two_markers_one_line, -same_marker_twice, -marker_word_boundary, -longest_marker_wins, -longest_marker_wins_at_one_position, -two_markers_block_comment_end, -marker_ends_in_punctuation, -other_alphabetic_after_marker, -second_match_after_multibyte, -digit_after_marker).
  • tests/test_need_id_refs_marker_fields.py: string, table and mixed forms; malformed tables; field = ""; duplicates in three forms; a field equal to the URL fields, naming a link type, or naming a link type's back links (with ref_url_field too); where the checks apply (URLs off, tables only, local URLs only); field registration.
  • tests/test_need_id_refs_marker_fields_build.py: Sphinx builds filling impl_url and test_url from one tree beside a plain marker going to ref_url_field; field = "" making no record; the conf.py dict form; an incremental build moving a reference from impl_url to test_url; a declared verifies link staying intact next to a verifies_back field; an environment pickled at env_version 3 being discarded.
  • Mutations, each reverted: a table's field ignored, field = "" attaching, the duplicate check off, the link-type check off, ids to the end of the line, no word boundary, the first marker winning over the longest, one match per marker, byte columns for a second match, the checks applied unconditionally, digits not word characters, the back-link refusal off: each turns at least one test red.

Checklist

  • I wrote this change myself and have read every line of it; it was not generated automatically from an issue.
  • I ran the package's tests (uv run poe test-<package>) and they pass. uv run poe test-codelinks -n 4: 2133 passed, 3 skipped (permission checks that do not apply as root).
  • Documentation is updated where behaviour or options change. components/configuration.rst and components/analyse.rst; uv run poe docs-codelinks succeeds.
  • The package's docs/changelog.rst has an entry under Unreleased. A ✨ entry for the field per marker and a 🐛 entry for the matching, each naming its behaviour changes.
  • uv run poe lint and uv run poe typecheck pass. Both exit 0.

…s entries are a string or a { marker, field } table
…f a marker's boundary and for every match's columns
…rn URLs on in the Doxygen recipe, and say exactly which lines extract as before
…at the word characters follow the running Python's Unicode tables
@github-actions github-actions Bot added the pkg: sphinx-codelinks Concerns the sphinx-codelinks package (packages/sphinx-codelinks) label Nov 7, 2026
@codecov

codecov Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.56098% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.03%. Comparing base (cf01110) to head (2561a4a).

Files with missing lines Patch % Lines
...es/sphinx-codelinks/src/sphinx_codelinks/config.py 96.84% 3 Missing ⚠️
.../sphinx_codelinks/sphinx_extension/need_id_refs.py 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2499      +/-   ##
==========================================
+ Coverage   95.00%   95.03%   +0.03%     
==========================================
  Files         158      158              
  Lines       30357    30471     +114     
==========================================
+ Hits        28840    28959     +119     
+ Misses       1517     1512       -5     
Flag Coverage Δ
ai-index 100.00% <ø> (ø)
codelinks 95.91% <97.56%> (+0.17%) ⬆️
mounts 94.40% <ø> (ø)
pytests 94.88% <ø> (ø)
reports 97.02% <ø> (ø)
ub-directives 95.75% <ø> (ø)
ub-test-reports 91.14% <ø> (ø)

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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@chrisjsewell
chrisjsewell merged commit e2b38c0 into master Nov 7, 2026
48 checks passed
@chrisjsewell
chrisjsewell deleted the claude/lucid-hawking-pa89x2-doxygen branch November 7, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: sphinx-codelinks Concerns the sphinx-codelinks package (packages/sphinx-codelinks)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant