# 機能設計書 13-カスタムユーティリティ定義（@utility）

## 概要

本ドキュメントは、`@utility` ディレクティブによるカスタムユーティリティ定義機能の設計について記述する。CSSブロック内でカスタムユーティリティを定義し、候補クラスとして使用可能にする。

### 本機能の処理概要

`@utility` ディレクティブは、ユーザが独自のユーティリティクラスをCSS内で定義するための仕組みである。staticユーティリティ（固定値）とfunctionalユーティリティ（動的値、`-*` サフィックス付き）の両方を定義できる。

**業務上の目的・背景**：Tailwind CSSの組み込みユーティリティでカバーできない独自のCSSプロパティやスタイルパターンをユーティリティクラスとして定義し、Tailwindのクラスベースのワークフローに統合する必要がある。`@utility` ディレクティブはこのニーズに応え、JavaScriptプラグインなしで純粋なCSS内でユーティリティを拡張できるようにする。

**機能の利用シーン**：カスタムCSSプロパティをユーティリティクラスとして利用したい場合、既存ユーティリティにない独自のスタイルパターンを定義する場合、v4で新しく導入された `--value()` / `--modifier()` APIを使用してテーマ値を動的に参照するユーティリティを作成する場合に使用される。

**主要な処理内容**：
1. `@utility` ディレクティブの検出とバリデーション（ネスト禁止、空ボディ禁止、名前の妥当性チェック）
2. createCssUtility関数によるユーティリティ生成（static / functional の判定）
3. functionalユーティリティの場合、`--value()` / `--modifier()` API によるテーマ値の動的解決
4. 生成されたユーティリティのDesignSystem.utilities への登録
5. `@utility` ノードのASTからの除去（コンパイル済みCSSに含めない）

**関連システム・外部連携**：Utilities（utilities.ts）に登録される。Theme（theme.ts）からテーマ値を参照する。compile.ts経由でCSSが生成される。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに直接の関連画面なし。全画面で@utilityで定義されたカスタムユーティリティが利用可能 |

## 機能種別

定義処理 / CSS変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| node.params | string | Yes | ユーティリティ名（例: `my-utility`, `tab-size-*`） | 英数字・ハイフンで構成、小文字で開始。functionalは `-*` で終了 |
| node.nodes | AstNode[] | Yes | ユーティリティのCSSボディ | 空であってはならない |

### 入力データソース

- CSSファイル内の `@utility` ディレクティブ（パース済みAST）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| registerFn | (designSystem: DesignSystem) => void | DesignSystemへのユーティリティ登録関数 |

### 出力先

- DesignSystem.utilities に登録される
- `@utility` ノード自体はASTから除去される

## 処理フロー

### 処理シーケンス

```
1. @utility ディレクティブの検出
   ├─ ネストチェック（トップレベルのみ許可）
   ├─ 空ボディチェック
   └─ createCssUtility(node) を呼び出し

2. createCssUtility(node) による処理
   ├─ 名前のバリデーション
   ├─ functionalユーティリティ判定（`-*` サフィックスの有無）
   ├─ functionalの場合：
   │   ├─ AST内の --value() / --modifier() 関数呼び出しを検出
   │   ├─ テーマキーの正規化
   │   └─ 値解決ロジックの生成
   └─ staticの場合：
       └─ ノードのクローンを返すコンパイル関数を生成

3. DesignSystem への登録
   └─ designSystem.utilities.static() or .functional() で登録

4. @utility ノードの除去
   └─ WalkAction.ReplaceSkip([]) で空に置換
```

### フローチャート

