AshIntrospection.Codegen.TypeDiscovery (AshIntrospection v0.3.0)

View Source

Language-agnostic type discovery for Ash resources and types.

This module provides the core type discovery logic that recursively traverses the type dependency tree to find all Ash resources and types that need code generation.

Configuration

Type discovery is configured via a config map:

%{
  # Required: function to get RPC resources from otp_app
  get_rpc_resources: fn otp_app -> [...] end,

  # Optional: callback name for field names (default: :interop_field_names)
  field_names_callback: :interop_field_names,

  # Optional: function to check if a module has the language extension
  has_language_extension?: fn resource -> true/false end,

  # Optional: language name for warnings (default: "Interop")
  language_name: "TypeScript"
}

Type Discovery

The discovery process handles:

  • Ash resources (both embedded and non-embedded)
  • TypedStruct modules
  • Complex nested types (unions, maps, arrays, etc.)
  • Recursive type references with cycle detection
  • Path tracking for diagnostic purposes

Path Tracking

During traversal, paths are tracked as lists of segments:

  • {:root, ResourceModule} - Starting point
  • {:attribute, :field_name} - Attribute field
  • {:calculation, :calc_name} - Calculation
  • {:aggregate, :agg_name} - Aggregate
  • {:union_member, :type_name} - Union member
  • {:array_items} - Array items
  • {:map_field, :field_name} - Map field

Summary

Functions

Builds a formatted warning message for resources missing from RPC config.

Builds a warning message for non-RPC resources referenced by RPC resources.

Discovers embedded resources from RPC resources by scanning and filtering.

Discovers all types with field constraints referenced by the given resources.

Finds all non-RPC resources that are referenced by RPC resources.

Finds all non-RPC resources referenced by RPC resources, with paths showing where they're referenced.

Finds all embedded resources referenced by a single resource.

Finds all non-embedded resources referenced by a single resource.

Finds all Ash resources referenced by a single resource's public attributes, calculations, and aggregates.

Finds resources with a language extension that are not configured in any RPC block.

Finds all Ash resources used as struct arguments in RPC actions.

Formats a path (list of path segments) into a human-readable string.

Scans a single resource to find all referenced resources.

Finds all Ash resources referenced by RPC resources.

Traverses a fields keyword list (from Map/Keyword/Tuple/custom type constraints) to find any Ash resource references in the nested field types.

Recursively traverses a type and its constraints to find all Ash resource references.

Types

config()

@type config() :: %{
  optional(:get_rpc_resources) => (atom() -> [module()]),
  optional(:field_names_callback) => atom(),
  optional(:has_language_extension?) => (module() -> boolean()),
  optional(:language_name) => String.t()
}

Functions

build_missing_config_warning(otp_app, missing_resources, config \\ %{})

Builds a formatted warning message for resources missing from RPC config.

Parameters

  • otp_app - The OTP application name
  • missing_resources - List of resource modules
  • config - Configuration map with language_name

Returns

A formatted warning string.

build_non_rpc_references_warning(referenced_non_rpc_with_paths, config \\ %{})

Builds a warning message for non-RPC resources referenced by RPC resources.

Parameters

  • referenced_non_rpc_with_paths - Map of resource => [paths]
  • config - Configuration map with language_name

Returns

A formatted warning string.

find_embedded_resources(otp_app, config)

Discovers embedded resources from RPC resources by scanning and filtering.

Parameters

  • otp_app - The OTP application name
  • config - Configuration map

Returns

A list of embedded resource modules.

find_field_constrained_types(resources, config \\ %{})

Discovers all types with field constraints referenced by the given resources.

Scans public attributes of resources to find types with field constraints (Map with fields, Keyword with fields, Tuple with fields, Struct with fields, TypedStruct) in direct types, arrays, and union types.

Parameters

  • resources - A list of Ash resource modules to scan
  • config - Configuration map

Returns

A list of unique type info maps containing:

  • :instance_of - The module (if available)
  • :constraints - The type constraints
  • :field_name_mappings - Field name mappings (if available)

