# 機能設計書 32-stdioオプション

## 概要

本ドキュメントは、CoffeeScript CLIの`--stdio`（`-s`）オプションの機能設計を記述する。このオプションは、標準入力（stdin）からCoffeeScriptコードを受け取り、コンパイルした結果を標準出力（stdout）に出力するパイプライン処理を実現する機能である。

### 本機能の処理概要

**業務上の目的・背景**：Unix哲学に基づくパイプラインプログラミングをサポートし、他のコマンドラインツールとCoffeeScriptコンパイラを連携させることを目的とする。シェルスクリプトやビルドプロセスでの自動化、ファイルを介さないストリーム処理を可能にし、柔軟なワークフロー構築を支援する。

**機能の利用シーン**：
- シェルスクリプト内でCoffeeScriptをコンパイルする際、一時ファイルを作成せずにパイプで処理したい場合
- `cat`や`echo`でコードを生成し、直接コンパイルしたい場合
- 複数ファイルを`cat`で結合してからコンパイルしたい場合（`--join`の代替手段）
- CI/CDパイプラインでのビルドプロセス自動化

**主要な処理内容**：
1. `--stdio`オプションが指定されているかを判定
2. `process.openStdin()`で標準入力ストリームを開く
3. `data`イベントでチャンク単位のデータを受信し、バッファに蓄積
4. `end`イベントで入力完了を検知
5. 蓄積したバッファを結合してCoffeeScriptコードとして取得
6. `compileScript`関数でコンパイル処理を実行
7. 結果を標準出力に出力

**関連システム・外部連携**：Node.jsの標準入力/出力ストリーム（`process.stdin`、`process.stdout`）を使用。他のシェルコマンドとパイプ（`|`）で連携可能。

**権限による制御**：特になし。

## 関連画面

本機能はCLI機能のため、画面との直接的な関連はない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

入出力処理 / コンパイル

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --stdio / -s | Boolean | No | 標準入出力モードを有効にする | - |
| --literate / -l | Boolean | No | 入力をLiterate CoffeeScriptとして扱う | - |
| --compile / -c | Boolean | No | stdioとの組み合わせでprintモードを有効化 | - |
| stdin | String (stream) | Yes（--stdio指定時） | CoffeeScriptソースコード | 構文エラーの場合はコンパイルエラー |

### 入力データソース

標準入力ストリーム（`process.stdin`）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| compiledJS | String | コンパイルされたJavaScriptコード |

### 出力先

標準出力（`process.stdout`）

## 処理フロー

### 処理シーケンス

```
1. parseOptions関数でコマンドライン引数を解析
   └─ opts.stdioがtrueに設定される
2. run関数でopts.stdioをチェック
   └─ trueの場合、compileStdio()を呼び出し
3. compileStdio関数の実行
   └─ --mapオプションとの併用チェック（エラーの場合は終了）
4. 標準入力ストリームのオープン
   └─ process.openStdin()でstdinを取得
5. dataイベントハンドラの設定
   └─ 受信したバッファチャンクをbuffers配列に蓄積
6. endイベントハンドラの設定
   └─ Buffer.concatで全バッファを結合し、文字列に変換
7. compileScript関数の呼び出し
   └─ file引数はnull、inputは結合した文字列
8. コンパイル結果の出力
   └─ opts.printがtrueの場合、printLine(task.output.trim())で出力
```

### フローチャート

