# 機能設計書 27-候補抽出器（Extractor - Rust/oxide）

## 概要

本ドキュメントは、Tailwind CSSにおけるRust製候補クラス抽出エンジン（oxide crate内のExtractor）の仕様・処理フロー・内部構造を記述した機能設計書である。

### 本機能の処理概要

Extractorはソースコードのバイト列から、Tailwind CSSの候補クラス名とCSS変数名を高速に抽出するステートマシンベースのパーサーである。HTML、JavaScript、各種テンプレート言語など多様なソースコードに対応する。

**業務上の目的・背景**：Tailwind CSSではソースファイルからユーティリティクラス候補を抽出し、使用されているクラスのみのCSSを生成するPurge処理を行う。大規模プロジェクトでは数千ファイルからの抽出が必要となるため、Rustによる高速な実装が求められる。正規表現ベースではなく、ステートマシンベースのパーサーにより、正確かつ高速な抽出を実現する。

**機能の利用シーン**：初回ビルド時の全ファイルからの候補抽出、watchモードでの変更ファイルからの差分抽出、IDE連携での候補位置検出（get_candidates_with_positions）で使用される。

**主要な処理内容**：
1. CssVariableMachineでCSS変数（`--`で始まる識別子）を抽出する
2. CandidateMachineでユーティリティクラス候補を抽出する
3. サブ候補の抽出（角括弧内の候補検出）を行う
4. カバー範囲の重複排除（drop_covered_spans）を行う

**関連システム・外部連携**：Scanner（ファイルスキャナー）から呼び出される。CandidateMachine、CssVariableMachine、VariantMachine等の内部マシンと連携する。

**権限による制御**：特になし。入力バイト列に対する純粋な文字列解析処理。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | トップページ | 補助機能 | Viteプラグイン経由でスキャンされたファイルから候補クラス名を抽出する |
| 3 | レイアウト | 補助機能 | PostCSSプラグイン経由でスキャンされたファイルから候補クラス名を抽出する |

## 機能種別

データ解析処理（テキストからの候補クラス抽出）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | &[u8] | Yes | 解析対象のバイト列 | - |

### 入力データソース

ファイルシステムから読み込まれたソースコードのバイト列。pre_process_inputによるプリプロセス済み。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| extracted | Vec<Extracted> | 抽出結果（Candidate or CssVariable） |

### 出力先

Scannerの候補リストに集約される。

## 処理フロー

### 処理シーケンス

```
1. Extractor::new(input)
   └─ Cursor, CssVariableMachine, CandidateMachineの初期化
2. extract()
   ├─ CSS変数抽出フェーズ
   │   └─ CssVariableMachineで--で始まる識別子を抽出
   ├─ 候補抽出フェーズ
   │   ├─ CandidateMachineで候補を検出
   │   ├─ in_flight_spansに追加
   │   └─ extract_sub_candidatesでサブ候補を抽出
   └─ drop_covered_spansで重複排除
```

### フローチャート

