# 機能設計書 3-@babel/traverse

## 概要

本ドキュメントは、BabelのAST走査モジュールである`@babel/traverse`パッケージの設計仕様を記述する。このパッケージは、ツリー全体の状態を管理し、ノードの置換・削除・追加を担当する。プラグイン開発において中核的な役割を果たす。

### 本機能の処理概要

**業務上の目的・背景**：ASTを変換するには、ツリー構造を効率的に走査し、各ノードに対して操作を行う仕組みが必要である。@babel/traverseは、Visitorパターンを採用してASTを深さ優先で走査し、プラグインが特定のノードタイプに対して変換処理を適用できるようにする。これにより、プラグイン開発者は低レベルのツリー操作を意識せずに変換ロジックに集中できる。

**機能の利用シーン**：@babel/coreの変換パイプライン内でプラグインを実行する場合、カスタムコード解析ツールでASTを走査する場合、ESLintルールやPrettierプラグインでコード構造を検査する場合に利用される。

**主要な処理内容**：
1. ASTの深さ優先走査（Visitorパターン）
2. NodePathオブジェクトによるノード操作のカプセル化
3. Scopeによるスコープ・バインディング管理
4. ノードの置換・削除・挿入API提供
5. 型推論・評価機能
6. キャッシュによる走査効率化

**関連システム・外部連携**：@babel/core（変換パイプライン）、@babel/types（ノード操作）、@babel/parser（AST入力）、各種Babelプラグインと連携する。

**権限による制御**：特になし。純粋なメモリ内AST操作のみ。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本パッケージは画面との直接連携なし（内部API） |

## 機能種別

AST走査・変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| parent | t.Node | Yes | 走査対象のASTノード | 有効なASTノード |
| opts | TraverseOptions | No | 走査オプション（Visitor含む） | オブジェクト形式 |
| scope | Scope | No | 初期スコープ | Scopeインスタンス |
| state | any | No | Visitor間で共有する状態 | 任意 |
| parentPath | NodePath | No | 親パス | NodePathインスタンス |
| visitSelf | boolean | No | ルートノード自身を訪問するか | boolean |

### Visitorオプション

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|-----|------|
| [NodeType] | Function \| Object | No | ノードタイプ別のvisitor関数 |
| enter | Function | No | 全ノードの入場時に呼ばれる |
| exit | Function | No | 全ノードの退場時に呼ばれる |
| noScope | boolean | No | スコープ追跡を無効化 |
| denylist | string[] | No | 走査をスキップするノードタイプ |
| shouldSkip | Function | No | ノードをスキップするか判定 |

### 入力データソース

- @babel/coreからの変換パイプライン
- プラグインからの直接呼び出し
- 解析ツールからのプログラマティック利用

## 出力仕様

### 出力データ

traverse関数自体は戻り値なし（void）。NodePathを通じてASTを直接変更する。

| 項目名 | 型 | 説明 |
|--------|-----|------|
| NodePath.node | t.Node | 現在のASTノード |
| NodePath.scope | Scope | 現在のスコープ |
| NodePath.parent | t.Node | 親ノード |
| Scope.bindings | Record<string, Binding> | スコープ内のバインディング |

### 出力先

- 入力ASTの直接変更（in-place mutation）
- NodePath/Scopeオブジェクトの状態変更

## 処理フロー

### 処理シーケンス

```
1. traverse関数の呼び出し
   └─ 親ノードとVisitorオプションを受け取る
2. Visitorの展開 (visitors.explode)
   └─ enter/exitハンドラの正規化
   └─ エイリアスの展開
3. traverseNode実行
   └─ 各子ノードを深さ優先で走査
4. 各ノードでNodePath生成
   └─ キャッシュからパスを取得または生成
5. Visitorコールバック実行
   └─ enter → visitor[type] → exit
6. ノード操作の反映
   └─ replace/remove/insert等の適用
```

### フローチャート

