# 機能設計書 39-tty

## 概要

本ドキュメントは、Node.js の `tty` モジュール（端末（TTY）制御機能）の機能設計書である。このモジュールは、テレタイプ端末（TTY）に関連する機能を提供し、端末のサイズ取得、Raw モード設定、色深度の判定などを行う。

### 本機能の処理概要

tty モジュールは、プロセスがTTY（端末）に接続されているかどうかを判定し、端末の入出力を制御するための機能を提供する。ReadStream（入力）とWriteStream（出力）クラスを通じて、端末特有の機能（Raw モード、ウィンドウサイズ、色サポート等）にアクセスできる。

**業務上の目的・背景**：CLIアプリケーションでは、端末の特性に応じた表示や入力処理が必要となる。ttyモジュールは、端末の能力を判定し、適切な制御を行うための基盤を提供する。

**機能の利用シーン**：
- 端末かどうかの判定（パイプやリダイレクトとの区別）
- カラー出力のサポート判定
- ウィンドウサイズの取得・変更検知
- Raw モードでのキー入力処理
- カーソル制御・画面制御

**主要な処理内容**：
1. TTY判定（`isatty()`）
2. 端末入力ストリームの作成（`ReadStream`）
3. 端末出力ストリームの作成（`WriteStream`）
4. Raw モードの設定（`setRawMode()`）
5. ウィンドウサイズの取得（`getWindowSize()` / `columns` / `rows`）
6. 色深度の判定（`getColorDepth()` / `hasColors()`）

**関連システム・外部連携**：
- オペレーティングシステムの TTY サブシステム
- `readline` モジュール（端末入力）
- `net` モジュール（ソケット基盤）

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

## 関連画面

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

## 機能種別

端末制御 / 入出力 / デバイス判定

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fd | number | Yes | ファイルディスクリプタ | 0以上の整数 |
| flag | boolean | Yes | Raw モードのオン/オフ | 真偽値 |
| x | number | No | カーソルX座標 | 正の整数 |
| y | number | No | カーソルY座標 | 正の整数 |
| env | object | No | 環境変数オブジェクト | オブジェクト |
| depth | number | No | 必要な色深度 | 正の整数 |

### 入力データソース

- ファイルディスクリプタ（stdin: 0、stdout: 1、stderr: 2）
- オペレーティングシステムからの端末情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isTTY | boolean | 端末かどうか |
| columns | number | 端末の列数 |
| rows | number | 端末の行数 |
| colorDepth | number | サポートする色深度（1, 4, 8, 24） |

### 出力先

- 関数の戻り値
- WriteStreamのプロパティ

## 処理フロー

### 処理シーケンス

```
1. TTY判定
   └─ isatty(fd) で端末かどうかを判定
2. ストリーム作成
   └─ new ReadStream(fd) または new WriteStream(fd)
3. 初期化
   └─ TTYネイティブハンドルの作成と初期化
4. ウィンドウサイズ取得
   └─ getWindowSize() で列数・行数を取得
5. Raw モード設定（オプション）
   └─ setRawMode(true) でキーごとの入力を有効化
```

### フローチャート

