# 機能設計書 30-@babel/plugin-transform-nullish-coalescing-operator

## 概要

本ドキュメントは、`@babel/plugin-transform-nullish-coalescing-operator` プラグインの機能設計を記載したものである。このプラグインは、ES2020のNullish Coalescing演算子（`??`）を三項演算子によるnullチェックに変換するBabelプラグインである。

### 本機能の処理概要

**業務上の目的・背景**：ES2020で導入されたNullish Coalescing演算子（`??`）は、左辺がnullまたはundefinedの場合にのみ右辺を返す演算子である。従来の論理OR演算子（`||`）とは異なり、0や空文字列などのfalsy値を有効な値として扱う。古いJavaScript環境ではこの構文がサポートされていないため、明示的なnullチェックに変換する必要がある。

**機能の利用シーン**：このプラグインは以下のような場面で利用される。
- `value ?? defaultValue` のようなnullishチェック
- `obj.prop ?? fallback` のようなプロパティアクセスとの組み合わせ
- `func() ?? defaultValue` のような関数呼び出し結果のnullishチェック

**主要な処理内容**：
1. LogicalExpression（`??`演算子）の検出
2. 左辺の純粋性を判定し、一時変数の生成を最適化
3. `noDocumentAll` assumptionに基づくnullチェック方式の選択
4. `pureGetters` assumptionに基づくゲッター最適化
5. パターンスコープ（デフォルトパラメータ）内のIIFE処理

**関連システム・外部連携**：
- `@babel/core`：Babelのコア機能との連携
- `@babel/helper-plugin-utils`：プラグインユーティリティの利用
- `@babel/types`：ASTノードの検証・構築
- `@babel/template`：テンプレートAST構築

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

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

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

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

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

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

3. `??`演算子の処理
   └─ 演算子が`??`かどうかを確認
   └─ 左辺の純粋性を判定
      └─ pureGettersかつパターン内かつ単純なメンバー式: 純粋
      └─ 識別子かつバインディングあり: 純粋
      └─ それ以外: 一時変数を生成
   └─ パターンスコープ内の場合はIIFEでラップ
   └─ 三項演算子に変換

4. nullチェック生成
   └─ noDocumentAll: `!= null` を使用
   └─ それ以外: `!== null && !== undefined` を使用
```

### フローチャート

```mermaid
flowchart TD
    A[LogicalExpression検出] --> B{演算子が??}
    B -->|No| Z[処理スキップ]
    B -->|Yes| C{左辺が純粋?}

    C -->|Yes pureGetters+パターン+単純MemberExpression| D[ref = 左辺をそのまま使用]
    C -->|Yes 識別子+バインディング| D
    C -->|No パターン内| E[IIFEでラップ]
    C -->|No 通常| F[一時変数を生成]

    E --> G[再走査で処理]
    D --> H{noDocumentAll?}
    F --> H

    H -->|Yes| I[!= null チェック]
    H -->|No| J[!== null && !== undefined チェック]

    I --> K[三項演算子に変換]
    J --> K
    K --> L[AST置換]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | noDocumentAll | `!= null`を使用した簡潔なチェック | looseモードまたはassumption有効時 |
| BR-002 | pureGetters | ゲッターの副作用がないと仮定した最適化 | assumptionがtrueの場合 |
| BR-003 | 純粋識別子 | バインディングを持つ識別子は一時変数不要 | スコープにバインディングがある場合 |
| BR-004 | パターンスコープ | デフォルトパラメータ内ではIIFEでラップ | scope.path.isPattern()がtrue |

### 計算ロジック

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

// 出力
const value = a !== null && a !== void 0 ? a : b;
```

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

// 出力
const value = a != null ? a : b;
```

**一時変数が必要な場合**：
```javascript
// 入力
const value = obj.prop ?? defaultValue;

// 出力
var _obj$prop;
const value = (_obj$prop = obj.prop) !== null && _obj$prop !== void 0
  ? _obj$prop
  : defaultValue;
```

**デフォルトパラメータ内の処理**：
```javascript
// 入力
function fn(x = a.b ?? c) {}

// 出力
function fn(x = (() => a.b ?? c)()) {}
// IIFEでラップ後、再走査で通常の変換が適用される
```

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

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

## エラー処理

### エラーケース一覧

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

本プラグインは通常のNullish Coalescing演算子に対してエラーを発生させない。

### リトライ仕様

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

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

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

## パフォーマンス要件

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

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

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

## 備考

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

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/babel-plugin-transform-nullish-coalescing-operator/src/index.ts` | Options型定義（4-6行目）とassumption設定（10-11行目） |

**読解のコツ**: `pureGetters`のデフォルトはfalse。`noDocumentAll`はlooseオプションで有効化。

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

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

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

**主要処理フロー**:
1. **17行目**: LogicalExpressionビジター開始
2. **19-21行目**: `??`演算子かどうかの確認
3. **26-39行目**: 左辺の純粋性判定と一時変数処理
4. **40-45行目**: パターンスコープ内のIIFE処理
5. **52-70行目**: 三項演算子への変換

#### Step 3: 純粋性判定を理解する

一時変数の生成を最適化するための純粋性判定ロジック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/babel-plugin-transform-nullish-coalescing-operator/src/index.ts` | 純粋性判定条件（26-39行目） |

**純粋と判定される条件**:
1. `pureGetters`が有効かつ`scope.path.isPattern()`かつ単純なMemberExpression
2. 識別子かつスコープにバインディングがある（グローバル変数は除く）

#### Step 4: nullチェック生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.ts | `packages/babel-plugin-transform-nullish-coalescing-operator/src/index.ts` | 三項演算子生成（52-70行目） |

**チェック方式**:
- **noDocumentAll=true**: `assignment != null`
- **noDocumentAll=false**: `assignment !== null && ref !== void 0`

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

```
index.ts (エントリーポイント)
    │
    └─ visitor.LogicalExpression
           │
           ├─ 演算子チェック（node.operator !== "??"）
           │
           ├─ 純粋性判定
           │      ├─ pureGetters + パターン + MemberExpression
           │      │    └─ ref = 左辺をそのまま使用
           │      ├─ 識別子 + バインディングあり
           │      │    └─ ref = 左辺をそのまま使用
           │      └─ その他
           │           ├─ パターン内: IIFEラップ→return
           │           └─ 通常: 一時変数生成
           │
           └─ 三項演算子変換
                  ├─ noDocumentAll: != null チェック
                  └─ strict: !== null && !== void 0 チェック
```

### データフロー図

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

JavaScriptソース ───▶ @babel/parser ───▶ AST
                                           │
                                           ▼
                              ┌─────────────────────────┐
                              │  transform-nullish-coalescing │
                              │  ビジター               │
                              │    │                    │
                              │    ├─ ??演算子検出      │
                              │    │                    │
                              │    ├─ 純粋性判定        │
                              │    │   ├─ 純粋: 直接使用│
                              │    │   └─ 非純粋: 一時変数│
                              │    │                    │
                              │    ├─ パターン処理      │
                              │    │   └─ IIFE生成      │
                              │    │                    │
                              │    └─ nullチェック生成  │
                              │        ├─ loose: != null│
                              │        └─ strict: !== null│
                              └─────────────────────────┘
                                           │
                                           ▼
                              変換後AST ───▶ @babel/generator ───▶ ES5コード
```

### 関連ファイル一覧

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