# 機能設計書 16-@variantの適用（substituteAtVariant）

## 概要

本ドキュメントは、`@variant` ディレクティブを検出し、登録済みバリアントのスタイルルールに置換する substituteAtVariant 関数の設計について記述する。

### 本機能の処理概要

substituteAtVariant 関数は、CSS内の `@variant` ディレクティブを処理し、対応するバリアントのスタイルルールに置換する。これにより、CSS内でバリアントの効果を直接適用できる。

**業務上の目的・背景**：`@variant` ディレクティブは、CSS内でバリアントの効果を直接適用するために使用される。例えば、`@variant hover { color: red; }` と記述すると、hoverバリアントのセレクタラッピングが適用される。これはカスタムバリアント定義内での他バリアントの参照や、JSプラグインが生成するCSS内でバリアントを使用する場合に重要である。

**機能の利用シーン**：`@custom-variant` 定義内で他のバリアントを参照する場合、JSプラグイン（v3互換レイヤー）が生成するユーティリティCSS内でバリアントを使用する場合、CSS内でバリアントの効果を直接適用したい場合に使用される。

**主要な処理内容**：
1. AST内の `@variant` ノードを検出する
2. バリアント名（params）をparseVariantで解析する
3. applyVariant関数でバリアントの効果をルールに適用する
4. `@variant` ノードを適用結果のルールで置換する

**関連システム・外部連携**：Variants（variants.ts）に登録されたバリアント定義を参照する。compile.ts の applyVariant 関数を使用する。design-system.ts の parseVariant を使用する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに直接の関連画面なし。CSS内の@variantディレクティブの内部処理 |

## 機能種別

CSS変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ast | AstNode[] | Yes | 処理対象のAST配列 | - |
| designSystem | DesignSystem | Yes | デザインシステムオブジェクト | - |

### 入力データソース

- コンパイルパイプラインで処理中のAST

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| features | Features | 使用されたフィーチャーフラグ（Features.Variants） |

### 出力先

- 入力ASTが直接変更される（破壊的操作）
- `@variant` ノードがスタイルルールに置換される

## 処理フロー

### 処理シーケンス

```
1. AST の走査
   └─ @variant ノードを検出

2. バリアント解析
   ├─ parseVariant(variant, designSystem) でバリアント文字列を解析
   └─ 解析失敗時はエラーをスロー

3. バリアント適用
   ├─ styleRule('&', variantNode.nodes) で仮のルールを生成
   ├─ applyVariant(node, variantAst, variants) でバリアントを適用
   └─ 適用失敗時はエラーをスロー

4. ノード置換
   └─ WalkAction.Replace(node) で@variantノードを結果で置換
```

### フローチャート

