# 機能設計書 29-@babel/plugin-transform-optional-chaining

## 概要

本ドキュメントは、`@babel/plugin-transform-optional-chaining` プラグインの機能設計を記載したものである。このプラグインは、ES2020のオプショナルチェイニング演算子（`?.`）をnullチェックの連鎖に変換するBabelプラグインである。

### 本機能の処理概要

**業務上の目的・背景**：ES2020で導入されたオプショナルチェイニング演算子（`?.`）は、ネストされたオブジェクトプロパティへの安全なアクセスを可能にする。プロパティがnullまたはundefinedの場合、エラーをスローせずにundefinedを返す。古いJavaScript環境ではこの構文がサポートされていないため、明示的なnullチェックに変換する必要がある。

**機能の利用シーン**：このプラグインは以下のような場面で利用される。
- `obj?.prop` のようなオプショナルプロパティアクセス
- `obj?.[expr]` のようなオプショナル計算プロパティアクセス
- `func?.()` のようなオプショナル関数呼び出し
- `obj?.method?.()` のようなチェーン化されたオプショナルアクセス

**主要な処理内容**：
1. OptionalMemberExpressionとOptionalCallExpressionの検出
2. オプショナルチェーンの分析と一時変数の生成
3. `noDocumentAll` assumptionに基づくnullチェック方式の選択
4. `pureGetters` assumptionに基づくゲッター最適化
5. delete演算子との組み合わせ処理
6. 関数呼び出し時のthisコンテキスト保持

**関連システム・外部連携**：
- `@babel/core`：Babelのコア機能との連携
- `@babel/helper-plugin-utils`：プラグインユーティリティの利用
- `@babel/helper-skip-transparent-expression-wrappers`：透過的なラッパー式のスキップ
- `@babel/types`：ASTノードの検証・構築

**権限による制御**：特になし。ビルド時に実行されるトランスパイル処理のため、権限による制御は不要。

## 関連画面

本プラグインはビルドツールとして動作するため、直接的な関連画面はない。

## 機能種別

コード変換処理（AST変換）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loose | boolean | No | looseモードの有効化。`noDocumentAll`と`pureGetters`を有効にする | デフォルト: false |

### 入力データソース

- JavaScriptソースコード（AST形式）
- Babelの設定ファイル（babel.config.js, .babelrc等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| transformedAST | AST | 変換後のAST |

### 出力先

変換されたASTは@babel/generatorによってJavaScriptコードとして出力される。

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化
   └─ オプション（loose）の読み込み
   └─ assumption設定の解決（noDocumentAll, pureGetters）

2. AST走査開始
   └─ OptionalCallExpression/OptionalMemberExpressionに対してビジターを実行

3. オプショナルチェーン処理
   └─ transform関数呼び出し
   └─ delete演算子との組み合わせを確認
   └─ 関数呼び出しでのthisコンテキスト処理
   └─ transformOptionalChain呼び出し

4. transformOptionalChain処理
   └─ パターンスコープ内の場合はIIFEでラップ
   └─ オプショナルノードを収集
   └─ 各オプショナルに対してnullチェックを生成
   └─ noDocumentAll: `!= null` を使用
   └─ それ以外: `!== null && !== undefined` を使用
   └─ 関数呼び出しのthisコンテキストを保持
```

### フローチャート

```mermaid
flowchart TD
    A[Optional*検出] --> B[transform関数呼び出し]
    B --> C{delete演算子?}
    C -->|Yes| D[trueをifNullishとして使用]
    C -->|No| E{関数呼び出しのcallee?}
    E -->|Yes| F[bindでthis保持]
    E -->|No| G[transformOptionalChain]
    D --> G
    F --> G

    G --> H{パターンスコープ内?}
    H -->|Yes| I[IIFEでラップ]
    H -->|No| J[オプショナルノード収集]
    I --> J

    J --> K[オプショナルを通常ノードに変換]
    K --> L{eval呼び出し?}
    L -->|Yes| M[間接eval変換]
    L -->|No| N[一時変数生成]

    M --> O{noDocumentAll?}
    N --> O
    O -->|Yes| P[!= null チェック]
    O -->|No| Q[!== null && !== undefined チェック]

    P --> R[条件式/論理式生成]
    Q --> R
    R --> S[AST置換]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | noDocumentAll | `!= null`を使用した簡潔なチェック | looseモードまたはassumption有効時 |
| BR-002 | pureGetters | ゲッターの副作用がないと仮定した最適化 | looseモードまたはassumption有効時 |
| BR-003 | eval間接化 | `eval?.()`を`(0, eval)()`に変換 | eval関数のオプショナル呼び出し時 |
| BR-004 | thisコンテキスト | メンバー呼び出しのthisを適切に保持 | `(obj?.method)()`形式の呼び出し時 |

### 計算ロジック

**基本的な変換例（strictモード）**：
```javascript
// 入力
const value = obj?.prop?.nested;

// 出力
const value = obj === null || obj === void 0 ? void 0 :
  (_obj$prop = obj.prop) === null || _obj$prop === void 0 ? void 0 :
  _obj$prop.nested;
```

