# 通知設計書 36-DebugError

## 概要

本ドキュメントは、Prettier CLIの`--debug-check`オプション使用時に整合性チェックで不一致が検出された場合に発生するエラー通知「DebugError」の設計仕様を記載する。

### 本通知の処理概要

本通知は、`--debug-check`モードにおいてフォーマットの冪等性またはAST整合性のチェックに失敗した際に、詳細なエラー情報とdiffを出力する機能を提供する。

**業務上の目的・背景**：Prettierの`--debug-check`オプションは、フォーマット処理の整合性を検証するために使用される。具体的には以下の2つのチェックを行う：
1. **冪等性チェック**：`prettier(input) === prettier(prettier(input))`であることを検証。フォーマット結果を再度フォーマットしても同じ結果になることを確認する。
2. **AST整合性チェック**：元のコードのASTとフォーマット後のコードのASTが等価であることを検証。フォーマットによってコードの意味が変わっていないことを確認する。

このエラー通知により、Prettier開発者やプラグイン開発者がフォーマット処理のバグを発見・修正できるようにする。

**通知の送信タイミング**：format関数内の`--debug-check`処理ブロック（126-159行目）において、冪等性チェックまたはAST整合性チェックで不一致が検出された時点でDebugErrorがスローされる。

**通知の受信者**：Prettier開発者、プラグイン開発者、またはフォーマット結果の整合性を検証したいユーザー。

**通知内容の概要**：以下のいずれかのエラーメッセージとdiff出力が表示される：
- 冪等性チェック失敗：「prettier(input) !== prettier(prettier(input))」+ diff
- AST整合性チェック失敗：「ast(input) !== ast(prettier(input))」+ AST diff + コードdiff

**期待されるアクション**：Prettier開発者は表示されたdiffを分析し、フォーマット処理のバグを特定・修正することが期待される。

## 通知種別

CLI標準エラー出力（stderr）へのエラーメッセージ

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無し |

### 送信先決定ロジック

handleError関数内でDebugErrorインスタンスを検出し、`context.logger.error`を通じてstderrに出力される。ファイル名とエラーメッセージが結合されて出力される。

## 通知テンプレート

### CLI出力の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | stderr |
| プレフィックス | [error] |
| 色 | 赤（red） |

### 本文テンプレート

冪等性チェック失敗の場合：
```
[error] {filename}: prettier(input) !== prettier(prettier(input))
{diff between pp and pppp}
```

