# 機能設計書 35-repl

## 概要

本ドキュメントは、Node.js の `repl` モジュール（対話型実行環境（REPL））の機能設計書である。このモジュールは、Read-Eval-Print Loop（読み取り・評価・出力のループ）を実装し、対話型のJavaScript実行環境を提供する。

### 本機能の処理概要

repl モジュールは、ユーザーがJavaScriptコードを対話的に入力・実行し、結果を即座に確認できる環境を提供する。標準入出力やネットワークソケットを介して接続可能で、コマンド履歴、タブ補完、複数行入力、カスタムコマンドなどの機能を備えている。

**業務上の目的・背景**：開発者がNode.js環境でコードを対話的にテスト・デバッグするために、REPL環境は不可欠である。APIの動作確認、プロトタイピング、デバッグセッションなど、様々な開発シーンで利用される。

**機能の利用シーン**：
- `node` コマンドの対話モード（引数なしで起動）
- アプリケーション内でのデバッグインターフェース
- リモートデバッグ用のソケットベースREPL
- カスタムCLIツールの構築
- 教育・学習目的でのJavaScript実行環境

**主要な処理内容**：
1. REPLサーバーの起動（`start()` / `new REPLServer()`）
2. コードの読み取り・評価・結果出力
3. コマンド履歴の管理
4. タブ補完機能
5. カスタムコマンドの定義（`.break`、`.clear`、`.exit`等）
6. エディタモードでの複数行入力

**関連システム・外部連携**：
- `vm` モジュール（コード評価）
- `readline` モジュール（行入力処理）
- `domain` モジュール（エラーハンドリング）
- `fs` モジュール（履歴ファイル、.load/.save）

**権限による制御**：特段の権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ターミナルベースの対話型UIのため画面なし |

## 機能種別

対話型実行 / コード評価 / CLI

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| prompt | string | No | 表示するプロンプト文字列 | デフォルト: '> ' |
| input | Readable | No | 入力ストリーム | Readableであること |
| output | Writable | No | 出力ストリーム | Writableであること |
| eval | Function | No | カスタム評価関数 | 関数であること |
| useGlobal | boolean | No | グローバルコンテキストを使用するか | デフォルト: false |
| ignoreUndefined | boolean | No | undefinedを出力しないか | デフォルト: false |
| replMode | symbol | No | sloppyモードかstrictモードか | REPL_MODE_SLOPPY/STRICT |
| terminal | boolean | No | TTYとして扱うか | - |
| preview | boolean | No | プレビュー機能を有効にするか | - |
| useColors | boolean | No | カラー出力を使用するか | - |

### 入力データソース

- 標準入力（stdin）
- ネットワークソケット
- カスタムストリーム

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | any | 評価結果 |
| _ | any | 最後に評価された値 |
| _error | Error | 最後に発生したエラー |

### 出力先

- 標準出力（stdout）
- 指定された出力ストリーム
- ファイル（.save コマンド）

## 処理フロー

### 処理シーケンス

```
1. REPLサーバー初期化
   └─ start(options) または new REPLServer(options)
2. コンテキスト作成
   └─ createContext() でVMコンテキストを作成
3. プロンプト表示
   └─ displayPrompt() でプロンプトを出力
4. 入力読み取り
   └─ readline で1行ずつ読み取り
5. コマンド判定
   └─ '.' で始まる場合はREPLコマンドとして処理
6. コード評価
   └─ eval(code, context, filename, callback)
7. 結果出力
   └─ writer(result) で整形して出力
8. ループ継続
   └─ 3へ戻る（.exitまで）
```

### フローチャート

