# 機能設計書 51-v-slotディレクティブ変換

## 概要

本ドキュメントは、Vue 3テンプレートコンパイラにおけるv-slotディレクティブの変換処理について記述する。v-slotディレクティブをスロットレンダリングコードに変換し、コンポーネント間のコンテンツ配信メカニズムを実現する。

### 本機能の処理概要

v-slotディレクティブ変換は、Vueテンプレート内のスロット関連構文を解析し、レンダリング関数で使用可能なスロットオブジェクトを構築する処理である。コンポーネントの子コンテンツをスロットとして適切に分類・変換し、スコープ付きスロットやダイナミックスロットにも対応する。

**業務上の目的・背景**：Vueのコンポーネントシステムにおいて、スロットは親コンポーネントから子コンポーネントへのコンテンツ配信の主要メカニズムである。テンプレート内のv-slot構文を効率的なレンダリングコードに変換することで、再利用可能なコンポーネント設計を支援し、開発生産性を向上させる。

**機能の利用シーン**：テンプレートコンパイル時に、`<Comp v-slot="{ prop }">` や `<template v-slot:name="{ prop }">` といったスロット構文が検出された際に自動的に呼び出される。コンポーネント間のコンテンツ配信パターン（デフォルトスロット、名前付きスロット、スコープ付きスロット）のすべてに対応する。

**主要な処理内容**：
1. スロットスコープの追跡（trackSlotScopes）による識別子管理
2. v-for付きスロットのスコープ追跡（trackVForSlotScopes）
3. コンポーネント直接指定のv-slotの処理
4. `<template v-slot>` による名前付きスロットの処理
5. 条件付きスロット（v-if/v-else-if/v-else）の動的スロット変換
6. v-for付きスロットの動的スロット変換
7. スロットフラグ（STABLE/FORWARDED/DYNAMIC）の決定
8. 重複スロット名の検出とエラー報告

**関連システム・外部連携**：@vue/compiler-coreパッケージ内の変換パイプラインの一部として動作する。transformElementから呼び出され、buildSlots関数がスロットオブジェクトを構築する。ランタイムのcreateSlots、renderList、withCtxヘルパーと連携する。

**権限による制御**：該当なし（コンパイル時処理）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | Index（メイン画面） | 補助機能 | v-slotスロットレンダリングのコンパイル結果をリアルタイム確認 |

## 機能種別

テンプレート変換処理（コンパイラ変換プラグイン）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| node | ElementNode | Yes | 処理対象のコンポーネントまたはテンプレート要素ノード | type === NodeTypes.ELEMENT |
| context | TransformContext | Yes | 変換コンテキスト（スコープ情報、ヘルパー関数等を保持） | - |
| buildSlotFn | SlotFnBuilder | No | スロット関数のビルダー（デフォルトはbuildClientSlotFn） | - |

### 入力データソース

テンプレート解析（Parser）により生成されたAST（抽象構文木）のElementNode。v-slotディレクティブが付与されたコンポーネント要素やtemplate要素が対象。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| slots | SlotsExpression | スロットオブジェクト式（ObjectExpressionまたはcreateSlots呼び出し） |
| hasDynamicSlots | boolean | 動的スロットが含まれるかどうかのフラグ |

### 出力先

コンポーネントVNodeCallのchildren引数としてコード生成パイプラインへ渡される。

## 処理フロー

### 処理シーケンス

```
1. スコープ追跡の初期化
   └─ trackSlotScopes: v-slotのスコープカウンターをインクリメント
   └─ trackVForSlotScopes: v-for付きスロットのスコープ変数を登録

2. 動的スロット判定の初期化
   └─ vSlotスコープまたはvForスコープが0より大きい場合は動的
   └─ prefixIdentifiers有効時はスコープ変数参照を精密チェック

3. コンポーネント直接v-slotの処理
   └─ <Comp v-slot="{ prop }"> 形式の検出
   └─ 動的なスロット引数の場合はhasDynamicSlots = true
   └─ slotsPropertiesにデフォルトスロットを追加

4. テンプレートスロットの反復処理
   └─ 子要素を順に走査
   └─ <template v-slot:name="{ prop }"> の検出
   └─ コンポーネント直接v-slotとの混在チェック（エラー）
   └─ 静的/動的スロット名の判定
   └─ 条件付きスロット（v-if/v-else）の処理
   └─ v-for付きスロットの処理
   └─ 重複スロット名の検出

5. 暗黙のデフォルトスロットの構築
   └─ テンプレートスロットがない場合: 全子要素をデフォルトスロットに
   └─ 名前付きスロットと混在する場合: 暗黙の子要素をデフォルトスロットに

6. スロットフラグの決定
   └─ DYNAMIC: 動的スロットがある場合
   └─ FORWARDED: 転送スロットがある場合
   └─ STABLE: それ以外（安定スロット）

7. 最終スロットオブジェクトの構築
   └─ ObjectExpressionにスロットプロパティとフラグを統合
   └─ 動的スロットがある場合はcreateSlots()でラップ
```