AST整合性チェック失敗の場合：
```
[error] {filename}: ast(input) !== ast(prettier(input))
{AST diff}
{diff between input and pp}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| filename | 処理対象ファイル名 | fileNameToDisplay / filepath | Yes |
| diff | 差分出力 | createTwoFilesPatch関数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 冪等性チェック失敗 | format関数実行時 | `pp !== pppp` | 2回フォーマットした結果が異なる |
| AST整合性チェック失敗 | format関数実行時 | `ast !== past` | 元のASTとフォーマット後のASTが異なる |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `--debug-check`が未指定の場合 | デバッグチェックモード無効 |
| 冪等性・AST整合性の両方が成功した場合 | 正常なフォーマット結果 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[format関数呼び出し] --> B{--debug-check<br>が有効?}
    B -->|No| C[通常フォーマット]
    B -->|Yes| D[1回目フォーマット pp]
    D --> E[2回目フォーマット pppp]
    E --> F{pp === pppp?}
    F -->|No| G[DebugError生成<br>冪等性失敗]
    F -->|Yes| H[ASTパース: ast, past]
    H --> I{ast === past?}
    I -->|No| J[DebugError生成<br>AST整合性失敗]
    I -->|Yes| K[成功: filepath返却]
    G --> L[throw DebugError]
    J --> L
    L --> M[handleError呼び出し]
    M --> N[logger.error出力]
    N --> O[process.exitCode = 2]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（CLIツールのためデータベースは使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 冪等性違反 | pp !== pppp | DebugErrorをスローし、diffを出力 |
| AST整合性違反 | ast !== past | DebugErrorをスローし、AST diffとコードdiffを出力 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0回（リトライ無し） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

該当なし（CLI同期処理のため）

### 配信時間帯

該当なし（CLI実行時即座に出力）

## セキュリティ考慮事項

- ソースコードの内容がdiffとして出力されるため、機密性の高いコードを処理する場合は出力の取り扱いに注意が必要
- AST diffが大きすぎる場合（2MB超）は「AST diff too large to render」と表示され、メモリ枯渇を防止する

## 備考

- DebugErrorクラスは`src/cli/format.js`で定義されているローカルクラス
- `name`プロパティに`'DebugError'`が設定されており、handleError内での判定に使用される
- diff生成には`createTwoFilesPatch`関数（jsdiffライブラリのラッパー）が使用される
- ASTのパース時には`massage: true`オプションが指定され、位置情報など比較に不要な情報が除去される
- handleError関数はDebugErrorを特別扱いし、`{filename}: {error.message}`形式で出力する
- `--debug-check`と`--write`の同時使用は禁止されており、index.jsで事前チェックされる

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

DebugErrorクラスの定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | format.js | `src/cli/format.js` | DebugErrorクラス定義（22-24行目） |

**読解のコツ**: DebugErrorはErrorを継承し、`name`プロパティを`'DebugError'`に設定するシンプルなクラス。

#### Step 2: エントリーポイントを理解する

--debug-checkオプションの検証と排他チェック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.js | `src/cli/index.js` | --write と --debug-check の排他チェック（53-55行目） |
| 2-2 | cli-options.evaluate.js | `src/cli/cli-options.evaluate.js` | debugCheckオプション定義（142-144行目） |

**主要処理フロー**:
1. **index.js 53-55行目**: `--write`と`--debug-check`の同時使用を禁止

#### Step 3: debug-check処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | format.js | `src/cli/format.js` | format関数内のdebug-check処理ブロック（126-159行目） |

**主要処理フロー**:
- **127行目**: 1回目のフォーマット `pp = prettier.format(input, opt)`
- **128行目**: 2回目のフォーマット `pppp = prettier.format(pp, opt)`
- **129-132行目**: 冪等性チェック `pp !== pppp` → DebugError
- **134-139行目**: AST取得（massage: trueでノーマライズ）
- **143-155行目**: AST整合性チェック `ast !== past` → DebugError

#### Step 4: エラーハンドリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | format.js | `src/cli/format.js` | handleError関数内のDebugError処理（61-63行目） |

**主要処理フロー**:
- **61行目**: `error instanceof DebugError`の判定
- **63行目**: `{filename}: {error.message}`形式で出力

#### Step 5: diff生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | format.js | `src/cli/format.js` | diff関数定義（18-20行目） |

**主要処理フロー**:
- **19行目**: `createTwoFilesPatch`を使用してUnified Diff形式で出力

### プログラム呼び出し階層図

```
formatFiles/formatStdin (src/cli/format.js)
    │
    └─ format (src/cli/format.js:102)
           │
           └─ if (context.argv.debugCheck) (126行目)
                  │
                  ├─ prettier.format(input) → pp (127行目)
                  │
                  ├─ prettier.format(pp) → pppp (128行目)
                  │
                  ├─ if (pp !== pppp) → throw DebugError (129-132行目)
                  │      └─ "prettier(input) !== prettier(prettier(input))\n" + diff(pp, pppp)
                  │
                  ├─ prettier.__debug.parse(input) → ast (136行目)
                  │
                  ├─ prettier.__debug.parse(pp) → past (139行目)
                  │
                  └─ if (ast !== past) → throw DebugError (143-155行目)
                         └─ "ast(input) !== ast(prettier(input))\n" + astDiff + diff(input, pp)

    (catch block)
    └─ handleError (src/cli/format.js:26)
           │
           └─ if (error instanceof DebugError) (61行目)
                  └─ logger.error(`${filename}: ${error.message}`) (63行目)
```

### データフロー図

```
[入力]                   [処理]                        [出力]

input                format関数
  │                      ↓
  │                 prettier.format(input)
  │                      ↓
  │                      pp
  │                      ↓
  │                 prettier.format(pp)
  │                      ↓
  │                     pppp
  │                      ↓
  │                  pp !== pppp?
  │                      ↓ (Yes)
  │                 DebugError
  │                      ↓
  └─────────────────▶ handleError ─────────▶ stderr: [error] file: prettier(input) !== ...
                           ↓                          + diff output
                     process.exitCode = 2
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| format.js | `src/cli/format.js` | ソース | DebugErrorクラス、format関数、handleError関数 |
| index.js | `src/cli/index.js` | ソース | --write と --debug-check の排他チェック |
| cli-options.evaluate.js | `src/cli/cli-options.evaluate.js` | ソース | debugCheckオプション定義 |
| logger.js | `src/cli/logger.js` | ソース | ログ出力機能 |
| prettier-internal.js | `src/cli/prettier-internal.js` | ソース | createTwoFilesPatchのエクスポート |
