# `Choreo.Lab.Compose`
[🔗](https://github.com/code-shoily/choreo/blob/v0.14.1/lib/choreo/lab/compose.ex#L1)

Pipe-friendly composition helpers for assembling Choreo models in Livebook.

This module is ordinary Elixir, not a macro DSL. It is a thin convenience
layer over the stable composition primitives in `Choreo`: clusters, embedding,
normal graph connections, and semantic trace links.

`Choreo` remains the primitive composition API. `Choreo.Lab.Compose` is the
ergonomic exploration API for building larger composed models from smaller
Choreo diagrams.

Prefer alias-qualified usage for better editor autocomplete:

    alias Choreo.Lab.Compose

    Choreo.new()
    |> Compose.cluster("system", label: "System")
    |> Compose.embed(infra, into: "system", as: :infra)
    |> Compose.embed(auth_fsm, into: "system", as: :auth)
    |> Compose.trace(:infra_auth, :auth_unauthenticated, :executes)

`connect/4` creates a normal visible relationship. `trace/4` creates a
semantic cross-model relationship that `Choreo.Analysis.Tracing` and
`Choreo.View.focus_trace/4` can follow.

# `cluster_id`

```elixir
@type cluster_id() :: String.t() | atom()
```

# `node_id`

```elixir
@type node_id() :: Yog.node_id()
```

# `system`

```elixir
@type system() :: Choreo.t()
```

# `cluster`

```elixir
@spec cluster(system(), cluster_id(), keyword()) :: system()
```

Adds a visual cluster/grouping boundary to a composed system.

    iex> system = Choreo.new() |> Choreo.Lab.Compose.cluster(:auth, label: "Auth")
    iex> Map.has_key?(system.clusters, "cluster_auth")
    true

# `connect`

```elixir
@spec connect(system(), node_id(), node_id(), String.t() | keyword()) :: system()
```

Connects two nodes with a normal visible relationship.

The third argument may be a label string, a keyword list, or omitted.

    iex> system =
    ...>   Choreo.new()
    ...>   |> Choreo.add_service(:api)
    ...>   |> Choreo.add_database(:db)
    ...>   |> Choreo.Lab.Compose.connect(:api, :db, "reads")
    iex> [{:api, :db, _weight, meta}] = Choreo.edges_with_meta(system)
    iex> meta.label
    "reads"

# `embed`

```elixir
@spec embed(system(), struct(), keyword()) :: system()
```

Embeds a child diagram into a cluster of the parent system.

Required options:

  * `:into` — target cluster name/id

Prefix options:

  * `:as` — friendly alias converted to a prefix with a trailing underscore
  * `:prefix` — explicit prefix passed through to `Choreo.embed/4`

`:prefix` wins over `:as` when both are supplied.

    iex> child = Choreo.new() |> Choreo.add_service(:api)
    iex> system =
    ...>   Choreo.new()
    ...>   |> Choreo.Lab.Compose.cluster(:system)
    ...>   |> Choreo.Lab.Compose.embed(child, into: :system, as: :child)
    iex> Map.has_key?(Choreo.nodes(system), :child_api)
    true

# `taxonomy`

```elixir
@spec taxonomy() :: %{structure: [atom()], links: [atom()], options: [atom()]}
```

Returns the composition helper vocabulary for Livebook discovery.

    iex> taxonomy = Choreo.Lab.Compose.taxonomy()
    iex> :embed in taxonomy.structure
    true
    iex> :trace in taxonomy.links
    true
    iex> :as in taxonomy.options
    true

# `trace`

```elixir
@spec trace(system(), node_id(), node_id(), atom() | keyword()) :: system()
```

Adds a semantic trace relationship between two nodes.

The fourth argument may be a trace type atom, a keyword list, or omitted.

    iex> system =
    ...>   Choreo.new()
    ...>   |> Choreo.add_service(:api)
    ...>   |> Choreo.add_service(:auth)
    ...>   |> Choreo.Lab.Compose.trace(:api, :auth, :executes)
    iex> [{:api, :auth, _weight, meta}] = Choreo.edges_with_meta(system)
    iex> {meta.edge_type, meta.type, meta.label}
    {:trace, :executes, "executes"}

# `verbs`

```elixir
@spec verbs() :: %{structure: [atom()], links: [atom()], options: [atom()]}
```

Compatibility alias for `taxonomy/0`.

---

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