# 機能設計書 40-@propertyポリフィル

## 概要

本ドキュメントは、Tailwind CSSにおける@propertyルールのフォールバックCSS生成ポリフィル機能の機能設計を記述する。

### 本機能の処理概要

CSS @propertyルールをサポートしていないブラウザ向けに、初期値の代替宣言を生成するポリフィル機能である。@propertyルールのinherits属性に基づいて、`:root, :host`または`*, ::before, ::after, ::backdrop`セレクタ内にフォールバック宣言を出力する。

**業務上の目的・背景**：Tailwind CSS v4では、カスタムプロパティの初期値定義に@propertyルールを使用している（例: `--tw-shadow`、`--tw-translate-x`等）。@propertyはモダンブラウザでは広くサポートされているが、一部の古いFirefoxバージョン等ではサポートされていない。本ポリフィルは、@propertyをサポートしていないブラウザでもカスタムプロパティの初期値が正しく適用されるよう、`@supports`クエリで条件分岐したフォールバック宣言を生成する。これにより、Tailwind CSSが生成するshadow、ring、transform等のユーティリティが非対応ブラウザでも正しく表示される。

**機能の利用シーン**：
- Tailwind CSSのCSSコンパイル時（compile/compileAst関数のbuild呼び出し時）
- optimizeAst関数内でAST最適化の一環として実行
- Polyfills.AtPropertyフラグが有効な場合のみ動作

**主要な処理内容**：
1. AST最適化時に@propertyルールを検出する
2. 各@propertyルールからプロパティ名、initial-value、inheritsの値を抽出する
3. inheritsの値に基づいてフォールバック宣言を分類する
   - inherits: true → `:root, :host`ルールに追加
   - inherits: false → `*, ::before, ::after, ::backdrop`ルールに追加
4. フォールバック宣言を@supportsクエリでラップし、@propertyをサポートしていないブラウザでのみ適用する
5. `@layer properties`でカスケード制御する

**関連システム・外部連携**：Lightning CSS（最適化エンジン）と連携する。Lightning CSSが@layerの順序を変更する可能性があるため、`@layer properties;`の空宣言を適切な位置に挿入する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面に直接関連しない内部処理機能 |

## 機能種別

計算処理（CSSポリフィルの生成）

## 入力仕様

### 入力パラメータ

本機能は独立した関数ではなく、optimizeAst関数内の処理の一部である。

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ast | AstNode[] | Yes | 最適化対象のAST（@propertyルールを含む） | 有効なASTノード配列 |
| polyfills | Polyfills | Yes | ポリフィルフラグ。Polyfills.AtPropertyビットが有効な場合のみ処理する | ビットフラグ値 |

### 入力データソース

compile/compileAst関数のbuild()呼び出し時にoptimizeAstに渡されるAST。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (AST変更) | AstNode[] | 元のASTにフォールバック宣言とレイヤー宣言が追加されたAST |

出力されるフォールバックCSSの構造:
```css
/* ASTの適切な位置に挿入 */
@layer properties;

/* ASTの末尾に追加 */
@layer properties {
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline)))
    or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
    :root, :host {
      /* inherits: true のプロパティ */
      --tw-property-name: initial-value;
    }
    *, ::before, ::after, ::backdrop {
      /* inherits: false のプロパティ */
      --tw-property-name: initial-value;
    }
  }
}
```

### 出力先

optimizeAst関数の戻り値であるnewAst配列に直接追加される。

## 処理フロー

### 処理シーケンス

```
1. @propertyルールの検出（optimizeAst内のtransform関数）
   └─ node.kind === 'at-rule' && node.name === '@property' && depth === 0
2. 重複@propertyの除去
   └─ seenAtProperties Setで重複チェック
3. Polyfills.AtPropertyフラグの確認
   └─ polyfills & Polyfills.AtProperty が真の場合のみ処理
4. @propertyの子ノードからプロパティ情報を抽出
   ├─ initial-value宣言の値
   └─ inherits宣言の値（'true'/'false'）
5. フォールバック宣言の生成
   ├─ decl(property, initialValue ?? 'initial')
   └─ inheritsに基づいて分類:
       ├─ true → propertyFallbacksRoot配列に追加
       └─ false → propertyFallbacksUniversal配列に追加
6. フォールバックASTの構築（optimizeAst末尾）
   a. propertyFallbacksRootがある場合:
      └─ rule(':root, :host', propertyFallbacksRoot)
   b. propertyFallbacksUniversalがある場合:
      └─ rule('*, ::before, ::after, ::backdrop', propertyFallbacksUniversal)
7. @layer properties;の挿入
   └─ @charset, @import, コメントの後の最初の有効ノード位置に挿入
8. @layer properties { @supports (...) { ... } }の追加
   └─ newAstの末尾に追加
```

