はじめに
READMEやドキュメントのプルリクエストで、「見出しの前に空行を入れてください」「リストの記号は-に統一しましょう」といった指摘をしたり、されたりした経験はありませんか?
Markdownは自由度が高いフォーマットです。見出しひとつとっても# 見出しと見出し\n===の2通りの書き方があり、リストは-・*・+のどれでも動いてしまいます。だからこそ、複数人でドキュメントを書くと表記ゆれが必ず発生し、レビューの時間がスタイルの指摘に費やされてしまうのです。
コードの世界ではESLintやPrettierがこの問題を解決してくれました。同じことをMarkdownでやってくれるのが、今回紹介するmarkdownlintです。
Markdownlintとは
markdownlintは、Node.js製のMarkdown用スタイルチェッカー・リンターです。David Anson氏によって開発されており、CommonMark仕様に準拠したmicromarkパーサーをベースに、GitHub Flavored Markdown(GFM)や脚注、数式構文までサポートしています。
VS CodeのMarkdown拡張機能としても広く使われているため、「エディタで黄色い波線を見たことがある」という方も多いのではないでしょうか。その裏側で動いているのが、まさにこのライブラリです。
主な特徴
- 60以上のビルトインルール - MD001(見出しレベルは1段階ずつ増加)からMD060まで、見出し・リスト・空白・コードブロックなどを網羅的にチェックします
- 自動修正に対応 - 多くのルールが
--fixオプションによる自動修正をサポートしており、指摘を手作業で直す必要がありません - 柔軟な設定 - JSON/YAMLの設定ファイルでルールを個別にオン・オフでき、インラインコメントで一時的な無効化も可能です
- 豊富なエコシステム - CLI、VS Code拡張、GitHub Actions、pre-commitフックなど、ワークフローのどこにでも組み込めます
インストール
CLIとして使う場合は、後継として推奨されているmarkdownlint-cli2をインストールするのが現在の定番です。
# npm(プロジェクトの開発依存として)
npm install markdownlint-cli2 --save-dev
# グローバルインストール
npm install markdownlint-cli2 --global
# Homebrew
brew install markdownlint-cli2
# Docker
docker pull davidanson/markdownlint-cli2
ライブラリとしてNode.jsのコードから使う場合は、本体をインストールします。
npm install markdownlint --save-dev
基本的な使い方
CLIでチェックする
もっともシンプルな使い方は、globパターンでMarkdownファイルを指定するだけです。
# カレントディレクトリ以下のすべての.mdをチェック(node_modulesは除外)
npx markdownlint-cli2 "**/*.md" "#node_modules"
問題があると、次のようにファイル名・行番号・ルール名付きで報告されます。
README.md:12 MD022/blanks-around-headings Headings should be surrounded by blank lines
README.md:25:81 MD013/line-length Line length [Expected: 80; Actual: 95]
自動修正する
--fixを付けると、修正可能な問題を自動で直してくれます。末尾の空白や見出し前後の空行などは、これだけで一掃できます。
npx markdownlint-cli2 --fix "**/*.md" "#node_modules"
設定ファイルでルールを調整する
プロジェクトルートに.markdownlint.jsonを置くと、ルールをカスタマイズできます。
{
"default": true,
"MD013": { "line_length": 120 },
"MD033": false,
"no-hard-tabs": true
}
default: true- まずすべてのルールを有効にしますMD013- 1行の最大文字数を120文字に緩和しますMD033: false- インラインHTMLの禁止ルールを無効化します(HTMLを併用するドキュメントでは必須級の設定です)- ルールは
no-hard-tabsのようなエイリアス名でも指定できます
特定の箇所だけルールを外したいときは、インラインコメントが便利です。
<!-- markdownlint-disable-next-line MD013 -->
この行だけは、どうしても長くなってしまうので行長チェックを無効にします。
Node.js APIから使う
ドキュメント生成パイプラインに組み込みたい場合は、APIを直接呼び出せます。同期・非同期・Promiseの3つのスタイルが用意されています。
import { lint } from "markdownlint/promise";
const results = await lint({
files: ["README.md"],
config: {
default: true,
MD013: { line_length: 120 },
},
});
console.log(results.toString());
// => README.md: 12: MD022/blanks-around-headings ...
実践的なユースケース
npm scriptsに組み込む
チーム全員が同じコマンドでチェックできるよう、package.jsonにスクリプトを登録しておきましょう。
{
"scripts": {
"lint:md": "markdownlint-cli2 \"**/*.md\" \"#node_modules\"",
"lint:md:fix": "markdownlint-cli2 --fix \"**/*.md\" \"#node_modules\""
}
}
設定・対象ファイルを1か所にまとめる
markdownlint-cli2専用の設定ファイル.markdownlint-cli2.jsoncを使うと、ルール設定に加えて対象globや除外パターンまで一元管理できます。コメントが書けるJSONC形式なのも嬉しいポイントです。
{
// チェック対象
"globs": ["docs/**/*.md", "README.md"],
// 除外対象
"ignores": ["node_modules", "CHANGELOG.md"],
// ルール設定
"config": {
"default": true,
"MD013": false, // 日本語は行長チェックと相性が悪いので無効化
"MD033": false
}
}
これでコマンドはnpx markdownlint-cli2だけで済むようになります。
GitHub ActionsでCIに組み込む
公式のActionを使えば、プルリクエストのたびに自動チェックが走ります。
name: Lint Markdown
on:
pull_request:
paths:
- "**/*.md"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: markdownlint
uses: DavidAnson/markdownlint-cli2-action@v20
with:
globs: |
**/*.md
!node_modules
これで「スタイルの指摘はCIが、内容のレビューは人間が」という理想的な分担が実現します。
VS Codeでリアルタイムにチェックする
拡張機能「markdownlint」(DavidAnson.vscode-markdownlint)をインストールすると、編集中にリアルタイムで警告が表示されます。保存時に自動修正したい場合は、settings.jsonに次を追加します。
{
"editor.codeActionsOnSave": {
"source.fixAll.markdownlint": "explicit"
}
}
CLI・CI・エディタで同じ.markdownlint.jsonが参照されるため、設定を1つ書けばどこでも同じ基準でチェックされるのが気持ちいいところです。
まとめ
markdownlintを導入すると、次のことが実現できます。
- 60以上のルールでMarkdownの表記ゆれを自動検出できる
--fixオプションで大半の問題は手を動かさずに修正できる- 設定ファイル1つで、エディタ・CLI・CIすべてに同じ基準を適用できる
- レビューからスタイル指摘が消え、内容の議論に集中できる
コードにリンターを入れるのが当たり前になったように、ドキュメントにもリンターを入れるのはもはや自然な流れです。まずはnpx markdownlint-cli2 "**/*.md" "#node_modules"を手元のリポジトリで実行して、どれだけ指摘が出るか眺めてみてください。意外な発見があるはずです。