# 機能設計書 20---compileオプション

## 概要

本ドキュメントは、CoffeeScriptのcoffeeコマンドにおける`--compile`オプションの設計を記述する。このオプションは、CoffeeScriptファイルをJavaScriptファイルにコンパイルして保存する機能を提供する。

### 本機能の処理概要

`--compile`オプションは、CoffeeScriptファイルをJavaScriptに変換し、結果を.jsファイルとしてファイルシステムに保存する機能である。

**業務上の目的・背景**：CoffeeScriptで書かれたソースコードを本番環境やブラウザで実行するためには、JavaScriptにコンパイルする必要がある。`--compile`オプションは、この変換処理を行い、.jsファイルとして保存する。これにより、ビルドプロセスに組み込んだり、配布用のJavaScriptファイルを生成したりすることができる。ディレクトリを指定した場合は再帰的に全ての.coffeeファイルをコンパイルし、`--output`オプションと組み合わせて出力先を指定することも可能である。

**機能の利用シーン**：
- 単一ファイルコンパイル：`coffee -c script.coffee` で script.js を生成
- ディレクトリコンパイル：`coffee -c src/` で src/ 内の全 .coffee ファイルをコンパイル
- 出力先指定：`coffee -c -o dist/ src/` で dist/ にコンパイル結果を出力
- ソースマップ付き：`coffee -c -m script.coffee` で script.js と script.js.map を生成
- 監視付きコンパイル：`coffee -c -w script.coffee` でファイル変更時に自動再コンパイル

**主要な処理内容**：
1. オプション解析：`-c` または `--compile` フラグの検出
2. ソースファイルの読み込み：ファイルシステムからCoffeeScriptコードを読み込み
3. コンパイル実行：CoffeeScript.compile() でJavaScriptに変換
4. 出力パス計算：outputPath() で出力先ファイルパスを決定
5. ディレクトリ作成：必要に応じてmkdirpで出力ディレクトリを作成
6. ファイル書き出し：writeJs() でJavaScriptファイルを保存
7. ソースマップ出力（オプション）：.js.mapファイルの生成

**関連システム・外部連携**：
- command.coffee：CLIオプション処理
- coffeescript.coffee：コンパイルエンジン
- sourcemap.litcoffee：ソースマップ生成
- Node.js fs：ファイルシステム操作

**権限による制御**：特になし。OSレベルのファイル書き込み権限に依存。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | Annotated Source - Command | 補助機能 | コンパイルオプションの解説を含む |
| 33 | Annotated Source - Command | 補助機能 | コンパイルオプションの解説を含む（v2） |

## 機能種別

CLI / ファイル変換・保存

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -c, --compile | Flag | Yes | コンパイルモードを有効化 | - |
| source | Path | Yes | コンパイル対象のファイルまたはディレクトリ | 存在するパス |
| -o, --output | Path | No | 出力先パス | 書き込み可能なパス |
| -m, --map | Flag | No | ソースマップを生成 | - |
| -M, --inline-map | Flag | No | インラインソースマップを生成 | - |
| -b, --bare | Flag | No | トップレベル関数ラッパーなし | - |
| -t, --transpile | Flag | No | Babelでトランスパイル | - |
| --no-header | Flag | No | "Generated by"ヘッダーを抑制 | - |

### 入力データソース

ファイルシステム上のCoffeeScriptファイル（.coffee, .litcoffee, .coffee.md）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| .jsファイル | File | コンパイルされたJavaScriptファイル |
| .js.mapファイル | File | ソースマップファイル（--map時） |

### 出力先

- デフォルト：ソースファイルと同じディレクトリに .js 拡張子で出力
- --output指定時：指定されたディレクトリまたはファイルパスに出力

## 処理フロー

### 処理シーケンス

```
1. run()でコマンド実行
   └─ opts.compileがtrueの場合、コンパイルモード

2. compilePath()でパスを処理
   ├─ ディレクトリの場合、再帰的にファイルを処理
   └─ ファイルの場合、compileScript()を呼び出し

3. compileScript()でコンパイル
   ├─ CoffeeScript.compile()でJavaScriptに変換
   ├─ opts.mapがtrueの場合、v3SourceMapを取得
   └─ writeJs()を呼び出し

4. outputPath()で出力パスを計算
   ├─ --outputが指定されている場合、指定パスを使用
   └─ 未指定の場合、ソースファイルと同じ場所

5. writeJs()でファイル書き出し
   ├─ mkdirp()で出力ディレクトリを作成
   ├─ fs.writeFile()でJSファイルを書き出し
   └─ --mapの場合、.js.mapファイルも書き出し
```

### フローチャート