**基本的な変換例（looseモード/noDocumentAll）**：
```javascript
// 入力
const value = obj?.prop?.nested;

// 出力
const value = obj?.prop?.nested != null ? obj.prop.nested : void 0;
```

**オプショナル関数呼び出しの変換例**：
```javascript
// 入力
const result = obj?.method?.();

// 出力
const result = obj === null || obj === void 0 ? void 0 :
  (_obj$method = obj.method) === null || _obj$method === void 0 ? void 0 :
  _obj$method.call(obj);
```

**delete演算子との組み合わせ**：
```javascript
// 入力
delete obj?.prop;

// 出力
obj === null || obj === void 0 ? true : delete obj.prop;
```

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

本プラグインはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | - | - |

本プラグインは通常のオプショナルチェイニングに対してエラーを発生させない。

### リトライ仕様

ビルドプロセスのため、リトライは不要。

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

該当なし。ビルドプロセスはトランザクション管理を行わない。

## パフォーマンス要件

- AST走査は1パスで完了すること
- 一時変数の生成は必要最小限に抑えること

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

- ソースコードの変換のみを行い、外部リソースへのアクセスは行わない
- document.allの特殊な動作（falsy object）への対応（noDocumentAll無効時）

## 備考

- ES2020のオプショナルチェイニングはTC39によって標準化されている
- looseモードではdocument.allの特殊な挙動に対応しない
- nullish coalescing演算子（`??`）と組み合わせて使用されることが多い

---

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

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

### 推奨読解順序

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

まず、プラグインのオプションと型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/babel-plugin-transform-optional-chaining/src/index.ts` | Options型定義（5-7行目）とassumption設定（11-13行目） |

**読解のコツ**: `noDocumentAll`はHTML仕様のdocument.allの特殊動作への対応を制御。

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

処理の起点となるビジターパターンを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/babel-plugin-transform-optional-chaining/src/index.ts` | visitorオブジェクト（18-25行目） |

**主要処理フロー**:
1. **19-21行目**: OptionalCallExpression/OptionalMemberExpressionの検出
2. **22行目**: transform関数呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transform.ts | `packages/babel-plugin-transform-optional-chaining/src/transform.ts` | transform関数（240-301行目）、transformOptionalChain関数（69-238行目） |

**主要処理フロー**:
- **251-257行目**: delete演算子処理
- **260-289行目**: 関数呼び出しのthisコンテキスト処理
- **291-299行目**: transformOptionalChain呼び出し

#### Step 4: transformOptionalChain関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | transform.ts | `packages/babel-plugin-transform-optional-chaining/src/transform.ts` | transformOptionalChain関数（69-238行目） |

**主要処理フロー**:
- **80-86行目**: パターンスコープ内のIIFEラップ
- **90-110行目**: オプショナルノードの収集と変換
- **118-170行目**: 各オプショナルに対するチェック生成
- **202-206行目**: nullチェックテンプレートの選択

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

```
index.ts (エントリーポイント)
    │
    └─ visitor["OptionalCallExpression|OptionalMemberExpression"]
           │
           └─ transform (transform.ts)
                  │
                  ├─ findOutermostTransparentParent
                  │
                  ├─ delete演算子処理
                  │      └─ transformOptionalChain（ifNullish: true）
                  │
                  └─ 通常処理
                         ├─ wrapLast（thisbind処理）
                         └─ transformOptionalChain
                                ├─ needsMemoize
                                ├─ skipTransparentExprWrappers
                                ├─ オプショナルノード収集
                                ├─ nullチェック生成
                                │    ├─ NULLISH_CHECK_NO_DDA（loose）
                                │    └─ NULLISH_CHECK（strict）
                                └─ path.replaceWith
```

### データフロー図

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

JavaScriptソース ───▶ @babel/parser ───▶ AST
                                           │
                                           ▼
                              ┌─────────────────────────┐
                              │  transform-optional-chaining │
                              │  ビジター               │
                              │    │                    │
                              │    ├─ Optional*検出     │
                              │    │                    │
                              │    ├─ transform呼び出し │
                              │    │   ├─ delete処理    │
                              │    │   └─ this処理      │
                              │    │                    │
                              │    └─ transformOptionalChain│
                              │        ├─ ノード収集    │
                              │        ├─ nullチェック  │
                              │        └─ 条件式生成    │
                              └─────────────────────────┘
                                           │
                                           ▼
                              変換後AST ───▶ @babel/generator ───▶ ES5コード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-plugin-transform-optional-chaining/src/index.ts` | ソース | プラグインエントリーポイント |
| transform.ts | `packages/babel-plugin-transform-optional-chaining/src/transform.ts` | ソース | 変換ロジック |
| util.ts | `packages/babel-plugin-transform-optional-chaining/src/util.ts` | ソース | ユーティリティ関数 |
| package.json | `packages/babel-plugin-transform-optional-chaining/package.json` | 設定 | パッケージ定義、依存関係 |
| test/fixtures/ | `packages/babel-plugin-transform-optional-chaining/test/fixtures/` | テスト | テストフィクスチャ |