```mermaid
flowchart TD
    A[traverse呼び出し] --> B[visitors.explode]
    B --> C[traverseNode]
    C --> D{子ノードあり?}
    D -->|Yes| E[NodePath.get]
    E --> F{キャッシュあり?}
    F -->|Yes| G[キャッシュから取得]
    F -->|No| H[新規NodePath生成]
    G --> I[visit実行]
    H --> I
    I --> J{shouldSkip?}
    J -->|Yes| K[次のノードへ]
    J -->|No| L[enter callback]
    L --> M[visitor callback]
    M --> N[exit callback]
    N --> O{shouldStop?}
    O -->|Yes| P[走査終了]
    O -->|No| K
    K --> C
    D -->|No| P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 深さ優先走査 | 子ノードを先に走査してから兄弟ノードへ | デフォルト動作 |
| BR-02 | enter/exit順序 | enterはノード訪問時、exitは子ノード処理後 | 常時 |
| BR-03 | path.skip() | 現在ノードの子ノード走査をスキップ | skip()呼び出し時 |
| BR-04 | path.stop() | 走査全体を中断 | stop()呼び出し時 |
| BR-05 | NodePathキャッシュ | 同一ノードには同一NodePathが返される | 常時 |
| BR-06 | Scopeキャッシュ | スコープ情報はノード単位でキャッシュ | 常時 |

### 計算ロジック

特になし

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

該当なし（メモリ内処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 引数エラー | 親ノードなしでtraverse呼び出し | エラーメッセージで通知 |
| - | スコープエラー | Program/File以外でスコープなし走査 | 適切なスコープを渡す |
| - | パス操作エラー | 削除済みノードの操作 | path.removedフラグで確認 |

### リトライ仕様

リトライ機能なし

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

該当なし（ASTの直接変更、ロールバック機能なし）

## パフォーマンス要件

- NodePathとScopeはキャッシュされ、同一ノードへの再アクセスは高速
- noScope: trueでスコープ追跡を無効化すると性能向上
- traverse.cheapで軽量な走査が可能

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

- AST操作のみでコード実行は発生しない
- Visitor関数は呼び出し元から提供されるため、信頼できるコードを使用すること

## 備考

- Babel 8ではScope#references/uidsは廃止、Scope#referencesSet/uidsSetを使用
- virtualTypesとして追加の疑似ノードタイプ（ReferencedIdentifier等）をサポート

---

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

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

### 推奨読解順序

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

まず、NodePathとScopeの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | path/index.ts | `packages/babel-traverse/src/path/index.ts` | NodePathクラスの定義（56-210行目） |
| 1-2 | scope/index.ts | `packages/babel-traverse/src/scope/index.ts` | Scopeクラスの定義（415-1387行目） |
| 1-3 | scope/binding.ts | `packages/babel-traverse/src/scope/binding.ts` | Bindingクラスの定義 |

**読解のコツ**: NodePathは複数のファイルに分割されており、index.tsで各機能をimportしてprototypeに追加している。

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

処理の起点となるtraverse関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/babel-traverse/src/index.ts` | traverse関数（35-93行目）、静的メソッド（97-151行目） |

**主要処理フロー**:
1. **62-72行目**: 引数のバリデーション（親ノードとスコープの確認）
2. **82行目**: visitors.explodeでVisitorを展開
3. **84-92行目**: traverseNodeで実際の走査を実行

#### Step 3: Visitor展開処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | visitors.ts | `packages/babel-traverse/src/visitors.ts` | explode関数、merge関数 |

#### Step 4: NodePath操作メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | path/replacement.ts | `packages/babel-traverse/src/path/replacement.ts` | replaceWith、replaceWithMultiple |
| 4-2 | path/removal.ts | `packages/babel-traverse/src/path/removal.ts` | remove |
| 4-3 | path/modification.ts | `packages/babel-traverse/src/path/modification.ts` | insertBefore、insertAfter |
| 4-4 | path/family.ts | `packages/babel-traverse/src/path/family.ts` | get、getSibling |

**主要処理フロー** (path/index.ts):
- **212-311行目**: methodsオブジェクトで各機能モジュールのメソッドを集約
- **313行目**: Object.assignでprototypeに追加
- **319-334行目**: @babel/typesのisXxx/assertXxxメソッドを動的に追加

