# 機能設計書 9-ASTウォーカー（walk）

## 概要

本ドキュメントは、ASTツリーを走査するwalk関数の機能設計書である。Continue・Skip・Stop・Replace等のアクションによりツリーの走査制御・ノード置換が可能で、enter/exitコールバックに対応する。

### 本機能の処理概要

**業務上の目的・背景**：Tailwind CSSのコンパイルパイプラインでは、ASTを走査して各種ディレクティブの検出・ノードの変換・フィルタリングを行う必要がある。walk関数はジェネリックなAST走査ユーティリティとして、enter/exitフェーズの2段階コールバックと6種類のアクション（Continue, Skip, Stop, Replace, ReplaceSkip, ReplaceStop）を提供し、柔軟なAST操作を実現する。

**機能の利用シーン**：parseCss内のディレクティブ処理、optimizeAst内の変換処理、substituteAtApply、substituteAtVariant、substituteFunctions、compileCandidates内のバリアント適用など、コンパイルパイプラインのほぼ全段階で使用される。ValueParser・SelectorParser等の独自ASTに対しても使用可能なジェネリック設計である。

**主要な処理内容**：
1. AST配列の各ノードに対してenterコールバックを呼び出す
2. enterの戻り値に応じたアクション（Continue/Skip/Stop/Replace/ReplaceSkip/ReplaceStop）を実行する
3. 子ノードがある場合は再帰的に深さ優先で走査する
4. 子ノードの走査完了後、exitコールバックを呼び出す
5. exitの戻り値に応じたアクション（Continue/Stop/Replace/ReplaceStop/ReplaceSkip）を実行する
6. VisitContextを通じて親ノード・深さ・パス情報を提供する

**関連システム・外部連携**：特になし。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 全画面のCSSコンパイルで間接的に使用される基盤ユーティリティ |

## 機能種別

ユーティリティ関数（AST走査・操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ast | T[] | Yes | 走査対象のAST配列（ジェネリック） | nodesプロパティを持つオブジェクトの配列 |
| hooks | Function \| Object | Yes | enter関数、またはenter/exitを持つオブジェクト | enter/exit関数 |

### 入力データソース

- コンパイルパイプラインの各段階から渡されるAST配列

## 出力仕様

### 出力データ

walk関数自体はvoidを返却する。AST配列はin-placeで変更される（Replace/ReplaceSkip/ReplaceStopアクション使用時）。

### 出力先

- 入力として渡されたAST配列が直接変更される

## 処理フロー

### 処理シーケンス

```
1. スタックの初期化
   └─ [ast, offset=0, parent=null] をスタックにプッシュ
2. メインループ（スタックが空になるまで）
   ├─ 現在のフレームを取得（nodes, offset, parent）
   ├─ offset >= nodes.length の場合: スタックポップ、depth減算
   ├─ enterフェーズ（offset >= 0の場合）:
   │   ├─ Continue: 子ノードがあればスタックプッシュ、exit用にoffsetを反転
   │   ├─ Stop: 即座にreturn
   │   ├─ Skip: exit用にoffsetを反転（子ノード走査をスキップ）
   │   ├─ Replace: nodes.splice、同じoffsetで再処理
   │   ├─ ReplaceStop: nodes.splice、即座にreturn
   │   └─ ReplaceSkip: nodes.splice、置換ノード数分offsetを進める
   └─ exitフェーズ（offset < 0の場合）:
       ├─ Continue: 次のシブリングへ進む
       ├─ Stop: 即座にreturn
       ├─ Replace: nodes.splice、置換ノード数分offsetを進める
       ├─ ReplaceStop: nodes.splice、即座にreturn
       └─ ReplaceSkip: nodes.splice、置換ノード数分offsetを進める
```

### フローチャート

