# 機能設計書 29-@sourceディレクティブ

## 概要

本ドキュメントは、Tailwind CSSにおける`@source`ディレクティブの仕様・処理フロー・内部構造を記述した機能設計書である。

### 本機能の処理概要

`@source`ディレクティブは、Tailwind CSSがユーティリティクラスを検出するためのスキャン対象パスを指定するCSS内のディレクティブである。`@source "./src"` のようにディレクトリや glob パターンを指定できる。`not`修飾子による除外、`inline()`によるインライン候補の直接指定にも対応する。

**業務上の目的・背景**：Tailwind CSSはソースファイルからユーティリティクラスの使用状況を検出する。`@source`ディレクティブにより、CSS内でスキャン対象のファイルパスを宣言的に指定できる。これにより、設定ファイルなしでスキャン対象を制御でき、CSSファイル自体がスキャン範囲の情報を持つことで管理が容易になる。

**機能の利用シーン**：スキャン対象のディレクトリを追加する場合（例: `@source "./src"`）、特定のファイルパターンを指定する場合（例: `@source "./pages/**/*.tsx"`）、スキャン対象を除外する場合（例: `@source not "./test"`）、インライン候補を直接指定する場合（例: `@source inline("bg-red-500 text-white")`）で使用される。

**主要な処理内容**：
1. CSSのASTを走査し、`@source`アットルールノードを検出する
2. パラメータを解析し、`not`修飾子と`inline()`修飾子を判定する
3. パスのクォート検証を行う
4. inlineの場合はブレース展開してinlineCandidatesまたはignoredCandidatesに追加する
5. 非inlineの場合はsourcesリスト（base, pattern, negated）に追加する
6. @sourceノードをASTから除去する

**関連システム・外部連携**：Scanner（ファイルスキャナー）、ブレース展開（brace-expansion）、コンパイルパイプライン（index.ts）と連携する。

**権限による制御**：特になし。CSS処理パイプラインの一部として自動的に実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はCSS処理パイプラインの内部処理であり、特定の画面とは直接関連しない |

## 機能種別

設定処理（スキャン対象パスの宣言的指定）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| node.params | string | Yes | @sourceディレクティブのパラメータ | クォートで囲まれていること |

### パラメータの形式

- `@source "./path"` - 基本形式
- `@source not "./path"` - 除外指定
- `@source inline("candidate1 candidate2")` - インライン候補指定
- `@source not inline("candidate1")` - インライン候補の除外

### 入力データソース

CSS ASTから`@source`アットルールノードが抽出される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| sources | {base, pattern, negated}[] | スキャン対象パスのリスト |
| inlineCandidates | string[] | インライン候補のリスト |
| ignoredCandidates | string[] | 除外インライン候補のリスト |

### 出力先

sourcesはScannerのPublicSourceEntryとして渡される。inlineCandidatesはbuild関数の候補リストに追加される。

## 処理フロー

### 処理シーケンス

```
1. ASTを走査して@sourceノードを検出
   └─ node.name === '@source'
2. バリデーション
   ├─ bodyがないことを確認
   └─ トップレベルであることを確認（ネスト不可）
3. パラメータ解析
   ├─ 'not 'プレフィックスの検出
   └─ 'inline('プレフィックスの検出
4. パスのクォート検証
   └─ シングルまたはダブルクォートで囲まれていること
5. パスの展開
   ├─ inline: segment + brace展開してcandidatesに追加
   └─ 非inline: sourcesリストに追加
6. @sourceノードをASTから除去
   └─ WalkAction.ReplaceSkip([])
```

### フローチャート