```mermaid
flowchart TD
    A[coffee -c source.coffee] --> B[run関数]
    B --> C[compilePath]
    C --> D{ディレクトリ?}
    D -->|Yes| E[再帰的に各ファイルを処理]
    D -->|No| F[compileScript]
    E --> F
    F --> G[CoffeeScript.compile]
    G --> H{--map?}
    H -->|Yes| I[ソースマップも取得]
    H -->|No| J[JSのみ取得]
    I --> K[outputPath計算]
    J --> K
    K --> L[writeJs]
    L --> M{ディレクトリ存在?}
    M -->|No| N[mkdirp]
    M -->|Yes| O[fs.writeFile]
    N --> O
    O --> P{--map?}
    P -->|Yes| Q[.js.mapファイル書き出し]
    P -->|No| R[完了]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-20-01 | 拡張子変換 | .coffee/.litcoffee/.coffee.md を .js に変換 | コンパイル時 |
| BR-20-02 | 暗黙のコンパイル | --output指定時は--compileも暗黙的に有効 | --output指定時 |
| BR-20-03 | ディレクトリ再帰 | ディレクトリ指定時は再帰的に全ファイルを処理 | ディレクトリ指定時 |
| BR-20-04 | 構造保持 | --outputでディレクトリを指定した場合、元のディレクトリ構造を保持 | --output + ディレクトリ |
| BR-20-05 | ヘッダー付加 | デフォルトで"Generated by CoffeeScript"ヘッダーを付加 | --no-header未指定時 |
| BR-20-06 | 空ファイル防止 | 出力が空の場合、空白1文字を書き出し | 出力が空の場合 |

### 計算ロジック

出力パス計算（outputPath関数）:
```coffeescript
outputPath = (source, base, extension=".js") ->
  basename  = helpers.baseFileName source, yes, useWinPathSep
  srcDir    = path.dirname source
  dir = unless opts.outputPath
    srcDir
  else if source is base
    opts.outputPath
  else
    path.join opts.outputPath, path.relative base, srcDir
  path.join dir, basename + extension
```

## データベース操作仕様

### 操作別データベース影響一覧

データベースは使用しない。

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ENOENT | ファイル未発見 | ソースファイルが存在しない | エラーメッセージを表示してexit 1 |
| SyntaxError | 構文エラー | CoffeeScriptの構文が不正 | エラーメッセージを表示、--watchなら続行 |
| EACCES | 権限エラー | 出力先への書き込み権限がない | エラーメッセージを表示してexit 1 |

### リトライ仕様

--watchモードでは構文エラー発生後も監視を継続し、ファイル修正後に再コンパイルを試みる。

## トランザクション仕様

トランザクションは使用しない。ファイル書き込みは非アトミック。

## パフォーマンス要件

特に定められていない。

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

- 出力先パスの検証はOSレベルの権限に依存
- シンボリックリンクの追跡に注意

## 備考

- --mapオプションでソースマップを生成し、デバッグを容易にする
- --inline-mapオプションでソースマップをJSファイル内にインライン化
- --transpileオプションでBabelを使用してES5へ変換可能

---

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

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

### 推奨読解順序

#### Step 1: オプション定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | command.coffee | `src/command.coffee` | 37行目の--compile オプション定義を理解する |

**読解のコツ**: SWITCHES配列の `['-c', '--compile', 'compile to JavaScript and save as .js files']` が--compileオプションの定義。

**主要処理フロー**:
- **37行目**: `['-c', '--compile', 'compile to JavaScript and save as .js files']`

#### Step 2: オプション解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.coffee | `src/command.coffee` | 445-449行目のparseOptions関数を理解する |

**主要処理フロー**:
- **447行目**: `o.compile or= !!o.output` で--outputがあれば--compileを暗黙的に有効化
- **448行目**: `o.run = not (o.compile or o.print or o.map)` で実行モードを決定

#### Step 3: コンパイル処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | command.coffee | `src/command.coffee` | 222-237行目のcompileScript内のコンパイル分岐を理解する |

**主要処理フロー**:
- **223行目**: `compiled = CoffeeScript.compile task.input, task.options`
- **225-227行目**: --mapの場合、jsとv3SourceMapを分離
- **232-237行目**: --compileまたは--mapの場合、writeJsを呼び出し

#### Step 4: ファイル出力を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | command.coffee | `src/command.coffee` | 376-385行目のoutputPath関数を理解する |
| 4-2 | command.coffee | `src/command.coffee` | 407-426行目のwriteJs関数を理解する |

**主要処理フロー**:
- **376-385行目**: 出力パスの計算ロジック
- **411行目**: `if opts.compile` でコンパイルモードを確認
- **412行目**: `js = ' ' if js.length <= 0` で空ファイル防止
- **413行目**: ソースマップ参照をJSファイル末尾に追加
- **414-419行目**: fs.writeFileでJSファイルを書き出し
- **420-424行目**: --mapの場合、ソースマップファイルも書き出し

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

```
coffee -c source.coffee
    │
    └─ exports.run() (command.coffee:72)
           │
           ├─ parseOptions() (command.coffee:445)
           │      └─ opts.compile = true を設定
           │
           └─ compilePath() (command.coffee:151)
                  │
                  └─ compileScript() (command.coffee:202)
                         │
                         ├─ CoffeeScript.compile() (coffeescript.coffee)
                         │
                         ├─ outputPath() (command.coffee:376)
                         │      └─ 出力パスを計算
                         │
                         └─ writeJs() (command.coffee:407)
                                │
                                ├─ mkdirp() (command.coffee:388)
                                │      └─ 出力ディレクトリを作成
                                │
                                ├─ fs.writeFile() - JSファイル
                                │
                                └─ fs.writeFile() - .js.mapファイル（オプション）
```

### データフロー図

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

source.coffee          coffeeコマンド                   結果
    │                        │                              │
fs.readFileSync ─────▶  CoffeeScript.compile        ├─ source.js
                              │                        │
                        outputPath()                 ├─ source.js.map
                              │                        │   (オプション)
                        writeJs()                    │
                              │                      └─ ディレクトリ構造
                        fs.writeFile() ─────────────────────▶
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| command.coffee | `src/command.coffee` | ソース | --compileオプション処理 |
| coffeescript.coffee | `src/coffeescript.coffee` | ソース | コンパイルエンジン |
| sourcemap.litcoffee | `src/sourcemap.litcoffee` | ソース | ソースマップ生成 |
| optparse.coffee | `src/optparse.coffee` | ソース | オプション解析 |
