検証
blume validate はコンテンツ内のすべてのリンク(ページ、アンカー、アセット、オプションで外部 URL)をチェックし、壊れたリンクがあれば CI を失敗させます。
blume validate はビルドと同じ方法でコンテンツを読み込み、見つかったすべてのリンクをチェックします。何も生成・ビルドしないため、blume build の前に置く高速なゲートとして使えます。
blume validate
- 内部ページリンク(
/guides/intro、./sibling)は、実在するページに解決される必要があります。壊れたリンクはエラーとして報告されます。Markdown と MDX がレンダリングするすべての形式のリンクが読み取られます。対象は、インラインリンク(ラベルが次の行に折り返されているものを含む)、[label]: /targetの定義の位置でチェックされる参照スタイルのリンク(同じラベルが 2 回定義されている場合は、実際にレンダリングされる最初の定義)、自動リンク(.md内の<https://…>)、コンポーネントの文字列のhref(<Card href="./install">)です。コンテンツ内の Markdown ファイルへのルート相対リンク(/guides/setup.md)は、ビルド時にリンク先がそのファイルの公開ページに向けられるため、そのページに対してチェックされます。その場所にファイルが存在しない場合は、ページの Markdown コピーとしてチェックされます。リンク先はレンダラーと同じ方法で読み取られます。そのため、[x](<https://example.com/a(b>)はhttps://example.com/a(bを、.png)はimage(1).pngを指します。リンク先の前後に空白があっても、後ろにいずれかの引用符("…"、'…'、(…))で囲んだタイトルが続いていても同様です。コード内(ブロック引用内のフェンスを含むフェンスコードブロック、またはインラインコード)やコメント内(.mdの<!-- … -->、.mdxの{/* … */})のリンクはレンダリングされないため、チェックされません。ページへの小文字の HTML<a href>は書かれたとおりに出力されるため、ブラウザーが読むのと同じ方法でチェックされます。相対パスはページの URL を基準に解決され、basePathは付加されません(ルート相対パスには、他のすべてのリンクと同様にデプロイのbaseが付加されます)。href={…}式はチェックされません。 - アンカーリンク(
#section、/guides/intro#setup)は、リンク先ページのアンカーと一致する必要があります。アンカーとは、見出しの id(自動生成されたもの、または固定したもの)、生の HTML 要素のid属性、または<a name>のことです。一致しないものは警告として報告されます。コードブロック、インラインコード、HTML コメント、<Prompt>ブロック内の id は対象外です。 - その他のリンクスキーム(
mailto:、tel:、アプリのvscode:ディープリンク)はチェックされません。読者のブラウザーやインストール済みのアプリがそのリンクを処理できるかどうかは判断できないためです。ただし、ReadMe 独自のリンクスキームは例外です。doc:、ref:、page:、changelog:、blog:は ReadMe 上でしか解決されず、それ以外の場所ではリンク切れとして出力されるため、それぞれ警告として報告されます。代わりにページのパスでリンクしてください。 - アセットリンクは、ファイルの置き場所に応じてチェックされます。絶対パス(
/logo.png)はpublic/ディレクトリを基準に、相対パスの画像埋め込み(、またはカードの<Card img="./cover.png">)はそのページ自身のフォルダーを基準にチェックされます。その他のファイルへの相対リンク([spec](./spec.pdf)、<a href>、コンポーネントのhref)も、そのページ自身のフォルダーを基準にチェックされます。Blume はそのファイルをページと一緒にその場所に公開するためです。ページと同じフォルダーにファイルが存在しない場合は、サイトのルートとしてpublic/を基準に解決されます。メディア要素のsrc(.md内の生の HTML、または.mdx内の要素としての<img>、<source>、<video>、<audio>)も同じ方法でチェックされます。相対パスの場合はまずページと同じフォルダーで探され、見つからなければブラウザーがリクエストする場所としてpublic/を基準に探されます。public/フォルダーがないプロジェクトは公開ファイルを出力しないため、そのようなプロジェクトでは絶対パスのアセットは存在しないものとして報告されます。.htmlリンク(./setup.html、/guides/setup.html)もファイルリンクとして扱われます。Blume はページをそのルートで配信し、.htmlの URL では配信しません。そのため、public/にそのファイルがない限りリンクは報告され、一致するページがある場合はそのページのルートが修正案として示されます。 - リダイレクト先(
redirects内)は、どこかに到達する必要があります。完全一致の内部toはページ、ファイル、または別のリダイレクトに、パターンのtoは、リテラルの先頭部分(/v2/:slug*の/v2/)の配下で何かが配信されているパスに到達する必要があります。どこにも到達しないものは警告となり、blume.config.ts内のそのtoの位置で報告されます。リダイレクトのfromへのリンクは、いずれの場合も有効です。外部のリダイレクト先はチェックされません。 - 外部リンクは
--externalを指定した場合にのみチェックされます(ネットワークが必要なため、デフォルトではオフです)。404 や 410 が返された場合、またはホスト名が解決できない場合は、リンク切れとしてエラーになります。それ以外の失敗は警告になります。原因はリンクそのものよりも、相手側のサイトやネットワークであることが多いためです。具体的には、その他のエラーステータス(ボットを拒否するサイトからの 401 や 403、429 のレート制限、5xx の障害)、接続の拒否や切断、10 秒以内に応答がない場合が該当します。プレースホルダーのドメイン、ローカルサーバー、ボットを拒否するサイトなど、コマンドを実行する環境からはチェックできない URL を除外するには、--ignoreを指定します。リンク構文で囲まれておらず、GitHub Flavored Markdown が単独でリンクにする裸の URL は読み取られません。こうした URL はblume audit --externalがビルド済みのサイトでチェックします。
ページとして扱われるもの
リンクは Markdown ページだけでなく、ビルドされたサイトが配信するすべてのものに対して解決されます。対象には、カスタムの .astro ページ、API リファレンスのページ、生成された変更履歴のインデックス、設定されたすべてのリダイレクトが含まれます。多言語サイトでは、未翻訳ページが各ロケールで使うフォールバック URL も含まれます。Blume がページと並べて書き出すファイルも、設定で有効になっている場合は対象になります。具体的には、/llms.txt と /llms-full.txt、サイトマップ、/robots.txt、RSS フィード、/openapi.json、/agent-readability.json、/skill.md、そして /.well-known/agent-skills/index.json などの .well-known ディスカバリーファイルです。index.html を含む public/ 内のフォルダーも、静的ホストが配信するのと同じように対象になります。たとえば public/demo/index.html は /demo または /demo/ として扱われます。フロントマターが無効なページや、.mdx がパースできないページ(BLUME_MDX_SYNTAX)など、読み込みに失敗したページは、リンクの検出結果と一緒に報告されます。読み込まれないページは問題のない結果ではなく、リンク検証の死角になるためです。
フラグ
--external— 外部のhttp(s)リンクもネットワーク経由でチェックします。--ignore <glob>—--externalと併用すると、URL が glob に一致する外部リンクにはリクエストを送らず、何も報告しません。glob は、スキームを含むリンクの完全な URL と照合されます。*は 1 つのパスセグメント内で、**は複数のセグメントにまたがって一致します。そのため、--ignore "https://api.acme.example/**"はそのホストへのすべてのリンクを、--ignore "http://localhost:*/**"はすべてのローカルサーバーをスキップします。複数のパターンを指定するにはフラグを繰り返します。シェルに展開されないよう、各パターンはクォートで囲んでください。内部リンクは常にチェックされます。内部リンクは自分のページに対して解決されるため、壊れている場合は修正するか、リダイレクトを追加してください。--strict— 警告があった場合も 0 以外のコードで終了します。info レベルの通知は、引き続き参考情報として扱われます。--json— 診断結果をターミナル向けのレポートではなく、JSON として stdout に出力します。
診断
| コード | 重大度 | 意味 |
|---|---|---|
BLUME_BROKEN_LINK |
error | 内部リンクが、どのページも配信していないルートを指しています。存在するファイルへの相対リンクで、そのファイル名またはフォルダー名が _ で始まる場合は、修正案でその旨が示されます。そのファイルはパーシャルであり、公開されないためです。 |
BLUME_BROKEN_ANCHOR |
warning | ページは存在しますが、フラグメントに一致するアンカーがありません。 |
BLUME_BROKEN_ASSET |
warning | 絶対パスのファイルが public/ に存在しない、相対パスで埋め込んだ画像がページと同じフォルダーにない、.html リンクが指すファイルが public/ にない、またはメディアの src が指すファイルがその URL で配信されていません。 |
BLUME_BROKEN_REDIRECT |
warning | リダイレクトの内部 to が、どのページ、ファイル、他のリダイレクトにも到達しません。 |
BLUME_UNSUPPORTED_LINK_SCHEME |
warning | リンクが ReadMe のリンクスキーム(doc:、ref:、page:、changelog:、blog:)のいずれかを使っていますが、ブラウザーはこれをたどれません。 |
BLUME_DEAD_LINK |
error または warning | 外部リンク(--external 指定時)が 404/410 を返したかホスト名が解決できなかった(error)、またはその他のエラーステータスが返された、接続できなかった、時間内に応答がなかった(warning)ことを示します。 |
判定の基準になるのは終了コードです。エラーがあると 0 以外のコードで終了し、--strict を指定すると警告でも同様に終了します。
JSON 出力
--json を指定すると、blume validate(および blume doctor)は 1 つのオブジェクトを stdout に書き出します。このオブジェクトには、diagnostics リストと、重大度ごとの件数をまとめた summary が含まれます。diagnostics の各エントリには、code、severity、message、suggestion、そのコードを説明するページを指す docsUrl、そしてプロジェクトルートからの相対パスである file が含まれます。検出結果に位置情報がある場合は、line と column も含まれます。終了コードは変わらないため、同じ呼び出しを CI のゲートとエディター連携の両方に使えます。