# 機能設計書 20-標準入力フォーマット

## 概要

本ドキュメントは、Prettier CLIにおける標準入力フォーマット機能について記述する。

### 本機能の処理概要

**業務上の目的・背景**：エディタ統合やパイプ処理において、ファイルを介さずにコードをフォーマットする必要がある場合がある。標準入力フォーマット機能は、stdinからコードを受け取り、フォーマット結果をstdoutに出力する。--stdin-filepathオプションを使用することで、パーサーを自動推論させたり、適切な設定ファイルを解決させたりできる。

**機能の利用シーン**：
- エディタからの選択範囲フォーマット時
- パイプ処理でのコード整形時（例: `cat file.js | prettier --stdin-filepath file.js`）
- 一時ファイルを作成せずにコードを整形したい場合
- API経由でのコード整形時

**主要な処理内容**：
1. 標準入力からコードを読み込み（get-stdin）
2. --stdin-filepathが指定されている場合、パスを絶対パスに解決
3. 無視ルールの適用確認
4. 設定ファイルの解決
5. フォーマット処理の実行
6. 結果を標準出力に出力

**関連システム・外部連携**：
- get-stdin ライブラリ（stdin読み込み）
- パターン展開システム（使用しない - ファイルパターンなし時にstdinモード）
- 設定解決システム（resolveConfig）

**権限による制御**：ファイルシステムアクセス権限は--stdin-filepath使用時のみ必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 15 | Usage - CLI | 補助機能 | CLIでの標準入力フォーマット方法を説明 |

## 機能種別

データ変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stdin | stream | Yes | 標準入力からのコード | - |
| --stdin-filepath | string | No | 推論用の仮想ファイルパス | - |
| --parser | string | No | 使用するパーサー（省略時は--stdin-filepathから推論） | 有効なパーサー名 |
| --check / -c | boolean | No | チェックモード | - |
| --list-different / -l | boolean | No | 差分表示モード | - |

### 入力データソース

- 標準入力（stdin）からのテキストストリーム

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| stdout | string | フォーマットされたコード |
| stderr | string | エラーメッセージ（エラー時）、カーソルオフセット（cursorOffset指定時） |
| exitCode | number | 終了コード（0: 成功、1: 差分あり（--check時）、2: エラー） |

### 出力先

- 標準出力（フォーマット結果）
- 標準エラー出力（エラーメッセージ、カーソル位置）

## 処理フロー

### 処理シーケンス

```
1. useStdinの判定
   └─ hasFilePatterns=false && (!isStreamTTY(stdin) || context.argv.filepath)
2. formatStdin関数の呼び出し
   └─ --cacheは使用不可のチェック
3. 標準入力からコードを読み込み
   └─ getStdin()関数で全入力を取得
4. --stdin-filepathの絶対パス解決
   └─ path.resolve(filepath)
5. 無視ルールの確認（filepathがある場合）
   └─ createIsIgnoredFromContextOrDie()
   └─ 無視対象の場合は入力をそのまま出力
6. 設定の取得
   └─ getOptionsForFile(context, absoluteFilepath)
7. --check/--list-different処理
   └─ listDifferent関数を呼び出し（該当時は早期リターン）
8. フォーマット実行
   └─ format(context, input, options)
9. 結果の出力
   └─ writeOutput(context, formatted, options)
```

### フローチャート