### フローチャート

```mermaid
flowchart TD
    A[開始: buildSlots] --> B{コンポーネント直接v-slotあり?}
    B -->|Yes| C[slotsPropertiesにデフォルトスロット追加]
    B -->|No| D[子要素を反復処理]
    C --> D
    D --> E{template v-slot検出?}
    E -->|Yes| F{v-if/v-else付き?}
    E -->|No| G{暗黙の子要素?}
    F -->|Yes| H[conditionalExpression構築]
    F -->|No| I{v-for付き?}
    I -->|Yes| J[RENDER_LISTで動的スロット構築]
    I -->|No| K[静的スロットプロパティ追加]
    H --> D
    J --> D
    K --> D
    G -->|Yes| L[implicitDefaultChildrenに追加]
    G -->|No| D
    L --> D
    D --> M[暗黙のデフォルトスロット構築]
    M --> N[スロットフラグ決定]
    N --> O{動的スロットあり?}
    O -->|Yes| P[createSlots()でラップ]
    O -->|No| Q[ObjectExpression返却]
    P --> R[終了]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-51-01 | 混在禁止 | コンポーネント直接v-slotとtemplate v-slotの混在はエラー | onComponentSlotが存在する状態でtemplate v-slotが検出された場合 |
| BR-51-02 | 重複名禁止 | 同名の静的スロットは重複エラー | seenSlotNamesに既に存在するスロット名が検出された場合 |
| BR-51-03 | 動的スロット判定 | v-forまたはv-slotスコープ内のスロットは動的 | context.scopes.vSlot > 0 または context.scopes.vFor > 0 |
| BR-51-04 | スロットフラグ | DYNAMIC > FORWARDED > STABLE の優先順位 | hasDynamicSlots判定後、hasForwardedSlots判定 |
| BR-51-05 | v-else隣接チェック | v-elseは直前にv-ifが必要 | v-elseの前にv-if付きtemplateが見つからない場合はエラー |

### 計算ロジック

スロットフラグの決定ロジック:
- `hasDynamicSlots` が true の場合: `SlotFlags.DYNAMIC` (値: 2)
- `hasForwardedSlots(node.children)` が true の場合: `SlotFlags.FORWARDED` (値: 3)
- それ以外: `SlotFlags.STABLE` (値: 1)

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

該当なし（コンパイル時処理のため、データベース操作は発生しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| X_V_SLOT_MIXED_SLOT_USAGE | コンパイルエラー | コンポーネント直接v-slotとtemplate v-slotの混在 | いずれか一方の記法に統一する |
| X_V_SLOT_DUPLICATE_SLOT_NAMES | コンパイルエラー | 同名の静的スロットが複数存在 | スロット名を一意にする |
| X_V_ELSE_NO_ADJACENT_IF | コンパイルエラー | v-elseの前にv-ifがない | v-if/v-else-ifを正しく配置する |
| X_V_FOR_MALFORMED_EXPRESSION | コンパイルエラー | v-forの式が不正 | v-for式を正しい構文に修正する |

### リトライ仕様

該当なし（コンパイルエラーは即座に報告される）

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

該当なし（コンパイル時処理）

## パフォーマンス要件

- prefixIdentifiers有効時のスコープ変数参照チェックにより、不要な動的スロット判定を回避
- 静的スロットは安定フラグ（STABLE）を付与し、ランタイムでの差分計算を最適化

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

該当なし（コンパイル時処理であり、ユーザー入力の直接処理は行わない）

## 備考

- v-slot処理はDirectiveTransformではなく、transformElementのビルドフェーズで呼び出される特殊な変換である
- SSR向けにはbuildSlotFnパラメータでカスタムのスロット関数ビルダーを差し替え可能
- Vue 2互換モード（`__COMPAT__`）ではnonScopedSlotフラグが設定される

---

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

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

### 推奨読解順序

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

まず、スロット関連の型定義とAST構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ast.ts | `packages/compiler-core/src/ast.ts` | SlotsExpression、FunctionExpression、ObjectExpression等のスロット関連AST型定義 |
| 1-2 | runtimeHelpers.ts | `packages/compiler-core/src/runtimeHelpers.ts` | CREATE_SLOTS、RENDER_LIST、WITH_CTXヘルパー定義 |

**読解のコツ**: SlotsExpressionはObjectExpression（静的スロット）またはCallExpression（動的スロットを含む場合はcreateSlots呼び出し）のユニオン型である。

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

スロット変換のエントリーポイントであるtrackSlotScopesとbuildSlotsを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | vSlot.ts | `packages/compiler-core/src/transforms/vSlot.ts` | スロット変換の全体構造 |

**主要処理フロー**:
1. **48-71行目**: trackSlotScopes - NodeTransformとしてv-slotのスコープ深さを追跡
2. **75-98行目**: trackVForSlotScopes - v-for付きスロットのスコープ変数を登録
3. **118-380行目**: buildSlots - スロットオブジェクト構築のメインロジック

#### Step 3: コンポーネント直接v-slotの処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | vSlot.ts | `packages/compiler-core/src/transforms/vSlot.ts` | コンポーネント直接v-slot処理 |

**主要処理フロー**:
- **151-163行目**: findDir(node, 'slot', true) でコンポーネント上のv-slotを検出し、slotsPropertiesにデフォルトスロットとして追加

#### Step 4: テンプレートスロットの反復処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | vSlot.ts | `packages/compiler-core/src/transforms/vSlot.ts` | template v-slot処理ループ |

**主要処理フロー**:
- **173-310行目**: 子要素をforループで走査し、template v-slotを検出
- **218-226行目**: v-if付きスロットをconditionalExpressionとして動的スロット配列に追加
- **227-265行目**: v-else/v-else-if付きスロットを既存の条件分岐チェーンに連結
- **266-290行目**: v-for付きスロットをRENDER_LIST呼び出しとして動的スロット配列に追加
- **291-309行目**: 通常の静的スロットをslotsPropertiesに追加

#### Step 5: スロットフラグとオブジェクト構築

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | vSlot.ts | `packages/compiler-core/src/transforms/vSlot.ts` | スロットフラグ決定と最終構築 |

**主要処理フロー**:
- **350-354行目**: hasDynamicSlots / hasForwardedSlots / STABLE の3段階でスロットフラグを決定
- **355-374行目**: スロットオブジェクトを構築し、動的スロットがあればcreateSlots()でラップ

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

```
transformElement (エントリーポイント)
    │
    ├─ trackSlotScopes (NodeTransform)
    │      └─ context.scopes.vSlot++ / --
    │
    ├─ trackVForSlotScopes (NodeTransform)
    │      └─ finalizeForParseResult
    │      └─ context.addIdentifiers / removeIdentifiers
    │
    └─ buildSlots (メイン処理)
           ├─ findDir(node, 'slot', true)
           ├─ buildClientSlotFn / buildSlotFn
           │      └─ createFunctionExpression
           ├─ createConditionalExpression (v-if付きスロット)
           ├─ createCallExpression(RENDER_LIST) (v-for付きスロット)
           ├─ buildDynamicSlot
           │      └─ createObjectExpression
           ├─ hasForwardedSlots (再帰チェック)
           └─ createCallExpression(CREATE_SLOTS) (動的スロット時)
