# 帳票設計書 5-コード差分

## 概要

本ドキュメントは、フォーマット前後の差分を出力する帳票「コード差分（diff）」の設計仕様を定義する。

### 本帳票の処理概要

**業務上の目的・背景**：コードレビューやCI/CDパイプラインにおいて、Prettierによるフォーマット変更の影響範囲を事前に確認することは重要である。本帳票は、フォーマット前後のソースコードの差分をunified diff形式で出力し、どの部分がどのように変更されるかを視覚的に把握できるようにする。これにより、意図しない変更の検出やフォーマットルールの調整判断に活用できる。

**帳票の利用シーン**：プルリクエスト前のフォーマット確認、CI/CDでの自動チェック時のエラー詳細表示、フォーマットルール変更時の影響確認、コードレビュー時の変更内容確認など。

**主要な出力内容**：
1. 差分ヘッダー（ファイル情報）
2. ハンク（変更箇所）情報
3. 削除行（-）と追加行（+）

**帳票の出力タイミング**：`--check`モードでフォーマット差異がある場合に、差分情報が内部的に生成される。`--debug-check`オプション使用時にも差分が出力される。

**帳票の利用者**：コードレビュアー、CI/CDシステム、品質管理担当者

## 帳票種別

差分出力（unified diff形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| CLI-01 | コマンドライン | `prettier --check` | コマンド実行（差分検出時） |
| CLI-02 | コマンドライン | `prettier --debug-check` | コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（unified diff形式） |
| 出力先 | 標準出力 / 標準エラー出力 |
| 文字コード | UTF-8 |
| コンテキスト行数 | 2行 |

### Unified Diff形式

```diff
--- a/file.js
+++ b/file.js
@@ -1,5 +1,5 @@
 const foo = {
-  bar: 1,
-  baz: 2
+  bar: 1,
+  baz: 2,
 };
```

## 帳票レイアウト

### レイアウト概要

出力はunified diff形式で、ファイルヘッダーとハンク（変更箇所）で構成される。

```
┌─────────────────────────────────────┐
│  --- (元ファイル)                    │
│  +++ (変更後ファイル)                 │
├─────────────────────────────────────┤
│  @@ -開始行,行数 +開始行,行数 @@      │
│   コンテキスト行                      │
│  -削除行                             │
│  +追加行                             │
│   コンテキスト行                      │
├─────────────────────────────────────┤
│  @@ 次のハンク...                    │
└─────────────────────────────────────┘
```

### 出力項目

| No | 項目名 | 説明 | 表示形式 |
|----|-------|------|---------|
| 1 | 元ファイル | `---` で始まる行 | `--- ` |
| 2 | 変更後ファイル | `+++` で始まる行 | `+++ ` |
| 3 | ハンクヘッダー | 変更位置情報 | `@@ -start,count +start,count @@` |
| 4 | コンテキスト行 | 変更なしの行 | スペースで開始 |
| 5 | 削除行 | 削除される行 | `-` で開始 |
| 6 | 追加行 | 追加される行 | `+` で開始 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 元テキスト | フォーマット前のソースコード | Yes |
| 変更後テキスト | フォーマット後のソースコード | Yes |
| コンテキスト | 差分前後の表示行数 | No（デフォルト: 2） |

### 出力トリガー

| 条件 | 出力先 | 説明 |
|------|--------|------|
| --debug-check & 冪等性違反 | 標準エラー出力 | prettier(input) !== prettier(prettier(input)) |
| --debug-check & AST不一致 | 標準エラー出力 | ast(input) !== ast(prettier(input)) |
| 内部エラー処理 | エラーメッセージ内 | デバッグ情報として使用 |

## データフロー仕様

### 入力データ

| データ項目 | 型 | 説明 |
|-----------|-----|------|
| a | string | 元テキスト（比較元） |
| b | string | 変更後テキスト（比較先） |
| oldFileName | string | 元ファイル名（表示用） |
| newFileName | string | 変更後ファイル名（表示用） |
| options.context | number | コンテキスト行数 |

### 出力データ

| データ項目 | 型 | 説明 |
|-----------|-----|------|
| patch | string | unified diff形式の差分文字列 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[フォーマット実行] --> B[prettier.format]
    B --> C{--debug-check?}
    C -->|Yes| D[2回フォーマット]
    D --> E{pp === pppp?}
    E -->|No| F[diff生成]
    F --> G[DebugError発生]
    E -->|Yes| H[AST比較]
    H --> I{ast === past?}
    I -->|No| J[AST diff + コード diff生成]
    J --> G
    I -->|Yes| K[正常終了]
    C -->|No| L[通常フォーマット]
