Repository navigation
Commit eaf079b
feat(md): render Markdown footnotes via markdown-it-footnote (#243)
## What
Adds `markdown-it-footnote` support to `@void/md` so Markdown footnotes
render:
```md
Here is a statement.[^1]
[^1]: And here is the footnote body.
```
This upstreams a yarn patch we currently apply downstream against
`@void/md`.
## Why
`@void/md` previously had no footnote plugin, so `[^1]` refs/definitions
passed through as literal text.
A subtle second bug blocked a naive add: `compile()` shared **one**
`env` object across `compiler.parse()` and `compiler.renderAsync()`.
Because `markdown-exit`'s `renderAsync(src, env)` re-parses internally
(`this.renderer.renderAsync(this.parse(src, env), …)`), a stateful
plugin like footnote would append its refs/definitions to the same
`env.footnotes` **twice** — producing duplicated footnote lists and
wrong `fn`/`fnref` ids.
## How
Three edits in `packages/md/src/compile.ts`:
1. `import footnote from 'markdown-it-footnote'`.
2. `markdown.use(footnote)` — registered **after** the emoji `full`
plugin and **before** `anchor`, so footnote back-reference markers
aren't treated as heading-anchor targets.
3. Give each markdown-it call its **own fresh `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.0` added to `@void/md` dependencies
(minimal lockfile addition).
- v4 ships **no** types, so an ambient module shim was added to
`src/env.d.ts` matching the existing
`markdown-it-attrs`/`emoji`/`container` shims — no `@types`
devDependency needed.
- Docs updated (`packages/md/README.md` feature list +
`docs/guide/pages-routing/markdown.md` Footnotes section).
> Note: this repo releases via `v*` git tags (no changesets), so no
changeset was added.
## Verified
- `vp run --filter ./packages/md build` — passes
- `vp run --filter ./packages/md typecheck` — passes
- `vp lint packages/md` — 0 warnings/errors
- `vp test run packages/md` — **87 passed** (10 files), including 2 new
tests:
- a footnote renders **exactly once** (single
`fn1`/`fnref1`/`class="footnotes"`/`footnote-item`)
- headings/TOC intact alongside footnotes (`slug: 'section'`,
`id="section"` present)
- Render proof (throwaway, since deleted) confirmed the exact output:
```html
<p>Ref here.<sup class="footnote-ref"><a href="#fn1"
id="fnref1">[1]</a></sup></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>The footnote body. <a
href="#fnref1" class="footnote-backref">↩︎</a></p>
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!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/md` via `markdown-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 `env`
was passed to both `parse()` and `renderAsync()`; because `renderAsync`
re-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/pages` heading text/slugs and match
rendered anchor ids. Type shim added for the untyped plugin dependency.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c5f62f9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent 83307db commit eaf079b
9 files changed
Lines changed: 99 additions & 4 deletions
File tree
- docs/guide/pages-routing
- packages/md
- src
- test/unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
437 | 437 | | |
438 | 438 | | |
439 | 439 | | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
440 | 452 | | |
441 | 453 | | |
442 | 454 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
115 | 115 | | |
116 | 116 | | |
117 | 117 | | |
| 118 | + | |
118 | 119 | | |
119 | 120 | | |
120 | 121 | | |
| |||
143 | 144 | | |
144 | 145 | | |
145 | 146 | | |
146 | | - | |
| 147 | + | |
147 | 148 | | |
148 | 149 | | |
149 | 150 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
137 | 138 | | |
138 | 139 | | |
139 | 140 | | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
140 | 146 | | |
141 | 147 | | |
142 | 148 | | |
| |||
173 | 179 | | |
174 | 180 | | |
175 | 181 | | |
176 | | - | |
177 | | - | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
178 | 190 | | |
179 | | - | |
| 191 | + | |
180 | 192 | | |
181 | 193 | | |
182 | 194 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
15 | 20 | | |
16 | 21 | | |
17 | 22 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
14 | 21 | | |
15 | 22 | | |
16 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
90 | 111 | | |
91 | 112 | | |
92 | 113 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments