# 機能設計書 28-Globパターンマッチング

## 概要

本ドキュメントは、Tailwind CSSにおけるglobパターンマッチング機能（oxide crate内のglob.rs）の仕様・処理フロー・内部構造を記述した機能設計書である。

### 本機能の処理概要

globパターンマッチング機能は、`@source`ディレクティブで指定されたglobパターンを最適化し、ファイルスキャン対象を効率的に決定するための機能である。静的パスの巻き上げ（hoist）、ブレース展開後のパターン結合、重複排除を行う。

**業務上の目的・背景**：大規模プロジェクトでは`node_modules`等の大量のファイルを含むディレクトリが存在する。globパターンを最適化してスキャン範囲を絞り込むことで、不要なディレクトリの走査を避け、ビルド速度を大幅に改善する。例えば`{pages,components}/**/*.js`を`pages/**/*.js`と`components/**/*.js`に分割し、それぞれのディレクトリのみを走査する。

**機能の利用シーン**：`@source`ディレクティブのパターン解決時、Scannerのglob生成時、ファイルウォッチャーの設定時に使用される。

**主要な処理内容**：
1. `split_pattern`でglobパターンを静的部分と動的部分に分割する
2. `hoist_static_glob_parts`で静的部分をベースパスに移動する
3. `optimize_patterns`で同じベースパスのパターンを結合し、安定した結果を生成する

**関連システム・外部連携**：Scanner（ファイルスキャナー）、sources.rs（ソースエントリ変換）と連携する。

**権限による制御**：特になし。パス解決のためにファイルシステムへの読み取りアクセスが必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はファイルスキャン基盤の内部処理であり、特定の画面とは直接関連しない |

## 機能種別

データ変換処理（globパターンの最適化）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| entries | &Vec<GlobEntry> | Yes | 最適化対象のglobエントリ一覧 | - |

### 入力データソース

`@source`ディレクティブから生成されたGlobEntry、またはScannerのソースエントリから変換されたGlobEntry。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Vec<GlobEntry> | 最適化されたglobエントリ一覧（ベースパス順ソート済み） |

### 出力先

ScannerのWalkBuilder構築、ファイルウォッチャーの設定に使用される。

## 処理フロー

### 処理シーケンス

```
1. optimize_patterns(entries)
   ├─ hoist_static_glob_parts(entries, true)
   │   ├─ split_pattern(pattern)で静的/動的部分に分割
   │   ├─ dunce::canonicalizeでベースパスを正規化
   │   └─ ファイルの場合は親ディレクトリをベースにする
   ├─ FxHashMapでベースパスごとにパターンを集約
   ├─ 単一パターンはそのまま、複数は{p1,p2}形式に結合
   └─ ベースパス順にソート
```

### フローチャート

