# 機能設計書 17-候補パーサー（parseCandidate）

## 概要

本ドキュメントは、ユーティリティクラス文字列を解析しCandidate構造体に変換するparseCandidate関数の設計について記述する。arbitrary・named・static・functionalの各種候補に対応し、バリアント・修飾子の解析も行う。

### 本機能の処理概要

parseCandidate関数は、`hover:bg-red-500/50!` のようなユーティリティクラス文字列を受け取り、バリアント部分（`hover:`）、ルート名（`bg`）、値部分（`red-500`）、修飾子（`/50`）、重要フラグ（`!`）に分解して構造化された Candidate オブジェクトを生成する。

**業務上の目的・背景**：Tailwind CSSのコンパイルパイプラインでは、HTMLテンプレートやJSXファイルから抽出された候補クラス文字列を解析し、ユーティリティの種類・値・バリアント・修飾子を特定する必要がある。parseCandidate はこの文字列解析の中核であり、候補クラスからCSS生成までの変換パイプラインの最初のステップを担当する。

**機能の利用シーン**：コンパイルパイプラインで候補クラスをCSSに変換する際、IntelliSenseで候補クラスの構造を解析する際、`@apply` ディレクティブのクラス名を解析する際に使用される。

**主要な処理内容**：
1. 入力文字列のバリアント部分とベース部分の分離（`:` で分割）
2. プレフィックスの処理（テーマにプレフィックスが設定されている場合）
3. バリアント文字列のパース（parseVariant の呼び出し）
4. 重要フラグ（`!`）の検出（先頭または末尾）
5. 修飾子（`/` 以降）の分離とパース
6. arbitrary プロパティ（`[property:value]` 形式）の処理
7. functional ユーティリティの値解析（arbitrary / named / fraction）
8. static ユーティリティの検出
9. ルート名の探索（findRoots による複数候補の生成）

**関連システム・外部連携**：DesignSystem（design-system.ts）を通じてUtilities・Variantsの登録情報を参照する。segment（segment.ts）でネストを考慮した文字列分割を行う。

**権限による制御**：権限による制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | Appコンポーネント | 補助機能 | m-3・p-3・border・text-blue-500等のクラス文字列をCandidate構造体に解析する |
| 4 | トップページ | 補助機能 | skew-7のクラス文字列をCandidate構造体に解析する |
| 5 | レイアウト | 補助機能 | [&_h1]:font-thinのクラス文字列を解析し、任意値バリアント付きCandidate構造体に変換する |
| 6 | トップページ | 補助機能 | text-3xl・font-bold・underline・border・ring等のクラス文字列をCandidate構造体に解析する |

## 機能種別

解析処理 / データ変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | string | Yes | ユーティリティクラス文字列（例: `hover:bg-red-500/50!`） | 空文字でも最低1要素の配列が生成される |
| designSystem | DesignSystem | Yes | デザインシステムオブジェクト | - |

### 入力データソース

- HTMLテンプレート・JSXファイルから抽出された候補クラス文字列
- `@apply` ディレクティブのクラス名
- `@source inline()` で直接指定された候補

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Candidate | Iterable<Candidate> | arbitrary / static / functional のいずれかの種別を持つ構造体 |

### 出力先

- compileCandidates（compile.ts）でCSS生成に使用
- design-system.ts の parsedCandidates キャッシュに格納

## 処理フロー

### 処理シーケンス

```
1. バリアントとベースの分離
   ├─ segment(input, ':') で分割
   ├─ プレフィックスチェック（最初のセグメント）
   └─ 最後のセグメントをベースとして取得

2. バリアントの解析
   └─ 各バリアント文字列に対して parseVariant を呼び出し

3. 重要フラグの検出
   ├─ 末尾 `!` チェック
   └─ 先頭 `!` チェック（レガシー構文）

4. static ユーティリティの検出
   └─ utilities.has(base, 'static') でチェック

5. 修飾子の分離
   └─ segment(base, '/') で分割

6. ベースの解析
   ├─ arbitrary プロパティ `[prop:val]`
   ├─ arbitrary 値 `name-[val]`
   ├─ CSS変数値 `name-(--var)`
   └─ named 値 `name-val`
```

### フローチャート

