# 機能設計書 46-@babel/plugin-transform-react-jsx

## 概要

本ドキュメントは、BabelプラグインであるJSX構文のJavaScript関数呼び出しへの変換機能について記述する。

### 本機能の処理概要

**業務上の目的・背景**：
JSX（JavaScript XML）はReactで使用される構文拡張であり、HTMLライクな記法でUIコンポーネントを記述できる。しかし、JSXはJavaScriptの標準構文ではないため、ブラウザで実行するにはJavaScriptに変換する必要がある。本プラグインは、JSX構文をReact.createElement()呼び出しまたは新しいjsx-runtime形式に変換する。

**機能の利用シーン**：
- Reactアプリケーションのビルドプロセス
- @babel/preset-reactを通じた利用
- Preact、Inferno等の他のJSXライブラリとの連携
- SSR（Server-Side Rendering）環境でのJSX変換

**主要な処理内容**：
1. JSXElementをjsx()/jsxs()/createElement()関数呼び出しに変換
2. JSXFragmentを対応するフラグメント呼び出しに変換
3. JSX属性をpropsオブジェクトに変換
4. 子要素をchildren propまたは追加引数として処理
5. key属性の特別処理（jsx-runtimeでは別引数）
6. スプレッド属性のサポート
7. 開発モード用の__source/__self属性の自動追加

**関連システム・外部連携**：
@babel/plugin-syntax-jsxで構文解析を継承。@babel/helper-module-importsでランタイムインポートを生成。@babel/helper-annotate-as-pureでPure注釈を追加。

**権限による制御**：
プラグインオプション（runtime、importSource、pragma、pragmaFrag、throwIfNamespace等）による動作制御が可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1-5 | Babelトランスフォームデモ等 | 補助機能 | JSX構文の変換に使用（presetsに"react"を指定） |

## 機能種別

データ変換（AST変換）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| runtime | "automatic" / "classic" | No | ランタイムモード（デフォルト: "automatic"） | - |
| importSource | string | No | JSXランタイムのインポート元（デフォルト: "react"） | - |
| pragma | string | No | クラシックモードのJSX変換関数（デフォルト: "React.createElement"） | - |
| pragmaFrag | string | No | クラシックモードのフラグメント（デフォルト: "React.Fragment"） | - |
| throwIfNamespace | boolean | No | 名前空間タグでエラー（デフォルト: true） | - |
| pure | string | No | Pure注釈の追加 | - |
| filter | function | No | 変換対象のフィルタリング | runtime="classic"時のみ |

### 入力データソース

JSX構文を含むJavaScript/TypeScriptソースコード（AST形式）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| transformedAST | t.Program | JSXが関数呼び出しに変換されたAST |
| jsxCalls | t.CallExpression | jsx()/jsxs()/createElement()呼び出し |

### 出力先

変換されたAST（@babel/coreに返却）

## 処理フロー

### 処理シーケンス

```
1. Program.enterビジター
   └─ runtimeモード決定（コメントプラグマ解析）
   └─ classic: pragma/pragmaFragの設定
   └─ automatic: jsx/jsxs/createElementのインポート準備
   └─ 開発モード: __source/__selfの追加
2. JSXElementビジター
   └─ タグ名の変換（文字列/識別子）
   └─ 属性のpropsオブジェクト変換
   └─ key属性の抽出（automaticモード）
   └─ 子要素の処理
   └─ jsx()/jsxs()/createElement()呼び出し生成
3. JSXFragmentビジター
   └─ Fragmentの関数呼び出し変換
4. JSXAttributeビジター
   └─ JSXElementの値をJSXExpressionContainerでラップ
5. JSXNamespacedNameビジター
   └─ throwIfNamespace=trueでエラー送出
6. JSXSpreadChildビジター
   └─ エラー送出（React非サポート）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[Program.enter]
    B --> C{runtimeモード?}
    C -->|automatic| D[jsx/jsxs/createElementインポート準備]
    C -->|classic| E[pragma/pragmaFrag設定]
    D --> F{開発モード?}
    E --> F
    F -->|Yes| G[__source/__self追加]
    F -->|No| H[JSXElement処理]
    G --> H
    H --> I[タグ名変換]
    I --> J[属性→props変換]
    J --> K{automaticモード?}
    K -->|Yes| L[key属性を別引数に]
    K -->|No| M[keyはpropsに含める]
    L --> N{子要素数}
    M --> N
    N -->|>1| O[jsxs()呼び出し]
    N -->|<=1| P[jsx()呼び出し]
    O --> Q[終了]
    P --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-01 | automaticランタイム | jsx/jsxsをjsx-runtimeからインポート | runtime="automatic"時 |
| BR-46-02 | classicランタイム | React.createElementを使用 | runtime="classic"時 |
| BR-46-03 | jsxs使用 | 複数の子要素がある場合jsxsを使用 | automatic & children.length > 1時 |
| BR-46-04 | key属性の特別処理 | keyはpropsではなく別引数として渡す | automaticモード時 |
| BR-46-05 | スプレッド後のkey | スプレッド属性の後にkeyがある場合createElement使用 | key after spread時 |
| BR-46-06 | 名前空間タグエラー | ns:tagの形式でエラー | throwIfNamespace=true時 |
| BR-46-07 | スプレッド子要素エラー | {...children}形式でエラー | JSXSpreadChild検出時 |
| BR-46-08 | Pure注釈 | 呼び出しに#__PURE__コメントを追加 | pureオプションまたはデフォルト |

### 計算ロジック

タグ名変換ロジック:
- 小文字で始まる: 文字列リテラル（"div"）
- 大文字で始まる: 識別子参照（MyComponent）
- ドット区切り: MemberExpression（Foo.Bar）
- 名前空間: 文字列リテラル（"ns:tag"）※throwIfNamespace=false時

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

該当なし（ファイルシステム操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NAMESPACE_TAG | 構文エラー | throwIfNamespace=trueで名前空間タグ使用 | throwIfNamespaceをfalseに設定 |
| SPREAD_CHILDREN | 構文エラー | {...children}形式の使用 | 通常の子要素として渡す |
| DUPLICATE_SOURCE_SELF | 設定エラー | __source/__selfが重複 | 古いプラグインを削除 |
| KEY_SHORTHAND | 構文エラー | key属性を値なしで使用 | 明示的な値を設定 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

特定のパフォーマンス要件なし（変換処理は同期的に実行）

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

- ユーザー入力をJSX属性として使用する場合、XSS対策はReactランタイムに依存
- __source/__selfは開発モードでのデバッグ情報のため、本番ビルドでは除外推奨

## 備考

- React 17以降はautomatic runtimeがデフォルト
- automatic runtimeではReactをインポートせずにJSXが使用可能
- 開発モード（development=true）では__source/__selfが自動追加される
- useSpread/useBuiltInsオプションはBabel 8で削除済み

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/babel-plugin-transform-react-jsx/src/index.ts` | createPlugin呼び出し（5-8行目） |

