# 通知設計書 36-source map write error

## 概要

本ドキュメントは、CoffeeScriptコンパイラでソースマップファイルの書き込みに失敗した場合に発生するエラー通知「source map write error」の設計仕様を記載する。

### 本通知の処理概要

CoffeeScriptのCLI（`coffee`コマンド）で`--map`オプションを使用してコンパイルした際、ソースマップファイル（`.js.map`）のファイルシステムへの書き込みに失敗した場合に、エラーメッセージを標準出力に表示し、プロセスを終了コード1で終了する通知機能である。

**業務上の目的・背景**：ソースマップはデバッグ時にコンパイル後のJavaScriptからオリジナルのCoffeeScriptソースへのマッピングを提供する重要なファイルである。書き込み失敗は、ディスク容量不足、権限問題、ファイルロックなど様々な理由で発生しうる。このエラー通知により、ユーザーは問題を認識し、ファイルシステムの状態を確認できる。

**通知の送信タイミング**：`writeJs`関数内で`fs.writeFile`によるソースマップファイルの書き込みが完了し、コールバックでエラーが返された時点で通知される。

**通知の受信者**：コマンドラインでCoffeeScriptコンパイラを実行している開発者またはビルドシステム。標準出力（stdout）に出力されるため、ターミナルまたはログ収集システムが受信者となる。

**通知内容の概要**：「Could not write source map: {エラーメッセージ}」の形式でエラー内容を出力する。エラーメッセージにはファイルシステムからの詳細なエラー情報が含まれる。

**期待されるアクション**：ユーザーはエラーメッセージを確認し、以下のいずれかの対応を行うことが期待される：
1. 出力ディレクトリの書き込み権限を確認
2. ディスク容量を確認
3. ファイルがロックされていないか確認
4. 出力パスを変更して再実行

## 通知種別

コンソール出力（標準出力）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（fs.writeFileコールバック） |
| 優先度 | 高 |
| リトライ | 無し |

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

標準出力（stdout）への直接出力のため、受信者決定ロジックは不要。コマンド実行元のターミナルまたはパイプ先に出力される。

## 通知テンプレート

### コンソール出力の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | stdout（printLine関数経由） |
| 形式 | テキスト |

### 本文テンプレート

```
Could not write source map: {message}
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| message | ファイルシステムエラーの詳細メッセージ | err.message | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ファイル書き込み | fs.writeFile コールバック | errがnullでない | ソースマップ書き込み失敗 |

### 前提条件

| 条件 | 説明 |
|-----|------|
| opts.map === true | --mapオプションが指定されている |
| generatedSourceMap !== null | ソースマップが生成されている |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 書き込み成功 | fs.writeFileがエラーなく完了した場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[coffee --compile --map 実行] --> B[compileScript関数]
    B --> C[CoffeeScript.compile]
    C --> D{opts.map?}
    D -->|Yes| E[ソースマップ生成]
    E --> F[writeJs関数呼び出し]
    F --> G[fs.writeFile sourceMapPath]
    G --> H{書き込み成功?}
    H -->|Yes| I[正常終了]
    H -->|No| J[printLine Could not write source map: err.message]
    J --> K[process.exit 1]
```

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

### 参照テーブル一覧

なし

### ファイルシステム操作

| 操作 | 関数 | 目的 |
|-----|------|------|
| ファイル書き込み | fs.writeFile | ソースマップファイルの保存 |

### 更新テーブル一覧

なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| EACCES | 書き込み権限がない | エラーメッセージを表示して終了 |
| ENOSPC | ディスク容量不足 | エラーメッセージを表示して終了 |
| EBUSY | ファイルがロック中 | エラーメッセージを表示して終了 |
| ENOENT | ディレクトリが存在しない | エラーメッセージを表示して終了 |

### リトライ仕様

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

## 配信設定

### レート制限

なし（ファイル書き込みごとに発生）

### 配信時間帯

制限なし

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

- エラーメッセージにファイルパスが含まれる可能性があるため、機密性の高いパス情報がログに記録される可能性がある
- プロセス終了コード1により、シェルスクリプトやCI/CDパイプラインでエラー検知が可能

## 備考

- ソースマップファイルのパスは`{jsPath}.map`の形式で決定される
- このエラーは非同期処理のコールバック内で発生するため、他のファイルのコンパイルが並行して行われている可能性がある
- JavaScriptファイルの書き込みエラーは別のエラーハンドリングで処理される

---

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

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

### 推奨読解順序

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

ソースマップ関連のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | command.coffee | `src/command.coffee` | SWITCHES配列（43行目: -m, --map）を確認 |
| 1-2 | command.coffee | `src/command.coffee` | writeJs関数のパラメータ（407行目）を確認 |

**読解のコツ**: generatedSourceMapがnullでない場合にのみソースマップが書き込まれることを理解しておく。

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

処理の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.coffee | `src/command.coffee` | compileScript関数（202-246行目）でソースマップ生成を確認 |
| 2-2 | command.coffee | `src/command.coffee` | 237行目でwriteJs呼び出しを確認 |

**主要処理フロー**:
1. **223行目**: `compiled = CoffeeScript.compile task.input, task.options`
2. **225-227行目**: opts.mapの場合にソースマップを抽出
3. **237行目**: `writeJs base, task.file, task.output, saveTo, task.sourceMap`

#### Step 3: ファイル書き込み処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | command.coffee | `src/command.coffee` | writeJs関数（407-426行目）でソースマップ書き込みを確認 |

**主要処理フロー**:
- **407行目**: `writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->`
- **408行目**: `sourceMapPath = "#{jsPath}.map"`
- **420-424行目**: ソースマップ書き込み処理
- **421行目**: `fs.writeFile sourceMapPath, generatedSourceMap, (err) ->`
- **422-424行目**: エラー時の処理

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

```
compileScript (command.coffee:202)
    │
    ├─ CoffeeScript.compile
    │      └─ [opts.sourceMap] → v3SourceMap生成
    │
    └─ writeJs (command.coffee:407)
           │
           ├─ fs.writeFile jsPath (JavaScript書き込み)
           │
           └─ [generatedSourceMap !== null]
                  └─ fs.writeFile sourceMapPath
                         └─ [err]
                                └─ printLine + process.exit(1)
```

### データフロー図

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

task.input ───▶ CoffeeScript.compile() ───▶ compiled.v3SourceMap
                                                    │
                                                    ▼
                                          writeJs()
                                                    │
                                                    ▼
                                          fs.writeFile(sourceMapPath)
                                                    │
                                    ┌───────────────┴───────────────┐
                                    │ 成功                         │ 失敗
                                    ▼                               ▼
                              正常終了                        printLine()
                                                                    │
                                                                    ▼
                                                              process.exit(1)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| command.coffee | `src/command.coffee` | ソース | CLIエントリーポイント、ファイル書き込み処理 |
| coffeescript.coffee | `src/coffeescript.coffee` | ソース | ソースマップ生成 |
| sourcemap.coffee | `src/sourcemap.coffee` | ソース | ソースマップデータ構造 |
