ci: validate internal documentation anchors - #784
Conversation
Several internal links pointed to anchors that do not exist on their target pages, so they landed at the top of the page instead of the intended section. Most were headings that had since been renamed — for example "Handling ETH Balance Checks" became "Handling ETH (Native Token) Balance Checks", and "Rebalance liquidity" became "Rebalance pools". Point each link at the anchor that actually exists. Link text and surrounding prose are unchanged.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
15d2d36 to
4959c9e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4959c9eaec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const slugger = new GithubSlugger() | ||
| const anchors = new Set<string>() | ||
| for (const event of eventsByRoute.get(page.route) ?? []) { | ||
| if (event.type === 'heading') anchors.add(headingAnchor(event.text, slugger)) |
There was a problem hiding this comment.
Parse explicit heading anchors before slugging
When a page follows the prescribed rename pattern ## Tempo API pagination modes {#modes}, nodeText includes {#modes} in the heading text and the checker records a generated slug such as tempo-api-pagination-modes-modes instead of the explicit modes ID. A preserved link to #modes then fails the required Verify workflow even though the heading deliberately retains that deep link; extract explicit heading IDs rather than passing the suffix to GithubSlugger.
AGENTS.md reference: AGENTS.md:L66-L70
Useful? React with 👍 / 👎.
| } | ||
|
|
||
| function targetFor(href: string, page: Page): { route: string; fragment: string } | undefined { | ||
| if (/^(?:https?:|mailto:|tel:)/.test(href)) return |
There was a problem hiding this comment.
Validate canonical absolute documentation links
For canonical links such as https://tempo.xyz/developers/docs/...#fragment, this early return classifies the URL as external before the existing /developers/docs normalization can run. The repository already has these internal fragment links in src/pages/docs/protocol/tips/tip-1020.mdx and src/pages/docs/protocol/tip20/spec.mdx, so a target heading can be renamed and leave them stale without this required check reporting anything; recognize the canonical docs origin and normalize its mount before filtering external URLs.
AGENTS.md reference: AGENTS.md:L7-L10
Useful? React with 👍 / 👎.
| import path from 'node:path' | ||
| import { checkInternalAnchors } from '../src/lib/internal-anchor-links.ts' | ||
|
|
||
| const result = checkInternalAnchors(path.resolve('src/pages')) |
There was a problem hiding this comment.
Include redirect fragments in anchor validation
Because the command passes only src/pages to the checker, fragment-bearing redirect destinations in src/lib/docs-routing.ts and vocs.config.ts never become link events. Existing mappings such as docs-routing.ts:30 and vocs.config.ts:1281 can therefore point at a renamed heading indefinitely while this required check passes, silently breaking the legacy deep links those redirects preserve; include redirect destinations in the anchor candidates and validate their fragments against the canonical pages.
AGENTS.md reference: AGENTS.md:L9-L10
Useful? React with 👍 / 👎.
| if (!fs.existsSync(importedFile)) { | ||
| throw new Error(`${file}:${line} imports missing Markdown file ${importedFile}`) | ||
| } | ||
| events.push(...sourceEvents(importedFile, [...stack, file])) |
There was a problem hiding this comment.
Reset slug generation at imported MDX boundaries
Imported .mdx files compile as separate modules, so Vocs' heading slugger resets for each file, but flattening imported events here makes the checker slug every heading in one host-page sequence. If a host page and its imported snippet both contain ## Setup, the rendered DOM has two id="setup" headings, while this checker invents setup-1 for the snippet and incorrectly accepts a link to that nonexistent fragment; preserve a separate slugger scope for each compiled MDX file when expanding shared snippets.
AGENTS.md reference: AGENTS.md:L20-L22
Useful? React with 👍 / 👎.
Motivation
Internal documentation links can target headings that no longer exist because Vocs validates the target page but not its fragment.
Supersedes #743 while preserving the original contributor's link fixes and commit attribution.
Summary
href/toattributesKey design considerations