# 機能設計書 26-ファイルスキャナー（Scanner - Rust/oxide）

## 概要

本ドキュメントは、Tailwind CSSにおけるRust製ファイルスキャナー（oxide crate内のScanner）の仕様・処理フロー・内部構造を記述した機能設計書である。

### 本機能の処理概要

Scannerはファイルシステムを走査してソースファイルを発見し、それらからTailwind CSS候補クラスを抽出する高性能なRust実装のスキャナーである。globパターンによるファイルフィルタリング、自動ソース検出、gitignoreルールの尊重、変更検知（mtime追跡）に対応する。

**業務上の目的・背景**：Tailwind CSSのビルドプロセスでは、プロジェクト内のすべてのソースファイルからユーティリティクラス候補を抽出する必要がある。ファイル数が多い大規模プロジェクトでは、この処理がボトルネックとなるため、Rustで高速な実装を提供する。自動ソース検出により、明示的な設定なしでスキャン対象を決定できる。

**機能の利用シーン**：初回ビルド時のプロジェクト全体のスキャン、watchモードでの変更ファイルの差分スキャン、Vite/PostCSS/Webpack/CLIプラグインからのスキャン呼び出しで使用される。

**主要な処理内容**：
1. ソースエントリ（PublicSourceEntry）のブレース展開と最適化を行う
2. WalkBuilderでファイルシステムを走査し、ソースファイルを発見する
3. 自動ソース検出ルールとgitignoreルールでファイルをフィルタリングする
4. 発見されたファイルを読み込み、Extractorで候補クラスを抽出する
5. CSSファイルからCSS変数を抽出する
6. 結果をキャッシュし、再スキャン時には変更ファイルのみを処理する

**関連システム・外部連携**：Extractor（候補抽出器）、globパターンマッチング、自動ソース検出ルール、gitignoreライブラリと連携する。

**権限による制御**：ファイルシステムへの読み取りアクセス権が必要。gitignoreルールによるファイルフィルタリングが適用される。

## 関連画面

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

## 機能種別

データ収集処理（ファイルシステム走査・候補抽出）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sources | Vec<PublicSourceEntry> | Yes | スキャン対象のソースエントリ一覧 | - |

### 入力データソース

- ファイルシステム上のソースファイル
- @sourceディレクティブから生成されたPublicSourceEntry
- gitignoreファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| candidates | Vec<String> | 抽出された候補クラス名のソート済みリスト |
| files | Vec<String> | スキャンされたファイルパスのリスト |
| globs | Vec<GlobEntry> | 生成されたglobパターン（ウォッチャー設定用） |

### 出力先

呼び出し元（Vite/PostCSS/Webpack/CLIプラグイン）に返される。

## 処理フロー

### 処理シーケンス

```
1. Scanner::new(sources)
   ├─ init_tracing()でトレーシング初期化
   ├─ PublicSourceEntryをSourceEntryに変換（ブレース展開+最適化）
   └─ create_walker(sources)でWalkBuilder構築
2. scanner.scan()
   ├─ discover_sources()
   │   ├─ WalkBuilderでファイルシステム走査
   │   ├─ ファイル/ディレクトリの分類
   │   ├─ 拡張子の追跡
   │   ├─ mtime追跡（2回目以降のスキャン）
   │   └─ ファイル読み込み+プリプロセス
   └─ extract_candidates(blobs, css_files)
       ├─ parse_all_blobs()で候補抽出
       ├─ extract_css_variables()でCSS変数抽出
       └─ 新規候補のフィルタリング+キャッシュ
```

### フローチャート