```mermaid
flowchart TD
    A[開始: CLI] --> B{ファイルパターンあり?}
    B -->|Yes| C[formatFiles]
    B -->|No| D{stdin TTY?}
    D -->|Yes| E{--filepath指定?}
    E -->|No| F[ヘルプ表示]
    E -->|Yes| G[formatStdin]
    D -->|No| G
    G --> H[getStdin読み込み]
    H --> I{--stdin-filepath?}
    I -->|Yes| J[絶対パス解決]
    I -->|No| K[filepath=undefined]
    J --> L{無視対象?}
    K --> L
    L -->|Yes| M[入力をそのまま出力]
    L -->|No| N[getOptionsForFile]
    N --> O{--check/--list-different?}
    O -->|Yes| P[listDifferent処理]
    O -->|No| Q[format実行]
    P --> R{差分あり?}
    R -->|Yes| S[終了]
    R -->|No| S
    Q --> T[writeOutput]
    M --> S
    T --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-020-01 | stdin判定 | ファイルパターンなし && (非TTY or --filepath) | 常時 |
| BR-020-02 | --cache不可 | 標準入力モードでは--cacheオプション使用不可 | --cache使用時 |
| BR-020-03 | パーサー推論 | --stdin-filepath拡張子からパーサーを推論 | --parser未指定時 |
| BR-020-04 | 無視対象時 | 入力をそのまま出力（フォーマットしない） | isIgnored=true時 |
| BR-020-05 | カーソル出力 | cursorOffset指定時はstderrにオフセット出力 | options.cursorOffset >= 0時 |

### 計算ロジック

特になし

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

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

データベース操作なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 2 | UndefinedParserError | パーサーが不明（--stdin-filepath/--parser未指定） | エラーメッセージ出力 |
| 2 | SyntaxError | パースエラー | エラー位置出力 |
| - | CacheError | --cache使用時 | "cannot be used when formatting stdin" |

### リトライ仕様

リトライは行わない

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

トランザクション管理なし

## パフォーマンス要件

- 入力サイズに応じた処理時間
- stdin読み込み完了後にフォーマット開始

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

- 標準入力からの任意コード受け付け
- 設定ファイル解決時のファイルシステムアクセス

## 備考

- formatStdin関数内でperformanceTestFlagの処理もサポート
- エディタ統合での主要な利用形態

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.js | `src/cli/index.js` | useStdin判定とformatStdin呼び出し |

**主要処理フロー**:
1. **97-101行目**: useStdin判定ロジック
2. **102-108行目**: formatStdin呼び出しと--cacheエラーチェック

#### Step 2: formatStdin処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | format.js | `src/cli/format.js` | formatStdin関数 |

**主要処理フロー**:
- **225-270行目**: formatStdin関数本体
- **229行目**: getStdin()で標準入力読み込み
- **233行目**: 絶対パス解決
- **236-239行目**: 無視判定
- **241-243行目**: 無視対象時のそのまま出力
- **246-250行目**: 設定取得
- **252-254行目**: listDifferent処理
- **256行目**: format実行
- **266行目**: writeOutput出力

#### Step 3: 出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | format.js | `src/cli/format.js` | writeOutput関数 |

**主要処理フロー**:
- **74-83行目**: writeOutput関数
- **76-78行目**: process.stdout.writeで結果出力
- **80-82行目**: cursorOffset時のstderr出力

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

```
prettier --stdin-filepath file.js < input.js
    │
    └─ run() [index.js]
           │
           └─ main(context)
                  │
                  ├─ useStdin判定
                  │      └─ !hasFilePatterns && (!isTTY || filepath)
                  │
                  └─ formatStdin(context) [format.js]
                         │
                         ├─ getStdin() [get-stdin]
                         │
                         ├─ path.resolve(filepath)
                         │
                         ├─ createIsIgnoredFromContextOrDie()
                         │
                         ├─ getOptionsForFile(context, filepath)
                         │
                         ├─ listDifferent() [--check/--list-different時]
                         │
                         ├─ format(context, input, options)
                         │      └─ prettier.formatWithCursor()
                         │
                         └─ writeOutput(context, result, options)
                                └─ process.stdout.write()
```

### データフロー図

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

stdin ───▶ getStdin() ───▶ input (string)
                │
                ▼
--stdin-filepath ───▶ path.resolve() ───▶ absoluteFilepath
                │
                ▼
          isIgnored(filepath)?
                │
        ┌───────┴───────┐
        │               │
     [true]          [false]
        │               │
        ▼               ▼
    input出力    getOptionsForFile()
                        │
                        ▼
               format(input, options)
                        │
                        ▼
               writeOutput(result)
                        │
                        ▼
                     stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `src/cli/index.js` | ソース | useStdin判定、formatStdin呼び出し |
| format.js | `src/cli/format.js` | ソース | formatStdin関数、writeOutput関数 |
| mockable.js | `src/cli/mockable.js` | ソース | isStreamTTY関数 |
| options/get-options-for-file.js | `src/cli/options/get-options-for-file.js` | ソース | ファイル別設定取得 |
| prettier-internal.js | `src/cli/prettier-internal.js` | ソース | createIsIgnoredFunction |
| context.js | `src/cli/context.js` | ソース | argv.filepath取得 |
