# 通知設計書 11-ファイル名 (unchanged)

## 概要

本ドキュメントは、Prettier CLI において `--write` オプション使用時にフォーマット不要のファイルに対して表示されるログ通知「ファイル名 (unchanged)」について定義する設計書である。

### 本通知の処理概要

Prettier CLI がファイルのフォーマット処理を実行し、フォーマット前後でファイル内容に変更がない場合に、ユーザーに対してファイル名と処理時間、および「(unchanged)」というステータスを通知する。この通知により、ユーザーは当該ファイルが既にPrettierのコードスタイルに準拠していることを確認できる。

**業務上の目的・背景**：開発者がコードフォーマットを実行する際、どのファイルがフォーマット対象となり、どのファイルが既に整形済みであるかを把握することは重要である。この通知により、ユーザーは処理対象のファイルのうち、変更が不要だったファイルを明確に識別でき、フォーマット処理の結果を視覚的に確認できる。これはCI/CDパイプラインでのログ確認や、大規模プロジェクトでのフォーマット作業の進捗追跡に役立つ。

**通知の送信タイミング**：`prettier --write` コマンドを実行し、対象ファイルのフォーマット処理完了後、フォーマット前後のコンテンツを比較して変更がなかった場合に即座に通知される。具体的には、`format.js` の `formatFiles` 関数内で `isDifferent === false` の条件を満たした時点で出力される。

**通知の受信者**：CLI を実行している開発者またはCI/CDシステム。標準出力（stdout）に出力されるため、ターミナルで実行している場合はリアルタイムで表示され、パイプライン実行時はログとして記録される。

**通知内容の概要**：グレー色で装飾されたファイル名、処理にかかった時間（ミリ秒単位）、および「(unchanged)」というステータス文字列で構成される。キャッシュから取得した場合は追加で「(cached)」も表示される。

**期待されるアクション**：この通知を受け取った場合、ユーザーは特にアクションを取る必要はない。ファイルが既にPrettierのコードスタイルに準拠していることを確認するための情報提供であり、問題がないことを示している。

## 通知種別

CLI 標準出力（ログ出力）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ファイル処理完了時に即座に出力） |
| 優先度 | 中（通常のログ出力） |
| リトライ | なし（一度きりの出力） |

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

CLI 実行環境の標準出力（`process.stdout`）に対して直接出力する。ログレベルが `log` 以上に設定されている場合のみ出力される（デフォルトで有効）。`--check` または `--list-different` オプションが同時に指定されている場合はこの通知は抑止される。

## 通知テンプレート

### CLI出力通知の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | 標準出力（stdout） |
| 形式 | テキスト |
| カラー | ファイル名部分はグレー（picocolors.gray） |

### 本文テンプレート

```
{ファイル名} {処理時間}ms (unchanged)
```

キャッシュが有効な場合：
```
{ファイル名} {処理時間}ms (unchanged) (cached)
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| fileNameToDisplay | 表示用ファイル名（現在の作業ディレクトリからの相対パス） | `path.relative(cwd, filename)` をPOSIX形式に正規化 | Yes |
| timeToDisplay | 処理時間（ミリ秒単位） | フォーマット処理開始時刻と完了時刻の差分を `Math.round()` | Yes |
| isCacheExists | キャッシュ存在フラグ | `FormatResultsCache.existsAvailableFormatResultsCache()` の戻り値 | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| CLI実行 | ファイルフォーマット完了 | `--write` オプションが指定されており、フォーマット前後でファイル内容に変更がない場合 | `isDifferent === false` の評価で判定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `--check` オプション指定時 | チェックモードでは変更なしファイルの通知は行わない |
| `--list-different` オプション指定時 | 差分一覧モードでは変更なしファイルの通知は行わない |
| パフォーマンステストモード | `--debug-benchmark` や `--debug-repeat` 指定時は早期リターンにより出力されない |
| ログレベルが `log` 未満 | `--log-level warn` や `--log-level error` 指定時は出力されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[formatFiles開始] --> B[ファイル読み込み]
    B --> C[キャッシュチェック]
    C -->|キャッシュあり| D[result.formatted = input]
    C -->|キャッシュなし| E[format関数でフォーマット実行]
    D --> F[isDifferent判定]
    E --> F
    F -->|変更あり| G[ファイル書き込み・変更ありログ出力]
    F -->|変更なし| H{--check or --list-different?}
    H -->|Yes| I[通知スキップ]
    H -->|No| J{キャッシュから取得?}
    J -->|Yes| K[ファイル名 + 時間 + unchanged + cached 出力]
    J -->|No| L[ファイル名 + 時間 + unchanged 出力]
    G --> M[終了]
    I --> M
    K --> M
    L --> M
```

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

### 参照テーブル一覧

本通知はデータベースを使用しない。ファイルシステムとキャッシュファイルのみを参照する。

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| FormatResultsCache | フォーマット結果のキャッシュ | ファイルベースのキャッシュ（node_modules/.cache/prettier/.prettier-cache） |