```mermaid
flowchart TD
    A["@utility ディレクティブ検出"] --> B{ネストされている?}
    B -->|Yes| C["エラー: @utility cannot be nested"]
    B -->|No| D{ボディが空?}
    D -->|Yes| E["エラー: @utility is empty"]
    D -->|No| F["createCssUtility(node)"]
    F --> G{名前が有効?}
    G -->|No| H["エラー: invalid utility name"]
    G -->|Yes| I{"-*" で終わる?}
    I -->|Yes| J["functional ユーティリティ生成"]
    I -->|No| K["static ユーティリティ生成"]
    J --> L["customUtilities に追加"]
    K --> L
    L --> M["後段で DesignSystem に登録"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-13-01 | トップレベル制約 | `@utility` はCSSのトップレベルにのみ配置可能。ネストは禁止 | 常時 |
| BR-13-02 | 空ボディ禁止 | `@utility` のボディには少なくとも1つのプロパティを含む必要がある | 常時 |
| BR-13-03 | functionalサフィックス | functionalユーティリティは名前が `-*` で終わる必要がある | functionalユーティリティ定義時 |
| BR-13-04 | ワイルドカード位置 | `*` は名前の末尾に1回のみ出現可能（`-*` 形式） | 名前に `*` を含む場合 |
| BR-13-05 | 名前規則 | ユーティリティ名は英数字で構成し、小文字で開始する必要がある | 常時 |

### 計算ロジック

functionalユーティリティでは `--value()` と `--modifier()` のCSS関数APIが利用可能。`--value(--spacing)` のようにテーマ名前空間を参照でき、候補値からテーマ値を動的に解決する。`--value(number)` や `--value([number])` のような型制約もサポートする。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | `@utility` がネストされている場合 | `@utility cannot be nested` をスロー |
| - | Error | `@utility` のボディが空の場合 | `@utility {name} is empty` をスロー |
| - | Error | functionalが `-*` で終わらない場合 | `invalid utility name. A functional utility must end in -*` をスロー |
| - | Error | `*` が名前の中間に出現する場合 | `The dynamic portion marked by -* must appear once at the end` をスロー |
| - | Error | 名前が不正な文字で構成されている場合 | `invalid utility name` をスロー |

### リトライ仕様

リトライ処理は存在しない。コンパイル時エラーとして即座にスローされる。

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

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

## パフォーマンス要件

コンパイル時に1回のみ実行される。ユーティリティ数に依存するが、通常は少数のカスタムユーティリティのため性能への影響は軽微。

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

CSSの `@utility` ディレクティブはCSS仕様の範囲で処理される。

## 備考

- `@utility` は Tailwind CSS v4 で新しく導入されたディレクティブであり、v3 のプラグインAPI（addUtilities / matchUtilities）をCSS内で実現する
- エスケープ文字に対応しており、`@utility foo-1\/2` のような名前も `foo-1/2` として認識される

---

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

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

### 推奨読解順序

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

`@utility` ディレクティブの検出と初期バリデーションを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/tailwindcss/src/index.ts` | 222-254行目: `@utility` ディレクティブの検出、ネストチェック、空ボディチェック、createCssUtility呼び出し |

**主要処理フロー**:
1. **222-223行目**: `@utility` ノードの検出
2. **224-226行目**: ネストチェック - トップレベルでない場合はエラー
3. **228-232行目**: 空ボディチェック
4. **234行目**: createCssUtility(node) の呼び出し
5. **253行目**: customUtilities 配列への追加

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

ユーティリティ生成のメインロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | utilities.ts | `packages/tailwindcss/src/utilities.ts` | 5944行目以降: createCssUtility関数。名前のバリデーション、functional/static判定 |

**主要処理フロー**:
- **5949行目**: 名前のアンエスケープ処理
- **5952行目**: functionalユーティリティの判定（isValidFunctionalUtilityName）
- **5979行目以降**: functional の場合の処理。--value() / --modifier() APIの解析
- **6000行目以降**: ASTウォークによる --value() / --modifier() 関数の検出と正規化

#### Step 3: @utility ノードの後処理を理解する

登録後のノード除去処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/tailwindcss/src/index.ts` | 684-693行目: @utility ノードの除去処理 |

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

```
compile (index.ts)
    │
    ├─ walk(ast) で @utility 検出（222行目）
    │      ├─ バリデーション（ネスト・空ボディ・名前チェック）
    │      └─ createCssUtility(node) （utilities.ts 5944行目）
    │             ├─ isValidFunctionalUtilityName(name)
    │             ├─ functional: --value() / --modifier() 解析
    │             └─ static: クローンベースのコンパイル関数生成
    │
    ├─ customUtilities.push(utility)
    │
    ├─ designSystem.utilities.static(name, compileFn) or
    │  designSystem.utilities.functional(name, compileFn)
    │
    └─ @utility ノード除去（689行目）
```

### データフロー図

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

@utility my-class {     ───▶ createCssUtility(node)   ───▶ static ユーティリティ登録
  color: red;                                                compileFn → AstNode[]
}

@utility tab-size-* {   ───▶ createCssUtility(node)   ───▶ functional ユーティリティ登録
  tab-size: --value();       --value() / --modifier()        compileFn(candidate) → AstNode[]
}                            API 解析
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/tailwindcss/src/index.ts` | ソース | @utility ディレクティブの検出とバリデーション |
| utilities.ts | `packages/tailwindcss/src/utilities.ts` | ソース | createCssUtility関数の本体。ユーティリティ生成ロジック |
| design-system.ts | `packages/tailwindcss/src/design-system.ts` | ソース | DesignSystem.utilities への登録先 |
| ast.ts | `packages/tailwindcss/src/ast.ts` | ソース | ASTノードの型定義。AtRule型 |
| theme.ts | `packages/tailwindcss/src/theme.ts` | ソース | --value() でのテーマ値参照 |
| value-parser.ts | `packages/tailwindcss/src/value-parser.ts` | ソース | --value() / --modifier() 関数のパース |
| escape.ts | `packages/tailwindcss/src/utils/escape.ts` | ソース | ユーティリティ名のアンエスケープ |