```mermaid
flowchart TD
    A[Scanner::new] --> B[SourceEntry変換]
    B --> C[WalkBuilder構築]
    C --> D[scanner.scan]
    D --> E[discover_sources]
    E --> F{初回スキャン?}
    F -->|Yes| G[walk_synchronous]
    F -->|No| H[walk_parallel]
    G --> I[ファイル読み込み+プリプロセス]
    H --> I
    I --> J[extract_candidates]
    J --> K[parse_all_blobs / Extractor]
    K --> L[CSS変数抽出]
    L --> M[新規候補フィルタリング]
    M --> N[ソート済み結果を返す]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 自動ソース検出 | gitignoreルールとバイナリ拡張子フィルタに基づく自動検出 | SourceEntry::Auto |
| BR-02 | 外部ソース | node_modules等の外部ディレクトリはgitignoreルールを緩和して走査 | SourceEntry::External |
| BR-03 | CSSファイル特別扱い | CSSファイルは候補抽出ではなくCSS変数抽出のみ行う | 拡張子が"css" |
| BR-04 | 初回同期/2回目以降並列 | 初回スキャンはsynchronous walk、2回目以降はparallel walkを使用 | has_scanned_once |
| BR-05 | mtime追跡 | 2回目以降のスキャンではmtimeチェックで変更ファイルのみ処理 | has_scanned_once == true |
| BR-06 | プリプロセス | 拡張子に応じたプリプロセス処理（Clojure, Elixir, Razor等） | ファイル拡張子による |

### 計算ロジック

候補の重複排除: FxHashSetを使用して既に発見済みの候補を追跡し、新規候補のみを返す。

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

本機能はデータベース操作を行わない。ファイルシステムからの読み取りのみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | tracingログ | ファイル読み込み失敗 | ログ出力して該当ファイルをスキップ |
| - | tracingログ | globパス解決失敗 | ログ出力して該当エントリをスキップ |

### リトライ仕様

リトライは行わない。ファイル読み込み失敗時はスキップする。

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

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

## パフォーマンス要件

- 初回スキャンは同期walkを使用（スレッド生成オーバーヘッド回避）
- 2回目以降は並列walkを使用（watchモードでの再スキャン高速化）
- rayonによる並列ファイル読み込み・候補抽出
- FxHashSet/FxHashMap使用による高速ハッシュ
- mtime追跡による変更ファイルのみの差分スキャン
- FlushOnDrop最適化（256件ごとのバッチ書き込み）

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

- ファイルシステムの読み取りアクセスのみ
- symlink追跡が有効（follow_links: true）
- gitignoreルールによるファイルフィルタリング

## 備考

- Rustで実装されたcrates/oxide crateの一部
- N-API（napi-rs）経由でNode.jsから呼び出される
- プリプロセスにより各言語固有のシンタックスに対応（Svelte, Vue, Clojure, Ruby等）
- parallel walkではFlushOnDropパターンでスレッドセーフなバッチ集約を行う

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lib.rs | `crates/oxide/src/lib.rs` | **1-13行目**: モジュール構成とpublic re-exports（GlobEntry, PublicSourceEntry, Scanner, ChangedContent） |
| 1-2 | sources.rs | `crates/oxide/src/scanner/sources.rs` | **10-19行目**: PublicSourceEntry構造体（base, pattern, negated） |
| 1-3 | sources.rs | `crates/oxide/src/scanner/sources.rs` | **21-61行目**: SourceEntry列挙型（Auto, Pattern, Ignored, External） |
| 1-4 | mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | **37-93行目**: Scanner構造体のフィールド（sources, walker, files, candidates, mtimes等） |

**読解のコツ**: SourceEntryの4つのバリアント（Auto/Pattern/Ignored/External）が、スキャン動作の違いを決定する。Autoは自動検出、Externalはgitignoreルール緩和、Patternは明示的なglobパターン、Ignoredは除外パターン。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | **96-121行目**: Scanner::new関数 |

**主要処理フロー**:
1. **97行目**: init_tracing()でトレーシング初期化
2. **106行目**: public_source_entries_to_private_source_entriesでSourceEntry変換
3. **114行目**: create_walker(&sources)でWalkBuilder構築

#### Step 3: スキャン処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | **123-134行目**: scan関数 |
| 3-2 | mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | **357-447行目**: discover_sources関数（ファイルシステム走査） |

**主要処理フロー**:
- **369-373行目**: 初回は同期walk、2回目以降は並列walk
- **391-405行目**: mtime追跡による変更ファイルの検出
- **407-424行目**: CSS/非CSSファイルの分類
- **428-440行目**: 並列ファイル読み込みとプリプロセス

#### Step 4: 候補抽出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | **220-248行目**: extract_candidates関数 |
| 4-2 | mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | **510-547行目**: extract関数（並列抽出の共通ロジック） |

#### Step 5: WalkBuilder構築を理解する

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

**主要処理フロー**:
- **712-713行目**: 最初のソースルートでWalkBuilder初期化
- **715行目**: symlink追跡を有効化
- **726行目**: gitリポジトリが不要なケースの設定
- **770行目**: 自動ソース検出ルールの設定
- **809-846行目**: ソースパターンマッチングフィルタ

#### Step 6: ソースエントリ変換を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | sources.rs | `crates/oxide/src/scanner/sources.rs` | **193-226行目**: public_source_entries_to_private_source_entries関数 |
| 6-2 | sources.rs | `crates/oxide/src/scanner/sources.rs` | **103-171行目**: PublicSourceEntry::optimize関数 |
| 6-3 | sources.rs | `crates/oxide/src/scanner/sources.rs` | **229-261行目**: From<PublicSourceEntry> for SourceEntry実装 |

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

```
Scanner::new(sources)
    ├─ init_tracing()
    ├─ public_source_entries_to_private_source_entries(sources)
    │      ├─ brace expansion
    │      ├─ PublicSourceEntry::optimize()
    │      └─ Into<SourceEntry>
    └─ create_walker(&sources)
           └─ WalkBuilder設定