### テーブル別参照項目詳細

#### FormatResultsCache

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| fileDescriptor | ファイル情報とハッシュ値 | ファイルパスをキーとして検索 |
| meta.data.hashOfOptions | オプションのハッシュ値 | キャッシュの有効性判定に使用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| FormatResultsCache | UPDATE | フォーマット結果のキャッシュを更新（変更なしファイルの場合） |

#### 送信ログテーブル

本通知ではログテーブルへの記録は行わない。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 出力エラー | 標準出力への書き込みが失敗した場合 | Node.jsのストリームエラーとして伝播 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（CLI実行時に即座に出力）

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

- ファイル名がコンソールに出力されるため、機密性の高いファイル名やパスが含まれる場合は注意が必要
- 標準出力への出力のみであり、ネットワーク送信は行わない
- ログの永続化は利用者の環境に依存する

## 備考

- `picocolors` ライブラリを使用してファイル名をグレー色で装飾している
- TTY環境では、ファイル名は一時的にプレビュー表示され、処理完了後に上書きされる（clearable オプション）
- 処理時間は `mockable.getTimestamp()` を使用して計測され、テスト時のモック化が可能

---

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

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

### 推奨読解順序

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

まず、フォーマット結果キャッシュの仕組みを理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | format-results-cache.js | `src/cli/format-results-cache.js` | キャッシュの保存・取得・判定ロジックを理解する |

**読解のコツ**: `file-entry-cache` ライブラリを使用したファイルベースのキャッシュ機構。`existsAvailableFormatResultsCache` メソッドがキャッシュ有効性の判定を行う。

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

処理の起点となるCLIのエントリーポイントを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.js | `src/cli/index.js` | CLIのメインフロー、`formatFiles` 関数への導線を確認 |

**主要処理フロー**:
1. **行13-37**: `run` 関数でコンテキスト初期化
2. **行111-113**: ファイルパターンがある場合に `formatFiles` を呼び出し

#### Step 3: フォーマット処理を理解する

メインのフォーマット処理とログ出力のロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | format.js | `src/cli/format.js` | `formatFiles` 関数内の unchanged 通知ロジックを確認（行433-439） |

**主要処理フロー**:
- **行398**: `isDifferent` の判定（`output !== input`）
- **行433**: `--check` と `--list-different` が指定されていない場合の処理開始
- **行434**: unchanged メッセージの構築（`picocolors.gray(fileNameToDisplay)` で装飾）
- **行435-436**: キャッシュ存在時は `(cached)` を追加して出力
- **行437-439**: キャッシュなしの場合は通常の unchanged メッセージを出力

#### Step 4: ロガーの仕組みを理解する

ログ出力の実際の仕組みを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | logger.js | `src/cli/logger.js` | `log` メソッドの実装、ログレベルによる出力制御を確認 |

**主要処理フロー**:
- **行21-28**: ロガーの作成、各ログレベルのメソッド定義
- **行35**: `log` メソッドは `stdout` に出力
- **行57-78**: ログレベルによる出力可否の判定

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

```
src/cli/index.js::run()
    │
    ├─ Context 初期化
    │
    └─ main()
           │
           └─ formatFiles()  [src/cli/format.js:272]
                  │
                  ├─ expandPatterns()  [src/cli/expand-patterns.js]
                  │      └─ ファイルパターンの展開
                  │
                  ├─ fs.readFile()  [Node.js]
                  │      └─ ファイル読み込み
                  │
                  ├─ FormatResultsCache.existsAvailableFormatResultsCache()
                  │      └─ キャッシュ有効性判定
                  │
                  ├─ format()  [src/cli/format.js:102]
                  │      └─ prettier.formatWithCursor() 呼び出し
                  │
                  └─ context.logger.log()  [行436, 438]
                         └─ unchanged メッセージ出力
```

### データフロー図

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

ファイルパス ───────────▶ readFile() ───────────▶ input (元のコンテンツ)
                                │
                                ▼
                         format() 実行
                                │
                                ▼
                         output (フォーマット後)
                                │
                                ▼
                         isDifferent判定
                         (output !== input)
                                │
                                ▼
                         [false] ───────────▶ logger.log()
                                               │
                                               ▼
                                        "{ファイル名} {時間}ms (unchanged)"
                                               │
                                               ▼
                                        標準出力 (stdout)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `src/cli/index.js` | ソース | CLIエントリーポイント |
| format.js | `src/cli/format.js` | ソース | フォーマット処理とログ出力のメインロジック |
| format-results-cache.js | `src/cli/format-results-cache.js` | ソース | フォーマット結果のキャッシュ管理 |
| logger.js | `src/cli/logger.js` | ソース | ログ出力機能 |
| utilities.js | `src/cli/utilities.js` | ソース | ユーティリティ関数（normalizeToPosix等） |
| prettier-internal.js | `src/cli/prettier-internal.js` | ソース | picocolorsのエクスポート |
| mockable.js | `src/cli/mockable.js` | ソース | テスト用のモック可能な関数 |
