# Variant Sources Plugin

## NAME

`VariantsSourcesPlugin` и extension `variantSources`.

## SYNOPSIS

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

variants {
    layer('main')

    variant('browser') {
        role('main') { layers('main') }
    }

    variant('node') {
        role('main') { layers('main') }
    }
}

variantSources {
    bind('main').sourceSetNamePattern = '{layer}'

    bind('main') {
        configureSourceSet {
            declareOutputs('compiled')
        }
    }

    whenRegistered { sourceSetName() }
    whenBound('browser') { roleName() }
}
```

## DESCRIPTION

`VariantsSourcesPlugin` применяет `VariantsPlugin` и `SourcesPlugin`, затем
материализует source sets из модели `variants`.

Точка запуска materialization:

- `variants.whenFinalized(model -> registerSourceSets(...))`

### materialization

Для каждой usage-связки `variant/role/layer` вычисляется имя source set,
регистрируется `GenericSourceSet` (если он еще не существует), затем
вызываются callbacks.

### binding

`bind('<layer>')` возвращает `BuildLayerBinding` и задает policy для этого
слоя:

- как именовать source set;
- как конфигурировать source set;
- какие callbacks вызвать на registration/binding.

### sourceSetNamePattern

`sourceSetNamePattern` определяет naming policy materialized source set.

Default:

- `{variant}{layerCap}`

Tokens:

- `{variant}`, `{variantCap}`
- `{role}`, `{roleCap}`
- `{layer}`, `{layerCap}`

Имя санитизируется (`[^A-Za-z0-9_.-] -> _`).

Ограничение:

- один `sourceSetName` не может быть порожден разными слоями.

## EVENTS

### whenRegistered

- callback на новый уникальный source set;
- replayable;
- при shared source set срабатывает один раз.

### whenBound

- callback на каждую usage-связку `variant/role/layer`;
- replayable;
- подходит для per-usage логики.

### variant filter

Глобальные callbacks поддерживают фильтр по варианту:

- `whenRegistered(String variantName, ...)`
- `whenBound(String variantName, ...)`

## SOURCE SET CONTEXT

`SourceSetContext` содержит:

- `variantName`, `roleName`, `layerName`, `sourceSetName`;
- `sourceSet` (`NamedDomainObjectProvider<GenericSourceSet>`).

Sugar:

- `configureSourceSet(Action|Closure)`.

## API

### VariantSourcesExtension

- `bind(String)` — получить/создать binding по имени слоя.
- `bind(String, Action|Closure)` — сконфигурировать binding.
- `bindings(Action|Closure)` — контейнерная конфигурация bindings.
- `whenRegistered(...)` — глобальные callbacks регистрации source set.
- `whenBound(...)` — глобальные callbacks usage-binding.

### BuildLayerBinding

- `sourceSetNamePattern` — naming policy для source set слоя.
- `configureSourceSet(...)` — слойная конфигурация `GenericSourceSet`.
- `whenRegistered(...)` — callbacks регистрации в рамках слоя.
- `whenBound(...)` — callbacks usage-binding в рамках слоя.

## KEY CLASSES

- `VariantsSourcesPlugin` — точка входа plugin adapter.
- `VariantSourcesExtension` — глобальный DSL bind/events.
- `BuildLayerBinding` — layer-local policy и callbacks.
- `SourceSetContext` — payload callbacks и sugar-конфигурирование.

## NOTES

- `sourceSetNamePattern` фиксируется при первом чтении в materialization
  (`finalizeValueOnRead`).
- Closure callbacks используют delegate-first.
- Для вложенных closure лучше явный параметр (`ctx -> ...`).
