# 通知設計書 14-Unable to write file

## 概要

本ドキュメントは、Prettier CLI において `--write` オプション使用時にファイル書き込みに失敗した場合に表示されるエラー通知「Unable to write file」について定義する設計書である。

### 本通知の処理概要

Prettier CLI がフォーマット処理を完了し、`--write` オプションによりフォーマット結果をファイルに書き戻そうとした際に、ファイルアクセス権限の問題、ディスク容量不足、またはその他のI/Oエラーにより書き込みに失敗した場合、ユーザーに対してエラー内容を通知する。この通知により、ユーザーはどのファイルの書き込みに失敗したか、およびその原因を把握できる。

**業務上の目的・背景**：開発者がコードフォーマットを実行し、変更をファイルに反映させる際、書き込み処理が成功することは重要である。ファイルシステムの問題（権限不足、ディスクフル、ファイルロック等）が発生した場合、ユーザーに明確なエラーメッセージを提供することで、問題の特定と解決を支援する。これはCI/CDパイプラインでのエラー診断や、読み取り専用ファイルシステム環境での問題解決に特に重要である。

**通知の送信タイミング**：`prettier --write` コマンドを実行し、フォーマット結果をファイルに書き込もうとした際にエラーが発生した時点で即座に通知される。具体的には、`format.js` の `formatFiles` 関数内で `mockable.writeFormattedFile()` の実行時にエラーがキャッチされた時点で出力される（行420-432）。

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

**通知内容の概要**：「Unable to write file」という固定メッセージ、書き込みに失敗したファイル名、およびエラーの詳細メッセージ（Node.jsのエラーオブジェクトの `message` プロパティ）で構成される。

**期待されるアクション**：この通知を受け取った場合、ユーザーは以下のアクションを検討する必要がある。(1) ファイルの書き込み権限を確認、(2) ディスク空き容量を確認、(3) ファイルが別のプロセスにロックされていないか確認、(4) ファイルが読み取り専用でないか確認。

## 通知種別

CLI 標準エラー出力（エラー通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ファイル書き込みエラー発生時に即座に出力） |
| 優先度 | 高（エラー通知） |
| リトライ | なし（一度きりの出力、ただし処理は継続） |

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

CLI 実行環境の標準エラー出力（`process.stderr`）に対して直接出力する。ログレベルが `error` 以上に設定されている場合のみ出力される（デフォルトで有効）。

## 通知テンプレート

### CLI出力通知の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | 標準エラー出力（stderr） |
| 形式 | テキスト |
| カラー | プレフィックス `[error]` は赤色（picocolors.red） |

### 本文テンプレート

```
[error] Unable to write file "{ファイル名}":
{エラーメッセージ}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| fileNameToDisplay | 表示用ファイル名（現在の作業ディレクトリからの相対パス） | `path.relative(cwd, filename)` をPOSIX形式に正規化 | Yes |
| error.message | エラー詳細メッセージ | `mockable.writeFormattedFile()` が投げるエラーオブジェクトの `message` プロパティ | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ファイル操作 | ファイル書き込み失敗 | `--write` オプションが指定されており、`mockable.writeFormattedFile()` の実行時にエラーが発生した場合 | try-catch でキャッチされたエラー |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `--write` オプション未指定 | 書き込み処理自体が実行されない |
| ファイル内容に変更なし | `isDifferent === false` の場合は書き込みが行われない |
| ログレベルが `error` 未満 | `--log-level silent` 指定時は出力されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[formatFiles開始] --> B[ファイル読み込み]
    B --> C[フォーマット処理]
    C --> D[isDifferent判定]
    D -->|変更なし| E[書き込みスキップ]
    D -->|変更あり| F{--write オプション?}
    F -->|なし| G[標準出力に出力]
    F -->|あり| H[ファイル名+処理時間ログ出力]
    H --> I[mockable.writeFormattedFile実行]
    I -->|成功| J[キャッシュ更新]
    I -->|失敗| K[エラーキャッチ]
    K --> L[context.logger.error出力]
    L --> M[process.exitCode = 2]
    E --> N[終了]
    G --> N
    J --> N
    M --> N
```

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

### 参照テーブル一覧

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

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | N/A | N/A |

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