#### Step 5: Scope管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | scope/index.ts | `packages/babel-traverse/src/scope/index.ts` | crawl（953-1026行目）、registerBinding（748-793行目） |

**主要処理フロー**:
- **437-454行目**: コンストラクタでキャッシュチェックと初期化
- **946-951行目**: init()で遅延初期化
- **953-1026行目**: crawl()でスコープ内のバインディングを収集

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

```
traverse (index.ts)
    │
    ├─ visitors.explode
    │      └─ Visitorの正規化・エイリアス展開
    │
    └─ traverseNode (traverse-node.ts)
           │
           ├─ NodePath.get (path/index.ts)
           │      └─ キャッシュから取得または新規生成
           │
           ├─ visit (context.ts)
           │      ├─ enter callback
           │      ├─ visitor[type] callback
           │      └─ exit callback
           │
           └─ Scope (scope/index.ts)
                  ├─ crawl - バインディング収集
                  ├─ getBinding - バインディング取得
                  ├─ generateUid - 一意識別子生成
                  └─ registerBinding - バインディング登録
```

### データフロー図

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

AST (t.Node) ───────▶ traverse ───────▶ 変更されたAST
                          │
Visitor ───────▶ visitors.explode ───────▶ ExplodedVisitor
                          │
                   traverseNode
                          │
                    ┌─────┴─────┐
                    │           │
              NodePath      Scope
                 │             │
          ┌──────┼──────┐     │
          │      │      │     │
       replace remove insert  bindings
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-traverse/src/index.ts` | ソース | 公開APIのエントリーポイント |
| traverse-node.ts | `packages/babel-traverse/src/traverse-node.ts` | ソース | ノード走査のコア実装 |
| context.ts | `packages/babel-traverse/src/context.ts` | ソース | TraversalContextクラス |
| visitors.ts | `packages/babel-traverse/src/visitors.ts` | ソース | Visitor処理ユーティリティ |
| types.ts | `packages/babel-traverse/src/types.ts` | ソース | 型定義 |
| cache.ts | `packages/babel-traverse/src/cache.ts` | ソース | キャッシュ管理 |
| hub.ts | `packages/babel-traverse/src/hub.ts` | ソース | Hubインターフェース |
| path/index.ts | `packages/babel-traverse/src/path/index.ts` | ソース | NodePathクラス定義 |
| path/ancestry.ts | `packages/babel-traverse/src/path/ancestry.ts` | ソース | 祖先ノード操作 |
| path/family.ts | `packages/babel-traverse/src/path/family.ts` | ソース | 関連ノード取得 |
| path/replacement.ts | `packages/babel-traverse/src/path/replacement.ts` | ソース | ノード置換 |
| path/removal.ts | `packages/babel-traverse/src/path/removal.ts` | ソース | ノード削除 |
| path/modification.ts | `packages/babel-traverse/src/path/modification.ts` | ソース | ノード挿入 |
| path/introspection.ts | `packages/babel-traverse/src/path/introspection.ts` | ソース | ノード検査 |
| path/context.ts | `packages/babel-traverse/src/path/context.ts` | ソース | 走査制御（skip, stop） |
| path/conversion.ts | `packages/babel-traverse/src/path/conversion.ts` | ソース | ノード変換 |
| path/evaluation.ts | `packages/babel-traverse/src/path/evaluation.ts` | ソース | 式評価 |
| path/inference/index.ts | `packages/babel-traverse/src/path/inference/index.ts` | ソース | 型推論 |
| path/comments.ts | `packages/babel-traverse/src/path/comments.ts` | ソース | コメント操作 |
| scope/index.ts | `packages/babel-traverse/src/scope/index.ts` | ソース | Scopeクラス定義 |
| scope/binding.ts | `packages/babel-traverse/src/scope/binding.ts` | ソース | Bindingクラス定義 |
| scope/lib/renamer.ts | `packages/babel-traverse/src/scope/lib/renamer.ts` | ソース | 識別子リネーム |