```mermaid
flowchart TD
    A[coffee --stdio 実行] --> B{--map オプションあり?}
    B -->|Yes| C[エラー: --stdio and --map cannot be used together]
    C --> D[process.exit 1]
    B -->|No| E[buffers = 空配列]
    E --> F[stdin = process.openStdin]
    F --> G[stdin.on 'data' イベント待機]
    G --> H{データ受信?}
    H -->|Yes| I[buffers.push buffer]
    I --> G
    H -->|No/end| J[stdin.on 'end' イベント]
    J --> K[Buffer.concat で結合]
    K --> L[toString で文字列変換]
    L --> M[compileScript null, input]
    M --> N{コンパイル成功?}
    N -->|Yes| O[printLine で結果出力]
    N -->|No| P[エラーメッセージ出力]
    O --> Q[終了]
    P --> R[process.exit 1]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-32-01 | ソースマップ非対応 | `--stdio`と`--map`は同時に使用できない | --stdio指定時 |
| BR-32-02 | ファイル名null | stdioモードではファイル名がnullとして処理される | --stdio指定時 |
| BR-32-03 | printモード自動有効 | `--stdio`と`--compile`の組み合わせで`--print`が自動的に有効になる | --stdio && --compile |
| BR-32-04 | ストリーム完全読み込み | endイベントまでデータを完全に受信してからコンパイル | 常時 |

### 計算ロジック

特になし。

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 標準エラー | --stdioと--mapの併用 | --mapオプションを外す |
| SYNTAX_ERROR | SyntaxError | 入力されたCoffeeScriptに構文エラーがある | コードを修正する |
| - | 実行時エラー | stdinの読み取りエラー | 入力元を確認する |

### リトライ仕様

リトライは行わない。エラー発生時は即座にprocess.exit(1)で終了。

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

該当なし。

## パフォーマンス要件

- 大量のデータを処理する場合、メモリ使用量に注意
- バッファはすべてメモリ上に蓄積されるため、非常に大きなファイルには不向き

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

- 標準入力から受け取ったコードをコンパイルするため、信頼できないソースからの入力には注意
- コンパイル結果の実行には別途セキュリティ検討が必要

## 備考

- `--join`オプションの非推奨に伴い、複数ファイル結合の代替手段として`cat ... | coffee --stdio`が推奨される
- `--literate`オプションとの併用で、Literate CoffeeScriptのstdio処理も可能

---

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

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

### 推奨読解順序

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

まず、--stdioオプションがどのように定義されているかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | command.coffee | `src/command.coffee` | SWITCHESでの-s/--stdioオプション定義 |

**主要処理フロー**:
- **51行目**: `-s`/`--stdio`オプションの定義（`'listen for and compile scripts over stdio'`）

#### Step 2: オプション解析と実行フロー分岐を理解する

run関数での分岐処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.coffee | `src/command.coffee` | run関数内でのopts.stdioチェック |
| 2-2 | command.coffee | `src/command.coffee` | parseOptions関数でのprint設定 |

**主要処理フロー**:
- **101行目**: `return compileStdio() if opts.stdio` - stdioモードの場合はcompileStdioを呼び出し
- **449行目**: `o.print = !! (o.print or (o.eval or o.stdio and o.compile))` - stdio && compileでprintが有効化

#### Step 3: compileStdio関数を理解する

標準入出力処理の本体を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | command.coffee | `src/command.coffee` | compileStdio関数の実装 |

**主要処理フロー**:
- **250行目**: compileStdio関数の開始
- **251-253行目**: --mapオプションとの併用チェック
  ```coffeescript
  if opts.map
    console.error '--stdio and --map cannot be used together'
    process.exit 1
  ```
- **254行目**: `buffers = []` - 受信データ格納用配列の初期化
- **255行目**: `stdin = process.openStdin()` - 標準入力ストリームのオープン
- **256-257行目**: `stdin.on 'data', (buffer) -> buffers.push buffer if buffer` - dataイベントハンドラ
- **258-259行目**: `stdin.on 'end', -> compileScript null, Buffer.concat(buffers).toString()` - endイベントハンドラ

**読解のコツ**: Node.jsのStreamイベントモデルを理解していると読みやすい。`data`は複数回発火し、`end`は入力完了時に1回発火する。

#### Step 4: compileScript関数との連携を理解する

コンパイル処理がどのように実行されるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | command.coffee | `src/command.coffee` | compileScript関数（ファイル名がnullの場合の処理） |

**主要処理フロー**:
- **202行目**: `compileScript = (file, input, base = null) ->` - fileがnullで呼ばれる
- **203行目**: `options = compileOptions file, base` - コンパイルオプション生成
- **230-231行目**: `if opts.print then printLine task.output.trim()` - 結果を標準出力に出力

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

```
exports.run (command.coffee:72)
    │
    ├─ parseOptions (command.coffee:445)
    │      └─ o.print = true (if stdio && compile)
    │
    └─ compileStdio (command.coffee:250)
           │
           ├─ opts.map チェック
           │      └─ エラー時 process.exit(1)
           │
           ├─ process.openStdin()
           │
           ├─ stdin.on('data', ...)
           │      └─ buffers.push(buffer)
           │
           └─ stdin.on('end', ...)
                  └─ compileScript(null, Buffer.concat(buffers).toString())
                         │
                         ├─ compileOptions(null, null)
                         │
                         ├─ CoffeeScript.compile(input, options)
                         │
                         └─ printLine(task.output.trim())
```

### データフロー図

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

stdin                 compileStdio                      stdout
(パイプ/リダイレクト)       │                               │
     │                     │                               │
     ▼                     ▼                               ▼
chunk1 ───data───▶ buffers.push(chunk1)
chunk2 ───data───▶ buffers.push(chunk2)
...                        │
EOF ──────end────▶ Buffer.concat(buffers)
                          │
                          ▼
                   compileScript(null, input)
                          │
                          ▼
                   CoffeeScript.compile
                          │
                          ▼
                   printLine(js) ───▶ process.stdout.write
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| command.coffee | `src/command.coffee` | ソース | CLI本体、compileStdio関数、run関数 |
| optparse.coffee | `src/optparse.coffee` | ソース | オプションパーサー |
| coffeescript.coffee | `src/coffeescript.coffee` | ソース | compile関数（コンパイル本体） |
