# 機能設計書 24-@applyの置換（substituteAtApply）

## 概要

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

### 本機能の処理概要

`@apply`ディレクティブは、CSS内でTailwind CSSのユーティリティクラスを展開するための機能である。`@apply flex items-center`と記述すると、対応するCSSプロパティ群に置換される。本機能はトポロジカルソートにより依存関係を解決し、循環依存を検出する。

**業務上の目的・背景**：カスタムCSS内でTailwind CSSのユーティリティクラスを再利用したい需要がある。`@apply`を使うことで、ユーティリティクラスの定義をカスタムCSS内で展開でき、コンポーネントスタイルの定義時にTailwindのユーティリティを活用できる。特にCSSモジュールやスコープ付きCSSでの利用が想定される。

**機能の利用シーン**：CSSモジュール内でユーティリティクラスを適用する場合（例: `.button { @apply px-4 py-2 rounded; }`）、`@utility`定義内で他のユーティリティを参照する場合、グローバルCSS内でのコンポーネントスタイル定義で使用される。

**主要な処理内容**：
1. ASTを走査し、`@apply`ノードと`@utility`定義ノードを収集する
2. `@apply`の依存関係を解析し、依存先の`@utility`定義を追跡する
3. トポロジカルソートで処理順序を決定し、循環依存を検出する
4. 順序に従って`@apply`ノードを実際のユーティリティCSSに展開する
5. ソースマップ情報を保持しつつノードを置換する

**関連システム・外部連携**：compileCandidates（候補のコンパイル）、DesignSystem（候補パース・テーマ解決）、walkユーティリティ（AST走査）と連携する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | トップページ | 主機能 | page.module.cssの@apply skew-7ディレクティブを検出し、skew-7ユーティリティのCSSに展開する |

## 機能種別

データ変換処理（CSSディレクティブの展開・置換）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ast | AstNode[] | Yes | 処理対象のCSS AST | - |
| designSystem | DesignSystem | Yes | ユーティリティ解決に使用するデザインシステム | - |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| features | Features | Features.AtApplyフラグを含むビットフラグ |

### 出力先

AST上の`@apply`ノードがユーティリティCSSノードに直接置換される（インプレース変換）。

## 処理フロー

### 処理シーケンス

```
1. ルートルールで全体をラップ
   └─ rule('&', ast) でルートノードを作成
2. ASTを走査してノードを収集
   ├─ @keyframes内の@applyを禁止
   ├─ @utility定義を収集（definitions Map）
   ├─ @utility内の@applyの依存関係を追跡
   └─ 通常の@applyノードの依存関係を追跡（parents Set）
3. トポロジカルソートで処理順序を決定
   ├─ 依存関係グラフを走査
   ├─ 循環依存を検出（wip Set）
   └─ ソート済みリストを生成（sorted Array）
4. ソート順に@applyを展開
   ├─ 候補クラスをcompileCandidatesでコンパイル
   ├─ 無効な候補に対するエラー処理
   ├─ ソースマップ情報の付与
   └─ WalkAction.Replaceでノードを置換
```

### フローチャート