```mermaid
flowchart TD
    A["AST走査開始"] --> B{"@variant ノード?"}
    B -->|No| C["次のノードへ"]
    B -->|Yes| D["parseVariant でバリアント解析"]
    D --> E{解析成功?}
    E -->|No| F["エラー: unknown variant"]
    E -->|Yes| G["styleRule('&', nodes) 生成"]
    G --> H["applyVariant(node, ast, variants)"]
    H --> I{適用成功?}
    I -->|No| J["エラー: cannot use @variant"]
    I -->|Yes| K["WalkAction.Replace(node)"]
    K --> L["Features.Variants フラグ設定"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-16-01 | 登録済みバリアント必須 | `@variant` で参照するバリアントは事前にVariantsレジストリに登録されている必要がある | 常時 |
| BR-16-02 | 破壊的置換 | `@variant` ノードは結果のルールノードで直接置換される | 常時 |
| BR-16-03 | Features フラグ | バリアント適用時に Features.Variants フラグが設定される | 成功時 |

### 計算ロジック

`&` セレクタをルートとする仮のスタイルルールを作成し、その上にバリアントのapplyFnを適用する。結果として、バリアントのセレクタやメディアクエリがルールをラップする形に変換される。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | 未知のバリアントが指定された場合 | `Cannot use @variant with unknown variant: {name}` をスロー |
| - | Error | バリアントの適用に失敗した場合 | `Cannot use @variant with variant: {name}` をスロー |

### リトライ仕様

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

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

トランザクション管理は存在しない。AST変更は即座に反映される。

## パフォーマンス要件

ASTの走査は `walk` 関数による線形走査。`@variant` ノードの出現数に比例した処理時間。

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

CSS仕様の範囲内で処理される。

## 備考

- substituteAtVariant はカスタムバリアント定義のfromAst()内でも使用される（variants.ts 104行目）
- design-system.ts のcompiledAstNodesキャッシュ内でもsubstituteAtVariantが呼び出される（97-99行目）
- JSプラグインが生成するユーティリティ内で `@variant` を使用可能にするための重要な処理

---

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

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

### 推奨読解順序

#### Step 1: substituteAtVariant関数を理解する

メイン関数の実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | variants.ts | `packages/tailwindcss/src/variants.ts` | substituteAtVariant関数（1210-1235行目）。AST走査、parseVariant、applyVariant、WalkAction.Replaceの一連の処理 |

**主要処理フロー**:
1. **1210行目**: 関数シグネチャ。ast と designSystem を受け取り Features を返す
2. **1212-1213行目**: walk で @variant ノードを検出
3. **1216行目**: `styleRule('&', variantNode.nodes)` で仮のルールを生成
4. **1218行目**: `variantNode.params` からバリアント名を取得
5. **1220-1223行目**: `designSystem.parseVariant(variant)` でバリアントを解析。null なら例外
6. **1225-1228行目**: `applyVariant(node, variantAst, designSystem.variants)` で適用。null なら例外
7. **1231行目**: `Features.Variants` フラグを設定
8. **1232行目**: `WalkAction.Replace(node)` でノードを置換

#### Step 2: 呼び出し元を理解する

substituteAtVariant がどこから呼び出されるかを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | variants.ts | `packages/tailwindcss/src/variants.ts` | fromAst()内での呼び出し（104行目）。カスタムバリアントのボディ内の@variantを処理 |
| 2-2 | design-system.ts | `packages/tailwindcss/src/design-system.ts` | compiledAstNodes内での呼び出し（97-99行目）。JSプラグイン生成ユーティリティ内の@variantを処理 |

#### Step 3: applyVariant関数を理解する

バリアント適用の内部実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | compile.ts | `packages/tailwindcss/src/compile.ts` | applyVariant関数。バリアントのapplyFnをルールに適用する処理 |

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

```
substituteAtVariant(ast, designSystem)
    │
    ├─ walk(ast, callback)
    │      │
    │      ├─ styleRule('&', variantNode.nodes)
    │      │
    │      ├─ designSystem.parseVariant(variant)
    │      │      └─ parseVariant(variant, designSystem) [candidate.ts]
    │      │
    │      ├─ applyVariant(node, variantAst, designSystem.variants)
    │      │      └─ variants.get(name).applyFn(rule, variant)
    │      │
    │      └─ WalkAction.Replace(node)
    │
    └─ return Features.Variants
```

### データフロー図

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

@variant hover {      ───▶ parseVariant("hover")      ───▶ Variant構造体
  color: red;               ↓
}                     ───▶ styleRule('&', [{color:red}]) ───▶ 仮ルール生成
                            ↓
                      ───▶ applyVariant(rule, variant)  ───▶ &:hover { color: red; }
                            ↓
                      ───▶ WalkAction.Replace()         ───▶ AST置換完了
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| variants.ts | `packages/tailwindcss/src/variants.ts` | ソース | substituteAtVariant関数の本体 |
| compile.ts | `packages/tailwindcss/src/compile.ts` | ソース | applyVariant関数。バリアントの実際の適用処理 |
| candidate.ts | `packages/tailwindcss/src/candidate.ts` | ソース | parseVariant関数。バリアント文字列の解析 |
| design-system.ts | `packages/tailwindcss/src/design-system.ts` | ソース | parseVariant/substituteAtVariantの呼び出し元 |
| ast.ts | `packages/tailwindcss/src/ast.ts` | ソース | styleRule関数。ASTノード生成 |
| walk.ts | `packages/tailwindcss/src/walk.ts` | ソース | ASTウォーカー。WalkAction.Replace |
