# 機能設計書 34-@babel/plugin-transform-object-rest-spread

## 概要

本ドキュメントは、Babelの変換プラグイン「@babel/plugin-transform-object-rest-spread」の機能設計を記述する。本プラグインはES2018のオブジェクトrest/spread構文を、古いJavaScript環境でも動作する形式に変換する。

### 本機能の処理概要

本プラグインは、オブジェクトリテラル内のスプレッド演算子（`...obj`）およびオブジェクト分割代入内のrest要素（`{a, ...rest} = obj`）を、Object.assignやヘルパー関数を用いた実装に変換する機能を提供する。

**業務上の目的・背景**：ES2018で正式に仕様化されたオブジェクトrest/spread構文は、オブジェクトの浅いコピーやマージ、特定プロパティの抽出を簡潔に記述できる。しかし、古いブラウザやNode.jsバージョンではこの構文をサポートしていないため、トランスパイルが必要となる。本プラグインにより、開発者はモダンな構文を使用しながらも、幅広い環境での互換性を確保できる。

**機能の利用シーン**：
- オブジェクトのマージや浅いコピーを行うアプリケーション開発
- 関数パラメータでの分割代入とrest要素の使用
- Reactコンポーネントでのpropsの展開
- `@babel/preset-env`の一部として自動的に適用される場合

**主要な処理内容**：
1. ObjectExpression内のSpreadElementを検出し、Object.assignまたはヘルパー関数呼び出しに変換
2. ObjectPattern内のRestElementを検出し、objectWithoutPropertiesヘルパーを用いた変換
3. 関数パラメータ内のrest要素を関数本体内の変数宣言に変換
4. 計算プロパティキーの評価順序を維持するためのメモ化処理
5. for-of/for-in文内の分割代入のrest要素を適切に変換

**関連システム・外部連携**：
- `@babel/helper-compilation-targets`: ターゲット環境の判定
- `@babel/plugin-transform-parameters`: 関数パラメータの変換
- `@babel/plugin-transform-destructuring`: 分割代入との連携
- `@babel/helper-plugin-utils`: プラグインユーティリティ
- `@babel/core`: Babelコアとの統合

**権限による制御**：特になし。変換はビルド時に実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIまたはビルドツール経由で使用されるため、画面との関連なし |

## 機能種別

コード変換処理 / AST操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| useBuiltIns | boolean | No | trueの場合、ヘルパー関数の代わりにObject.assignを使用 | boolean型であること |
| loose | boolean | No | trueの場合、仕様準拠よりもパフォーマンスを優先した簡易な変換を行う | boolean型であること |

### 入力データソース

- Babelによってパースされたソースコード（AST形式）
- ObjectExpression内のSpreadElement、ObjectPattern内のRestElement

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化
   ├─ ターゲット環境でのObject.assignサポート確認
   └─ オプション（useBuiltIns, loose）の設定

2. 関数パラメータの処理（Function visitor）
   ├─ rest要素を含むパラメータを検出
   └─ 関数本体内の変数宣言に変換

3. 変数宣言の処理（VariableDeclarator visitor）
   ├─ ObjectPattern内のrest要素を検出
   ├─ 計算プロパティキーのメモ化（評価順序維持）
   └─ objectWithoutPropertiesヘルパーを用いた変換

4. オブジェクトリテラルの処理（ObjectExpression visitor）
   ├─ SpreadElementを検出
   └─ Object.assignまたはobjectSpread2ヘルパーに変換

5. その他の構文の処理
   ├─ ExportNamedDeclaration
   ├─ CatchClause
   ├─ AssignmentExpression
   ├─ ForXStatement
   └─ ArrayPattern
```

### フローチャート

```mermaid
flowchart TD
    A[ASTノードの訪問] --> B{ノードの種類}
    B -->|ObjectExpression| C{SpreadElementあり?}
    B -->|ObjectPattern| D{RestElementあり?}
    B -->|Function| E{パラメータにrest?}
    C -->|Yes| F{useBuiltIns?}
    C -->|No| Z[変換なし]
    D -->|Yes| G[objectWithoutProperties変換]
    D -->|No| Z
    E -->|Yes| H[関数本体に変数宣言追加]
    E -->|No| Z
    F -->|Yes| I[Object.assign使用]
    F -->|No| J[objectSpread2ヘルパー使用]
    G --> K[変換完了]
    H --> K
    I --> K
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-34-01 | 評価順序の維持 | 計算プロパティキーの評価順序を元のコードと同一に維持 | 計算プロパティ使用時 |
| BR-34-02 | useBuiltIns動作 | Object.assignをネイティブで使用し、ヘルパーを回避 | useBuiltIns=true |
| BR-34-03 | looseモード動作 | setSpreadProperties、objectRestNoSymbols等のassumptionを有効化 | loose=true |
| BR-34-04 | pureGetters動作 | getterが純粋と仮定し、最適化を適用 | assumption有効時 |

