
# アーキテクチャ

TailwindPHPは1:1の移植版です。コードベースはTailwindCSS本体と同じ構造を再現し、同じファイル名と構成を使っています。直接移植できない部分（PHPにはRustもV8もありません）は`src/_tailwindphp/`に切り分けています。このページではコンパイルパイプライン、ソースの構成、`lightningcss`の再実装、相違点を記録する際の規約を説明します。

## 処理パイプライン

CSSの生成はいくつもの段階で行われます。個別のビルド工程はなく、`tw::generate()`を呼び出すたびにパイプライン全体が実行されます。

```
CSS input          (@import "tailwindcss"; @theme { … })
  │
  ▼
┌──────────────┐
│  Parse CSS   │  css-parser.php → ast.php nodes
└──────┬───────┘
       ▼  design system (theme, utilities, variants)
┌──────────────┐
│ Scan content │  candidate.php — extract class names from HTML
└──────┬───────┘
       ▼  candidates
┌──────────────┐
│   Compile    │  compile.php — candidate → AST, via design-system.php
└──────┬───────┘
       ▼  AST
┌──────────────┐
│   Optimize   │  _tailwindphp/LightningCss.php — nesting, @media, calc()
└──────┬───────┘
       ▼
┌──────────────┐
│  Serialize   │  ast.php toCss()   (minified when requested)
└──────┬───────┘
       ▼
CSS output
```

**解析。** `css-parser.php`はCSS入力（`@import`、`@theme`、`@utility`、`@layer`、生のルール）を読み込み、`ast.php`ノード（スタイルルール、アットルール、宣言）からなる抽象構文木を作ります。仮想モジュール用の`@import`ディレクティブ（`tailwindcss`、`tailwindcss/preflight`、…）とファイルパスは、この段階で解決され、置き換えられます。

**デザインシステムの構築。** `theme.php`は、解析済みの`@theme`ブロックと既定値からテーマの値（色、余白、ブレークポイント）を解決します。`design-system.php`は、テーマと`utilities.php`および`variants.php`で定義されたユーティリティやバリアントの検索を結び付ける中心的なレジストリです。

**コンテンツのスキャン。** `candidate.php`は渡されたコンテンツ（HTML、テンプレート）からクラス名候補を抽出し、それぞれを構成要素（基本ユーティリティ、バリアント、修飾子、任意の値、importantフラグ）に解析します。

**コンパイル。** `compile.php`はデザインシステムを参照し、各候補をASTノードに変換してバリアントと修飾子を適用します。実際のユーティリティに解決できない候補は破棄されます。

**シリアライズと最適化。** `ast.php`の`toCss()`はツリーをたどり（ヘルパーは`walk.php`にあります）、CSS文字列を出力します。`_tailwindphp/LightningCss.php`内の`lightningcss`相当の変換を適用し、Rustによる後処理を経たTailwindCSSの出力と一致させます。

