# 機能設計書 44-テンプレート解析（Parser）

## 概要

本ドキュメントは、Vue 3テンプレートコンパイラの字句解析・構文解析機能について記述する。Tokenizer（字句解析器）とParser（構文解析器）の2段構成でVueテンプレート文法を解析し、AST（抽象構文木）を生成する。

### 本機能の処理概要

テンプレート解析は、Vueテンプレートの文字列を入力として受け取り、コンパイラが処理可能なAST（抽象構文木）を生成するプロセスである。htmlparser2ベースのTokenizerが字句解析を行い、Parserがトークンイベントに基づいてASTノードを組み立てる。

**業務上の目的・背景**：VueのテンプレートはHTML拡張構文（ディレクティブ、補間式、コンポーネント参照など）を含むため、標準的なHTMLパーサーでは処理できない。独自のパーサーにより、これらの拡張構文を正確に解析し、後続のトランスフォーム処理やコード生成に必要なAST構造を生成する必要がある。

**機能の利用シーン**：`baseCompile()` 関数内でテンプレート文字列からASTへの変換の最初のステップとして呼び出される。SFCコンパイラ、Vue CLI、Vite等のビルドツール、およびブラウザ内コンパイルで使用される。

**主要な処理内容**：
1. Tokenizerがテンプレート文字列を1文字ずつ走査し、トークンイベントを発火
2. Parserがトークンイベントに応じてASTノード（要素、テキスト、補間、コメント、ディレクティブ等）を生成
3. ホワイトスペースの圧縮・除去処理
4. 要素タイプの判定（ELEMENT/COMPONENT/SLOT/TEMPLATE）
5. ソースマップ用の位置情報（行・列・オフセット）の追跡

**関連システム・外部連携**：@vue/compiler-domによるHTML固有のパーサーオプション提供、@babel/parserによる式の検証（非ブラウザビルド時）

**権限による制御**：権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | Index（メイン画面） | 主機能 | Vueテンプレートの字句解析・構文解析によるAST生成と結果表示 |
| 5 | Options Panel（コンパイルオプション） | API連携 | コンパイルオプション変更時のテンプレート再解析トリガー |

## 機能種別

テンプレートコンパイル（字句解析・構文解析）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | string | Yes | テンプレート文字列 | なし |
| options | ParserOptions | No | パーサー設定オプション | 個別オプションのnullチェック |

### ParserOptionsの主要プロパティ

| パラメータ名 | 型 | デフォルト | 説明 |
|-------------|-----|-----------|------|
| parseMode | 'base' \| 'html' \| 'sfc' | 'base' | 解析モード |
| delimiters | [string, string] | ['{{', '}}'] | 補間式のデリミタ |
| whitespace | 'condense' \| 'preserve' | 'condense' | ホワイトスペース処理 |
| isVoidTag | (tag: string) => boolean | NO | ボイドタグ判定 |
| isPreTag | (tag: string) => boolean | NO | プリフォーマットタグ判定 |
| isCustomElement | (tag: string) => boolean | NO | カスタム要素判定 |
| prefixIdentifiers | boolean | false | 識別子プレフィックス有効化 |
| comments | boolean | __DEV__ | コメント保持 |

### 入力データソース

テンプレート文字列。SFCの`<template>`ブロック、またはインラインテンプレート文字列。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| RootNode | RootNode | AST（抽象構文木）のルートノード |
| children | TemplateChildNode[] | ルートノードの子ノード配列 |
| loc | SourceLocation | ソース位置情報 |

### 出力先

`baseCompile()` 関数に返却され、後続のtransform処理に渡される。

## 処理フロー

### 処理シーケンス

```
1. baseParse() 呼び出し
   └─ パーサー状態のリセット（reset()）
2. オプションのマージ
   └─ defaultParserOptions と入力オプションをマージ
3. Tokenizer の設定
   └─ 解析モード（BASE/HTML/SFC）の設定
   └─ XML モード判定
   └─ デリミタ設定
4. RootNode の作成
   └─ createRoot([], input) でルートノードを初期化
5. Tokenizer の実行
   └─ tokenizer.parse(currentInput) でトークン化
   └─ 各トークンイベントに対してParserコールバックが発火
6. ホワイトスペース圧縮
   └─ condenseWhitespace(root.children)
7. ルートノードの位置情報設定
   └─ root.loc = getLoc(0, input.length)
8. ASTの返却
```

### フローチャート