**読解のコツ**: index.tsはcreate-plugin.tsのラッパーで、development=falseを設定。

#### Step 2: プラグイン作成関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | create-plugin.ts | `packages/babel-plugin-transform-react-jsx/src/create-plugin.ts` | createPlugin関数（59-772行目） |

**主要処理フロー**:
- **22-27行目**: DEFAULTオプション定義
- **50-58行目**: Options型定義
- **81-100行目**: 廃止オプション（useSpread、useBuiltIns）のエラー
- **129-209行目**: Program.enter（ランタイムモード設定）
- **326-360行目**: JSXElement.exit
- **532-610行目**: buildJSXElementCall（automaticモード用）
- **683-699行目**: buildCreateElementCall（classicモード用）

#### Step 3: ランタイムモード分岐を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create-plugin.ts | `packages/babel-plugin-transform-react-jsx/src/create-plugin.ts` | Program.enter内のランタイム設定（174-209行目） |

**主要処理フロー**:
- **175行目**: classicモードでpragma/pragmaFragを設定
- **189行目**: automaticモードでjsx/jsxs/createElement/Fragmentをインポート準備
- **788-821行目**: createImportLazily（遅延インポート生成）

#### Step 4: JSX要素変換を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | create-plugin.ts | `packages/babel-plugin-transform-react-jsx/src/create-plugin.ts` | buildJSXElementCall（532-610行目） |

**主要処理フロー**:
- **543-568行目**: key/__source/__selfの抽出
- **570行目**: t.react.buildChildren（子要素抽出）
- **591-609行目**: 開発モード用の追加引数（isStaticChildren、__source、__self）

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

```
@babel/plugin-transform-react-jsx/src/index.ts
    │
    └─ ./create-plugin.ts
           │
           ├─ @babel/plugin-syntax-jsx (inherits)
           │      └─ JSX構文解析の有効化
           │
           ├─ @babel/helper-module-imports
           │      ├─ addNamed()
           │      ├─ addNamespace()
           │      └─ isModule()
           │
           ├─ @babel/helper-annotate-as-pure
           │      └─ annotateAsPure()
           │
           └─ @babel/core/types
                  └─ t.react.buildChildren()
```

### データフロー図

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

JSXソースコード  ──▶  Parser (JSX AST生成)
                              │
                              ▼
                     ランタイムモード決定
                              │
                     ┌────────┼────────┐
                     ▼        ▼        ▼
              タグ変換   属性変換   子要素変換
                     │        │        │
                     └────────┼────────┘
                              │
                              ▼
                     jsx()/createElement()生成
                              │
                              ▼
                       JavaScriptAST ──▶ Generator ──▶ JSコード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-plugin-transform-react-jsx/src/index.ts` | ソース | エントリーポイント |
| create-plugin.ts | `packages/babel-plugin-transform-react-jsx/src/create-plugin.ts` | ソース | メインプラグイン実装（842行） |
| development.ts | `packages/babel-plugin-transform-react-jsx/src/development.ts` | ソース | 開発モード用エントリーポイント |
| package.json | `packages/babel-plugin-transform-react-jsx/package.json` | 設定 | 依存関係・メタデータ |
| plugin-syntax-jsx | `packages/babel-plugin-syntax-jsx/` | ソース | JSX構文解析プラグイン |
