Skip to content

Commit ec3a7a3

Browse files
authored
Support multiple validator options (Zod, Valibot, and ArkType) (#39)
1 parent 872b25e commit ec3a7a3

File tree

49 files changed

+5835
-1875
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+5835
-1875
lines changed

.changeset/arktype-nullish-fix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tangrams": patch
3+
---
4+
5+
Fix ArkType emitter to generate nullish optional fields matching Zod/Valibot behavior
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"tangrams": minor
3+
---
4+
5+
Add multi-validator support with Zod, Valibot, and ArkType
6+
7+
- Add `validator` config option to choose between `"zod"` (default), `"valibot"`, or `"arktype"` for schema generation
8+
- Implement IR (Intermediate Representation) architecture that decouples spec parsing from code generation
9+
- Add dedicated emitters for each validator library with proper syntax and type inference
10+
- All three validators implement Standard Schema, ensuring compatibility with TanStack Form
11+
- Add `valibot` and `arktype` as optional peer dependencies
12+
- Update `buildQuery` function type to accept `null` values for nullish optional fields
13+
- Update documentation with validator configuration examples
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"tangrams": patch
3+
---
4+
5+
Fix validator schema generation issues discovered through runtime validation testing
6+
7+
- Fix Valibot datetime format to use `v.pipe(v.string(), v.isoTimestamp())` instead of `v.isoDateTime()` for proper ISO 8601 validation with seconds and timezone
8+
- Fix property name double-quoting where names with special characters (e.g., `special-name`) were incorrectly quoted twice in generated schemas

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ tangrams is a comprehensive code generation tool for the TanStack ecosystem. It
1616
## Features
1717

1818
- **TanStack Query** - Generate type-safe `queryOptions` and `mutationOptions`
19-
- **TanStack Form** - Generate type-safe `formOptions` with Zod validation schemas
19+
- **TanStack Form** - Generate type-safe `formOptions` with validation schemas
2020
- **TanStack DB** - Generate `queryCollectionOptions` with auto-detected CRUD operations
2121
- **Standalone Functions** - Generate standalone async fetch functions
2222
- **TanStack Pacer** - Generate rate-limited operation wrappers _(coming soon)_
@@ -45,13 +45,18 @@ Install dependencies based on what you're generating:
4545

4646
```bash
4747
# TanStack Query (generates includes "query")
48-
bun add @tanstack/react-query zod
48+
bun add @tanstack/react-query
4949

5050
# TanStack Form (generates includes "form")
51-
bun add @tanstack/react-form zod
51+
bun add @tanstack/react-form
5252

5353
# TanStack DB (generates includes "db")
54-
bun add @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query zod
54+
bun add @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query
55+
56+
# Validation library (choose one - zod is the default)
57+
bun add zod # Default validator
58+
# bun add valibot # Lightweight alternative
59+
# bun add arktype # Type-first validation
5560

5661
# GraphQL sources
5762
bun add graphql-request
@@ -112,7 +117,7 @@ For comprehensive documentation, configuration reference, and usage examples, vi
112117

113118
- **[Getting Started](https://tangrams.dev/docs)** - Installation, configuration reference, and all available options
114119
- **[TanStack Query](https://tangrams.dev/docs/tanstack-query)** - Generate `queryOptions` and `mutationOptions`
115-
- **[TanStack Form](https://tangrams.dev/docs/tanstack-form)** - Generate `formOptions` with Zod validation
120+
- **[TanStack Form](https://tangrams.dev/docs/tanstack-form)** - Generate `formOptions` with schema validation
116121
- **[TanStack DB](https://tangrams.dev/docs/tanstack-db)** - Generate collections with local-first data sync
117122

118123
## CLI Reference

apps/docs/content/docs/index.mdx

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Tangrams generates code that integrates seamlessly with the TanStack ecosystem:
1717
|-------|-------------------|-----------|
1818
| **Query Options** | `queryOptions()` with typed variables and responses | `useQuery`, `useSuspenseQuery` |
1919
| **Mutation Options** | `mutationOptions()` with typed inputs | `useMutation` |
20-
| **Form Options** | `formOptions()` with Zod validators | `useForm` |
20+
| **Form Options** | `formOptions()` with schema validation | `useForm` |
2121
| **DB Collections** | Collection options with persistence handlers | TanStack DB |
2222

2323
## Quick Start
@@ -95,6 +95,11 @@ export default defineConfig({
9595
// Output directory for all generated files (default: "./src/generated")
9696
output: "./src/generated",
9797

98+
// Validation library for generated schemas (default: "zod")
99+
// Supported: "zod", "valibot", "arktype"
100+
// All three implement Standard Schema for TanStack Form compatibility
101+
validator: "zod",
102+
98103
// Array of data sources to generate from
99104
sources: [
100105
// ===================
@@ -225,8 +230,61 @@ export default defineConfig({
225230
| Option | Type | Default | Description |
226231
|--------|------|---------|-------------|
227232
| `output` | `string` | `"./src/generated"` | Output directory for all generated files |
233+
| `validator` | `"zod" \| "valibot" \| "arktype"` | `"zod"` | Validation library for generated schemas |
228234
| `sources` | `SourceConfig[]` | (required) | Array of data sources (minimum 1 required) |
229235

236+
### Validator Libraries
237+
238+
Tangrams supports three validation libraries that all implement [Standard Schema](https://github.com/standard-schema/standard-schema):
239+
240+
| Library | Import | Description |
241+
|---------|--------|-------------|
242+
| **Zod** | `zod` | The default. Full-featured schema validation with great TypeScript inference. |
243+
| **Valibot** | `valibot` | Lightweight alternative with modular design and smaller bundle size. |
244+
| **ArkType** | `arktype` | Type-first validation with runtime safety and excellent TypeScript integration. |
245+
246+
All three libraries work seamlessly with TanStack Form since they implement the Standard Schema protocol. Choose based on your preferences for bundle size, API style, or existing usage in your project.
247+
248+
```typescript
249+
// Use Zod (default)
250+
export default defineConfig({
251+
validator: "zod",
252+
sources: [/* ... */],
253+
})
254+
255+
// Use Valibot for smaller bundles
256+
export default defineConfig({
257+
validator: "valibot",
258+
sources: [/* ... */],
259+
})
260+
261+
// Use ArkType for type-first validation
262+
export default defineConfig({
263+
validator: "arktype",
264+
sources: [/* ... */],
265+
})
266+
```
267+
268+
Install your chosen validator as a peer dependency:
269+
270+
<Tabs items={['Zod', 'Valibot', 'ArkType']}>
271+
<Tab value="Zod">
272+
```bash
273+
bun add zod
274+
```
275+
</Tab>
276+
<Tab value="Valibot">
277+
```bash
278+
bun add valibot
279+
```
280+
</Tab>
281+
<Tab value="ArkType">
282+
```bash
283+
bun add arktype
284+
```
285+
</Tab>
286+
</Tabs>
287+
230288
### GraphQL Source Options
231289

232290
| Option | Type | Required | Description |
@@ -275,7 +333,7 @@ The `generates` array specifies which TanStack artifacts to generate:
275333
| Value | Description | Dependencies |
276334
|-------|-------------|--------------|
277335
| `"query"` | TanStack Query (`queryOptions`, `mutationOptions`) | None |
278-
| `"form"` | TanStack Form (`formOptions` with Zod validation) | None |
336+
| `"form"` | TanStack Form (`formOptions` with schema validation) | None |
279337
| `"db"` | TanStack DB (`queryCollectionOptions`) | Auto-enables `"query"` |
280338

281339
**Examples:**
@@ -395,7 +453,7 @@ Generated files are organized by source name:
395453
src/generated/
396454
└── <source-name>/
397455
├── client.ts # API client (GraphQL or REST)
398-
├── schema.ts # Zod schemas + TypeScript types
456+
├── schema.ts # Validation schemas + TypeScript types
399457
├── functions.ts # Standalone fetch functions
400458
├── query/
401459
│ └── operations.ts # queryOptions, mutationOptions
@@ -442,5 +500,5 @@ When using `--watch`, Tangrams watches your config file, GraphQL documents, and
442500
Choose your TanStack library to get started:
443501

444502
- [TanStack Query](/docs/tanstack-query) - Generate `queryOptions` and `mutationOptions`
445-
- [TanStack Form](/docs/tanstack-form) - Generate `formOptions` with Zod validation
503+
- [TanStack Form](/docs/tanstack-form) - Generate `formOptions` with schema validation
446504
- [TanStack DB](/docs/tanstack-db) - Generate collections with local-first data sync

apps/docs/content/docs/tanstack-db.mdx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,44 @@ Tangrams generates TanStack DB collection options that provide local-first data
1111

1212
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
1313

14+
### Core
15+
1416
<Tabs items={['bun', 'npm', 'pnpm']}>
1517
<Tab value="bun">
1618
```bash
17-
bun add @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query zod
19+
bun add @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query
1820
```
1921
</Tab>
2022
<Tab value="npm">
2123
```bash
22-
npm install @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query zod
24+
npm install @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query
2325
```
2426
</Tab>
2527
<Tab value="pnpm">
2628
```bash
27-
pnpm add @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query zod
29+
pnpm add @tanstack/react-db @tanstack/query-db-collection @tanstack/react-query
30+
```
31+
</Tab>
32+
</Tabs>
33+
34+
### Validation Library
35+
36+
Install your chosen validator (Zod is the default). See [Validator Libraries](/docs#validator-libraries) for details.
37+
38+
<Tabs items={['Zod', 'Valibot', 'ArkType']}>
39+
<Tab value="Zod">
40+
```bash
41+
bun add zod
42+
```
43+
</Tab>
44+
<Tab value="Valibot">
45+
```bash
46+
bun add valibot
47+
```
48+
</Tab>
49+
<Tab value="ArkType">
50+
```bash
51+
bun add arktype
2852
```
2953
</Tab>
3054
</Tabs>
@@ -162,7 +186,7 @@ bunx tangrams generate
162186
src/generated/
163187
└── <source>/
164188
├── client.ts # API client (shared)
165-
├── schema.ts # Zod schemas + TypeScript types (inferred via z.infer)
189+
├── schema.ts # Validation schemas + TypeScript types
166190
├── functions.ts # Standalone fetch functions (auto-generated)
167191
├── query/
168192
│ └── operations.ts # queryOptions and mutationOptions

apps/docs/content/docs/tanstack-form.mdx

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,56 @@
11
---
22
title: TanStack Form
3-
description: Generate formOptions for TanStack Form with Zod validation.
3+
description: Generate formOptions for TanStack Form with schema validation.
44
---
55

66
# TanStack Form
77

8-
Tangrams generates `formOptions` with Zod validators from your mutations. These snap right into TanStack Form's `useForm` hook.
8+
Tangrams generates `formOptions` with validation schemas from your mutations. These snap right into TanStack Form's `useForm` hook.
9+
10+
By default, Tangrams uses Zod for validation, but you can also use [Valibot or ArkType](/docs#validator-libraries) by setting the `validator` option in your config.
911

1012
## Peer Dependencies
1113

1214
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
1315

16+
### Core
17+
1418
<Tabs items={['bun', 'npm', 'pnpm']}>
1519
<Tab value="bun">
1620
```bash
17-
bun add @tanstack/react-form zod
21+
bun add @tanstack/react-form
1822
```
1923
</Tab>
2024
<Tab value="npm">
2125
```bash
22-
npm install @tanstack/react-form zod
26+
npm install @tanstack/react-form
2327
```
2428
</Tab>
2529
<Tab value="pnpm">
2630
```bash
27-
pnpm add @tanstack/react-form zod
31+
pnpm add @tanstack/react-form
32+
```
33+
</Tab>
34+
</Tabs>
35+
36+
### Validation Library
37+
38+
Install your chosen validator (Zod is the default):
39+
40+
<Tabs items={['Zod', 'Valibot', 'ArkType']}>
41+
<Tab value="Zod">
42+
```bash
43+
bun add zod
44+
```
45+
</Tab>
46+
<Tab value="Valibot">
47+
```bash
48+
bun add valibot
49+
```
50+
</Tab>
51+
<Tab value="ArkType">
52+
```bash
53+
bun add arktype
2854
```
2955
</Tab>
3056
</Tabs>
@@ -109,7 +135,7 @@ bunx tangrams generate
109135
```
110136
src/generated/
111137
└── <source>/
112-
├── schema.ts # Zod schemas for request bodies
138+
├── schema.ts # Validation schemas for request bodies
113139
└── form/
114140
└── forms.ts # formOptions exports
115141
```
@@ -119,7 +145,7 @@ src/generated/
119145
For each mutation with a request body, Tangrams generates a `formOptions` export with:
120146

121147
- **`defaultValues`** - Empty object with type assertion for type safety
122-
- **`validators`** - The Zod schema for validation (configurable timing)
148+
- **`validators`** - The validation schema (configurable timing)
123149

124150
**Example `forms.ts`:**
125151

apps/docs/content/docs/tanstack-query.mdx

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,39 @@ Install the required dependencies based on your data source:
1818
<Tabs items={['bun', 'npm', 'pnpm']}>
1919
<Tab value="bun">
2020
```bash
21-
bun add @tanstack/react-query zod
21+
bun add @tanstack/react-query
2222
```
2323
</Tab>
2424
<Tab value="npm">
2525
```bash
26-
npm install @tanstack/react-query zod
26+
npm install @tanstack/react-query
2727
```
2828
</Tab>
2929
<Tab value="pnpm">
3030
```bash
31-
pnpm add @tanstack/react-query zod
31+
pnpm add @tanstack/react-query
32+
```
33+
</Tab>
34+
</Tabs>
35+
36+
### Validation Library
37+
38+
Install your chosen validator (Zod is the default). See [Validator Libraries](/docs#validator-libraries) for details.
39+
40+
<Tabs items={['Zod', 'Valibot', 'ArkType']}>
41+
<Tab value="Zod">
42+
```bash
43+
bun add zod
44+
```
45+
</Tab>
46+
<Tab value="Valibot">
47+
```bash
48+
bun add valibot
49+
```
50+
</Tab>
51+
<Tab value="ArkType">
52+
```bash
53+
bun add arktype
3254
```
3355
</Tab>
3456
</Tabs>
@@ -191,7 +213,7 @@ bunx tangrams generate
191213
src/generated/
192214
└── <source>/
193215
├── client.ts # API client (shared)
194-
├── schema.ts # Zod schemas + TypeScript types (inferred via z.infer)
216+
├── schema.ts # Validation schemas + TypeScript types
195217
├── functions.ts # Standalone fetch functions (auto-generated)
196218
└── query/
197219
└── operations.ts # queryOptions and mutationOptions
@@ -215,7 +237,7 @@ export const getClient = async () => {
215237
}
216238
```
217239

218-
**`schema.ts`** - Zod schemas and TypeScript types from your schema and operations:
240+
**`schema.ts`** - Validation schemas and TypeScript types from your schema and operations (shown with Zod, the default):
219241

220242
```typescript
221243
import * as z from "zod"
@@ -261,7 +283,7 @@ export const createUserMutationOptions = () =>
261283

262284
### OpenAPI Output
263285

264-
**`<source>/schema.ts`** - Zod schemas and inferred TypeScript types:
286+
**`<source>/schema.ts`** - Validation schemas and inferred TypeScript types (shown with Zod, the default):
265287

266288
```typescript
267289
import * as z from "zod"
@@ -303,7 +325,7 @@ export const getClient = async () => {
303325
}
304326
```
305327

306-
**`operations.ts`** - Query and mutation options with Zod validation:
328+
**`operations.ts`** - Query and mutation options with schema validation:
307329

308330
```typescript
309331
export const listUsersQueryOptions = (params?: ListUsersParams) =>

0 commit comments

Comments
 (0)