Skip to content

refactor: extract filter ops to generic types, unify schema output#61

Closed
directormac wants to merge 2 commits intoash-project:mainfrom
directormac:output-optimization
Closed

refactor: extract filter ops to generic types, unify schema output#61
directormac wants to merge 2 commits intoash-project:mainfrom
directormac:output-optimization

Conversation

@directormac
Copy link
Copy Markdown
Contributor

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

Summary

This PR refactors ash_typescript's code generation to prioritize Developer Experience (DX), reduce output bloat, and improve TypeScript compiler performance. We've shifted from massive inline object definitions to reusable generic templates and extracted internal metadata into clean, developer-consumable public types.

Key Changes & Results

1. Clean Public Domain Models

Before: Developers used UserResourceSchema, which included noisy internal engine fields like __type and __primitiveFields.
After: We export a pristine User type. All internal metadata is hidden via a recursive Clean<T> utility.

- export type UserResourceSchema = { __type: "Resource", id: UUID, email: string, ... };
+ type UserResourceSchema = { __type: "Resource", id: UUID, email: string, ... };
+ export type User = Clean<UserResourceSchema>;

2. Reusable Generic Filter Types

Before: Every resource field inlined its own filter operations, leading to massive duplication (e.g., repeating { eq?: string, in?: string[] } hundreds of times).
After: All filters now reference shared generic templates (StringFilter, NumberFilter<T>, BooleanFilter, etc.).
Result: Drastic reduction in generated.ts file size and faster TS compilation.

- title?: { eq?: string; in?: string[]; ... };
+ title?: StringFilter;

3. Extracted as const Enums & Field Lists

Before: Field names and enum values were inlined as static unions.
After: They are extracted into as const arrays, providing runtime utility for developers (e.g., building dynamic forms).

export const userAttributeFields = ["id", "email", "role"] as const;
export type UserResourceSchema = {
  __primitiveFields: typeof userAttributeFields[number];
  // ...
};

4. Formatter-Aware Filter Operations

Generic filter operations (e.g., notEq, greaterThanOrEqual) now dynamically respect the project's :output_field_formatter setting (camelCase, PascalCase, snake_case), ensuring total consistency across the generated API.


New Configuration Options

In config :ash_typescript:

Option Type Description
extra_structs [Module] List of Ash.TypedStruct modules to include as root-level schema types, even if not referenced by a resource.
generate_filter_schemas boolean If true, generates Zod/Valibot schemas for filter inputs (e.g., UserFilterSchema). Defaults to false.
generate_clean_types boolean Toggles the output of the "Clean" public domain models. Defaults to true.

Contributor Checklist

  • I accept the AI Policy.
  • Bug fixes include regression tests (Updated 30+ tests for new generic filter structure).
  • Chores
  • Documentation changes
  • Features include unit/acceptance tests.
  • Refactoring.
  • Update dependencies.

Verification Results

  • Elixir Tests: mix test (2207 tests passed, 0 failures).
  • TS Compilation: Verified via npm run compileGenerated, compileShouldPass, and compileShouldFail, ``. All passed.

@directormac directormac closed this Apr 2, 2026
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.

1 participant