AshTypescript.TypeSystem.Introspection (ash_typescript v0.17.2)

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, unions, 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.

Classifies an Ash type into a category for processing purposes.

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.

Extracts union types from an attribute's constraints.

Extracts union types from type and constraints directly.

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}

classify_ash_type(type_module, attribute, is_array)

Classifies an Ash type into a category for processing purposes.

Returns one of:

  • :union_attribute - Union type
  • :embedded_resource - Single embedded resource
  • :embedded_resource_array - Array of embedded resources
  • :tuple - Tuple type
  • :attribute - Simple attribute (default)

Parameters

  • type_module - The Ash type module (e.g., Ash.Type.String, Ash.Type.Union)
  • attribute - The attribute struct containing type and constraints
  • is_array - Whether this is inside an array type

Examples

iex> attr = %{type: MyApp.Address, constraints: []}
iex> AshTypescript.TypeSystem.Introspection.classify_ash_type(MyApp.Address, attr, false)
:embedded_resource

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"}

get_union_types(attribute)

Extracts union types from an attribute's constraints.

Handles both direct union types and array union types.

Examples

iex> attr = %{type: Ash.Type.Union, constraints: [types: [note: [...], url: [...]]]}
iex> AshTypescript.TypeSystem.Introspection.get_union_types(attr)
[note: [...], url: [...]]

get_union_types_from_constraints(type, constraints)

Extracts union types from type and constraints directly.

Useful when you have constraints but not the full attribute struct. Handles both direct union types and array union types.

Examples

iex> constraints = [types: [note: [...], url: [...]]]
iex> AshTypescript.TypeSystem.Introspection.get_union_types_from_constraints(Ash.Type.Union, constraints)
[note: [...], url: [...]]

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]}