```

### diff生成フロー

```mermaid
flowchart TD
    A[diff関数呼び出し] --> B[createTwoFilesPatch]
    B --> C[テキスト行分割]
    C --> D[LCS計算]
    D --> E[ハンク生成]
    E --> F[コンテキスト行追加]
    F --> G[unified形式整形]
    G --> H[結果返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| DebugError | 冪等性違反 | prettier(input) !== prettier(prettier(input)) | フォーマットルール確認 |
| DebugError | AST不一致 | ast(input) !== ast(prettier(input)) | パーサー/プリンター確認 |
| AST差分サイズ超過 | AST差分 > 2MB | AST diff too large to render | ファイル分割検討 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 処理方式 | 同期処理 |
| AST最大サイズ | 2MB（MAX_AST_SIZE = 2097152） |
| アルゴリズム | LCS（Longest Common Subsequence） |

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

- 差分にはソースコードの一部が含まれるため、出力先に注意
- CI/CDログに出力される場合は機密コードの露出に注意

## 備考

- diffライブラリの`createTwoFilesPatch`関数を使用
- コンテキスト行数は2行固定（format.js内でハードコード）
- ファイル名は空文字列で渡される（表示には使用されない）

---

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

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

### 推奨読解順序

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

まず、diff出力の構造を理解することが重要。

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

**読解のコツ**: `createTwoFilesPatch`はdiffライブラリの関数で、unified diff形式の文字列を生成する。

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

差分出力のトリガーとなる処理を特定。

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

**主要処理フロー**:
1. **126行目**: debugCheck判定
2. **127-128行目**: 2回フォーマット実行
3. **129-132行目**: 冪等性チェックとdiff生成
4. **135-155行目**: AST比較とdiff生成

#### Step 3: diff生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | format.js | `src/cli/format.js` | diff関数（18-20行目） |
| 3-2 | index.js | `src/index.js` | createTwoFilesPatch export（8行目, 109行目） |
| 3-3 | prettier-internal.js | `src/cli/prettier-internal.js` | createTwoFilesPatch取得（14行目） |

**主要処理フロー**:
- **18-20行目**: diff関数はcreateTwoFilesPatchのラッパー
- **19行目**: コンテキスト行数2を指定

#### Step 4: エラー処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | format.js | `src/cli/format.js` | DebugErrorクラス（22-24行目） |
| 4-2 | format.js | `src/cli/format.js` | エラースロー（130-132行目, 149-155行目） |

**主要処理フロー**:
- **22-24行目**: DebugErrorクラス定義
- **130-132行目**: 冪等性違反時のエラー
- **143-148行目**: AST差分サイズチェック
- **149-155行目**: AST不一致時のエラー

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

```
CLI: formatFiles()/formatStdin() [src/cli/format.js]
    │
    └─ format() [src/cli/format.js:102]
           │
           └─ (--debug-check時)
                  │
                  ├─ prettier.format() [src/index.js:68] × 2回
                  │
                  ├─ diff() [src/cli/format.js:18]
                  │      │
                  │      └─ createTwoFilesPatch() [diff library]
                  │
                  ├─ prettier.__debug.parse() [src/index.js:119]
                  │
                  └─ DebugError [src/cli/format.js:22]
```

### データフロー図

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

ソースコード (input) ───▶ prettier.format() ───▶ pp (1回目フォーマット)
                              │
                              ▼
                        prettier.format(pp) ───▶ pppp (2回目フォーマット)
                              │
                              ▼
                         pp === pppp ?
                              │
                              ├─ (No)
                              │      │
                              │      ▼
                              │  diff(pp, pppp)
                              │      │
                              │      ▼
                              │  DebugError (差分付き)
                              │
                              └─ (Yes)
                                     │
                                     ▼
                               AST比較 (ast, past)
                                     │
                                     ├─ (不一致)
                                     │      │
                                     │      ▼
                                     │  diff(ast, past) + diff(input, pp)
                                     │      │
                                     │      ▼
                                     │  DebugError (差分付き)
                                     │
                                     └─ (一致)
                                            │
                                            ▼
                                        正常終了
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| format.js | `src/cli/format.js` | ソース | diff関数定義、DebugError処理 |
| index.js | `src/index.js` | ソース | createTwoFilesPatch export |
| prettier-internal.js | `src/cli/prettier-internal.js` | ソース | createTwoFilesPatch取得 |
| diff (npm) | node_modules/diff | 外部ライブラリ | createTwoFilesPatch実装 |
