Spectral.TypeInfo (Spectral v0.12.0)

View Source

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

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 typeinfo 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).

Summary

Types

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

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

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

Functions

Adds a function specification to the type_info structure.

Adds a record to the type_info structure.

Adds a type to the type_info structure.

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

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

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

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

Returns the module associated with a type_info structure.

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

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

Creates a new type_info structure for the given module.

Types

function_key()

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

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

type_info()

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

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

type_key()

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

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

Functions

add_function(type_info, name, arity, func_spec)

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

Adds a function specification to the type_info structure.

add_record(type_info, name, record)

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

Adds a record to the type_info structure.

add_type(type_info, name, arity, type)

@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(type_info, name, arity)

@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(type_info, name)

@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(type_info, name, arity)

@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(type_info, name, arity)

@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(type_info)

@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(type_info, name)

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

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

get_type(type_info, name, arity)

@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(module, implements_codec)

@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(args \\ [])

(macro)

sp_function_spec(record, args)

(macro)