```

### データフロー図

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

ElementNode        ───▶ trackSlotScopes        ───▶ スコープ追跡更新
(v-slot付き)             │
                         ▼
                    buildSlots
                         │
                    ┌────┴────┐
                    ▼         ▼
              静的スロット  動的スロット
              (Property[]) (ConditionalExpression
                            | CallExpression[])
                    │         │
                    ▼         ▼
              ObjectExpression
              (+ SlotFlags)
                    │
                    ▼
              {slots: SlotsExpression,    ───▶ VNodeCall.children
               hasDynamicSlots: boolean}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| vSlot.ts | `packages/compiler-core/src/transforms/vSlot.ts` | ソース | v-slotディレクティブ変換のメイン実装 |
| ast.ts | `packages/compiler-core/src/ast.ts` | ソース | SlotsExpression等のAST型定義 |
| transform.ts | `packages/compiler-core/src/transform.ts` | ソース | 変換コンテキスト（TransformContext）の定義 |
| errors.ts | `packages/compiler-core/src/errors.ts` | ソース | エラーコード定義（X_V_SLOT_*） |
| runtimeHelpers.ts | `packages/compiler-core/src/runtimeHelpers.ts` | ソース | CREATE_SLOTS、RENDER_LIST等のヘルパーシンボル定義 |
| utils.ts | `packages/compiler-core/src/utils.ts` | ソース | findDir、isVSlot等のユーティリティ関数 |
| vFor.ts | `packages/compiler-core/src/transforms/vFor.ts` | ソース | createForLoopParams、finalizeForParseResult（v-for連携） |
| slotFlags.ts | `packages/shared/src/slotFlags.ts` | ソース | SlotFlags定数（STABLE, DYNAMIC, FORWARDED） |