```mermaid
flowchart TD
    A[substituteAtApply開始] --> B["rule('&', ast)でラップ"]
    B --> C[ASTをwalkして収集]
    C --> D{@keyframes内の@apply?}
    D -->|Yes| E[エラー]
    D -->|No| F{@utility定義?}
    F -->|Yes| G[definitionsに登録]
    F -->|No| H{@applyノード?}
    H -->|Yes| I[parentsに追加, 依存関係を記録]
    I --> J[トポロジカルソート]
    J --> K{循環依存?}
    K -->|Yes| L[循環依存エラー]
    K -->|No| M[ソート済みリストで展開]
    M --> N[compileCandidatesでコンパイル]
    N --> O{無効な候補?}
    O -->|Yes| P[詳細なエラーメッセージ]
    O -->|No| Q[WalkAction.Replaceで置換]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | @keyframes内禁止 | `@keyframes`内で`@apply`は使用できない | @keyframes内の@apply検出時 |
| BR-02 | 循環依存検出 | `@utility`間の循環依存を検出してエラーにする | @utilityが他の@utilityを@applyで参照する場合 |
| BR-03 | prefix要求 | テーマにprefixが設定されている場合、候補にprefixが必要 | designSystem.theme.prefix存在時 |
| BR-04 | ブロックリスト制約 | 明示的に無効化された候補は@applyできない | invalidCandidates Setに含まれる場合 |
| BR-05 | important無視 | @applyではimportantフラグを無視する（respectImportant: false） | 常時 |
| BR-06 | テーマ空チェック | テーマが空の場合は@referenceの欠如を示唆するエラーメッセージを出す | theme.size === 0 |

### 計算ロジック

トポロジカルソート: DFS（深さ優先探索）ベースのトポロジカルソートで、`@utility`定義の依存関係を解決する。`wip`（Work In Progress）Setを使用して循環依存を検出する。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | @keyframes内で@applyを使用 | @keyframesの外に移動する |
| - | Error | @utility間の循環依存 | 循環を解消する |
| - | Error | prefixなしの候補を@apply | prefix付きの候補名を使用する |
| - | Error | ブロックリストに含まれる候補を@apply | 候補のブロックを解除する |
| - | Error | 不明なバリアントを含む候補を@apply | 存在するバリアントを使用する |
| - | Error | テーマが空で不明な候補を@apply | @importまたは@referenceを追加する |
| - | Error | 不明なユーティリティクラスを@apply | 正しいユーティリティ名を使用する |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。ASTのインプレース変換として実行される。

## パフォーマンス要件

- トポロジカルソートにより効率的な依存解決を行う
- DefaultMapを使用して依存関係の遅延初期化を行う

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

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

## 備考

- `@apply`は`@keyframes`内では使用できない（明示的なエラーチェックあり）
- `@utility`定義内の`@apply`も処理対象であり、依存関係に基づく順序制御が行われる
- ソースマップ情報はcandidateOffset計算により保持される

---

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

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

### 推奨読解順序

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

依存関係管理に使用するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | apply.ts | `packages/tailwindcss/src/apply.ts` | **20-26行目**: parents Set、dependencies DefaultMap、definitions DefaultMapの定義 |
| 1-2 | default-map.ts | `packages/tailwindcss/src/utils/default-map.ts` | DefaultMapの実装。キー不在時にデフォルト値を自動生成するMap |

**読解のコツ**: `parents`はwalk中に`@apply`を含むノードを追跡する。`dependencies`はノードごとの依存先ユーティリティ名のSet。`definitions`はユーティリティ名から`@utility`ノードへのマッピング。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | apply.ts | `packages/tailwindcss/src/apply.ts` | **10-17行目**: substituteAtApply関数の開始。ルートルールでASTをラップする |

**主要処理フロー**:
1. **17行目**: `rule('&', ast)`でルートルールを作成
2. **29-79行目**: ASTを走査して@utility定義と@applyノードを収集

#### Step 3: 収集フェーズを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | apply.ts | `packages/tailwindcss/src/apply.ts` | **29-79行目**: walk内のノード収集ロジック |

**主要処理フロー**:
- **33-39行目**: @keyframes内の@applyを禁止
- **44-59行目**: @utility定義の収集と内部@applyの依存関係追跡
- **62-78行目**: 通常@applyノードの依存関係追跡（親パスの全parents含む）

#### Step 4: トポロジカルソートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | apply.ts | `packages/tailwindcss/src/apply.ts` | **82-154行目**: トポロジカルソートの実装 |

**主要処理フロー**:
- **82-84行目**: seen、sorted、wipの初期化
- **86-150行目**: visit関数（DFSベースのトポロジカルソート）
- **92-134行目**: 循環依存検出とエラーメッセージ生成
- **152-154行目**: parentsの各ノードに対してvisitを実行

#### Step 5: 展開フェーズを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | apply.ts | `packages/tailwindcss/src/apply.ts` | **158-297行目**: ソート順での@apply展開 |

**主要処理フロー**:
- **164-171行目**: candidateOffsetsの計算（ソースマップ用）
- **177-244行目**: compileCandidatesの呼び出しとエラーハンドリング
- **248-278行目**: ソースマップ情報の付与
- **283-294行目**: ルールのアンラップとWalkAction.Replaceでの置換

#### Step 6: 依存関係解決ユーティリティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | apply.ts | `packages/tailwindcss/src/apply.ts` | **302-324行目**: resolveApplyDependencies generator関数 |

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

```
substituteAtApply(ast, designSystem)
    │
    ├─ rule('&', ast)  -- ルートルール作成
    │
    ├─ walk([root], callback)  -- ノード収集
    │      ├─ resolveApplyDependencies(node, designSystem)
    │      │      └─ designSystem.parseCandidate(candidate)
    │      └─ definitions.get(name).add(node)
    │
    ├─ visit(node, path)  -- トポロジカルソート
    │      └─ visit(dependency, path)  -- 再帰
    │
    └─ walk(parent.nodes, callback)  -- @apply展開
           ├─ compileCandidates(candidates, designSystem, options)
           │      └─ onInvalidCandidate(candidate)  -- エラーハンドリング
           ├─ cloneAstNode(node)
           └─ WalkAction.Replace(newNodes)
```

### データフロー図

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

AstNode[]              ──▶ 1. ノード収集                 ──▶ AstNode[]（@apply展開済み）
(@apply含むCSS AST)          ├─ @utility定義をMap化            + Features.AtApply
                             ├─ @applyのparents記録
                             └─ 依存関係グラフ構築
                       ──▶ 2. トポロジカルソート
                             └─ 処理順序決定
                       ──▶ 3. @apply展開
                             ├─ compileCandidates
                             ├─ ソースマップ付与
                             └─ ノード置換
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| apply.ts | `packages/tailwindcss/src/apply.ts` | ソース | @apply置換の主要実装 |
| compile.ts | `packages/tailwindcss/src/compile.ts` | ソース | compileCandidates関数の提供元 |
| ast.ts | `packages/tailwindcss/src/ast.ts` | ソース | rule, cloneAstNode, toCss等のAST操作 |
| design-system.ts | `packages/tailwindcss/src/design-system.ts` | ソース | parseCandidate, candidatesToCss等のAPI |
| walk.ts | `packages/tailwindcss/src/walk.ts` | ソース | AST走査ユーティリティ |
| default-map.ts | `packages/tailwindcss/src/utils/default-map.ts` | ソース | DefaultMapの実装 |
| segment.ts | `packages/tailwindcss/src/utils/segment.ts` | ソース | 文字列分割ユーティリティ |
| index.ts | `packages/tailwindcss/src/index.ts` | ソース | コンパイルパイプラインからsubstituteAtApplyを呼び出す |