### 計算ロジック

- excludedKeysの計算: rest要素以外のプロパティキーを配列として収集

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

該当なし（コンパイル時変換のため）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | SyntaxError | 不正なrest/spread構文 | パーサーレベルでエラー |
| - | Error | .looseが非boolean値 | オプション検証でエラー |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 変換処理は同期的に実行される
- excludedKeysのホイスティングによりランタイムオーバーヘッドを削減

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

- 特になし

## 備考

- 本プラグインは`@babel/preset-env`に含まれており、ターゲット環境に応じて自動的に適用される
- `@babel/plugin-transform-destructuring`との連携が必要な場合がある

---

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

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

### 推奨読解順序

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

本プラグインはObjectExpression（SpreadElement）とObjectPattern（RestElement）を変換対象とする。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/babel-plugin-transform-object-rest-spread/src/index.ts` | Optionsインターフェース（useBuiltIns, loose）の定義 |

**読解のコツ**: 複数のビジターが実装されており、それぞれの役割を理解することが重要。ヘルパー関数の使い分けにも注目。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/babel-plugin-transform-object-rest-spread/src/index.ts` | オプション処理、assumption設定、ヘルパー関数選択ロジック |

**主要処理フロー**:
1. **1-8行目**: 必要なモジュールのインポート
2. **13-16行目**: Optionsインターフェースの定義
3. **18-35行目**: プラグイン初期化、ターゲット判定、オプション設定
4. **37-43行目**: getExtendsHelper関数 - Object.assignまたはヘルパーを選択
5. **45-75行目**: iterateObjectRestElement関数 - rest要素を再帰的に検索
6. **77-91行目**: hasObjectRestElement、visitObjectRestElements関数
7. **93-100行目**: hasSpread関数 - SpreadElementの検出
8. **108-163行目**: extractNormalizedKeys関数 - 除外キーの正規化
9. **174-212行目**: replaceImpureComputedKeys関数 - 計算キーのメモ化
10. **288-361行目**: createObjectRest関数 - rest変換のメインロジック
11. **403-477行目**: Function visitor - 関数パラメータの処理
12. **481-665行目**: VariableDeclarator visitor - 変数宣言の処理
13. **845-898行目**: ObjectExpression visitor - スプレッドの処理

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | shouldStoreRHSInTemporaryVariable.ts | `packages/babel-plugin-transform-object-rest-spread/src/shouldStoreRHSInTemporaryVariable.ts` | RHSの一時変数化判定ロジック |

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

```
@babel/plugin-transform-object-rest-spread/src/index.ts
    │
    ├─ visitor.Function()
    │      ├─ hasObjectRestElement()
    │      ├─ convertFunctionParams() (from @babel/plugin-transform-parameters)
    │      └─ replaceRestElement()
    │
    ├─ visitor.VariableDeclarator()
    │      ├─ visitObjectRestElements()
    │      ├─ replaceImpureComputedKeys()
    │      └─ createObjectRest()
    │             └─ objectWithoutProperties helper
    │
    └─ visitor.ObjectExpression()
           ├─ hasSpread()
           └─ getExtendsHelper() または objectSpread2 helper
```

### データフロー図

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

{ ...obj }          ─▶  ObjectExpression visitor   ─▶  Object.assign({}, obj)
(SpreadElement)          │                              または
                         └─ getExtendsHelper()          _objectSpread2({}, obj)

{ a, ...rest } = x  ─▶  VariableDeclarator visitor ─▶  _rest = _objectWithoutProperties(x, ["a"])
(RestElement)            │
                         ├─ createObjectRest()
                         └─ extractNormalizedKeys()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-plugin-transform-object-rest-spread/src/index.ts` | ソース | プラグインエントリーポイント、変換ロジック |
| shouldStoreRHSInTemporaryVariable.ts | `packages/babel-plugin-transform-object-rest-spread/src/shouldStoreRHSInTemporaryVariable.ts` | ソース | RHS一時変数化判定 |
| compat-data.ts | `packages/babel-plugin-transform-object-rest-spread/src/compat-data.ts` | ソース | 互換性データ |
| package.json | `packages/babel-plugin-transform-object-rest-spread/package.json` | 設定 | パッケージ依存関係定義 |
| test/index.js | `packages/babel-plugin-transform-object-rest-spread/test/index.js` | テスト | テストランナー設定 |
| fixtures/object-spread/ | `packages/babel-plugin-transform-object-rest-spread/test/fixtures/object-spread/` | テスト | スプレッドのテストケース |
| fixtures/object-rest/ | `packages/babel-plugin-transform-object-rest-spread/test/fixtures/object-rest/` | テスト | restのテストケース |
