Discovers all types that need TypeScript definitions generated.
This module serves as the central type discovery system for the code generator. It recursively traverses the type dependency tree starting from RPC-configured resources to find all Ash resources and TypedStruct modules that need TypeScript type definitions.
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
Main Functions
scan_rpc_resources/1- Finds all Ash resources referenced by RPC resourcesfind_embedded_resources/1- Filters for embedded resources onlyget_rpc_resources/1- Gets RPC-configured resources from domains
Validation & Warnings
find_non_rpc_referenced_resources/1- Finds non-RPC resources referenced by RPC resourcesfind_non_rpc_referenced_resources_with_paths/1- Same as above but includes reference pathsfind_resources_missing_from_rpc_config/1- Finds resources with extension but not configuredbuild_rpc_warnings/1- Builds formatted warning message for misconfigured resources
Path Tracking
During traversal, paths are tracked as lists of segments like:
{: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
Examples
# Get non-RPC resources with paths showing where they're referenced
TypeDiscovery.find_non_rpc_referenced_resources_with_paths(:my_app)
# => %{
# MyApp.InternalResource => [
# "Todo -> metadata -> TodoMetadata -> internal",
# "User -> profile_data"
# ]
# }
# Build and output warnings for misconfigured resources
case TypeDiscovery.build_rpc_warnings(:my_app) do
nil -> :ok
message -> IO.warn(message)
end
Summary
Functions
Builds a formatted warning message for resources that may be misconfigured.
Discovers embedded resources from RPC resources by scanning and filtering.
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 Ash resources referenced by a single resource's public attributes, calculations, and aggregates.
Finds resources with the AshTypescript.Resource extension that are not configured in any typescript_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.
Gets all RPC resources configured in the given OTP application.
Scans a single RPC 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.
Functions
Builds a formatted warning message for resources that may be misconfigured.
Returns a formatted warning string if any issues are found based on configuration settings, or nil if everything is configured correctly.
Checks (based on configuration):
- Resources with AshTypescript.Resource extension but not in any typescript_rpc block
(if
AshTypescript.warn_on_missing_rpc_config?()is true) - Non-RPC resources that are referenced by RPC resources
(if
AshTypescript.warn_on_non_rpc_references?()is true)
Parameters
otp_app- The OTP application name
Returns
A formatted warning string, or nil if no warnings are needed.
Examples
iex> case TypeDiscovery.build_rpc_warnings(:my_app) do
...> nil -> :ok
...> message -> IO.warn(message)
...> end
Discovers embedded resources from RPC resources by scanning and filtering.
Returns a list of unique embedded resource modules referenced by RPC resources.
Parameters
otp_app- The OTP application name
Returns
A list of embedded resource modules.
Examples
iex> TypeDiscovery.find_embedded_resources(:my_app)
[MyApp.TodoMetadata, MyApp.TodoContent]
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
Returns
A list of non-RPC resource modules that are referenced by RPC resources.
Examples
iex> TypeDiscovery.find_non_rpc_referenced_resources(:my_app)
[MyApp.InternalResource, MyApp.Helper]
Finds all non-RPC resources referenced by RPC resources, with paths showing where they're referenced.
Parameters
otp_app- The OTP application name
Returns
A map where keys are non-RPC resource modules and values are lists of formatted path strings showing where each resource is referenced.
Examples
iex> TypeDiscovery.find_non_rpc_referenced_resources_with_paths(:my_app)
%{
MyApp.InternalResource => [
"Todo -> metadata -> TodoMetadata -> internal",
"User -> profile_data"
]
}
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.
Finds resources with the AshTypescript.Resource extension that are not configured in any typescript_rpc block.
Parameters
otp_app- The OTP application name
Returns
A list of non-embedded resource modules with the extension but not configured for RPC.
Examples
iex> TypeDiscovery.find_resources_missing_from_rpc_config(:my_app)
[MyApp.ForgottenResource]
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
Returns
A list of unique Ash resource modules used as struct arguments in RPC actions.
Examples
iex> TypeDiscovery.find_struct_argument_resources(:my_app)
[MyApp.TimeSlot, MyApp.Appointment]
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)"
Gets all RPC resources configured in the given OTP application.
Parameters
otp_app- The OTP application name
Returns
A list of unique resource modules that are configured as RPC resources in any domain.
Scans a single RPC resource to find all referenced resources.
Parameters
resource- An Ash resource modulevisited- A MapSet of already-visited resources (defaults to empty)
Returns
A tuple of {found_resources, updated_visited} where:
found_resources- List of{resource, path}tuplesupdated_visited- Updated MapSet of visited resources
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
Returns
A list of unique Ash resource modules that are referenced by RPC resources. This includes both embedded and non-embedded resources, as well as the RPC resources themselves if they self-reference. The caller can filter this list based on their needs.
Examples
iex> all_resources = AshTypescript.Codegen.TypeDiscovery.scan_rpc_resources(:my_app)
[MyApp.Todo, MyApp.User, MyApp.Organization, MyApp.TodoMetadata]
iex> # Filter for non-RPC resources
iex> rpc_resources = AshTypescript.Codegen.TypeDiscovery.get_rpc_resources(:my_app)
iex> non_rpc = Enum.reject(all_resources, &(&1 in rpc_resources))
iex> # Filter for embedded resources only
iex> embedded = Enum.filter(all_resources, &Ash.Resource.Info.embedded?/1)
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.
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.