### フローチャート

```mermaid
flowchart TD
    A[optimizeAst: AST走査開始] --> B{@propertyルール検出?}
    B -->|No| C[他のノード処理]
    B -->|Yes| D{重複チェック}
    D -->|重複| E[スキップ]
    D -->|新規| F{Polyfills.AtProperty有効?}
    F -->|No| G[@propertyルールのみ出力]
    F -->|Yes| H[子ノードからinitial-value/inherits抽出]
    H --> I{inherits値}
    I -->|true| J[propertyFallbacksRootに追加]
    I -->|false| K[propertyFallbacksUniversalに追加]
    J --> G
    K --> G
    G --> A
    A --> L{フォールバックあり?}
    L -->|No| M[newAstを返却]
    L -->|Yes| N[:root/:hostルール構築]
    N --> O[*/::before/::after/::backdropルール構築]
    O --> P[@layer properties;を適切な位置に挿入]
    P --> Q[@layer properties + @supports でラップ]
    Q --> R[newAst末尾に追加]
    R --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-40-01 | ポリフィルフラグ | Polyfills.AtProperty（ビット0）が有効な場合のみフォールバックを生成する | polyfills & Polyfills.AtProperty |
| BR-40-02 | 重複@property除去 | 同一プロパティ名の@propertyルールは最初のもののみ処理する | seenAtProperties.has(node.params) |
| BR-40-03 | inherits分類 | inherits: trueのプロパティは`:root, :host`に、falseは`*, ::before, ::after, ::backdrop`に配置する | inherits宣言の値 |
| BR-40-04 | initial-valueのデフォルト | initial-valueが指定されていない場合は`'initial'`を使用する | initial-valueが未定義の場合 |
| BR-40-05 | @supportsクエリ | @propertyをサポートしていないブラウザを検出するため、同時期に追加された機能の@supportsクエリを使用する | フォールバック出力時 |
| BR-40-06 | @layer properties | フォールバックを@layer propertiesでラップし、カスケード順序を制御する | フォールバック出力時 |
| BR-40-07 | @layer位置 | `@layer properties;`の空宣言は@charset、@import、コメントの後の最初の有効ノード位置に挿入する | フォールバック出力時 |
| BR-40-08 | トップレベルのみ | @propertyルールのフォールバック処理はdepth === 0（トップレベル）のもののみ対象 | 常に |

### 計算ロジック

@supportsクエリの条件式:
```
((-webkit-hyphens: none) and (not (margin-trim: inline)))
or
((-moz-orient: inline) and (not (color:rgb(from red r g b))))
```
この条件は、@propertyをサポートしていないブラウザ（特にFirefox/Safari）を検出するための間接的な機能テストである。@property自体を直接テストすることはできないため、同時期に実装された機能の有無で判定する。

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

### 操作別データベース影響一覧

データベース操作なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | initial-valueなし | @propertyにinitial-value宣言がない場合 | 'initial'をデフォルト値として使用 |

### リトライ仕様

リトライは不要。

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

トランザクション管理なし。

## パフォーマンス要件

- optimizeAstの走査と同時に処理されるため、追加の走査コストは発生しない
- フォールバック宣言の生成は@propertyの数に比例する

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

特になし。

## 備考

- Polyfills.AtPropertyのビット値は `1 << 0`（1）
- Polyfills.Allには AtProperty と ColorMix の両方が含まれる
- IntelliSense（candidatesToCss/candidatesToAst）ではPolyfills.Noneが使用されるため、このポリフィルは生成されない
- @supportsクエリは、CSSの@property機能を直接テストできないことへの回避策であり、将来のブラウザアップデートで見直しが必要になる可能性がある

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/tailwindcss/src/index.ts` | Polyfills列挙型の定義（41-52行目） |
| 1-2 | ast.ts | `packages/tailwindcss/src/ast.ts` | AstNode型、AtRule型（特にname='@property'のノード構造） |