該当なし

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| フォーマット対象ファイル | WRITE（失敗） | フォーマット結果の書き込み試行 |

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

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| EACCES | 書き込み権限がない | ファイルの権限を確認・変更 |
| EROFS | 読み取り専用ファイルシステム | ファイルシステムの設定を確認 |
| ENOSPC | ディスク空き容量不足 | ディスク空き容量を確保 |
| EBUSY | ファイルがビジー状態 | ファイルを使用しているプロセスを終了 |
| EIO | I/Oエラー | ディスクの状態を確認 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- ファイル名とエラーメッセージがコンソールに出力されるため、機密性の高いファイル名やパスが含まれる場合は注意が必要
- エラーメッセージにはファイルシステムの構造情報が含まれる可能性がある
- 標準エラー出力への出力のみであり、ネットワーク送信は行わない

## 備考

- このエラーが発生しても処理は中断されず、次のファイルの処理に継続する
- `process.exitCode = 2` が設定され、処理完了後に終了コード2でプロセスが終了する
- 書き込み成功時のみキャッシュが更新される（`shouldSetCache = true`）
- 書き込み処理は `mockable.writeFormattedFile()` を経由しており、テスト時のモック化が可能

---

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

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

### 推奨読解順序

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

Node.jsのファイルシステムエラーオブジェクトの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Node.js公式ドキュメント | - | `fs.writeFile` の戻り値とエラーオブジェクト（code, message プロパティ） |

**読解のコツ**: Node.jsのファイルシステムエラーは `code`（例: EACCES, ENOSPC）と `message`（人間可読なメッセージ）を持つ。

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

フォーマット処理のファイル書き込みロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | format.js | `src/cli/format.js` | ファイル書き込みとエラーハンドリング（行411-432） |

**主要処理フロー**:
1. **行411**: `context.argv.write` のチェック
2. **行415**: `isDifferent` のチェック（変更がある場合のみ書き込み）
3. **行421**: `mockable.writeFormattedFile(filename, output)` の実行
4. **行425**: `catch (error)` でエラーをキャッチ
5. **行426-428**: エラーメッセージを `context.logger.error()` で出力
6. **行431**: `process.exitCode = 2` を設定

#### Step 3: モック可能な関数を理解する

書き込み処理の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mockable.js | `src/cli/mockable.js` | `writeFormattedFile` 関数の実装 |

**読解のコツ**: `mockable` オブジェクトはテスト時にモック化可能な関数群を提供する。実際の書き込み処理は `fs.writeFile` を使用。

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

```
src/cli/format.js::formatFiles()  [行272]
    │
    ├─ format()  [src/cli/format.js:102]
    │      └─ prettier.formatWithCursor() 呼び出し
    │
    └─ --write 処理 [行411-440]
           │
           ├─ isDifferent チェック [行415]
           │
           ├─ context.logger.log()  [行417]
           │      └─ ファイル名+処理時間ログ出力
           │
           ├─ mockable.writeFormattedFile()  [行421]
           │      │
           │      └─ [エラー発生時]
           │             │
           │             ├─ context.logger.error()  [行426-428]
           │             │      │
           │             │      └─ "Unable to write file..." 出力
           │             │
           │             └─ process.exitCode = 2  [行431]
           │
           └─ shouldSetCache = true  [行424]
```

### データフロー図

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

フォーマット結果 ──────▶ isDifferent 判定
(output)                      │
                              ▼
                         [変更あり & --write]
                              │
                              ▼
                         writeFormattedFile()
                              │
                              ▼
                         [エラー発生]
                              │
                              ├─ error.message 取得
                              │
                              ▼
                         context.logger.error()
                              │
                              ▼
                         "[error] Unable to write file \"{ファイル名}\":
                          {エラーメッセージ}"
                              │
                              ▼
                         標準エラー出力 (stderr)
                              │
                              ▼
                         process.exitCode = 2
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| format.js | `src/cli/format.js` | ソース | フォーマット処理とファイル書き込みエラーハンドリング |
| mockable.js | `src/cli/mockable.js` | ソース | テスト可能な書き込み関数 |
| logger.js | `src/cli/logger.js` | ソース | エラーログ出力機能（stderr、赤色プレフィックス） |
| utilities.js | `src/cli/utilities.js` | ソース | ユーティリティ関数（normalizeToPosix等） |
| index.js | `src/cli/index.js` | ソース | CLIエントリーポイント |
