| id | 107 |
|---|---|
| title | No reference-style links rule |
| status | ✅ |
| summary | New rule MDS043 that forbids reference-style links and footnotes. These constructs require global definition resolution, moving Markdown from a context-free to a context-sensitive grammar — the "Exhibit D" complaint in the bgslabs.org rant. |
| model | opus |
Let users forbid the link forms whose meaning depends
on declarations elsewhere in the document. Inline
links ([text](url)) are fully local. Reference
links ([text][id] plus [id]: url) and footnotes
([^n] plus [^n]: ...) require a global pass over
the file to resolve. Forbidding them keeps every link
diff readable in isolation and removes one of the two
cases that pushes Markdown grammar above context-free.
- Inline links →
*ast.Linkwith non-nilDestinationon the node itself. - Reference links → also
*ast.Link, but resolved viaparser.Referencethat goldmark stores in the document context. The original source uses the[text][id]shape. - Reference definitions → not an AST node by default; they are consumed during parsing and never appear in the tree.
- Footnotes →
*ast.Footnoteand*ast.FootnoteReference, available only when the footnote extension is enabled.
The check must inspect the source, not just the
AST. Goldmark resolves inline links and reference
links to the same *ast.Link node. The original
shape — [text](url) vs [text][id] vs [text][]
— is recoverable only from the source bytes.
MDS034 (markdown-flavor) flags footnotes as a flavor
extension. MDS043 forbids them even on flavors that
support them, because the grammar concern is
independent of the renderer concern. The two rules
can be enabled together; MDS034 fires when the flavor
is commonmark and the file uses footnotes, MDS043
fires when the policy forbids footnotes regardless
of flavor.
rules:
no-reference-style:
allow-footnotes: false # opt back in if neededCategory: link. Disabled by default (opt-in).
When allow-footnotes: true, footnote references
are accepted under two constraints. The reference
must use the [^slug] shape with a meaningful slug.
The definition must sit immediately after the
referencing paragraph. Numeric [^1] is rejected
because the number carries no anchor.
Plan 112 ships profiles that auto-enable this rule:
profile: portableactivates withallow-footnotes: false.profile: githubdoes not activate this rule.profile: plainactivates withallow-footnotes: false.
User overrides on top of the profile still win via deep-merge.
Walk *ast.Link nodes. For each link, read the
source bytes between the closing ] and the next
non-whitespace character:
(→ inline link, accept.[→ reference or collapsed reference, flag asreference-style link.- nothing → shortcut reference (
[text]alone), flag asreference-style link.
Walk *ast.FootnoteReference. When allow-footnotes
is false, flag every occurrence. When true, validate
the slug format and the definition placement.
Reference definitions ([id]: url) emit a
diagnostic of their own when no inline-style link
in the file uses the id, since they are dead code.
When the file has reference-style links, the link
diagnostics already cover the issue and the
definition is left alone.
Reference-style → inline: substitute the resolved URL into the link, drop the definition. Possible when goldmark already resolved the reference.
Footnote → inline: not auto-fixed. The footnote text
is meant to be visually separated; turning it into
(...) parentheticals changes the document.
reference-style link; use inline form [text](url)
footnote reference; footnotes are not allowed
footnote slug is numeric; use a meaningful slug
unused reference definition: [{id}]
- Scaffold
internal/rules/noreferencestyle/. - Implement source-aware link form detection.
- Implement footnote checks gated on
allow-footnotes. - Implement unused-definition detection.
- Implement inline-rewrite auto-fix for reference-style links only.
- Register as MDS043 in category
link. - Add fixture tests covering inline, full
reference, collapsed reference, shortcut
reference, footnote (with and without
allow-footnotes), unused definition, and numeric footnote slug. - Add rule README.
-
[text](url)emits no diagnostic. -
[text][id]plus[id]: urlemits one diagnostic per link occurrence and fixes to[text](url). -
[text][]collapsed reference emits one diagnostic. -
[text]shortcut reference (with matching definition) emits one diagnostic. -
[^1]withallow-footnotes: falseemits one diagnostic. -
[^1]withallow-footnotes: trueemits one diagnostic for numeric slug. -
[^slug]withallow-footnotes: trueand definition right after the paragraph emits no diagnostic. -
[id]: urlwith no link referencing it emits one diagnostic. - Rule is disabled by default.
- All tests pass:
go test ./... -
go tool golangci-lint runreports no issues