```mermaid
flowchart TD
    A[optimize_patterns開始] --> B[hoist_static_glob_parts]
    B --> C{各エントリ処理}
    C --> D[split_pattern]
    D --> E{ワイルドカード含む?}
    E -->|No| F["静的パス全体をbase扱い"]
    E -->|Yes| G["最後の/の位置で分割"]
    F --> H[canonicalizeでパス正規化]
    G --> H
    H --> I{パス解決成功?}
    I -->|No| J[スキップ]
    I -->|Yes| K{ベースがファイル?}
    K -->|Yes| L[親ディレクトリをベースに]
    K -->|No| M[GlobEntryに格納]
    L --> M
    M --> N[FxHashMapで集約]
    N --> O{パターン数}
    O -->|1| P[そのまま]
    O -->|>1| Q["{p1,p2,...}"形式に結合]
    P --> R[ベースパス順ソート]
    Q --> R
    R --> S[結果を返す]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 静的パス巻き上げ | ワイルドカードより前の静的パスはベースパスに移動する | パターンにワイルドカードが含まれる場合 |
| BR-02 | パス正規化 | dunce::canonicalizeでベースパスを正規化する | 常時 |
| BR-03 | ファイルの親ディレクトリ化 | ベースパスがファイルの場合、親ディレクトリをベースにしファイル名をパターンにする | emit_parent_glob=trueかつベースがファイル |
| BR-04 | 静的パスのディレクトリ化 | ワイルドカードがなくディレクトリの場合、パターンを`**/*`にする | パターンにワイルドカードがない場合 |
| BR-05 | パターン結合 | 同じベースパスの複数パターンは`{p1,p2,...}`形式に結合する | 同一ベースパスに複数パターン |
| BR-06 | 安定ソート | 結果はベースパス順にソートされる | 常時 |

### 計算ロジック

split_pattern: パターン文字列を走査し、最初の`*`または`!`が出現する前の最後の`/`で分割する。

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | tracingログ | canonicalizeでパス解決に失敗 | ログ出力して該当エントリをスキップ |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。

## パフォーマンス要件

- FxHashMap使用による高速ハッシュ
- 静的パスの巻き上げによりスキャン範囲を大幅に削減

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

- ファイルシステムの読み取りアクセスのみ（canonicalize）

## 備考

- GlobEntry構造体はbase（ベースパス）とpattern（globパターン）の2フィールドを持つ
- split_patternは`*`と`!`の両方をダイナミックパートの開始として扱う
- テスト内でgitリポジトリの初期化が行われるのは、Scannerがgitignoreルールを使用するため

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | glob.rs | `crates/oxide/src/glob.rs` | **5-12行目**: GlobEntry構造体（base, pattern）の定義 |

#### Step 2: パターン分割を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | glob.rs | `crates/oxide/src/glob.rs` | **157-187行目**: split_pattern関数 |

**主要処理フロー**:
- **159-161行目**: ワイルドカードがない場合はパターン全体が静的
- **163-173行目**: 最初の`*`または`!`が出現する前の最後の`/`の位置を記録
- **176-178行目**: `*`が最初の文字の場合は静的部分なし
- **180-184行目**: 静的部分と動的部分に分割

#### Step 3: 静的パスの巻き上げを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | glob.rs | `crates/oxide/src/glob.rs` | **14-66行目**: hoist_static_glob_parts関数 |

**主要処理フロー**:
- **18行目**: split_patternで静的/動的に分割
- **20-24行目**: 静的部分をベースパスに結合
- **26-33行目**: canonicalizeでパス正規化（失敗時はスキップ）
- **35-44行目**: 動的部分がない場合のデフォルトパターン設定
- **49-57行目**: ファイルの場合は親ディレクトリをベースにする

#### Step 4: パターン最適化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | glob.rs | `crates/oxide/src/glob.rs` | **91-133行目**: optimize_patterns関数 |

**主要処理フロー**:
- **92行目**: hoist_static_glob_partsを呼び出し
- **95-100行目**: FxHashMapでベースパスごとにパターンを集約
- **102-127行目**: 単一パターンはそのまま、複数は`{p1,p2,...}`形式に結合
- **130行目**: ベースパス順にソート

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

```
optimize_patterns(entries)
    │
    ├─ hoist_static_glob_parts(entries, true)
    │      │
    │      ├─ split_pattern(pattern)
    │      │
    │      └─ dunce::canonicalize(base)
    │
    ├─ FxHashMap集約
    │
    └─ ソート
```

### データフロー図

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

Vec<GlobEntry>         ──▶ 1. split_pattern               ──▶ Vec<GlobEntry>
[base: "/project",           └─ 静的/動的分割                   [base: "/project/src",
 pattern: "src/**/*.js"]                                         pattern: "**/*.js"]
                       ──▶ 2. hoist_static_glob_parts
                             └─ 静的部分をbaseに移動
                       ──▶ 3. optimize_patterns
                             ├─ 同一baseのパターン結合
                             └─ ソート
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| glob.rs | `crates/oxide/src/glob.rs` | ソース | globパターンマッチングの主要実装 |
| lib.rs | `crates/oxide/src/lib.rs` | ソース | GlobEntryのpublic re-export |
| mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | ソース | optimize_patternsの呼び出し元 |
| sources.rs | `crates/oxide/src/scanner/sources.rs` | ソース | PublicSourceEntry::optimizeでsplit_patternを使用 |
