Lint Markdown internal links
Lint Markdown internal links
Use Remark. It’s the only linter I’m aware of that can check relative links across files.
I assume you already have node and npm installed. The versions I have currently are:
$ npm --version
7.19.1
$ node --version
v18.14.2
Use the following components:
- remark inspects and changes markdown via plugins.
- remarklint collects linting plugins for remark.
- remark-validate-links checks that markdown links and images point to existing local files and headings in a Git repo.
Basic Linting
A quickstart from the remarklint documentation.
Set up:
cd "$(mktemp --dir)"
npm install remark-cli remark-preset-lint-consistent remark-preset-lint-recommended
mkdir doc
cat > doc/example.md <<"EOF"
1) Hello, _Jupiter_ and *Neptune*!
EOF
npm exec -- remark doc/ --use remark-preset-lint-consistent --use remark-preset-lint-recommended
Output:
doc/example.md
1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint
1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint
1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint
⚠ 3 warnings
Structural integrity checking
Or relative link validation. A quick start from the remark-validate-links documentation.
npm install remark-validate-links
cat > doc/example-link.md <<"EOF"
# Alpha
Links are checked:
This [exists](#alpha).
This [one does not](#does-not).
# Bravo
Headings in `readme.md` are [checked](readme.md#no-such-heading).
And [missing files are reported](missing-example.js).
Definitions are also checked:
[alpha]: #alpha
[charlie]: #charlie
References w/o definitions are not checked: [delta]
EOF
# remark-validate-links fails unless it runs in a git repo with an origin remote.
# The README shows how avoid that by setting `options.repository`. I don't know
# how to set that via npm CLI.
git init .
git add remote origin localhost
npm exec -- remark doc/ --use remark-preset-lint-consistent --use remark-preset-lint-recommended --use remark-validate-links
Output:
doc/example-link.md
6:6-6:31 warning Link to unknown heading: `does-not` missing-heading remark-validate-links
10:29-10:65 warning Link to unknown file: `readme.md` missing-file remark-validate-links
10:29-10:65 warning Link to unknown heading in `readme.md`: `no-such-heading` missing-heading-in-file remark-validate-links
11:5-11:53 warning Link to unknown file: `missing-example.js` missing-file remark-validate-links
15:1-15:16 warning Found unused definition no-unused-definitions remark-lint
16:1-16:20 warning Found unused definition no-unused-definitions remark-lint
16:1-16:20 warning Link to unknown heading: `charlie` missing-heading remark-validate-links
18:45-18:52 warning Found reference to undefined definition no-undefined-references remark-lint
doc/example.md
1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint
1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint
1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint
⚠ 11 warnings
From here, it’s an exercise for the reader to integrate this into pre-commit and other development workflows.