```mermaid
flowchart TD
    A[isatty/fd] --> B{TTY?}
    B -->|Yes| C[true 返却]
    B -->|No| D[false 返却]

    E[new ReadStream/fd] --> F[TTY ネイティブ作成]
    F --> G{成功?}
    G -->|Yes| H[net.Socket 初期化]
    G -->|No| I[ERR_TTY_INIT_FAILED]
    H --> J[isRaw = false, isTTY = true]

    K[new WriteStream/fd] --> L[TTY ネイティブ作成]
    L --> M{成功?}
    M -->|Yes| N[net.Socket 初期化]
    M -->|No| O[ERR_TTY_INIT_FAILED]
    N --> P[setBlocking/true]
    P --> Q[getWindowSize/]
    Q --> R[columns, rows 設定]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | fd有効性 | ファイルディスクリプタは0以上2147483647以下の整数 | isatty呼び出し時 |
| BR-02 | Raw モード | Raw モード時はキー入力ごとにdataイベントが発火 | setRawMode(true)時 |
| BR-03 | 色深度判定 | TERM、COLORTERM、CI等の環境変数から判定 | getColorDepth呼び出し時 |
| BR-04 | resizeイベント | ウィンドウサイズ変更時にイベント発火 | WriteStream使用時 |

### 計算ロジック

色深度判定は環境変数と端末タイプから算出される。

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

該当なし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR_INVALID_FD | Error | 無効なファイルディスクリプタ | 有効なfdを渡す |
| ERR_TTY_INIT_FAILED | Error | TTY初期化失敗 | システム状態を確認 |

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- WriteStream はブロッキングモードで動作（出力のインターリーブ防止）
- isatty() は軽量で頻繁な呼び出しが可能

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

- Raw モードでのパスワード入力時はエコーを無効化すること
- 端末制御シーケンスのインジェクションに注意

## 備考

- `process.stdin` は fd=0 の ReadStream に相当
- `process.stdout` / `process.stderr` は fd=1/2 の WriteStream に相当
- SIGWINCH シグナルでウィンドウサイズ変更を検知

---

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

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

### 推奨読解順序

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

まず、tty モジュールのエクスポートと主要クラスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | tty.js | `lib/tty.js` | module.exports（168行目） |

**読解のコツ**: ReadStream と WriteStream は `net.Socket` を継承している。TTY固有の機能はネイティブバインディング（`internalBinding('tty_wrap')`）で提供される。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tty.js | `lib/tty.js` | internalBinding('tty_wrap')（30行目） |
| 2-2 | tty.js | `lib/tty.js` | isatty 関数（46-49行目） |
| 2-3 | tty.js | `lib/tty.js` | module.exports（168行目） |

**主要処理フロー**:
1. **30行目**: TTYネイティブバインディングのインポート
2. **46-49行目**: isatty - ファイルディスクリプタがTTYかどうか判定
3. **168行目**: isatty、ReadStream、WriteStream をエクスポート

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | tty.js | `lib/tty.js` | ReadStream コンストラクタ（51-72行目） |
| 3-2 | tty.js | `lib/tty.js` | setRawMode メソッド（77-86行目） |

**主要処理フロー**:
- **51-72行目**: コンストラクタ - TTYハンドル作成とSocket初期化
- **54-55行目**: fdのバリデーション
- **57-61行目**: TTYネイティブ作成とエラーチェック
- **63-68行目**: net.Socket.call() による初期化
- **77-86行目**: setRawMode - Raw モード設定

#### Step 4: WriteStream クラスの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | tty.js | `lib/tty.js` | WriteStream コンストラクタ（88-119行目） |
| 4-2 | tty.js | `lib/tty.js` | _refreshSize メソッド（130-145行目） |
| 4-3 | tty.js | `lib/tty.js` | カーソル制御メソッド（148-166行目） |

**主要処理フロー**:
- **88-119行目**: コンストラクタ - TTYハンドル作成と初期化
- **111行目**: setBlocking(true) - ブロッキングモード設定
- **113-118行目**: getWindowSize でcolumns/rows取得
- **126行目**: getColorDepth - 色深度取得
- **128行目**: hasColors - 色サポート判定
- **130-145行目**: _refreshSize - サイズ更新とresizeイベント

#### Step 5: 色深度判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | tty.js | `lib/tty.js` | internal/tty インポート（39-41行目） |

**主要処理フロー**:
- **39-41行目**: getColorDepth、hasColors を internal/tty からインポート
- WriteStream.prototype への割り当て（126-128行目）

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

```
isatty(fd)
    │
    ├─ NumberIsInteger(fd) チェック
    │
    └─ isTTY(fd)
           └─ TTY ネイティブ判定

new ReadStream(fd, options)
    │
    ├─ fd バリデーション
    │
    ├─ new TTY(fd, ctx)
    │      └─ TTY ネイティブハンドル作成
    │
    └─ net.Socket.call(this, { handle: tty, ... })
           └─ ソケット初期化

readStream.setRawMode(flag)
    │
    ├─ flag を boolean に変換
    │
    └─ this._handle.setRawMode(flag)
           └─ TTY ネイティブ Raw モード設定

new WriteStream(fd)
    │
    ├─ fd バリデーション
    │
    ├─ new TTY(fd, ctx)
    │
    ├─ net.Socket.call(this, { handle: tty, ... })
    │
    ├─ this._handle.setBlocking(true)
    │
    └─ this._handle.getWindowSize(winSize)
           └─ columns, rows 設定
```

### データフロー図

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

fd (number) ────────────▶ isatty() ──────────────────▶ boolean

fd (number) ────────────▶ new ReadStream() ───────────▶ ReadStream
                               │
                               └─ setRawMode(flag) ───▶ キー入力モード変更

fd (number) ────────────▶ new WriteStream() ──────────▶ WriteStream
                               │
                               ├─ columns, rows
                               └─ getColorDepth() ────▶ 色深度
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| tty.js | `lib/tty.js` | ソース | メインモジュール実装 |
| internal/tty.js | `lib/internal/tty.js` | ソース | 内部ヘルパー（getColorDepth等） |
| net.js | `lib/net.js` | ソース | Socket基盤クラス |
| errors.js | `lib/internal/errors.js` | ソース | エラーコード定義 |
| tty_wrap | `src/tty_wrap.cc` | C++ | TTYネイティブバインディング |
