AshIntrospection.Codegen.ValidationErrorTypes (AshIntrospection v0.3.0)

View Source

Provides language-agnostic classification of validation error types for Ash types.

This module uses a unified type-driven dispatch pattern for classifying Ash types into their corresponding validation error type categories. Language-specific generators (TypeScript, Kotlin, etc.) can use this classification to generate appropriate error type definitions.

Error Type Categories

The module classifies types into the following error categories:

CategoryDescriptionExample Target Type
:primitive_errorsSimple string errorsstring[] / List<String>
:array_errorsArray of inner error typeUserErrors[] / List<UserErrors>
:resource_errorsResource validation errorsUserValidationErrors
:typed_container_errorsMap/struct with field errors{ name?: string[]; age?: string[] }
:union_errorsUnion member errors{ text?: string[]; note?: NoteErrors }
:custom_type_errorsCustom type errorsMoneyValidationErrors
:unconstrained_map_errorsGeneric map errorsRecord<string, any>

Usage

Basic Type Classification

alias AshIntrospection.Codegen.ValidationErrorTypes

# Classify a primitive type
{:ok, {:primitive_errors, nil}} = ValidationErrorTypes.classify_error_type(:string, [])

# Classify an embedded resource
{:ok, {:resource_errors, MyApp.Address}} =
  ValidationErrorTypes.classify_error_type(Ash.Type.Struct, instance_of: MyApp.Address)

# Classify an array of resources
{:ok, {:array_errors, {:resource_errors, MyApp.Item}}} =
  ValidationErrorTypes.classify_error_type({:array, Ash.Type.Struct}, items: [instance_of: MyApp.Item])

# Classify a typed map
{:ok, {:typed_container_errors, field_classifications}} =
  ValidationErrorTypes.classify_error_type(Ash.Type.Map, fields: [name: [type: :string]])

Action Input Errors

# Get error classifications for all action inputs
action = Ash.Resource.Info.action(MyApp.User, :create)
classifications = ValidationErrorTypes.classify_action_input_errors(MyApp.User, action)

# Returns: [{:name, {:primitive_errors, nil}, %Ash.Resource.Attribute{...}}, ...]

Generating Language-Specific Types

# TypeScript example
defp to_typescript_error_type(classification) do
  case classification do
    {:primitive_errors, nil} -> "string[]"
    {:array_errors, inner} -> "#{to_typescript_error_type(inner)}[]"
    {:resource_errors, module} -> "#{type_name(module)}ValidationErrors"
    {:typed_container_errors, fields} -> generate_inline_object(fields)
    {:union_errors, members} -> generate_union_errors(members)
    {:custom_type_errors, module} -> "#{module.interop_type_name()}ValidationErrors"
    {:unconstrained_map_errors, nil} -> "Record<string, any>"
  end
end

Design Notes

The classifier always unwraps NewTypes first using AshIntrospection.TypeSystem.Introspection.unwrap_new_type/2 to ensure consistent handling regardless of type wrapper depth.

Summary

Functions

Returns the list of input fields for an action with their error type classifications.

Classifies an Ash type into its corresponding validation error type category.

Returns error type classifications for fields in a typed struct/container.

Returns error type classifications for all public attributes of a resource.

Functions

classify_action_input_errors(resource, action)

Returns the list of input fields for an action with their error type classifications.

This is useful for generating validation error types for action inputs.

Parameters

  • resource - The Ash resource module
  • action - The action struct

Returns

A list of {field_name, classification, field_struct} tuples, or empty list if no inputs.

classify_error_type(type, constraints \\ [])

@spec classify_error_type(
  atom() | tuple(),
  keyword()
) ::
  {:ok,
   {:primitive_errors, nil}
   | {:array_errors, term()}
   | {:resource_errors, module()}
   | {:typed_container_errors, list()}
   | {:union_errors, list()}
   | {:custom_type_errors, module()}
   | {:unconstrained_map_errors, nil}}

Classifies an Ash type into its corresponding validation error type category.

This is the unified dispatcher that handles all type-to-error-type classifications. NewTypes are unwrapped at entry for consistent handling.

Parameters

  • type - The Ash type (atom, tuple, or module)
  • constraints - Type constraints (keyword list)

Returns

{:ok, classification} where classification is one of:

  • {:primitive_errors, nil} - Simple string errors
  • {:array_errors, inner_classification} - Array with inner error type
  • {:resource_errors, resource_module} - Resource validation errors
  • {:typed_container_errors, field_classifications} - Container with field errors
  • {:union_errors, member_classifications} - Union member errors
  • {:custom_type_errors, type_module} - Custom type with interop_type_name
  • {:unconstrained_map_errors, nil} - Generic map errors

classify_field_errors(fields)

Returns error type classifications for fields in a typed struct/container.

Parameters

  • fields - Keyword list of field definitions from type constraints

Returns

A list of {field_name, classification} tuples.

classify_resource_attribute_errors(resource)

Returns error type classifications for all public attributes of a resource.

This is useful for generating validation error types for embedded resources.

Parameters

  • resource - The Ash resource module

Returns

A list of {field_name, classification, attribute_struct} tuples.