## 概要

zudo-docには、サイトビルド後に2種類の検証を行う組み込みリンクチェッカー（`scripts/check-links.js`）が含まれています。

## チェック内容

### モード1: ビルド済みHTMLスキャン

`dist/`内のすべての`.html`ファイルをスキャンし、内部`<a href="...">`リンクの各ターゲットがディスク上に存在するかを検証します。以下を処理します：

- ベースパスの除去（例：`/my-docs/docs/foo` → `docs/foo`）
- 末尾スラッシュの解決（`docs/foo/` → `docs/foo/index.html`）
- 拡張子の解決（`docs/foo` → `docs/foo/index.html`または`docs/foo.html`）
- 解決前のクエリ文字列とフラグメントの除去
- ファイルのディレクトリに対する相対リンクの解決
- パフォーマンスのための解決済みパスのキャッシュ

スキップされるリンク（チェック対象外）：

- 外部URL（`https://`、`http://`）
- アンカーのみのリンク（`#section`）
- `mailto:`、`javascript:`、`data:`、`tel:` URI
- バージョン付きドキュメントリンク（`/v/*/`） — バージョンコンテンツが不完全な場合があるため

### モード2: MDXソーススキャン

設定されたコンテンツディレクトリ内のすべての`.mdx`および`.md`ファイルをスキャンし、ベースパスをバイパスする絶対リンクを検出します。以下のようなリンクが対象です：

```mdx
<!-- These are flagged — they bypass the base path -->
[guide](/docs/guides/foo)
<a href="/ja/docs/guides/foo">link</a>

<!-- These are fine — they use relative paths -->
[guide](./foo.mdx)
[guide](../other/bar.mdx)
```

ベースパスが設定されている場合（例：`/my-docs/`）、`/docs/`や`/ja/docs/`で始まる絶対リンクはベースパスのプレフィックスが欠けているため壊れます。MDXソーススキャンは、これらが本番環境で壊れたリンクになる前に検出します。

フェンスドコードブロック内のリンクは無視されます。

## 画像チェッカー

zudo-docには、厳格なビルド後の画像・アセットチェッカー（`zudo-doc check images`）も含まれています。ビルド出力内のすべてのレンダリング済み`.html`ファイルをスキャンし、次の要素と属性から提供されるローカル参照を検査します：

- HTMLの`img[src]`と、各`img[srcset]`候補
- HTMLの`source[src]`と、各`source[srcset]`候補（`<picture>`内の`source`を含む）
- HTMLの`video[src]`と`video[poster]`
- HTMLの`audio[src]`、`track[src]`、`input[type="image"][src]`
- SVGの`image[href]`と`image[xlink:href]`

サイト絶対URL（`/images/diagram.png`）と相対URL（`./diagram.png`、`../images/diagram.png`、`images/diagram.png`）のどちらも、URLの規則に従って、そのURLを含むページを基準に解決します。設定された`base`パスとページの`<base href>`を考慮します。クエリ文字列とフラグメントはファイル検索に影響しません。ビルド出力内のファイルに解決できる参照だけが有効です。ディレクトリや、出力外を指すシンボリックリンクは報告されます。

外部URL（`http:`や`https:`などスキームを持つURLを含む）、`data:` URL、プロトコル相対URL（`//cdn.example/...`）、フラグメントのみの参照（`#diagram`）はスキップします。

### ビルド時プラグインと厳格CLI

パッケージのビルド時`img-src-check`プラグインはビルド後に実行され、既存の`onBrokenMarkdownLinks`設定を使用します。デフォルトは`warn`で、壊れたローカル参照を報告しますがビルドは失敗させません。`error`ではビルドが失敗し、`ignore`ではこのスキャンを無効にします。この設定は壊れたMarkdownリンクも制御するため、画像チェック自体を独立した厳格ゲートにしたい場合は、次のCLIを使用します。

厳格CLIは、アローリスト後も壊れたローカル参照が残っている場合に終了コードが0以外になります：

```bash
pnpm build && pnpm check:images
```

オプションは次のとおりです：

- `--dist <dir>` — ビルド出力ディレクトリ（デフォルト：`dist`）
- `--base <path>` — 公開URLのベース（デフォルト：`/`）
- `--allowlist <file>` — 壊れた参照の完全一致による例外
- `--help` — 現在のコマンドヘルプを表示

例えば、`/docs/`配下で公開するサイトは、ベースを明示できます：