**圧縮。** `minify`を有効にすると、`toCss()`はシリアライズ時に圧縮済みCSSを出力します。単独で`tw::minify()`文字列を処理する工程は`_tailwindphp/CssMinifier.php`が担います。[キャッシュと圧縮](https://tailwindphp.inline0.dev/ja/docs/advanced/caching)を参照してください。

## ソースの構成

`src/`はTailwindCSSの構成を再現しています。構造上の変更点は1つです。TailwindCSSの`utilities.ts`は6,000行を超えるため、保守性を高める目的でカテゴリごとに1ファイルを割り当て、`src/utilities/`に分割しています。

```
src/
├── _tailwindphp/                # PHP-specific — NOT part of the TailwindCSS port
│   ├── LightningCss.php         # CSS transforms (lightningcss Rust library equivalent)
│   ├── CssMinifier.php          # CSS minification
│   └── lib/                     # Companion library ports (TailwindPHP\Lib\*)
│       ├── clsx/                # clsx port
│       ├── tailwind-merge/      # tailwind-merge port
│       └── cva/                 # CVA port
│
├── plugin/                      # Plugin system
│   └── plugins/
│       ├── typography-plugin.php  # @tailwindcss/typography port
│       └── forms-plugin.php       # @tailwindcss/forms port
│
├── utilities/                   # Split from TailwindCSS utilities.ts (one file per category)
│   ├── accessibility.php        # sr-only, forced-colors
│   ├── backgrounds.php          # bg-*, gradient-*, from-*, via-*, to-*
│   ├── borders.php              # border-*, rounded-*, divide-*, outline-*
│   ├── effects.php              # shadow-*, opacity-*, mix-blend-*
│   ├── filters.php              # blur-*, brightness-*, contrast-*, …
│   ├── flexbox.php              # flex-*, grid-*, gap-*, justify-*, align-*
│   ├── interactivity.php        # cursor-*, scroll-*, touch-*, select-*
│   ├── layout.php               # display, position, z-*, overflow-*, …
│   ├── masks.php                # mask-linear-*, mask-radial-*, mask-conic-*
│   ├── sizing.php               # w-*, h-*, min-*, max-*, size-*
│   ├── spacing.php              # m-*, p-*, space-*
│   ├── svg.php                  # fill-*, stroke-*
│   ├── tables.php               # border-collapse, table-layout
│   ├── transforms.php           # translate-*, rotate-*, scale-*, skew-*
│   ├── transitions.php          # transition-*, duration-*, ease-*, delay-*
│   └── typography.php           # font-*, text-*, leading-*, tracking-*
│
├── utils/                       # Helper functions (ported from utils/)
│
├── index.php                    # Main entry — compile(), cn(), variants(), merge(), join()
├── ast.php                      # AST nodes and toCss()
├── candidate.php                # Candidate parsing (class name → parts)
├── compile.php                  # Candidate to CSS compilation
├── css-functions.php            # theme(), --theme(), --spacing(), --alpha()
├── css-parser.php               # CSS parsing
├── design-system.php            # Central registry for utilities/variants
├── plugin.php                   # Plugin system (PluginInterface, PluginAPI, PluginManager)
├── theme.php                    # Theme value resolution
├── utilities.php                # Utility registration and lookup
├── value-parser.php             # CSS value parsing
├── variants.php                 # Variant handling (hover, focus, responsive, …)
└── walk.php                     # AST traversal
```

## lightningcss相当の機能

TailwindCSSはCSSの後処理（ネスト、メディアクエリ処理、値の簡略化）を、Rustで書かれたパーサー、変換ツール、圧縮ツールの[lightningcss](https://lightningcss.dev/)に委ねています。PHPはRustライブラリを読み込めないため、`src/_tailwindphp/LightningCss.php`はTailwindPHPが実際に利用する変換処理を再実装しています。テストスイートが対象とするケースでは、バイト単位で同一の出力を生成します。

確認済みの変換処理：

| 変換 | 内容 |
|-----------|--------------|
| ネストのフラット化 | 参照実装の`&`セレクターを`:is(…)`ルールで解決し、ネストされたルールをフラット化します（`ast.php`の`handleNesting()`はTailwindCSSの処理を移植したもの）。`transformNesting`は、最初の宣言を含む階層より下に残ったネストをダウンレベル化します |
| 条件付きat-ruleのフラット化 | ネストされた`@media`、`@supports`、`@container`、`@starting-style`をソース順を保ってその場でフラット化し、条件が同一で直接隣接する兄弟ルールのみを統合します |
| 宣言の並べ替え | lightningcssの宣言ハンドラーの順序に従って宣言を並べ替え、参照実装と同じ順序でプロパティを出力します（`reorderDeclarations`） |
| `calc()`の簡略化 | `calc()`式を簡略化します（`simplifyCalcExpressions`） |
| 先頭のゼロを削除 | `0.5` → `.5`（`normalizeLeadingZeros`） |
| transform関数の空白 | transform関数内の空白を正規化します（`normalizeTransformFunctions`） |
| グリッド値の正規化 | span値の`/`の前後に空白を追加し、`grid-template-*`では整数のみの値をpxに変換します（`normalizeGridValues`） |
| 色の正規化 | 色の構文を正規化し、`color-mix()`を`oklab()`に評価します（`normalizeColors`、`evaluateColorMix`） |
| URLの引用符 | `url(./x.jpg)` → `url("./x.jpg")`（`normalizeUrlQuoting`） |
| ベンダープレフィックス | Autoprefixer相当のプレフィックス付与（`addVendorPrefixes`） |

このファイルは意図的に`_tailwindphp/`の下に隔離され、`@port-deviation:replacement`とマークされています。TailwindCSSのソースを移植するのではなく、外部依存関係を表すものです。

## 移植の差異を示すマーカー

各実装ファイルのdocblockには`@port-deviation:*`マーカーがあり、PHP実装がTypeScriptのオリジナルからどこで、なぜ異なるのかを示しています。読者がPHPとTailwindCSSのソースを比較するとき、意図的な差異かどうかを迷わずに済むようにするのが目的です。

| マーカー | 意味 |
|--------|---------|
| `@port-deviation:none` | 重要な差異のない直接的な1対1の移植 |
| `@port-deviation:async` | PHPではasync/awaitの代わりに同期コードを使用 |
| `@port-deviation:storage` | データ構造が異なる（PHP配列とJSのMap/Set） |
| `@port-deviation:types` | TypeScript型の代わりにPHPDocアノテーションを使用 |
| `@port-deviation:sourcemaps` | ソースマップの追跡を省略 |
| `@port-deviation:enum` | TypeScript列挙型の代わりにPHP定数を使用 |
| `@port-deviation:errors` | エラー処理の方法が異なる |
| `@port-deviation:replacement` | 外部ライブラリ（e.g。lightningcss）を置き換えるPHP実装 |
| `@port-deviation:helper` | 元の実装にはないPHP専用ヘルパー |
| `@port-deviation:performance` | 出力を同一に保つPHP専用の最適化 |
| `@port-deviation:omitted` | モジュールまたは機能全体を移植していない（対象範囲外） |

`@port-deviation:performance`マーカーと同等性の確認方法については、[パフォーマンスとテスト](https://tailwindphp.inline0.dev/ja/docs/advanced/performance)を参照してください。
