# `A2UIAgent.MacroExpander`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_agent/lib/a2ui_agent/macro_expander.ex#L1)

Puts macros (`A2UIAgent.Macro`) in front of a catalog: the model sees
a catalog with the macros as components, and the renderer gets the
base catalog's components they expand to.

    expander = A2UIAgent.MacroExpander.new(basic_catalog, [status_badge])

    # For the prompt: the base catalog with the macros added.
    {:ok, inference_catalog} = A2UIAgent.MacroExpander.inference_catalog(expander)

    # For the renderer: the model's messages with the macros expanded.
    {:ok, messages} = A2UIAgent.MacroExpander.to_transport(expander, model_messages)

A macro component the model writes, `{"id": "badge", "component":
"StatusBadge", ...}` (or with its arguments under `"parameters"`), is
replaced by its macro's tree, flattened with the macro component's id
as the root id (`A2UIAgent.Builder.flatten/2`) and checked against the
base catalog. Components the expansion makes may be macros
themselves; they are expanded in turn, up to a depth of 16.

A macro that fails (an argument it cannot take, a component the
catalog rejects) leaves its component as it was, and the failure is
logged. Expansion deeper than the limit fails the whole call.

Option `:passthrough_components` limits the base catalog's components
the model sees: `nil` (the default) keeps them all, a list keeps the
ones named, and `[]` leaves only the macros.

# `t`
*since 0.1.0* 

```elixir
@type t() :: %A2UIAgent.MacroExpander{
  catalog: A2UICore.Catalog.t(),
  macros: [A2UIAgent.Macro.t()],
  passthrough: MapSet.t(String.t()) | nil,
  table: %{optional(String.t()) =&gt; A2UIAgent.Macro.t()}
}
```

# `inference_catalog`
*since 0.1.0* 

```elixir
@spec inference_catalog(t()) ::
  {:ok, A2UICore.Catalog.t()} | {:error, A2UICore.Error.t()}
```

The catalog the model writes for: the base catalog's components (those
`:passthrough_components` keeps) and the macros, which are also added
to its `anyComponent` union. Same id and protocol version as the base
catalog.

Fails with a `:catalog` error when a macro has the name of a base
component.

# `macro_catalog`
*since 0.1.0* 

```elixir
@spec macro_catalog(t()) :: A2UICore.Catalog.t()
```

A catalog of the macros alone, under the id
`https://a2ui.org/catalogs/macros`, in the base catalog's protocol version.

# `new`
*since 0.1.0* 

```elixir
@spec new(A2UICore.Catalog.t(), [A2UIAgent.Macro.t()], keyword()) :: t()
```

An expander for `macros` over the base catalog. Option:
`:passthrough_components`.

Raises `ArgumentError` when two macros have the same name.

# `to_inference`
*since 0.1.0* 

```elixir
@spec to_inference(t(), [map()]) :: [map()]
```

Messages going the other way, which need no change: returns them as they are.

# `to_transport`
*since 0.1.0* 

```elixir
@spec to_transport(t(), [map()]) :: {:ok, [map()]} | {:error, A2UICore.Error.t()}
```

The model's messages with every macro component expanded (in the
components of `createSurface` and `updateComponents` messages).
Bindings and function calls are written for each message's
`version`.

Fails with a `:recursion` error when expansion goes deeper than
16.

---

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