Scanner::scan()
    ├─ discover_sources()
    │      ├─ walk_synchronous() / walk_parallel()
    │      ├─ pre_process_input(content, &ext)
    │      └─ ファイル読み込み（rayon並列）
    └─ extract_candidates(blobs, css_files)
           ├─ parse_all_blobs(blobs)
           │      └─ Extractor::new(blob).extract()
           └─ extract_css_variables(css_files)
                  └─ Extractor::new(blob).extract_variables_from_css()
```

### データフロー図

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

PublicSourceEntry[]    ──▶ 1. ソースエントリ変換           ──▶ Vec<String>（候補クラス）
                             ├─ ブレース展開                   Vec<String>（ファイルパス）
                             ├─ パス最適化                     Vec<GlobEntry>（glob）
                             └─ SourceEntry分類
                       ──▶ 2. ファイルシステム走査
                             ├─ WalkBuilder
                             ├─ gitignoreフィルタ
                             └─ 自動検出ルール
                       ──▶ 3. ファイル読み込み
                             ├─ 並列読み込み
                             └─ プリプロセス
                       ──▶ 4. 候補抽出
                             ├─ Extractor
                             └─ CSS変数抽出
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | ソース | Scanner構造体とスキャンロジック |
| sources.rs | `crates/oxide/src/scanner/sources.rs` | ソース | SourceEntry型定義と変換 |
| detect_sources.rs | `crates/oxide/src/scanner/detect_sources.rs` | ソース | ソース検出ロジック |
| auto_source_detection.rs | `crates/oxide/src/scanner/auto_source_detection.rs` | ソース | 自動ソース検出ルール |
| init_tracing.rs | `crates/oxide/src/scanner/init_tracing.rs` | ソース | トレーシング初期化 |
| lib.rs | `crates/oxide/src/lib.rs` | ソース | crateのモジュール定義 |
| mod.rs (extractor) | `crates/oxide/src/extractor/mod.rs` | ソース | Extractor（候補抽出器） |
| glob.rs | `crates/oxide/src/glob.rs` | ソース | globパターン最適化 |
