AshTypescript.TypeSystem.Introspection (ash_typescript v0.18.1)

Copy Markdown View Source

Core type introspection and classification for Ash types.

This module provides a centralized set of functions for determining the nature and characteristics of Ash types, including embedded resources, typed structs, NewTypes, custom types, and primitive types.

Used throughout the codebase for type checking, code generation, and runtime processing.

Summary

Functions

Builds a reverse mapping from client names to internal names.

Gets the type and constraints for a field from field specs.

Extracts the inner type from an array type.

Gets the typescript_field_names as a map, or empty map if not available.

Checks if constraints include non-empty field definitions.

Checks if a module has a typescript_field_names/0 callback.

Checks if a type is an Ash type module.

Checks if a type is a custom Ash type with a typescript_type_name callback.

Checks if a module is an embedded Ash resource.

Checks if a type is a primitive Ash type (not a complex or composite type).

Checks if constraints specify an instance_of that is an Ash resource.

Recursively unwraps Ash.Type.NewType to get the underlying type and constraints.

Functions

build_reverse_field_names_map(ts_field_names)

Builds a reverse mapping from client names to internal names.

Can take either a map of field names or a module with typescript_field_names/0.

Examples

iex> AshTypescript.TypeSystem.Introspection.build_reverse_field_names_map(%{is_active?: "isActive"})
%{"isActive" => :is_active?}

iex> AshTypescript.TypeSystem.Introspection.build_reverse_field_names_map(MyApp.TaskStats)
%{"isActive" => :is_active?, "meta1" => :meta_1}

get_field_spec_type(field_specs, field_name)

Gets the type and constraints for a field from field specs.

Examples

iex> specs = [name: [type: :string], age: [type: :integer]]
iex> AshTypescript.TypeSystem.Introspection.get_field_spec_type(specs, :name)
{:string, []}

iex> AshTypescript.TypeSystem.Introspection.get_field_spec_type(specs, :unknown)
{nil, []}

get_inner_type(type)

Extracts the inner type from an array type.

Examples

iex> AshTypescript.TypeSystem.Introspection.get_inner_type({:array, Ash.Type.String})
Ash.Type.String

iex> AshTypescript.TypeSystem.Introspection.get_inner_type(Ash.Type.String)
Ash.Type.String

get_typescript_field_names_map(module)

Gets the typescript_field_names as a map, or empty map if not available.

Examples

iex> AshTypescript.TypeSystem.Introspection.get_typescript_field_names_map(MyApp.TaskStats)
%{is_active?: "isActive", meta_1: "meta1"}

has_field_constraints?(constraints)

Checks if constraints include non-empty field definitions.

Examples

iex> AshTypescript.TypeSystem.Introspection.has_field_constraints?([fields: [name: [type: :string]]])
true

iex> AshTypescript.TypeSystem.Introspection.has_field_constraints?([fields: []])
false

has_typescript_field_names?(module)

Checks if a module has a typescript_field_names/0 callback.

Examples

iex> AshTypescript.TypeSystem.Introspection.has_typescript_field_names?(MyApp.TaskStats)
true

iex> AshTypescript.TypeSystem.Introspection.has_typescript_field_names?(Ash.Type.String)
false

is_ash_type?(module)

Checks if a type is an Ash type module.

Examples

iex> AshTypescript.TypeSystem.Introspection.is_ash_type?(Ash.Type.String)
true

iex> AshTypescript.TypeSystem.Introspection.is_ash_type?(MyApp.CustomType)
true

iex> AshTypescript.TypeSystem.Introspection.is_ash_type?(:string)
false

is_custom_type?(type)

Checks if a type is a custom Ash type with a typescript_type_name callback.

Custom types are Ash types that define a typescript_type_name/0 callback to specify their TypeScript representation.

Examples

iex> AshTypescript.TypeSystem.Introspection.is_custom_type?(MyApp.MyCustomType)
true

iex> AshTypescript.TypeSystem.Introspection.is_custom_type?(Ash.Type.String)
false

is_embedded_resource?(module)

Checks if a module is an embedded Ash resource.

Examples

iex> AshTypescript.TypeSystem.Introspection.is_embedded_resource?(MyApp.Accounts.Address)
true

iex> AshTypescript.TypeSystem.Introspection.is_embedded_resource?(MyApp.Accounts.User)
false

is_primitive_type?(type)

Checks if a type is a primitive Ash type (not a complex or composite type).

Primitive types include basic types like String, Integer, Boolean, Date, UUID, etc.

Examples

iex> AshTypescript.TypeSystem.Introspection.is_primitive_type?(Ash.Type.String)
true

iex> AshTypescript.TypeSystem.Introspection.is_primitive_type?(Ash.Type.Union)
false

is_resource_instance_of?(constraints)

Checks if constraints specify an instance_of that is an Ash resource.

Examples

iex> AshTypescript.TypeSystem.Introspection.is_resource_instance_of?([instance_of: MyApp.Todo])
true

iex> AshTypescript.TypeSystem.Introspection.is_resource_instance_of?([])
false

unwrap_new_type(type, constraints)

Recursively unwraps Ash.Type.NewType to get the underlying type and constraints.

When a type is wrapped in one or more NewType wrappers, this function recursively unwraps them until it reaches the base type. If the NewType has a typescript_field_names/0 callback and the constraints don't already have an instance_of key, it will add the NewType module as instance_of to preserve the reference for field name mapping.

Parameters

  • type - The type to unwrap (e.g., MyApp.CustomType)
  • constraints - The constraints for the type

Returns

A tuple {unwrapped_type, unwrapped_constraints} where:

  • unwrapped_type is the final underlying type after all NewType unwrapping
  • unwrapped_constraints are the final constraints, potentially augmented with instance_of

Examples

iex> # Simple NewType with typescript_field_names
iex> unwrap_new_type(MyApp.TaskStats, [])
{Ash.Type.Struct, [fields: [...], instance_of: MyApp.TaskStats]}

iex> # Nested NewTypes (outermost with callback wins)
iex> unwrap_new_type(MyApp.Wrapper, [])
{Ash.Type.String, [max_length: 100, instance_of: MyApp.Wrapper]}

iex> # Non-NewType (returns unchanged)
iex> unwrap_new_type(Ash.Type.String, [max_length: 50])
{Ash.Type.String, [max_length: 50]}