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

`$ref` handling for catalog documents.

A catalog document references three kinds of target:

  * the protocol's common types, as `common_types.json#/$defs/X` (or a
    path ending in `/common_types.json`);
  * its own definitions, as `#/…` or through a document named
    `catalog.json`;
  * a **peer catalog** it holds, as `<peer document>#/components/…` or
    `#/functions/…`, where the document names the peer by `catalogId`
    or `$id`, exactly or by path suffix, before falling back to the
    file name (protocol guide, "Cross-Catalog References").

`normalize/2` rewrites references into the common types and into the
catalog itself as local `#/$defs/…` pointers; `inline/4` writes local
and peer references inline, keeping references to common types.

`query/2`, `inline/4` and `strip_envelope/1` also read documents whose
objects are `Jason.OrderedObject`s, and keep their key order.

# `peer`
*since 0.1.0* 

```elixir
@type peer() :: %{
  catalog_id: String.t() | nil,
  schema_id: String.t() | nil,
  document: map()
}
```

A peer catalog for reference resolution: its ids and its document.

# `cross_document?`
*since 0.1.0* 

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

Whether any `$ref` in `node` may point into a peer catalog: one with a
document part other than the common types or `catalog.json`.

# `def_refs`
*since 0.1.0* 

```elixir
@spec def_refs(term()) :: MapSet.t(String.t())
```

The names of the `$defs` that local `#/$defs/…` references in `node`
target (the first segment after `#/$defs/`).

# `externalize`
*since 0.1.0* 

```elixir
@spec externalize(term(), MapSet.t(String.t()), String.t()) :: term()
```

Points local references to the names in `common_names` at the common
types document `document` (`#/$defs/X` becomes `<document>#/$defs/X`).

# `find_peer`
*since 0.1.0* 

```elixir
@spec find_peer(String.t(), [peer()]) :: peer() | nil
```

The peer a `$ref` document names, or `nil`. Common types and a document
named exactly `catalog.json` never name a peer; a path ending in
`/catalog.json` names one only by id. Otherwise ids are matched first
(exactly or by path suffix), then file names; the first match in
`peers` order wins.

# `inline`
*since 0.1.0* 

```elixir
@spec inline(term(), map(), [peer()], MapSet.t(String.t())) :: term()
```

Writes the local and peer references of `node` inline.

A `#/…` reference is replaced by its target in `root`, with the keys
beside the `$ref` merged over it; a reference into a peer (see
`find_peer/2`) by its target in the peer's document, whose own local
references resolve against that document. A reference to a name in
`preserved` (the common types) stays, and so does a reference that is
already being expanded or whose target is missing. A whole component
inherited through `#/components/<Name>` loses its envelope (`id`,
`component`, `catalogId`) and closure keywords.

# `localize`
*since 0.1.0* 

```elixir
@spec localize(String.t(), [peer()]) :: String.t()
```

Rewrites a cross-document `$defs` reference as a local pointer: one
into the common types, into a document named `catalog.json`, or into a
path ending in `/catalog.json` that names none of `peers`. Any other
reference is returned unchanged.

# `names_document?`
*since 0.1.0* 

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

Whether the document part of a `$ref` is the file `name` or a path
ending in it.

# `normalize`
*since 0.1.0* 

```elixir
@spec normalize(term(), [peer()]) :: term()
```

Applies `localize/2` to every `$ref` in `node`.

# `own_def_name`
*since 0.1.0* 

```elixir
@spec own_def_name(term()) :: String.t() | nil
```

The `$defs` name a reference into the same catalog targets: a local
`#/$defs/X`, or a pointer into a `catalog.json` document.

# `own_def_refs`
*since 0.1.0* 

```elixir
@spec own_def_refs(term()) :: MapSet.t(String.t())
```

Like `def_refs/1`, also counting references into a `catalog.json`
document, which a catalog uses for its own definitions.

# `query`
*since 0.1.0* 

```elixir
@spec query(term(), String.t()) :: term()
```

The node a `#/…` JSON pointer addresses in `document`, or `nil`.

# `reachable_defs`
*since 0.1.0* 

```elixir
@spec reachable_defs([term()], map()) :: MapSet.t(String.t())
```

The names in `defs` that `roots` reference, transitively (counting
references into `catalog.json`).

# `strip_envelope`
*since 0.1.0* 

```elixir
@spec strip_envelope(map()) :: map()
```

Removes a component's envelope (`id`, `component` and `catalogId`
properties and required names) and closure keywords, recursively
through `allOf`, where the members that declare `component` move
first.

---

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