```mermaid
flowchart TD
    A[baseParse入力] --> B[reset: 状態リセット]
    B --> C[オプションマージ]
    C --> D[Tokenizerモード設定]
    D --> E[RootNode生成]
    E --> F[tokenizer.parse実行]
    F --> G{トークンイベント}
    G -->|ontext| H[テキストノード生成]
    G -->|oninterpolation| I[補間ノード生成]
    G -->|onopentagname| J[要素ノード生成開始]
    G -->|onclosetag| K[要素ノード閉じ]
    G -->|ondirname| L[ディレクティブ解析]
    G -->|onattribname| M[属性解析]
    G -->|oncomment| N[コメントノード生成]
    G -->|onend| O[EOF処理]
    H --> P[ホワイトスペース圧縮]
    I --> P
    J --> P
    K --> P
    L --> P
    M --> P
    N --> P
    O --> P
    P --> Q[RootNode返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-44-01 | ディレクティブ省略記法 | `.` `:`はv-bind、`@`はv-on、`#`はv-slotに展開 | ディレクティブ名解析時 |
| BR-44-02 | コンポーネント判定 | 先頭大文字、`component`タグ、非ネイティブタグをコンポーネントとして判定 | 要素閉じタグ処理時 |
| BR-44-03 | v-pre処理 | v-preディレクティブが検出された場合、後続のディレクティブを属性に変換 | ondirname時 |
| BR-44-04 | ホワイトスペース圧縮 | condenseモードでは連続空白を1スペースに、特定条件の空白ノードを除去 | whitespace !== 'preserve'時 |
| BR-44-05 | SFCモード | SFCルートタグのinnerLoc（内部位置）を追跡 | parseMode === 'sfc'時 |
| BR-44-06 | forパース結合 | v-forディレクティブの式はパーサー段階でforParseResultに分解 | v-forディレクティブ検出時 |

### 計算ロジック

位置情報（SourceLocation）は、Tokenizerが管理するオフセット・行・列の情報に基づいて計算される。

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

データベース操作は存在しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| X_MISSING_END_TAG | コンパイルエラー | 閉じタグが不足している場合 | テンプレートの構文を修正 |
| X_INVALID_END_TAG | コンパイルエラー | 不正な閉じタグが検出された場合 | テンプレートの構文を修正 |
| X_MISSING_INTERPOLATION_END | コンパイルエラー | 補間式の閉じデリミタが不足 | `}}`を追加 |
| EOF_IN_TAG | コンパイルエラー | タグ内でEOFに到達 | テンプレートの構文を修正 |
| EOF_IN_COMMENT | コンパイルエラー | コメント内でEOFに到達 | コメントを正しく閉じる |
| DUPLICATE_ATTRIBUTE | コンパイルエラー | 重複する属性名が検出された場合 | 重複属性を除去 |
| X_MISSING_DIRECTIVE_NAME | コンパイルエラー | ディレクティブ名が空の場合 | ディレクティブ名を指定 |
| X_INVALID_EXPRESSION | コンパイルエラー | 式が無効な場合（非ブラウザ時） | JavaScript式を修正 |

### リトライ仕様

リトライ仕様は存在しない。エラーはonErrorコールバックを通じて報告される。

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

トランザクション処理は存在しない。

## パフォーマンス要件

- 文字単位の走査であるため、テンプレートサイズに線形の処理時間
- 式の検証（@babel/parser）は非ブラウザビルドでのみ実行されるため、ブラウザ内コンパイルでは軽量

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

- エンティティデコード処理が含まれるため、XSS対策に注意
- ブラウザビルドとサーバーサイドビルドでエンティティデコードの実装が異なる

## 備考

- Tokenizerはhtmlparser2のフォークであり、Vue固有の拡張（補間式、ディレクティブ）が追加されている
- パーサー状態はモジュールレベルの変数で管理される（シングルスレッド前提）
- SFCモードではルートタグのinnerLocが追跡され、`<template>`ブロックの内容位置が正確に記録される
- 2.x互換モード（__COMPAT__）ではv-bind:foo.syncのv-model:foo変換なども処理される

---

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

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

### 推奨読解順序

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

ASTノードの型定義を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ast.ts | `packages/compiler-core/src/ast.ts` | NodeTypes列挙型（29-61行目）: ROOT, ELEMENT, TEXT, COMMENT等のノードタイプ |
| 1-2 | ast.ts | `packages/compiler-core/src/ast.ts` | ElementTypes列挙型（63-68行目）: ELEMENT, COMPONENT, SLOT, TEMPLATE |
| 1-3 | ast.ts | `packages/compiler-core/src/ast.ts` | SourceLocation, Position型（77-87行目）: 位置情報 |

**読解のコツ**: ASTノードのtype属性はNodeTypes列挙型の値であり、パーサーが生成するノードの種別を決定する。ElementTypesはタグ閉じ時に動的に判定される。

#### Step 2: Tokenizerの状態管理を理解する