```mermaid
flowchart TD
    A[@source検出] --> B{bodyあり?}
    B -->|Yes| C[エラー: bodyは不可]
    B -->|No| D{ネストされている?}
    D -->|Yes| E[エラー: ネスト不可]
    D -->|No| F{notプレフィックス?}
    F -->|Yes| G[not = true, パスからnot除去]
    F -->|No| H[not = false]
    G --> I{inlineプレフィックス?}
    H --> I
    I -->|Yes| J[inline = true, inline()除去]
    I -->|No| K[inline = false]
    J --> L{パスがクォート付き?}
    K --> L
    L -->|No| M[エラー: パスはクォート必須]
    L -->|Yes| N{inline?}
    N -->|Yes| O[segment + brace展開]
    O --> P{not?}
    P -->|Yes| Q[ignoredCandidatesに追加]
    P -->|No| R[inlineCandidatesに追加]
    N -->|No| S[sourcesに追加]
    Q --> T["WalkAction.ReplaceSkip([])"]
    R --> T
    S --> T
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | body禁止 | `@source`にbody（中括弧ブロック）は不可 | @source検出時 |
| BR-02 | ネスト禁止 | `@source`はトップレベルでのみ使用可能 | @source検出時 |
| BR-03 | クォート必須 | パスはシングルまたはダブルクォートで囲む必要がある | パス解析時 |
| BR-04 | not修飾子 | `not`プレフィックスでスキャン対象を除外できる | パラメータが'not 'で始まる場合 |
| BR-05 | inline修飾子 | `inline()`で候補を直接指定できる | パラメータが'inline('で始まる場合 |
| BR-06 | ブレース展開 | inline候補はブレース展開される | inline=true |
| BR-07 | AST除去 | @sourceノードは処理後にASTから除去される | 常時 |

### 計算ロジック

特段の計算ロジックはない。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | @sourceにbodyがある | bodyを削除する |
| - | Error | @sourceがネストされている | トップレベルに移動する |
| - | Error | パスがクォートで囲まれていない | クォートで囲む |

### リトライ仕様

リトライは行わない。

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

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

## パフォーマンス要件

特段の要件なし。

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

特段のセキュリティ考慮事項はない。

## 備考

- `@source`はコンパイルパイプラインの初期段階（AST走査フェーズ）で処理される
- 処理結果のsourcesリストはScanner（Rust/oxide）に渡されてファイルスキャンに使用される
- `@source inline("...")`はテスト用途や、ファイルスキャンでは検出できない候補の明示指定に使用される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/tailwindcss/src/index.ts` | sourcesリストの型は`{base: string, pattern: string, negated: boolean}[]`。compileAst関数内で定義される |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/tailwindcss/src/index.ts` | **256-307行目**: @source処理のコードブロック |

**主要処理フロー**:
1. **257行目**: `node.name === '@source'`で@sourceノードを検出
2. **258-259行目**: bodyの存在チェック
3. **262-263行目**: ネストチェック（ctx.parent !== null）
4. **266-273行目**: notプレフィックスの検出
5. **275-278行目**: inlineプレフィックスの検出
6. **280-286行目**: クォートの検証
7. **288行目**: クォート除去してパスを取得
8. **290-297行目**: inline処理（segment + brace展開）
9. **298-304行目**: 非inline処理（sourcesリストへの追加）
10. **306行目**: WalkAction.ReplaceSkip([])でASTから除去

#### Step 3: ブレース展開を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | brace-expansion.ts | `packages/tailwindcss/src/utils/brace-expansion.ts` | expand関数の実装。`{a,b,c}`形式を`["a", "b", "c"]`に展開する |

#### Step 4: スキャナーへの接続を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | sources.rs | `crates/oxide/src/scanner/sources.rs` | **10-19行目**: PublicSourceEntry構造体。sourcesリストの要素がこの型に変換される |
| 4-2 | mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | **96-121行目**: Scanner::newでPublicSourceEntryを受け取る |

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

```
compileAst (index.ts)
    │
    ├─ walk(ast, callback)
    │      │
    │      └─ @source処理ブロック
    │             ├─ not修飾子の検出
    │             ├─ inline修飾子の検出
    │             ├─ パスのクォート検証
    │             │
    │             ├─ [inline=true]
    │             │      ├─ segment(source, ' ')
    │             │      └─ expand(candidate)
    │             │
    │             └─ [inline=false]
    │                    └─ sources.push({base, pattern, negated})
    │
    └─ sources → Scanner::new(sources)
           └─ public_source_entries_to_private_source_entries
```

### データフロー図

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

CSS AST               ──▶ @source検出・パース            ──▶ sources[]
(@source "./src"             ├─ not/inline修飾子解析           {base, pattern, negated}
 @source inline("flex"))     ├─ パスクォート検証
                             │                            ──▶ inlineCandidates[]
                             ├─ inline: segment+展開           ["flex", ...]
                             └─ 非inline: sources追加
                                                          ──▶ Scanner::new(sources)
                                                               → PublicSourceEntry
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/tailwindcss/src/index.ts` | ソース | @source処理の主要実装（256-307行目） |
| brace-expansion.ts | `packages/tailwindcss/src/utils/brace-expansion.ts` | ソース | ブレース展開ユーティリティ |
| segment.ts | `packages/tailwindcss/src/utils/segment.ts` | ソース | スペース区切りの文字列分割 |
| sources.rs | `crates/oxide/src/scanner/sources.rs` | ソース | PublicSourceEntry型定義 |
| mod.rs (scanner) | `crates/oxide/src/scanner/mod.rs` | ソース | Scannerの入力としてsourcesを受け取る |
| walk.ts | `packages/tailwindcss/src/walk.ts` | ソース | AST走査ユーティリティ |