find_non_rpc_referenced_resources(otp_app, config)

Finds all non-RPC resources that are referenced by RPC resources.

These are resources that appear in attributes, calculations, or aggregates of RPC resources but are not themselves configured as RPC resources.

Parameters

  • otp_app - The OTP application name
  • config - Configuration map

Returns

A list of non-RPC resource modules that are referenced by RPC resources.

find_non_rpc_referenced_resources_with_paths(otp_app, config)

Finds all non-RPC resources referenced by RPC resources, with paths showing where they're referenced.

Parameters

  • otp_app - The OTP application name
  • config - Configuration map

Returns

A map where keys are non-RPC resource modules and values are lists of formatted path strings showing where each resource is referenced.

find_referenced_embedded_resources(resource)

Finds all embedded resources referenced by a single resource.

Parameters

  • resource - An Ash resource module to scan

Returns

A list of embedded resource modules.

find_referenced_non_embedded_resources(resource)

Finds all non-embedded resources referenced by a single resource.

Parameters

  • resource - An Ash resource module to scan

Returns

A list of non-embedded resource modules.

find_referenced_resources(resource)

Finds all Ash resources referenced by a single resource's public attributes, calculations, and aggregates.

Parameters

  • resource - An Ash resource module to scan

Returns

A list of Ash resource modules referenced by the given resource.

find_resources_missing_from_rpc_config(otp_app, config)

Finds resources with a language extension that are not configured in any RPC block.

Parameters

  • otp_app - The OTP application name
  • config - Configuration map with get_rpc_resources and has_language_extension?

Returns

A list of non-embedded resource modules with the extension but not configured for RPC.

find_struct_argument_resources(actions)

Finds all Ash resources used as struct arguments in RPC actions.

Scans all RPC actions for arguments with type :struct or Ash.Type.Struct that have an instance_of constraint pointing to an Ash resource.

Parameters

  • otp_app - The OTP application name
  • config - Configuration map with get_rpc_action_info

Returns

A list of unique Ash resource modules used as struct arguments.

format_path(path)

Formats a path (list of path segments) into a human-readable string.

Parameters

  • path - A list of path segments

Returns

A formatted string representing the path.

Examples

iex> path = [{:root, MyApp.Todo}, {:attribute, :metadata}, {:union_member, :text}]
iex> TypeDiscovery.format_path(path)
"Todo -> metadata -> (union: text)"

scan_rpc_resource(resource, visited \\ MapSet.new())

Scans a single resource to find all referenced resources.

Parameters

  • resource - An Ash resource module
  • visited - A MapSet of already-visited resources (defaults to empty)

Returns

A tuple of {found_resources, updated_visited} where:

  • found_resources - List of {resource, path} tuples
  • updated_visited - Updated MapSet of visited resources

scan_rpc_resources(otp_app, config)

Finds all Ash resources referenced by RPC resources.

Recursively scans all public attributes, calculations, and aggregates of RPC resources, traversing complex types like maps with fields, unions, typed structs, etc., to find any Ash resource references.

Parameters

  • otp_app - The OTP application name to scan for domains and RPC resources
  • config - Configuration map with get_rpc_resources callback

Returns

A list of unique Ash resource modules that are referenced by RPC resources.

traverse_fields(fields)

Traverses a fields keyword list (from Map/Keyword/Tuple/custom type constraints) to find any Ash resource references in the nested field types.

Parameters

  • fields - A keyword list where keys are field names and values are field configs

Returns

A list of Ash resource modules found in the field definitions.

traverse_type(type, constraints)

Recursively traverses a type and its constraints to find all Ash resource references.

This function handles:

  • Direct Ash resource module references
  • Ash.Type.Struct with instance_of constraint
  • Ash.Type.Union with multiple type members
  • Ash.Type.Map, Ash.Type.Keyword, Ash.Type.Tuple with fields constraints
  • Custom types with fields constraints
  • Arrays of any of the above

Parameters

  • type - The type to traverse (module or type atom)
  • constraints - The constraints keyword list for the type

Returns

A list of Ash resource modules found in the type tree.