```mermaid
flowchart TD
    A[AST配列入力] --> B[スタック初期化]
    B --> C{スタック空?}
    C -->|Yes| D[終了]
    C -->|No| E[フレーム取得]
    E --> F{offset >= length?}
    F -->|Yes| G[スタックポップ]
    G --> C
    F -->|No| H{offset >= 0?}
    H -->|Yes| I[enterコールバック実行]
    I --> J{アクション種別}
    J -->|Continue| K[子ノードプッシュ+offset反転]
    J -->|Skip| L[offset反転のみ]
    J -->|Stop| D
    J -->|Replace| M[splice+再処理]
    J -->|ReplaceSkip| N[splice+offset進行]
    J -->|ReplaceStop| O[splice+終了]
    H -->|No| P[exitコールバック実行]
    P --> Q{アクション種別}
    Q -->|Continue| R[offset+1]
    Q -->|Stop| D
    Q -->|Replace| S[splice+offset進行]
    Q -->|ReplaceStop| T[splice+終了]
    Q -->|ReplaceSkip| U[splice+offset進行]
    K --> C
    L --> C
    M --> C
    N --> C
    R --> C
    S --> C
    U --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 深さ優先走査 | ノードの子ノードを先に走査する深さ優先方式 | 常時 |
| BR-02 | enterフェーズ | ノードに到達した時点でenterコールバックが呼ばれる | 常時 |
| BR-03 | exitフェーズ | 子ノードの走査完了後にexitコールバックが呼ばれる | exitコールバックが指定された場合 |
| BR-04 | Continue | 走査を続行し、子ノードがあれば深く潜る | デフォルトアクション |
| BR-05 | Skip | 子ノードの走査をスキップし、次のシブリングへ | enterフェーズのみ有効 |
| BR-06 | Stop | 走査を即座に中断する | 必要なノードが見つかった場合等 |
| BR-07 | Replace | ノードを置換し、同じ位置から再処理する | enterフェーズでの使用時 |
| BR-08 | ReplaceSkip | ノードを置換し、置換ノードの走査をスキップする | 置換後に再処理が不要な場合 |
| BR-09 | ReplaceStop | ノードを置換し、走査を即座に中断する | 置換後に走査を終了する場合 |
| BR-10 | ビット反転によるフェーズ管理 | offsetのビット反転（~演算子）でenter/exitフェーズを管理する | 内部実装 |

### 計算ロジック

- **フェーズ管理**: `offset >= 0`ならenterフェーズ、`offset < 0`ならexitフェーズ。`~offset`でビット反転して元のインデックスを復元
- **パス生成**: スタックフレームのparentを辿って現在ノードまでの祖先パスを生成（逆順で構築）

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | enterで無効なWalkActionが返された | `Invalid 'WalkAction.Unknown({kind})' in enter.` |
| - | Error | exitで無効なWalkActionが返された | `Invalid 'WalkAction.Unknown({kind})' in exit.` |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 再帰呼び出しではなくスタックベースの反復処理で実装されており、深いASTでもスタックオーバーフローを回避する
- VisitContextのpath()関数はスタックフレームを辿るため、呼び出しコストはO(depth)
- 連結リスト（Stack<T>）によるスタック管理で配列のリサイズを回避

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

特になし。

## 備考

- walk関数はジェネリック型`T extends object`を使用しており、AstNode以外のAST（ValueAstNode、SelectorAstNode等）にも使用可能
- `nodes`プロパティを持つオブジェクトであれば走査対象として扱われる
- WalkActionオブジェクトは`as const`で定義されており、型安全なアクション指定が可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | walk.ts | `packages/tailwindcss/src/walk.ts` | WalkAction定数オブジェクト（10-20行目）とWalkResult型（23-29行目） |
| 1-2 | walk.ts | `packages/tailwindcss/src/walk.ts` | VisitContext インターフェース（36-40行目）: parent, depth, path() |
| 1-3 | walk.ts | `packages/tailwindcss/src/walk.ts` | Stack インターフェース（55-58行目）: 連結リストによるスタック実装 |

**読解のコツ**: WalkActionは`const enum`ではなくオブジェクトとして定義されている（`WalkKind`が内部enum）。これにより、アクションオブジェクトの同一性比較が可能。`Replace`等のアクションはファクトリ関数で、ノード配列を含むオブジェクトを返す。ビット反転`~offset`はTypeScriptの2の補数演算を利用したenter/exitフェーズ切り替えのテクニックである。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | walk.ts | `packages/tailwindcss/src/walk.ts` | `walk`関数（42-53行目）。旧API（関数直接渡し）と新API（{enter, exit}オブジェクト）の両方に対応 |

**主要処理フロー**:
1. **51行目**: hooksが関数ならenterのみ、オブジェクトならenter/exitを取り出す
2. **52行目**: walkImplementation関数を呼び出す

#### Step 3: walkImplementation関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | walk.ts | `packages/tailwindcss/src/walk.ts` | `walkImplementation`関数（60-196行目）。スタックベースの反復走査 |

**主要処理フロー**:
- **65-66行目**: StackFrame型定義とスタック初期化。連結リスト構造
- **68-86行目**: VisitContextの初期化。path()はスタックフレームのparentを辿って構築
- **88行目**: メインのwhileループ開始
- **95-99行目**: ノード配列の走査完了時のスタックポップ
- **104-153行目**: enterフェーズの処理
  - **109-120行目**: Continue - 子ノードがあればスタックにプッシュ、offsetをビット反転
  - **122-123行目**: Stop - 即座にreturn
  - **125-128行目**: Skip - offsetをビット反転のみ
  - **130-133行目**: Replace - splice後、同じoffsetで再処理
  - **135-138行目**: ReplaceStop - splice後return
  - **140-144行目**: ReplaceSkip - splice後、置換ノード数分offset進行
- **157-194行目**: exitフェーズの処理（~offsetで元のインデックスを復元）
  - **163-164行目**: Continue - 次のシブリングへ
  - **167行目**: Stop - 即座にreturn
  - **170-173行目**: Replace - splice後、置換ノード数分offset進行
  - **176-179行目**: ReplaceStop - splice後return
  - **181-185行目**: ReplaceSkip - splice後、置換ノード数分offset進行

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

```
walk(ast, hooks)
    |
    +-- walkImplementation(ast, enter, exit)
         |
         +-- enter(node, ctx)          ... ユーザー提供のenterコールバック
         |    └─ WalkAction を返却
         |
         +-- exit(node, ctx)           ... ユーザー提供のexitコールバック
         |    └─ WalkAction を返却
         |
         +-- ctx.path()               ... 祖先パスの構築
```

### データフロー図

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

AstNode[]         ──▶  walk(ast, {enter, exit})  ──▶  AstNode[]（in-place変更）
                       ├─ 各ノードにenter呼び出し
                       ├─ 子ノードを深さ優先で走査
                       ├─ 各ノードにexit呼び出し
                       └─ Replace系アクションでsplice
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| walk.ts | `packages/tailwindcss/src/walk.ts` | ソース | walk関数本体、WalkAction定義、VisitContext |
| ast.ts | `packages/tailwindcss/src/ast.ts` | ソース | 主要な利用元（optimizeAst、cssContext） |
| index.ts | `packages/tailwindcss/src/index.ts` | ソース | 主要な利用元（parseCss内のディレクティブ処理） |
| compile.ts | `packages/tailwindcss/src/compile.ts` | ソース | applyVariant内で使用 |
| apply.ts | `packages/tailwindcss/src/apply.ts` | ソース | substituteAtApply内で使用 |
| css-functions.ts | `packages/tailwindcss/src/css-functions.ts` | ソース | substituteFunctions内で使用 |
| variants.ts | `packages/tailwindcss/src/variants.ts` | ソース | substituteAtVariant内で使用 |