```mermaid
flowchart TD
    A[REPLServer初期化] --> B[コンテキスト作成]
    B --> C[プロンプト表示]
    C --> D[入力待ち]
    D --> E{入力あり?}
    E -->|No| F{EOF?}
    F -->|Yes| G[終了]
    F -->|No| D
    E -->|Yes| H{REPLコマンド?}
    H -->|Yes| I[コマンド実行]
    I --> C
    H -->|No| J{複数行継続?}
    J -->|Yes| K[バッファに追加]
    K --> D
    J -->|No| L[eval実行]
    L --> M{エラー?}
    M -->|Yes| N[Recoverable?]
    N -->|Yes| K
    N -->|No| O[エラー出力]
    M -->|No| P[結果出力]
    O --> C
    P --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 最終値保存 | 評価結果は `_` 変数に保存される | 毎回の評価後 |
| BR-02 | エラー保存 | 最後のエラーは `_error` 変数に保存される | エラー発生時 |
| BR-03 | 複数行入力 | 構文が不完全な場合は継続入力を受け付ける | Recoverable エラー時 |
| BR-04 | Ctrl+C | 現在の入力をクリアする | SIGINT 受信時 |
| BR-05 | Ctrl+D | REPLを終了する | EOF 受信時 |

### 計算ロジック

特段の複雑な計算ロジックはなし。

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

該当なし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SyntaxError | Recoverable | 構文が不完全 | 継続入力を待つ |
| ReferenceError | Error | 未定義変数の参照 | 変数を定義する |
| ERR_INVALID_REPL_EVAL_CONFIG | Error | breakEvalOnSigint と custom eval の両方指定 | 設定を修正 |
| ERR_INVALID_REPL_INPUT | Error | uncaughtException リスナー登録試行 | リスナー登録を避ける |

### リトライ仕様

構文エラーがRecoverable（回復可能）な場合、追加入力を待機する。

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

該当なし

## パフォーマンス要件

- タブ補完はリアルタイムで応答
- プレビュー機能は入力に追従

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

- REPLは任意のコードを実行可能なため、信頼できるユーザーのみアクセス可能にすること
- ネットワーク経由のREPLは認証を設けること
- `--experimental-repl-await` でトップレベル await が使用可能

## 備考

- デフォルトで `--experimental-repl-await` が有効
- `.editor` コマンドでエディタモードに入る
- `.load` / `.save` でセッションの保存・復元が可能

---

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

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

### 推奨読解順序

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

まず、REPLServerクラスの構造と主要なプロパティを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | repl.js | `lib/repl.js` | モジュール冒頭のコメント（22-41行目） |

**読解のコツ**: ファイル冒頭のコメントにREPLの基本的な使い方が記載されている。REPLServerはreadline.Interfaceを継承している。

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

モジュールのエクスポートと start 関数を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | repl.js | `lib/repl.js` | module.exports（1390-1398行目） |
| 2-2 | repl.js | `lib/repl.js` | start 関数（1187-1190行目） |
| 2-3 | repl.js | `lib/repl.js` | REPLServer クラス（225-1183行目） |

**主要処理フロー**:
1. **1187-1190行目**: start() - REPLServerインスタンスを作成して返す
2. **1390-1398行目**: module.exports で主要APIをエクスポート

#### Step 3: REPLServer クラスの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | repl.js | `lib/repl.js` | コンストラクタ（225-358行目） |
| 3-2 | repl.js | `lib/repl.js` | defaultEval（404-632行目） |
| 3-3 | repl.js | `lib/repl.js` | createContext（1050-1104行目） |

**主要処理フロー**:
- **225-277行目**: オプション処理とストリーム設定
- **314-324行目**: breakEvalOnSigint 設定
- **368行目**: デフォルト評価関数の設定（eval_ ||= defaultEval）
- **404-632行目**: defaultEval - コードの評価処理
- **839-943行目**: 'line' イベントハンドラ - 入力処理

#### Step 4: コンテキスト管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | repl.js | `lib/repl.js` | createContext（1050-1104行目） |
| 4-2 | repl.js | `lib/repl.js` | resetContext（1105-1142行目） |

**主要処理フロー**:
- **1050-1104行目**: createContext - VMコンテキストまたはグローバル使用
- **1055-1062行目**: inspectorコマンドでコンテキストID取得
- **1085-1103行目**: module, require をコンテキストに追加
- **1105-1142行目**: resetContext - コンテキストのリセットと `_`, `_error` の設定

#### Step 5: デフォルトコマンドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | repl.js | `lib/repl.js` | defineDefaultCommands（1273-1388行目） |

**主要処理フロー**:
- **1274-1280行目**: .break コマンド
- **1288-1298行目**: .clear コマンド
- **1300-1305行目**: .exit コマンド
- **1307-1325行目**: .help コマンド
- **1327-1345行目**: .save コマンド
- **1347-1377行目**: .load コマンド
- **1378-1387行目**: .editor コマンド

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

```
repl.start(options)
    │
    └─ new REPLServer(options)
           │
           ├─ Interface.call(this, options)
           │      └─ readline.Interface 初期化
           │
           ├─ this.resetContext()
           │      └─ this.createContext()
           │             ├─ useGlobal ? globalThis : vm.createContext()
           │             └─ module, require 追加
           │
           ├─ defineDefaultCommands(this)
           │      └─ .break, .clear, .exit, .help, .save, .load, .editor 定義
           │
           └─ this.displayPrompt()

on('line', cmd)
    │
    ├─ trimmedCmd が '.' で始まる → parseREPLKeyword()
    │      └─ コマンド実行
    │
    └─ this.eval(evalCmd, context, filename, finish)
           │
           └─ defaultEval(code, context, file, cb)
                  │
                  ├─ processTopLevelAwait(code) // await 対応
                  ├─ makeContextifyScript(code, ...) // スクリプト作成
                  └─ runInContext/runInThisContext // 実行
```

### データフロー図

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

ユーザー入力 ─────────▶ readline ─────────────────▶ line イベント
      │
      ▼
'line' ハンドラ ────────▶ eval(code, context) ──────▶ 評価結果
      │                        │
      ▼                        ▼
コマンド判定 ─────────▶ commands[keyword].action() ──▶ コマンド結果
      │
      ▼
writer(result) ────────▶ inspect(result) ───────────▶ 出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| repl.js | `lib/repl.js` | ソース | メインモジュール実装 |
| utils.js | `lib/internal/repl/utils.js` | ソース | REPLユーティリティ |
| completion.js | `lib/internal/repl/completion.js` | ソース | タブ補完機能 |
| await.js | `lib/internal/repl/await.js` | ソース | トップレベルawait処理 |
| interface.js | `lib/internal/readline/interface.js` | ソース | readline基盤 |
| vm.js | `lib/vm.js` | ソース | コード評価 |
| domain.js | `lib/domain.js` | ソース | エラーハンドリング |
