# `A2UICore.Catalog.RefSpec`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_core/lib/a2ui_core/catalog/ref_spec.ex#L1)

Which properties of a component refer to other components, and how to
pull those references out of a component's properties.

A spec has three parts, mirroring the reference `ComponentRefSpec`:

  * `single` — properties holding one child (`child`, `contentChild`),
  * `list` — properties holding many children (`children`, `tabs`),
  * `nested` — for list properties whose items are objects, the keys
    inside each item that hold the child (`tabs` → `child`).

`extract/2` returns `{component_id, property_path}` pairs. Property
paths are the reference's: `"child"`, `"children[0]"`,
`"children.componentId"` (a template), `"tabs[1].child"`.

Specs are derived from catalog schemas by
`A2UICore.Catalog.ReferenceMap`; a surface keeps one per component
type.

Objects are traversed in sorted key order, so when a value holds
several references the order is deterministic (the reference follows
JSON insertion order).

    iex> spec = A2UICore.Catalog.RefSpec.new(single: ["child"], list: ["children"])
    iex> A2UICore.Catalog.RefSpec.extract(spec, %{"child" => "a", "children" => ["b", "c"]})
    [{"a", "child"}, {"b", "children[0]"}, {"c", "children[1]"}]

# `child_ref`
*since 0.1.0* 

```elixir
@type child_ref() :: {component_id :: String.t(), property_path :: String.t()}
```

A child reference: the referenced component id and the property path it came from.

# `t`
*since 0.1.0* 

```elixir
@type t() :: %A2UICore.Catalog.RefSpec{
  list: MapSet.t(String.t()),
  nested: %{optional(String.t()) =&gt; MapSet.t(String.t())},
  single: MapSet.t(String.t())
}
```

# `child_prop?`
*since 0.1.0* 

```elixir
@spec child_prop?(t(), String.t()) :: boolean()
```

True when `key` is a configured child property.

# `empty?`
*since 0.1.0* 

```elixir
@spec empty?(t()) :: boolean()
```

True when the spec names no child properties at all.

# `extract`
*since 0.1.0* 

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

Extracts `{component_id, property_path}` pairs from a component's
`props` according to the spec: single properties first, then list
properties.

# `from_value`
*since 0.1.0* 

```elixir
@spec from_value(term()) :: [{String.t(), String.t()}]
```

Extracts `{component_id, relative_path}` pairs from one property value
(a component id, a `{child: id}` / `{componentId: id, path: …}` object,
a list of those, or an object with nested child slots).

    iex> A2UICore.Catalog.RefSpec.from_value(%{"componentId" => "item", "path" => "/rows"})
    [{"item", "componentId"}]
    iex> A2UICore.Catalog.RefSpec.from_value([%{"child" => "x"}, "y"])
    [{"x", "[0].child"}, {"y", "[1]"}]

# `new`
*since 0.1.0* 

```elixir
@spec new(keyword()) :: t()
```

Builds a spec. Options: `:single` and `:list` (lists of property
names) and `:nested` (`%{list_property => [item_key]}`).

---

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