**読解のコツ**:
- `Polyfills`はconst enumで、ビットフラグとして使用される
- `Polyfills.AtProperty = 1 << 0`（値: 1）
- `Polyfills.ColorMix = 1 << 1`（値: 2）
- `Polyfills.All = AtProperty | ColorMix`（値: 3）
- `Polyfills.None = 0`

#### Step 2: フォールバック収集処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ast.ts | `packages/tailwindcss/src/ast.ts` | optimizeAst内のtransform関数の@property処理（340-380行目） |

**主要処理フロー**:
1. **341行目**: `node.kind === 'at-rule' && node.name === '@property' && depth === 0`で@propertyルールを検出
2. **343-344行目**: `seenAtProperties.has(node.params)`で重複チェック
3. **349行目**: `polyfills & Polyfills.AtProperty`でフラグ確認
4. **350-352行目**: プロパティ名(property)、initialValue、inheritsの変数初期化
5. **354-361行目**: @propertyの子ノードを走査し、initial-value/inheritsを抽出
6. **363行目**: `decl(property, initialValue ?? 'initial')`でフォールバック宣言生成
7. **366-370行目**: inheritsに基づきpropertyFallbacksRoot/propertyFallbacksUniversalに分類

#### Step 3: フォールバック出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ast.ts | `packages/tailwindcss/src/ast.ts` | optimizeAstの末尾部分のフォールバック出力（619-677行目） |

**主要処理フロー**:
1. **619行目**: `polyfills & Polyfills.AtProperty`の再確認
2. **622-626行目**: `:root, :host`ルールの構築（propertyFallbacksRootが存在する場合）
3. **628-632行目**: `*, ::before, ::after, ::backdrop`ルールの構築（propertyFallbacksUniversalが存在する場合）
4. **638-651行目**: `@layer properties;`の挿入位置を計算（@charset、@import、コメントの後）
5. **653-660行目**: `@layer properties;`の空宣言を挿入
6. **662-676行目**: `@layer properties { @supports (...) { ... } }`ブロックをnewAst末尾に追加
7. **667行目**: @supportsクエリの条件式（@propertyサポート検出の間接テスト）

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

```
compile/compileAst (index.ts)
    │
    └─ optimizeAst (ast.ts)
           │
           ├─ transform関数（再帰的AST走査）
           │      │
           │      └─ @propertyノード処理（341-380行目）
           │             ├─ seenAtProperties重複チェック
           │             ├─ initial-value/inherits抽出
           │             ├─ decl()でフォールバック宣言生成
           │             └─ propertyFallbacksRoot/Universal分類
           │
           └─ フォールバック出力（619-677行目）
                  ├─ rule(':root, :host', ...)
                  ├─ rule('*, ::before, ::after, ::backdrop', ...)
                  ├─ atRule('@layer', 'properties', []) 挿入
                  └─ rule('@layer properties', [
                         atRule('@supports', '...', fallbackAst)
                     ]) 追加
```

### データフロー図

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

AstNode[]            ───▶ optimizeAst                    ───▶ AstNode[]
(@propertyルール含む)       │                                    (フォールバック追加済み)
                           ├─ @property検出
                           │   ├─ --tw-shadow
                           │   │   inherits: false
                           │   │   initial-value: 0 0 #0000
                           │   ├─ --tw-ring-color
                           │   │   inherits: false
                           │   │   initial-value: ...
                           │   └─ ...
                           │
                           ├─ フォールバック分類
                           │   ├─ root: [inheritsプロパティ]
                           │   └─ universal: [非inheritsプロパティ]
                           │
                           └─ @layer + @supports生成     ───▶ @layer properties {
                                                                @supports (...) {
                                                                  :root, :host { ... }
                                                                  *, ::before, ::after { ... }
                                                                }
                                                              }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ast.ts | `packages/tailwindcss/src/ast.ts` | ソース | optimizeAst関数内の@propertyフォールバック生成処理 |
| index.ts | `packages/tailwindcss/src/index.ts` | ソース | Polyfills列挙型の定義。compile/compileAstでのPolyfills指定 |
| design-system.ts | `packages/tailwindcss/src/design-system.ts` | ソース | candidatesToAstでのPolyfills.None指定（IntelliSense用） |
