# Variants Plugin

## NAME

`VariantsPlugin` и extension `variants`.

## SYNOPSIS

```groovy
plugins {
    id 'org.implab.gradle-variants'
}

variants {
    layer('mainBase')
    layer('mainAmd')

    variant('browser') {
        attributes {
            string('jsRuntime', 'browser')
            string('jsModule', 'amd')
        }

        role('main') {
            layers('mainBase', 'mainAmd')
        }

        link('mainBase', 'mainAmd', 'ts:api')
        artifactSlot('mainCompiled')
    }
}
```

## DESCRIPTION

`VariantsPlugin` задает доменную модель сборки и ее валидацию. Плагин не
регистрирует compile/copy/bundle задачи напрямую.

### layers

Глобальные логические слои. Служат единым словарем имен, на которые затем
ссылаются роли и связи.

### variants

Именованные варианты исполнения/пакетирования (`browser`, `node`, и т.д.).
Вариант агрегирует роли, связи, атрибуты и artifact slots.

### roles

Роль описывает набор слоев в пределах варианта (`main`, `test`, `tools`).
Одна роль может ссылаться на несколько слоев.

### links

`link(from, to, kind)` — ориентированная связь между слоями внутри варианта.

`kind` задает независимый тип графа (например `ts:api`, `bundle:runtime`). Это
позволяет вести несколько параллельных графов зависимостей над теми же слоями.

Практические сценарии использования `link` в адаптерах:

- расчет topological order по выбранному `kind`;
- wiring task inputs/outputs между слоями;
- проверка допустимости дополнительных pipeline-зависимостей.

### attributes

Typed-атрибуты (`Attribute<T> -> Provider<T>`) для передачи параметров в
адаптеры и публикацию артефактов.

### artifact slots

Именованные слоты ожидаемых артефактов варианта. Используются как контракт
между моделью варианта и плагинами, создающими/публикующими результаты.

## VALIDATION

В `finalizeModel()` выполняется проверка:

- роль не может ссылаться на неизвестный layer;
- пустые имена layer запрещены;
- у link обязательны `from`, `to`, `kind`;
- `from`/`to` должны входить в слойную область варианта;
- tuple `(from, to, kind)` должен быть уникален;
- циклы в графе одного `kind` запрещены.

## LIFECYCLE

- `VariantsPlugin` вызывает `variants.finalizeModel()` на `afterEvaluate`.
- после `finalizeModel()` мутации модели запрещены.
- `whenFinalized(...)` replayable.

## API

### BuildVariantsExtension

- `layer(...)` — объявление или конфигурация `BuildLayer`.
- `variant(...)` — объявление или конфигурация `BuildVariant`.
- `layers { ... }`, `variants { ... }` — контейнерный DSL.
- `all(...)` — callback для всех вариантов.
- `getAll()`, `find(name)`, `require(name)` — доступ к вариантам.
- `validate()` — явный запуск валидации.
- `finalizeModel()` — валидация + финализация модели.
- `whenFinalized(...)` — callback по завершенной модели (replayable).

### BuildVariant

- `attributes { ... }` — атрибуты варианта (+ sugar `string/bool/integer`).
- `role(...)`, `roles { ... }` — роли варианта.
- `link(...)`, `links { ... }` — связи слоев внутри варианта.
- `artifactSlot(...)`, `artifactSlots { ... }` — артефактные слоты.

## KEY CLASSES

- `VariantsPlugin` — точка входа плагина.
- `BuildVariantsExtension` — root extension и lifecycle.
- `BuildVariant` — агрегатная модель варианта.
- `BuildLayer` — модель слоя.
- `BuildRole` — модель роли.
- `LayerLink` — модель направленной связи.
- `BuildArtifactSlot` — модель артефактного слота.
- `VariantAttributes` — typed wrapper для variant attributes.

## NOTES

- Модель `variants` intentionally agnostic к toolchain.
- Интеграция с задачами выполняется через `variantSources` и адаптеры.
