# 機能設計書 22-@babel/plugin-transform-spread

## 概要

本ドキュメントは、`@babel/plugin-transform-spread` プラグインの機能設計を記載したものである。このプラグインは、ES2015（ES6）のスプレッド構文（Spread Syntax）をES5互換のコードに変換するBabelプラグインである。

### 本機能の処理概要

**業務上の目的・背景**：ES2015で導入されたスプレッド構文（`...`演算子）は、配列リテラル、関数呼び出し、`new`式において要素や引数を展開するための便利な構文である。古いJavaScript環境ではこの構文がサポートされていないため、`Array.prototype.concat`や`Function.prototype.apply`を使用した従来の方法に変換する必要がある。

**機能の利用シーン**：このプラグインは以下のような場面で利用される。
- `[...arr1, ...arr2]` のような配列スプレッドの変換
- `fn(...args)` のような関数呼び出しでのスプレッドの変換
- `new Cls(...args)` のようなコンストラクタ呼び出しでのスプレッドの変換

**主要な処理内容**：
1. ArrayExpression内のSpreadElementを検出し、`concat`メソッドチェーンに変換
2. CallExpression内のスプレッド引数を検出し、`apply`メソッドに変換
3. NewExpression内のスプレッド引数を検出し、ヘルパー関数`_construct`を使用して変換
4. `arguments`オブジェクトのスプレッドを`Array.prototype.slice.call`に変換
5. 配列ライクオブジェクトの処理（`arrayLikeIsIterable`オプション）

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

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

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loose | boolean | No | looseモードの有効化。`iterableIsArray` assumptionを有効にする | - |
| allowArrayLike | boolean | No | 配列ライクオブジェクトをイテラブルとして扱う | - |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

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

2. AST走査開始
   └─ 各ノードタイプに対応するビジターを実行

3. ArrayExpression処理
   └─ SpreadElementの存在を確認
   └─ 要素を分割してconcatメソッドチェーンに変換

4. CallExpression処理
   └─ 引数にSpreadElementが含まれるか確認
   └─ super()呼び出しはエラーを発生
   └─ applyメソッドに変換、コンテキスト（this）を適切に設定

5. NewExpression処理
   └─ 引数にSpreadElementが含まれるか確認
   └─ constructヘルパーを使用して変換
```

### フローチャート

```mermaid
flowchart TD
    A[AST走査開始] --> B{ノードタイプ判定}
    B -->|ArrayExpression| C{SpreadElement含む?}
    C -->|Yes| D[build関数で要素分割]
    D --> E[concat呼び出しに変換]
    C -->|No| Z[処理スキップ]

    B -->|CallExpression| F{SpreadElement含む?}
    F -->|Yes| G{super呼び出し?}
    G -->|Yes| H[エラー発生]
    G -->|No| I[applyメソッドに変換]
    F -->|No| Z

    B -->|NewExpression| J{SpreadElement含む?}
    J -->|Yes| K[constructヘルパー使用]
    J -->|No| Z

    E --> L[AST置換]
    I --> L
    K --> L
    L --> M[次のノードへ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | スプレッド検出 | SpreadElementを検出して処理 | ArrayExpression, CallExpression, NewExpression |
| BR-002 | arguments最適化 | argumentsオブジェクトは`Array.prototype.slice.call`で変換 | スプレッド対象がargumentsの場合 |
| BR-003 | ホール処理 | 配列のホール（空要素）は`arrayLikeToArray`ヘルパーで処理 | 配列リテラルにホールがある場合 |
| BR-004 | コンテキスト保持 | メンバー呼び出しでは適切なthisコンテキストを維持 | `obj.method(...args)`の形式 |

### 計算ロジック

**配列スプレッドの変換例**：
```javascript
// 入力
const arr = [...a, ...b];

// 出力
var arr = [].concat(a, b);
```

**関数呼び出しスプレッドの変換例**：
```javascript
// 入力
fn(...args);

// 出力
fn.apply(void 0, args);
```

**メンバー関数呼び出しの変換例**：
```javascript
// 入力
obj.method(...args);

// 出力
(_obj = obj).method.apply(_obj, args);
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | BuildCodeFrameError | super()呼び出しでスプレッドを使用 | @babel/plugin-transform-classesを追加 |

### リトライ仕様

ビルドプロセスのため、リトライは不要。エラー発生時はビルドが中断される。

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

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

## パフォーマンス要件

- AST走査は1パスで完了すること
- 大規模ファイルでも線形時間で処理可能であること

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

- ソースコードの変換のみを行い、外部リソースへのアクセスは行わない
- 生成されるコードは入力コードと同等のセキュリティ特性を維持する

## 備考

- super()呼び出しでのスプレッドは、classesプラグインと併用が必要
- looseモードでは配列と仮定するため、非配列イテラブルでは動作が異なる可能性がある

---

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

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

### 推奨読解順序

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

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

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

**読解のコツ**: `ListElement`型（6行目）は配列要素の型を表し、SpreadElement、Expression、nullのいずれか。

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

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

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

**主要処理フロー**:
1. **114-152行目**: ArrayExpressionの処理
2. **153-222行目**: CallExpressionの処理
3. **224-248行目**: NewExpressionの処理

#### Step 3: ヘルパー関数を理解する

変換に使用されるヘルパー関数を理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/babel-plugin-transform-spread/src/index.ts` | getSpreadLiteral（20-59行目）、hasSpread（65-72行目）、build（80-108行目） |

**主要処理フロー**:
- **getSpreadLiteral**: スプレッド要素を適切な形式に変換
- **hasSpread**: SpreadElementの存在確認
- **build**: 要素を分割し、concat用の配列を構築
- **push**: 非スプレッド要素をグループ化

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

```
index.ts (エントリーポイント)
    │
    ├─ visitor.ArrayExpression
    │      ├─ hasSpread: SpreadElement存在確認
    │      ├─ build: 要素分割
    │      │    ├─ push: 非スプレッド要素グループ化
    │      │    └─ getSpreadLiteral: スプレッド要素変換
    │      └─ path.replaceWith: concat呼び出しに置換
    │
    ├─ visitor.CallExpression
    │      ├─ hasSpread: SpreadElement存在確認
    │      ├─ skipTransparentExprWrappers: ラッパースキップ
    │      ├─ build: 引数分割
    │      └─ path.replaceWith: apply呼び出しに置換
    │
    └─ visitor.NewExpression
           ├─ hasSpread: SpreadElement存在確認
           ├─ build: 引数分割
           └─ path.replaceWith: constructヘルパー呼び出しに置換
```

### データフロー図

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

JavaScriptソース ───▶ @babel/parser ───▶ AST
                                           │
                                           ▼
                              ┌─────────────────────────┐
                              │  transform-spread        │
                              │  ビジター               │
                              │    │                    │
                              │    ▼                    │
                              │  要素分析               │
                              │    ├─ hasSpread         │
                              │    ├─ build             │
                              │    └─ getSpreadLiteral  │
                              └─────────────────────────┘
                                           │
                                           ▼
                              変換後AST ───▶ @babel/generator ───▶ ES5コード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-plugin-transform-spread/src/index.ts` | ソース | プラグインエントリーポイント、ビジター・ヘルパー定義 |
| package.json | `packages/babel-plugin-transform-spread/package.json` | 設定 | パッケージ定義、依存関係 |
| test/index.js | `packages/babel-plugin-transform-spread/test/index.js` | テスト | テストランナー |
| test/fixtures/ | `packages/babel-plugin-transform-spread/test/fixtures/` | テスト | テストフィクスチャ |