```mermaid
flowchart TD
    A["入力: hover:bg-red-500/50!"] --> B["segment で : 分割"]
    B --> C["プレフィックスチェック"]
    C --> D["バリアント解析（parseVariant）"]
    D --> E["重要フラグ検出（!）"]
    E --> F{"static ユーティリティ?"}
    F -->|Yes| G["static Candidate を yield"]
    F -->|No| H["修飾子 / で分割"]
    H --> I{"[prop:val] 形式?"}
    I -->|Yes| J["arbitrary Candidate を yield"]
    I -->|No| K{"末尾が ] ?"}
    K -->|Yes| L["arbitrary 値の functional Candidate"]
    K -->|No| M{"末尾が ) ?"}
    M -->|Yes| N["CSS変数の functional Candidate"]
    M -->|No| O["findRoots で名前付き値を探索"]
    O --> P["named 値の functional Candidate を yield"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-17-01 | プレフィックス必須 | テーマにプレフィックスが設定されている場合、全候補は先頭にプレフィックスバリアントを持つ必要がある | theme.prefix が非null の場合 |
| BR-17-02 | 重要フラグ | 末尾 `!` または先頭 `!`（レガシー）で重要フラグが設定される | `!` が含まれる場合 |
| BR-17-03 | 複数修飾子禁止 | `/` による修飾子は1つまで。2つ以上は無効 | 候補に `/` が複数含まれる場合 |
| BR-17-04 | static優先 | static ユーティリティに完全一致する場合、static Candidate が先に yield される | `[` を含まない場合 |
| BR-17-05 | arbitrary 値検証 | arbitrary 値に `;` や `}` が含まれる場合は無効 | isValidArbitrary チェック |
| BR-17-06 | 空arbitrary禁止 | `[]` や `()` のような空のarbitrary値は無効 | arbitrary値が空の場合 |
| BR-17-07 | CSS変数接頭辞 | `(...)` 形式のarbitrary値は `--` で始まる必要がある（CSS変数） | `()` 形式の場合 |
| BR-17-08 | named値の正規表現 | named値は `[a-zA-Z0-9_.%-]+` に一致する必要がある | named値の場合 |
| BR-17-09 | fraction値 | `w-1/2` のような分数値はnamedUtilityValueのfractionプロパティに格納 | modifierSegmentが存在する場合 |

### 計算ロジック

findRoots 関数による複数のルート候補の探索: `bg-red-500` は `['bg', 'red-500']` と `['bg-red', '500']` の2つのルート候補を生成する。登録済みのfunctionalユーティリティに一致するルートのみが有効となる。

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | null/return | バリアントの解析に失敗した場合 | null を返す（generator関数では return） |
| - | 空Iterable | 有効なCandidateが見つからなかった場合 | 空のIterableを返す |

### リトライ仕様

リトライ処理は存在しない。

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

トランザクション管理は存在しない。

## パフォーマンス要件

- parseCandidate の結果は DefaultMap でキャッシュされる（design-system.ts 78-80行目）
- generator関数（`function*`）により、必要な分だけ遅延生成される

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

ユーザ入力のクラス名文字列をパースするが、CSS仕様の範囲内で処理される。isValidArbitrary によるサニタイズが行われる。

## 備考

- parseCandidate は generator 関数（`function*`）であり、1つの入力に対して複数の Candidate を yield する可能性がある（staticとfunctionalの両方にマッチする場合など）
- DesignSystem.parseCandidate はキャッシュ付きのラッパーであり、同一の入力に対して再パースを避ける

---

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

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

### 推奨読解順序

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

Candidate 型と関連する値型を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | candidate.ts | `packages/tailwindcss/src/candidate.ts` | ArbitraryUtilityValue / NamedUtilityValue 型（15-65行目）。ユーティリティ値の2種類の表現 |
| 1-2 | candidate.ts | `packages/tailwindcss/src/candidate.ts` | ArbitraryModifier / NamedModifier / CandidateModifier 型（67-91行目）。修飾子の2種類の表現 |
| 1-3 | candidate.ts | `packages/tailwindcss/src/candidate.ts` | Candidate 型（164-218行目）。arbitrary / static / functional の3種類 |

**読解のコツ**: TypeScript の discriminated union（タグ付き共用体）パターンが使用されている。`kind` プロパティで型を判別する。

#### Step 2: parseCandidate関数を理解する

メインの解析ロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | candidate.ts | `packages/tailwindcss/src/candidate.ts` | parseCandidate関数（316-611行目）。generator関数のエントリーポイント |

**主要処理フロー**:
1. **320行目**: `segment(input, ':')` でバリアントとベースを分離
2. **325-330行目**: プレフィックスチェック
3. **336行目**: ベースの取得（rawVariants.pop()）
4. **340-345行目**: バリアントの逆順パース
5. **347-360行目**: 重要フラグの検出（末尾 `!` / 先頭 `!`）
6. **364-372行目**: static ユーティリティのyield
7. **383行目**: `segment(base, '/')` で修飾子を分離
8. **401-443行目**: arbitrary プロパティ `[prop:val]` の処理
9. **465-518行目**: arbitrary 値 `name-[val]` / CSS変数 `name-(--var)` の処理
10. **522-526行目**: findRoots による名前付き値の探索

#### Step 3: ヘルパー関数を理解する

修飾子パースとルート探索の仕組みを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | candidate.ts | `packages/tailwindcss/src/candidate.ts` | parseModifier関数（614-658行目）。arbitrary / named 修飾子の解析 |
| 3-2 | candidate.ts | `packages/tailwindcss/src/candidate.ts` | findRoots関数（ファイル後方）。ハイフンで分割した複数のルート候補を生成 |

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

```
parseCandidate(input, designSystem)
    │
    ├─ segment(input, ':')  [segment.ts]
    │
    ├─ designSystem.parseVariant(rawVariant) × N
    │      └─ parseVariant(variant, designSystem) [candidate.ts]
    │
    ├─ designSystem.utilities.has(base, 'static')
    │
    ├─ segment(base, '/') で修飾子分離
    │      └─ parseModifier(modifierSegment) [candidate.ts]
    │
    ├─ decodeArbitraryValue(value) [decode-arbitrary-value.ts]
    │
    ├─ isValidArbitrary(value) [is-valid-arbitrary.ts]
    │
    └─ findRoots(base, predicate)
           └─ designSystem.utilities.has(root, 'functional')