```mermaid
flowchart TD
    A[Extractor::new] --> B[extract開始]
    B --> C[CSS変数抽出]
    C --> D[カーソルクローンで走査]
    D --> E{空白文字?}
    E -->|Yes| F[スキップ]
    E -->|No| G[CssVariableMachine.next]
    G --> H{Done?}
    H -->|Yes| I[Extracted::CssVariable追加]
    H -->|No| J[次の文字へ]
    B --> K[候補抽出]
    K --> L[カーソルクローンで走査]
    L --> M{空白文字?}
    M -->|Yes| N[スキップ]
    M -->|No| O[CandidateMachine.next]
    O --> P{Done?}
    P -->|Yes| Q[in_flight_spans追加]
    Q --> R[extract_sub_candidates]
    P -->|No| S[extract_sub_candidates for Idle]
    R --> T[次の文字へ]
    T --> U[drop_covered_spans]
    U --> V[結果を返す]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 空白区切り | 空白文字はスキップし、非空白文字から候補の検出を開始する | 常時 |
| BR-02 | サブ候補抽出 | 角括弧`[`内に候補がある場合、サブ候補として抽出する | CandidateMachineがIdleを返した場合 |
| BR-03 | カバー範囲重複排除 | 広い範囲の候補が狭い範囲の候補を包含する場合、狭い方を除外する | 最終結果生成時 |
| BR-04 | CSS変数抽出（CSS用） | CSSファイルからのCSS変数抽出はvar(接頭辞を確認する | extract_variables_from_css |

### 計算ロジック

drop_covered_spans: スパンをstart位置でソート（同じstartならend降順）し、max_endを追跡しながら、既存スパンに包含されるスパンを除外する。

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

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

## エラー処理

### エラーケース一覧

エラーは発生しない。無効な入力に対しては空の結果を返す。

### リトライ仕様

リトライは行わない。

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

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

## パフォーマンス要件

- ステートマシンベースのO(n)パーサーにより高速な解析を実現
- in_flight_spansはVec::with_capacity(15)で初期化（一般的なケースでの最適化）
- extractedはVec::with_capacity(100)で初期化
- CursorのクローンによりCSS変数と候補の独立走査を実現

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

- unsafe操作: String::from_utf8_unchecked使用（抽出時にバイト列の有効性が保証されるため）

## 備考

- Extracted列挙型はCandidate(&[u8])とCssVariable(&[u8])の2バリアント
- CandidateMachineは内部でVariantMachine, UtilityMachine, ArbitraryValueMachine等の下位マシンを組み合わせて動作する
- extract_sub_candidatesは角括弧内の候補（例: `[ClassPrefix('gap-y-4')]`内の`gap-y-4`）を検出する
- extract_variables_from_cssはvar()接頭辞チェック付きで、CSSファイル専用のCSS変数抽出を行う

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | **24-37行目**: Extracted列挙型（Candidate/CssVariable）の定義 |
| 1-2 | mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | **56-62行目**: Extractor構造体（cursor, css_variable_machine, candidate_machine） |
| 1-3 | machine.rs | `crates/oxide/src/extractor/machine.rs` | Machine trait、MachineState（Idle/Done）、Span構造体の定義 |

**読解のコツ**: Machineトレイトの`next`メソッドは、カーソルを進めながらマシンの状態遷移を行い、Done(Span)で抽出完了を通知する。Spanはstartとendのインデックスペアで、入力バイト列のスライスを参照する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | **64-72行目**: Extractor::new関数 |
| 2-2 | mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | **74-141行目**: extract関数の全体構造 |

**主要処理フロー**:
1. **78行目**: in_flight_spansの初期化（容量15）
2. **81行目**: extractedの初期化（容量100）
3. **86-100行目**: CSS変数抽出フェーズ
4. **103-138行目**: 候補抽出フェーズ
5. **131-137行目**: 残りのin_flight_spansをコミット

#### Step 3: サブ候補抽出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | **188-211行目**: extract_sub_candidates関数 |

**主要処理フロー**:
- **196行目**: `[`を検出した位置から新しいCandidateMachineで解析
- **202-208行目**: 範囲内でCandidateMachineを実行し、見つかったスパンをin_flight_spansに追加

#### Step 4: カバー範囲の重複排除を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | **213-231行目**: drop_covered_spans関数 |

#### Step 5: CSS変数抽出（CSS用）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | **143-177行目**: extract_variables_from_css関数 |

**主要処理フロー**:
- **158行目**: span.start < 4の場合はスキップ（var(の長さ分の余地がない）
- **163-164行目**: var(接頭辞のチェック

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

```
Extractor::new(input)
    └─ Cursor::new(input)

Extractor::extract()
    │
    ├─ CSS変数抽出フェーズ
    │      └─ CssVariableMachine::next(cursor)
    │
    ├─ 候補抽出フェーズ
    │      ├─ CandidateMachine::next(cursor)
    │      │      ├─ VariantMachine
    │      │      ├─ UtilityMachine
    │      │      │      ├─ NamedUtilityMachine
    │      │      │      ├─ ArbitraryValueMachine
    │      │      │      └─ ArbitraryVariableMachine
    │      │      ├─ ArbitraryPropertyMachine
    │      │      └─ ModifierMachine
    │      │
    │      └─ extract_sub_candidates(range, cursor, in_flight_spans)
    │             └─ CandidateMachine::next(cursor)
    │
    └─ drop_covered_spans(in_flight_spans)
```

### データフロー図

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

&[u8]                  ──▶ 1. CSS変数抽出                 ──▶ Vec<Extracted>
(ソースコード              ├─ CssVariableMachine              ├─ Candidate(&[u8])
 バイト列)                 └─ --で始まる識別子を検出           └─ CssVariable(&[u8])
                       ──▶ 2. 候補抽出
                             ├─ CandidateMachine
                             ├─ サブ候補抽出([...]内)
                             └─ カバー範囲の重複排除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | ソース | Extractor構造体と抽出ロジック |
| machine.rs | `crates/oxide/src/extractor/machine.rs` | ソース | Machine trait、MachineState、Span |
| candidate_machine.rs | `crates/oxide/src/extractor/candidate_machine.rs` | ソース | CandidateMachine実装 |
| css_variable_machine.rs | `crates/oxide/src/extractor/css_variable_machine.rs` | ソース | CssVariableMachine実装 |
| variant_machine.rs | `crates/oxide/src/extractor/variant_machine.rs` | ソース | VariantMachine実装 |
| utility_machine.rs | `crates/oxide/src/extractor/utility_machine.rs` | ソース | UtilityMachine実装 |
| named_utility_machine.rs | `crates/oxide/src/extractor/named_utility_machine.rs` | ソース | NamedUtilityMachine実装 |
| named_variant_machine.rs | `crates/oxide/src/extractor/named_variant_machine.rs` | ソース | NamedVariantMachine実装 |
| arbitrary_value_machine.rs | `crates/oxide/src/extractor/arbitrary_value_machine.rs` | ソース | ArbitraryValueMachine実装 |
| arbitrary_variable_machine.rs | `crates/oxide/src/extractor/arbitrary_variable_machine.rs` | ソース | ArbitraryVariableMachine実装 |
| arbitrary_property_machine.rs | `crates/oxide/src/extractor/arbitrary_property_machine.rs` | ソース | ArbitraryPropertyMachine実装 |
| modifier_machine.rs | `crates/oxide/src/extractor/modifier_machine.rs` | ソース | ModifierMachine実装 |
| boundary.rs | `crates/oxide/src/extractor/boundary.rs` | ソース | 境界文字の判定 |
| bracket_stack.rs | `crates/oxide/src/extractor/bracket_stack.rs` | ソース | 括弧スタック管理 |
| string_machine.rs | `crates/oxide/src/extractor/string_machine.rs` | ソース | 文字列リテラル解析 |
