# `Spectral.TypeInfo`
[🔗](https://github.com/andreashasse/spectral/blob/main/lib/spectral/type_info.ex#L1)

Elixir wrapper for the Erlang `:spectra_type_info` module.

Provides functions for creating and manipulating type information structures
that contain types, records, and function specifications.

> #### Advanced integrations {: .info}
>
> This module is intended for advanced integrations, such as building custom
> web framework plugins or other tooling on top of Spectral. Most applications
> will not need to use it directly.

## Type Info Structure

A type_info record (Erlang record from spectra library) has the structure:

    {:type_info, types, records, functions}

Where:
- `types` - Map of `{type_name, arity}` tuples to `sp_type` records
- `records` - Map of record names (atoms) to `sp_rec` records
- `functions` - Map of `{function_name, arity}` tuples to function spec information

## Usage

Typically, you'll get a type_info structure from a module's `__spectra_type_info__/0` function
and then query or modify it:

    type_info = Person.__spectra_type_info__()

    # Find a specific type
    case Spectral.TypeInfo.find_type(type_info, :t, 0) do
      {:ok, type} -> IO.inspect(type)
      :error -> IO.puts("Type not found")
    end

    # Add a new type
    new_type_info = Spectral.TypeInfo.add_type(type_info, :custom, 0, custom_type)

## Type Keys

Types and functions are indexed by tuples of `{name :: atom(), arity :: non_neg_integer()}`.
Records are indexed by their name (atom).

# `function_key`

```elixir
@type function_key() :: :spectra_type_info.function_key()
```

A key identifying a function. Alias for `:spectra_type_info.function_key()`.

# `type_info`

```elixir
@type type_info() :: :spectra_type_info.type_info()
```

A type information structure. Alias for `:spectra_type_info.type_info()`.

# `type_key`

```elixir
@type type_key() :: :spectra_type_info.type_key()
```

A key identifying a type. Alias for `:spectra_type_info.type_key()`.

# `add_function`

```elixir
@spec add_function(type_info(), atom(), arity(), [term()]) :: type_info()
```

Adds a function specification to the type_info structure.

# `add_record`

```elixir
@spec add_record(type_info(), atom(), term()) :: type_info()
```

Adds a record to the type_info structure.

# `add_type`

```elixir
@spec add_type(type_info(), atom(), arity(), term()) :: type_info()
```

Adds a type to the type_info structure.

## Examples

    iex> type_info = Person.__spectra_type_info__()
    iex> {:ok, person_type} = Spectral.TypeInfo.find_type(type_info, :t, 0)
    iex> new_info = Spectral.TypeInfo.new(:nomodule, false)
    iex> updated = Spectral.TypeInfo.add_type(new_info, :my_type, 0, person_type)
    iex> {:ok, _type} = Spectral.TypeInfo.find_type(updated, :my_type, 0)
    iex> :ok
    :ok

# `find_function`

```elixir
@spec find_function(type_info(), atom(), arity()) :: {:ok, [term()]} | :error
```

Finds a function specification in the type_info structure. Returns `{:ok, specs}` or `:error`.

## Examples

    iex> type_info = Spectral.TypeInfo.new(:nomodule, false)
    iex> Spectral.TypeInfo.find_function(type_info, :my_func, 2)
    :error

# `find_record`

```elixir
@spec find_record(type_info(), atom()) :: {:ok, term()} | :error
```

Finds a record in the type_info structure. Returns `{:ok, record}` or `:error`.

## Examples

    iex> type_info = Spectral.TypeInfo.new(:nomodule, false)
    iex> Spectral.TypeInfo.find_record(type_info, :person)
    :error

# `find_type`

```elixir
@spec find_type(type_info(), atom(), arity()) :: {:ok, term()} | :error
```

Finds a type in the type_info structure. Returns `{:ok, type}` or `:error`.

## Examples

    iex> type_info = Person.__spectra_type_info__()
    iex> {:ok, type} = Spectral.TypeInfo.find_type(type_info, :t, 0)
    iex> is_tuple(type)
    true

    iex> type_info = Spectral.TypeInfo.new(:nomodule, false)
    iex> Spectral.TypeInfo.find_type(type_info, :nonexistent, 0)
    :error

# `get_function_doc`

```elixir
@spec get_function_doc(type_info(), atom(), arity()) ::
  {:ok, map()} | {:error, :no_doc_found | :function_not_found}
```

Returns the endpoint documentation attached to a function via the `spectral/1` macro.

When `spectral/1` is placed before a `@spec` and function definition, the documentation
map (with keys like `:summary`, `:description`, `:deprecated`) is stored in the function
spec's metadata. This function retrieves it, using the first function spec when there are
multiple specs (e.g., multiple clauses with different guards).

## Parameters

- `type_info` - The type_info structure to search
- `name` - The function name (atom)
- `arity` - The function arity (non-negative integer)

## Returns

- `{:ok, doc}` - If a doc was attached to the function (map with endpoint doc fields)
- `{:error, :no_doc_found}` - If the function exists but has no `spectral/1` annotation
- `{:error, :function_not_found}` - If the function is not found in the type info

## Example

    type_info = MyController.__spectra_type_info__()
    {:ok, doc} = Spectral.TypeInfo.get_function_doc(type_info, :show, 2)
    # doc => %{summary: "Show resource", description: "Returns a resource by ID"}

# `get_module`

```elixir
@spec get_module(type_info()) :: module()
```

Returns the module associated with a type_info structure.

## Examples

    iex> type_info = Person.__spectra_type_info__()
    iex> Spectral.TypeInfo.get_module(type_info)
    Person

# `get_record`

```elixir
@spec get_record(type_info(), atom()) :: term()
```

Gets a record from the type_info structure, raising `{:record_not_found, name}` if absent.

# `get_type`

```elixir
@spec get_type(type_info(), atom(), arity()) :: term()
```

Gets a type from the type_info structure, raising `{:type_not_found, name, arity}` if absent.

## Examples

    iex> type_info = Person.__spectra_type_info__()
    iex> type = Spectral.TypeInfo.get_type(type_info, :t, 0)
    iex> is_tuple(type)
    true

# `new`

```elixir
@spec new(module(), boolean()) :: type_info()
```

Creates a new type_info structure for the given module.

Pass `implements_codec: true` when the module implements `Spectral.Codec`.
In practice you rarely need to call this directly — type info is normally
obtained via a module's `__spectra_type_info__/0` function.

## Examples

    iex> type_info = Spectral.TypeInfo.new(Person, false)
    iex> Spectral.TypeInfo.get_module(type_info)
    Person

# `sp_function_spec`
*macro* 

# `sp_function_spec`
*macro* 

---

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