Repository navigation
feat(md): render Markdown footnotes via markdown-it-footnote - #243
Conversation
Register `markdown-it-footnote` in the `@void/md` compiler so `text[^1]` references and `[^1]: definition` blocks render into a linked footnote list. Three changes in the compiler: - Import `markdown-it-footnote` and register it after the emoji plugin and before the anchor plugin, so footnote back-reference markers are not themselves treated as heading-anchor targets. - Give each markdown-it call its OWN fresh env in `compile()`. Previously `parse` and `renderAsync` shared one `env` object; because markdown-exit's `renderAsync` re-parses internally, footnote state accumulated into the same `env.footnotes` twice — producing duplicated footnote lists and wrong fn/fnref ids. A fresh env per call keeps the two parses independent, and heading/TOC extraction is unaffected (anchor ids derive per-parse from the identical content, not from shared env state). - markdown-it-footnote@4 ships no types, so add an ambient module shim in `env.d.ts` matching the existing attrs/emoji/container shims (no `@types` dependency needed). Verified: `@void/md` build + typecheck + lint pass; all 87 package tests pass, including new tests asserting a footnote renders exactly once (single fn1/fnref1/footnotes block) and that headings/TOC are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_89979c57-e635-481f-805d-aed205d4bb9f) |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cca4c69a03
ℹ️ 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".
The metadata compiler (extractMetadata) installed only markdown-it-anchor, so a footnote ref in a heading such as `## API[^1]` stayed literal there while compile() (which does install footnote) strips it. That produced a different slug/text in `@void/md/pages` than the rendered anchor id, so sidebar/TOC/search links pointed at a missing anchor. Register footnote before anchor to mirror compile.ts, keeping metadata heading slugs in sync with rendered ids. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_ddf3a0c4-1da3-4071-aa3c-c46915e03fe0) |
* fix(dispatch): harden static asset storage failures * fix(dispatch): address asset fallback review * fix(dispatch): preserve pre-stub timeout attribution
What
Adds
markdown-it-footnotesupport to@void/mdso Markdown footnotes render:This upstreams a yarn patch we currently apply downstream against
@void/md.Why
@void/mdpreviously had no footnote plugin, so[^1]refs/definitions passed through as literal text.A subtle second bug blocked a naive add:
compile()shared oneenvobject acrosscompiler.parse()andcompiler.renderAsync(). Becausemarkdown-exit'srenderAsync(src, env)re-parses internally (this.renderer.renderAsync(this.parse(src, env), …)), a stateful plugin like footnote would append its refs/definitions to the sameenv.footnotestwice — producing duplicated footnote lists and wrongfn/fnrefids.How
Three edits in
packages/md/src/compile.ts:import footnote from 'markdown-it-footnote'.markdown.use(footnote)— registered after the emojifullplugin and beforeanchor, so footnote back-reference markers aren't treated as heading-anchor targets.env(compiler.parse(content, {})/compiler.renderAsync(content, {})) instead of a shared object, fixing the double-accumulation. Heading/TOC extraction is unaffected — anchor ids derive per-parse from the identical content, not from shared env state.Supporting changes:
markdown-it-footnote@^4.0.0added to@void/mddependencies (minimal lockfile addition).src/env.d.tsmatching the existingmarkdown-it-attrs/emoji/containershims — no@typesdevDependency needed.packages/md/README.mdfeature list +docs/guide/pages-routing/markdown.mdFootnotes section).Verified
vp run --filter ./packages/md build— passesvp run --filter ./packages/md typecheck— passesvp lint packages/md— 0 warnings/errorsvp test run packages/md— 87 passed (10 files), including 2 new tests:fn1/fnref1/class="footnotes"/footnote-item)slug: 'section',id="section"present)🤖 Generated with Claude Code
Note
Low Risk
Scoped markdown rendering and metadata changes with targeted unit tests; no auth, security, or data-path impact.
Overview
Adds footnote rendering to
@void/mdviamarkdown-it-footnote([^1]refs and definitions → linked footnote list), with docs in the guide and package README.Fixes a compile pipeline bug where one shared markdown-it
envwas passed to bothparse()andrenderAsync(); becauserenderAsyncre-parses internally, stateful plugins (footnotes) would double-accumulate. Each call now uses a fresh{}env.Aligns lightweight metadata extraction with full compile: footnotes register before heading anchors so footnote markers in headings are stripped from
@void/md/pagesheading text/slugs and match rendered anchor ids. Type shim added for the untyped plugin dependency.Reviewed by Cursor Bugbot for commit c5f62f9. Bugbot is set up for automated code reviews on this repo. Configure here.