
# Архітектура

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` (правила стилів, at-правила, оголошення). На цьому етапі обробляються директиви `@import` для віртуальних модулів (`tailwindcss`, `tailwindcss/preflight`, …) і шляхи до файлів.

**Побудова дизайн-системи.** `theme.php` визначає значення теми (кольори, відступи, контрольні точки) з розібраних блоків `@theme` і значень за замовчуванням. `design-system.php` — це центральний реєстр, що пов’язує тему з пошуком утиліт і варіантів, визначеним у `utilities.php` та `variants.php`.

**Сканування вмісту.** `candidate.php` витягує кандидатні назви класів із переданого вмісту (HTML, шаблони) та розбирає кожну на частини: базову утиліту, варіанти, модифікатори, довільні значення й прапорець важливості.

**Компіляція.** `compile.php` перетворює кожного кандидата на вузли AST, шукаючи його в дизайн-системі та застосовуючи його варіанти й модифікатори. Кандидатів, які не відповідають жодній реальній утиліті, відкинуто.

**Серіалізація й оптимізація.** `ast.php` проходить деревом за допомогою `toCss()` (допоміжні функції в `walk.php`) і формує рядок CSS. Застосовуються перетворення, еквівалентні `lightningcss`, з `_tailwindphp/LightningCss.php`, щоб результат відповідав тому, що створює TailwindCSS після етапу післяобробки Rust.

**Мініфікація.** Коли ввімкнено `minify`, під час серіалізації `toCss()` формує мініфікований CSS. Окремий етап обробки рядка `tw::minify()` забезпечує `_tailwindphp/CssMinifier.php`. Див. розділ [Кешування та мініфікація](https://tailwindphp.inline0.dev/uk/docs/advanced/caching).

## Структура вихідного коду

`src/` відтворює TailwindCSS. Єдина структурна зміна: `utilities.ts` TailwindCSS займає 6,000+ рядків, тому для зручності супроводу його розділено на `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 — вкладеність, обробку медіазапитів і спрощення значень — бібліотеці [lightningcss](https://lightningcss.dev/), парсеру, трансформеру й мініфікатору, написаному на Rust. PHP не може завантажувати бібліотеку Rust, тому `src/_tailwindphp/LightningCss.php` повторно реалізує перетворення, на які справді покладається TailwindPHP, і створює побайтно ідентичний результат для випадків, охоплених тестовим набором.

Підтверджені перетворення:

| Перетворення | Що воно робить |
|-----------|--------------|
| Розгортання вкладених правил | Розв’язує селектори `&` за правилами `:is(…)` з еталонної реалізації та розгортає вкладені правила (`handleNesting()` у `ast.php`, порт етапу TailwindCSS); `transformNesting` розгортає вкладеність, що залишається нижче першого рівня з оголошеннями |
| Розгортання умовних at-правил | На місці розгортає вкладені `@media`, `@supports`, `@container` та `@starting-style`, зберігаючи порядок у вихідному коді, і об’єднує лише безпосередньо сусідні правила з однаковими умовами |
| Упорядкування оголошень | Переупорядковує оголошення відповідно до ланцюжка обробників оголошень lightningcss, тож властивості виводяться в еталонному порядку (`reorderDeclarations`) |
| Спрощення `calc()` | Спрощує вирази `calc()` (`simplifyCalcExpressions`) |
| Видалення нуля на початку | `0.5` → `.5` (`normalizeLeadingZeros`) |
| Інтервали у функціях перетворення | Нормалізує інтервали всередині функцій перетворення (`normalizeTransformFunctions`) |
| Нормалізація значень сітки | Додає пробіли навколо `/` у значеннях span; цілі числа без одиниць перетворює на px для `grid-template-*` (`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 замість Map/Set JS) |
| `@port-deviation:types` | Анотації PHPDoc замість типів TypeScript |
| `@port-deviation:sourcemaps` | Відстеження source map не реалізовано |
| `@port-deviation:enum` | Константи PHP замість переліків TypeScript |
| `@port-deviation:errors` | Інший підхід до обробки помилок |
| `@port-deviation:replacement` | Реалізація PHP замість зовнішньої бібліотеки (e.g. lightningcss) |
| `@port-deviation:helper` | Допоміжна функція для PHP, якої немає в оригіналі |
| `@port-deviation:performance` | Оптимізація для PHP, що зберігає ідентичний результат |
| `@port-deviation:omitted` | Модуль або функцію не перенесено (поза межами завдання) |

Про маркери `@port-deviation:performance` і забезпечення відповідності див. розділ [Продуктивність і тестування](https://tailwindphp.inline0.dev/uk/docs/advanced/performance).