```bash
pnpm check:images -- --dist dist --base /docs/ --allowlist=.check-images-allowlist
```

アローリストには、ビルド出力からの相対パスである`<page>`と元のURL値である`<url>`を組み合わせた、正確な`<page>:<url>`キーを1行に1つ記述します。空行と`#`で始まる行は無視されます：

```text
# A generated page still points at an intentionally absent asset
docs/generated/index.html:/images/legacy.png
```

例外は狭く保ち、元のアセットが修正されたら各行を削除してください。生成プロジェクトでは、ローカルアセットの壊れた参照が公開されないよう、ビルド（およびリンクチェック）の後に厳格チェックをCIへ追加することを推奨します：

```yaml
- name: Build site
  run: pnpm build
- name: Check images
  run: pnpm run check:images
```

## リンクチェッカーの実行

### 単独実行

まずサイトをビルドし、チェッカーを実行します：

```bash
pnpm build && pnpm check:links
```

### 失敗対象カテゴリのフラグ

デフォルトでは、問題が見つかってもチェッカーは終了コード0で終了します。コマンドを失敗させるカテゴリは、`--strict-broken`、`--strict-absolute`、`--strict-trailing`で明示的に選択します。b4pushとCIのワークフローでは、末尾スラッシュの指摘を情報扱いのままにし、リンク切れとMDX内の絶対リンクを失敗対象にしています：

```bash
pnpm check:links -- --strict-broken --strict-absolute --allowlist=.check-links-allowlist
```

現在のCLIオプションは`pnpm check:links -- --help`で確認できます。

### アローリスト

`--allowlist=PATH`は、厳格モードの失敗カウントから正確な`<file>:<line>:<href>`のエントリを除外します。ソース側で修正できない問題向けです。例えば、JAページが意図的にEN専用の姉妹ページにリンクしている場合や、対応するMDXファイルが存在しないランタイム生成ルートを指す絶対hrefなどです。リポジトリには実際のアローリストが`.check-links-allowlist`として同梱されています：1行につき1つの`<file>:<line>:<href>`エントリで、`#`コメントと空行は無視されます。各エントリは出力されるレポートと完全一致する必要があります — リポジトリルートからの相対ファイルパス、1始まりの行番号、ソースまたはビルド済みHTMLに現れたとおりのhrefです。根本原因が修正されたら、そのエントリを削除してください。そうすることで、厳格ゲートが同種の回帰を今後検出できるようになります。

### b4pushの一部として

リンクチェッカーはプッシュ前検証（`pnpm b4push`）の34ステップ中ステップ30で実行されます。その直後のステップ31で厳格な画像チェッカーが実行され、HTML検証に進みます：

```
28. Build
29. Content-fallback check
30. **Link check**
31. **Image check**
32. HTML validation
33. Preview smoke
34. Manual smoke
```

b4pushのステップ一覧の正式・権威的な定義は`scripts/run-b4push.sh`の冒頭コメントにあります。このスクリプトを、34ステップ全体の唯一の信頼できる情報源として扱ってください。

### CI内での実行

リンクチェッカーはPRチェックワークフロー（`pr-checks.yml`）の`build-site`ジョブで、`pnpm build`の直後に実行されます。厳格な画像チェッカーはリンクチェッカーの直後に実行されます。本番およびプレビューのデプロイワークフローでも、ビルド出力をアーカイブする前に同じ画像ゲートを実行します。

## 出力

問題がない場合：

```
Checking links (base: /my-docs/)...

✓ No broken links or absolute path issues found
```

問題がある場合：

```
Checking links (base: /my-docs/)...

=== Broken Links in Built HTML ===
  dist/docs/page/index.html:42  /my-docs/docs/missing-page

=== Absolute Links Bypassing Base Path (MDX Source) ===
  src/content/docs/guides/test.mdx:15  /docs/guides/foo

✗ Found 1 broken link and 1 absolute path warning
```

各エントリはファイルパス、行番号、問題のあるhrefを表示します。

## 設定

リンクチェッカーは解決済みの設定（`zfb.config.ts`で`zudoDoc({...})`に渡すフィールド）から設定を読み取ります：

- **`base`** — サイトのベースパス。リンク解決時のプレフィックス除去に使用
- **`docsDir`** — MDXソーススキャンのプライマリコンテンツディレクトリ
- **`locales`** — ロケール設定。`dir`フィールドでMDXソーススキャンの追加コンテンツディレクトリを指定（例：`locales: { ja: { dir: "src/content/docs-ja" } }`）