AshTypescript.Codegen.SchemaCore (ash_typescript v0.18.1)

Copy Markdown View Source

Shared logic for schema generation across all validation library targets.

All resource introspection, topological sorting, field resolution, and structural code generation lives here. Output syntax is delegated to a module implementing AshTypescript.Codegen.SchemaFormatter.

Consumers (e.g. ZodSchemaGenerator) pass __MODULE__ as the first formatter argument to each public function.

Summary

Functions

Whether an RPC action gets an input schema at all.

Returns the exported schema constant name for an RPC action's input.

Builds a JS regex flag string from Elixir Regex opts.

Composes a single input-field schema entry: resolves the field's type through the formatter, then wraps nullable/optional.

Computes the effective minimum length for a string schema.

Generates a schema definition for an RPC action's input. Returns an empty string when the action has no input.

Generates schemas for a list of resources (embedded resources, struct args). Returns an empty string when generation is disabled or the list is empty.

Maps a type-bearing spec input to a schema string.

Wraps a schema string with wrap_nullable (innermost) and/or wrap_optional (outermost) based on the two booleans, using the given formatter.

Returns true when a regex source string is safe to emit as a JS literal.

Functions

action_has_schema?(action)

Whether an RPC action gets an input schema at all.

An action with no inputs produces no schema, so anything that advertises or re-exports a schema name must ask this first — otherwise it points consumers at an export that does not exist.

action_schema_name(formatter, rpc_action_name)

Returns the exported schema constant name for an RPC action's input.

Single source of truth for the name — used by generate_action_schema/4 (the export itself), the namespace re-export collection, and both manifests, so they cannot drift from the configured *_schema_suffix.

build_js_flags(opts)

Builds a JS regex flag string from Elixir Regex opts.

compose_input_field(formatter, formatted_name, input, nullable?, omittable?)

Composes a single input-field schema entry: resolves the field's type through the formatter, then wraps nullable/optional.

This is the one place that knows how "input argument -> schema field" works — shared by RPC action input schemas (above) and typed-controller route argument schemas (RouteRenderer), so the two surfaces cannot drift.

effective_min_length(constraints, require_non_empty)

Computes the effective minimum length for a string schema.

Shared by the Zod and Valibot formatters so the rule cannot drift: an explicit :min_length replaces the implicit non-empty minimum — but when the string is non-empty (allow_empty?: false), the minimum is floored at 1, since the server nulls "" regardless of a declared min_length: 0. Returns nil when no minimum applies.

generate_action_schema(formatter, resource, action, rpc_action_name)

Generates a schema definition for an RPC action's input. Returns an empty string when the action has no input.

generate_schema_for_resource(formatter, resource, resource_lookup \\ nil)

Generates a schema for a single resource.

generate_schemas_for_resources(formatter, resources)

Generates schemas for a list of resources (embedded resources, struct args). Returns an empty string when generation is disabled or the list is empty.

Builds an augmented resource lookup that includes any orphan resources not already present in the cached spec — letting callers pass arbitrary embedded resources (e.g., test fixtures) without pre-registering them.

get_type(formatter, type_input, context \\ nil)

Maps a type-bearing spec input to a schema string.

Accepted shapes (all %Ash.Info.Manifest.*{}):

  • %Ash.Info.Manifest.Type{} — the canonical spec form
  • %Ash.Info.Manifest.Argument{} / %Ash.Info.Manifest.Field{} — anything with a :type field carrying a %Ash.Info.Manifest.Type{}
  • Aggregate kind atoms (e.g. :count, :sum) — looked up in formatter.aggregate_types()

Callers must feed spec data. Raw Ash types (atom modules, {:array, _} tuples, %{type: SomeType, constraints: [...]} shapes) are no longer accepted; resolve via Ash.Info.Manifest.Generator.TypeResolver.resolve/2 first.

Non-empty enforcement for string types is constraint-driven: whenever the string's folded constraints carry allow_empty?: false (the Ash default), the schema gets an effective min-length 1 (unless an explicit :min_length is set) — matching server-side validation regardless of the field's nilability. Strings with allow_empty?: true stay unconstrained. This applies uniformly, including nested string fields inside typed containers.

maybe_wrap_nullable_optional(formatter, schema, nullable?, omittable?)

Wraps a schema string with wrap_nullable (innermost) and/or wrap_optional (outermost) based on the two booleans, using the given formatter.

regex_safe_for_js?(source)

Returns true when a regex source string is safe to emit as a JS literal.