Tokenizerの状態遷移を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tokenizer.ts | `packages/compiler-core/src/tokenizer.ts` | ParseMode列挙型（41-45行目）: BASE, HTML, SFC |
| 2-2 | tokenizer.ts | `packages/compiler-core/src/tokenizer.ts` | State列挙型（87-100行目+）: Text, InterpolationOpen, BeforeTagName等の状態 |
| 2-3 | tokenizer.ts | `packages/compiler-core/src/tokenizer.ts` | CharCodes列挙型（47-81行目）: 文字コード定数 |

#### Step 3: Parserのエントリーポイントを理解する

baseParse()関数の処理フローを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | parser.ts | `packages/compiler-core/src/parser.ts` | baseParse関数（1028-1079行目）: メインエントリーポイント |
| 3-2 | parser.ts | `packages/compiler-core/src/parser.ts` | defaultParserOptions（70-83行目）: デフォルトオプション |
| 3-3 | parser.ts | `packages/compiler-core/src/parser.ts` | reset関数（1018-1026行目）: 状態リセット |

**主要処理フロー**:
1. **1029行目**: reset()で状態リセット
2. **1030-1041行目**: オプションのマージ
3. **1056-1061行目**: Tokenizerモードの設定
4. **1073行目**: createRoot([], input)でルートノード生成
5. **1074行目**: tokenizer.parse(currentInput)で解析実行
6. **1076行目**: condenseWhitespace(root.children)でホワイトスペース圧縮

#### Step 4: トークンイベントハンドラを理解する

Parserが各トークンイベントに対してどのようにASTノードを生成するか確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | parser.ts | `packages/compiler-core/src/parser.ts` | tokenizer初期化（100-489行目）: 全トークンイベントのハンドラ定義 |
| 4-2 | parser.ts | `packages/compiler-core/src/parser.ts` | ontext/ontextentity（103-109行目）: テキストノード処理 |
| 4-3 | parser.ts | `packages/compiler-core/src/parser.ts` | oninterpolation（111-137行目）: 補間式処理 |
| 4-4 | parser.ts | `packages/compiler-core/src/parser.ts` | onopentagname（139-151行目）: 開きタグ名処理 |
| 4-5 | parser.ts | `packages/compiler-core/src/parser.ts` | ondirname（201-246行目）: ディレクティブ名解析 |
| 4-6 | parser.ts | `packages/compiler-core/src/parser.ts` | onattribend（312-410行目）: 属性値確定処理 |

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

```
baseParse(input, options)
    │
    ├─ reset()
    │
    ├─ オプションマージ
    │
    ├─ createRoot([], input)
    │
    └─ tokenizer.parse(currentInput)
           │
           ├─ onopentagname → ElementNode生成
           │      └─ endOpenTag → addNode / stack管理
           │
           ├─ ondirname → DirectiveNode生成
           │      ├─ ondirarg → 引数解析
           │      ├─ ondirmodifier → 修飾子解析
           │      └─ onattribend → 式解析・値確定
           │
           ├─ onattribname → AttributeNode生成
           │
           ├─ ontext → TextNode生成
           │      └─ onText → 隣接テキストのマージ
           │
           ├─ oninterpolation → InterpolationNode生成
           │      └─ createExp → 式の検証
           │
           ├─ onclosetag → onCloseTag
           │      ├─ 要素タイプ判定
           │      ├─ ホワイトスペース圧縮
           │      └─ v-pre境界チェック
           │
           └─ onend → EOF処理
```

### データフロー図

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

テンプレート文字列     ──▶ Tokenizer                    ──▶ トークンイベント
                            │                                    │
                            ▼                                    ▼
                       文字単位走査                        Parser コールバック
                            │                                    │
                            ▼                                    ▼
                       状態遷移管理                        ASTノード生成
                                                                 │
                                                                 ▼
                                                          RootNode (AST)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| parser.ts | `packages/compiler-core/src/parser.ts` | ソース | baseParse()とトークンイベントハンドラの実装 |
| tokenizer.ts | `packages/compiler-core/src/tokenizer.ts` | ソース | Tokenizerクラスの実装（htmlparser2ベース） |
| ast.ts | `packages/compiler-core/src/ast.ts` | ソース | AST型定義（NodeTypes, ElementTypes等） |
| errors.ts | `packages/compiler-core/src/errors.ts` | ソース | エラーコードとエラー生成関数 |
| options.ts | `packages/compiler-core/src/options.ts` | ソース | ParserOptions型定義 |
| compile.ts | `packages/compiler-core/src/compile.ts` | ソース | baseCompile()からbaseParse()を呼び出す |
| parserOptions.ts | `packages/compiler-dom/src/parserOptions.ts` | ソース | DOM固有パーサーオプション |
| utils.ts | `packages/compiler-core/src/utils.ts` | ソース | forAliasRE, isSimpleIdentifier等のユーティリティ |