```

### データフロー図

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

"hover:bg-red-500/50!"  ───▶ segment(":") 分割          ───▶ ["hover", "bg-red-500/50!"]
                              ↓
                        ───▶ parseVariant("hover")       ───▶ { kind: 'static', root: 'hover' }
                              ↓
                        ───▶ 重要フラグ検出 "!"          ───▶ important: true
                              ↓
                        ───▶ segment("/") 分割            ───▶ ["bg-red-500", "50"]
                              ↓
                        ───▶ parseModifier("50")          ───▶ { kind: 'named', value: '50' }
                              ↓
                        ───▶ findRoots("bg-red-500")      ───▶ [["bg", "red-500"]]
                              ↓
                        ───▶ Candidate 生成               ───▶ { kind: 'functional', root: 'bg',
                                                                  value: { kind: 'named', value: 'red-500' },
                                                                  modifier: { kind: 'named', value: '50' },
                                                                  important: true, ... }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| candidate.ts | `packages/tailwindcss/src/candidate.ts` | ソース | parseCandidate関数本体、Candidate型定義、parseVariant関数 |
| design-system.ts | `packages/tailwindcss/src/design-system.ts` | ソース | parsedCandidatesキャッシュ（78-80行目） |
| segment.ts | `packages/tailwindcss/src/utils/segment.ts` | ソース | ネストを考慮した文字列分割 |
| decode-arbitrary-value.ts | `packages/tailwindcss/src/utils/decode-arbitrary-value.ts` | ソース | arbitrary値のデコード（アンダースコア→スペース等） |
| is-valid-arbitrary.ts | `packages/tailwindcss/src/utils/is-valid-arbitrary.ts` | ソース | arbitrary値のバリデーション |
| value-parser.ts | `packages/tailwindcss/src/value-parser.ts` | ソース | CSS値のパース |
| compile.ts | `packages/tailwindcss/src/compile.ts` | ソース | compileCandidates。parseCandidateの呼び出し元 |
