# `Macaw.Layers.Composite`
[🔗](https://github.com/dcoai/macaw_layers/blob/v0.2.2/lib/macaw/layers/composite.ex#L1)

Composites (spec/02 §8): a fragment whose content is a list of use sites and its own
variable declarations, stored as structure and flattened at deployment.

    %{composite: %{uses: [%Use{…}, …], vars: %{"color_1" => %{default: …}}}}

`flatten/3` resolves every site recursively — `ref → local → mask → bind` — through a
fetch, places each by its kind through the type's `place/3`, and stacks the placed
layers: a whole document with no ids and no uses. Composites nest; one that reaches
itself is refused at the site that closed the loop. A reference the store no longer
holds shows through and is reported.

Ported from visualize's `Visualize.Chart.Composite` and `Refs`, the placement and the
inlining of ids made the type's.

# `report`

```elixir
@type report() :: %{
  missing: [{Macaw.Layers.Fragment.id(), term()}],
  keyless: [{:use, pos_integer()}]
}
```

What `flatten/3` reports: every reference that showed through, `{id, at}`, `at` the use
id of the site that named it or the path of a reference inside the document, and every
name-keyed site with no key, by its use id.

# `composite?`

```elixir
@spec composite?(term()) :: boolean()
```

Whether a fragment is one key, `composite`, holding uses.

# `decompose`

```elixir
@spec decompose(module(), map()) :: map()
```

A whole document as a composite of inline sites, one kind each, through the type's
`decompose/1` (spec/02 §8.2): flattening it is the document again.

# `flatten`

```elixir
@spec flatten(module(), map(), (Macaw.Layers.Fragment.id() -&gt; {:ok, map()} | :error)) ::
  {:ok, map(), report()} | {:error, {:cycle, [Macaw.Layers.Fragment.id()]}}
```

A composite flattened through `fetch` (spec/02 §8.1): `{:ok, document, report}`, or
`{:error, {:cycle, chain}}`, `chain` the ids from the outer composite to the repeated
one. A fragment that is not a composite flattens to itself. Once the sites are placed,
the ids left at reference sites inside the document are resolved by the type's
`inline/2`, where it has one.

# `place`

```elixir
@spec place(module(), map(), String.t() | nil) :: {:ok, map()} | :keyless
```

One site's contribution as the layer that declares it where a whole document keeps its
kind (spec/02 §8.2), through the type's `place/3`, or `:keyless`. A contribution of no
kind (a whole document, an empty site) is its own layer.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
