Skip to content

feat: valibot#58

Open
directormac wants to merge 16 commits intoash-project:mainfrom
directormac:valibot
Open

feat: valibot#58
directormac wants to merge 16 commits intoash-project:mainfrom
directormac:valibot

Conversation

@directormac
Copy link
Copy Markdown

Contributor checklist

Leave anything that you believe does not apply unchecked.

  • I accept the AI Policy, or AI was not used in the creation of this PR.
  • Bug fixes include regression tests
  • Chores
  • Documentation changes
  • Features include unit/acceptance tests
  • Refactoring
  • Update dependencies

@Torkan
Copy link
Copy Markdown
Collaborator

Torkan commented Mar 29, 2026

Thanks for the contribution! Valibot support is a reasonable feature request. A few notes before this can move forward:

Code duplication

The main concern is that valibot_schema_generator.ex is essentially a copy of zod_schema_generator.ex with syntax swapped. The two files share identical logic for topological sorting, field processing, argument handling, accept fields, union types, etc. — the only real difference is the output syntax (v.pipe(v.string(), v.minLength(1)) vs z.string().min(1)).

Rather than maintaining two ~780-line generators in parallel, this should extract the shared logic and parameterize the output format. For example:

# Shared behaviour that both generators implement
defmodule AshTypescript.Codegen.SchemaFormatter do
  @callback format_string(constraints :: keyword()) :: String.t()
  @callback format_integer(constraints :: keyword()) :: String.t()
  @callback format_object(fields :: list()) :: String.t()
  @callback format_optional(inner :: String.t()) :: String.t()
  @callback format_array(inner :: String.t()) :: String.t()
  @callback format_enum(values :: list()) :: String.t()
  # ... etc
end

Then the core generator handles field discovery, topological sort, action introspection, etc. once — and delegates formatting to the appropriate implementation. The Zod and Valibot modules become thin ~100-line adapters.

API correctness

map_valibot_type_with_allow_nil emits v.string().min(1) — Valibot doesn't support method chaining. This should be v.pipe(v.string(), v.minLength(1)) to match the pipe-based API used elsewhere in the file.

Doc copy-paste

  • valibot_import_path/0 doc says "custom Zod builds" — should say Valibot
  • valibot_schema_suffix/0 doc says Defaults to "Schema" (e.g., createTodoSchema) — actual default is "ValibotSchema"

Tests

Several exported test functions in shouldFail/constraintValidation.ts (e.g. testInvalidEmailNoAt, testInvalidSlugUppercase, etc.) are never called from runValibotTests.ts. Also missing Elixir-side tests for the generator.

Introduces two new modules to eliminate the ~780-line duplication between
ZodSchemaGenerator and ValibotSchemaGenerator:

- SchemaFormatter: behaviour defining ~20 output-syntax callbacks
  (wrap_optional, wrap_array, format_enum, format_string, etc.)
- SchemaCore: all shared logic delegating output to a formatter module
  (topological sort, dep discovery, field/action introspection,
   resource schema generation, regex safety helpers)
…tter adapters

Both generators now implement SchemaFormatter and delegate all shared logic
to SchemaCore, reducing each from ~780 lines to ~175 lines.

Also fixes a Valibot API correctness bug: non-empty required strings now
emit v.pipe(v.string(), v.minLength(1)) instead of the invalid
v.string().min(1) (Valibot does not support method chaining).
… runners

- Add valibot_constraints_test.exs mirroring ZodConstraintsTest with
  Valibot-specific assertions (v.pipe composition, v.optional wrapping,
  v.picklist enums, no method chaining)
- Wire up 28 previously exported-but-uncalled functions in
  runValibotTests.ts (regex, float, CiString, optional, boundary tests)
@Torkan
Copy link
Copy Markdown
Collaborator

Torkan commented Mar 29, 2026

Refactoring looks good! The SchemaFormatter behaviour + SchemaCore extraction is clean.

Two remaining items:

  1. Doc copy-paste: valibot_import_path/0 still says "custom Zod builds" and valibot_schema_suffix/0 says Defaults to "Schema" (e.g., createTodoSchema) — should reference Valibot and the actual default "ValibotSchema".

  2. In rpc/codegen.ex, the namespace export name is built with a hardcoded _valibot_schema suffix:

    valibot_schema_name = format_output_field("#{rpc_action_name}_valibot_schema")

But the actual schema constant uses the configured valibot_schema_suffix via SchemaCore. If someone sets a custom suffix, the export won't match the constant. Should use the config like the Zod export does:

suffix = AshTypescript.Rpc.valibot_schema_suffix()
valibot_schema_name = format_output_field("#{rpc_action_name}#{suffix}")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants