Skip to content

Commit fc979de

Browse files
authored
Merge pull request #548 from traversable/zod-arbitrary
docs(zod): adds `zx.fold` usage with `z.clone` example to README
2 parents c6962ab + 453fa81 commit fc979de

File tree

5 files changed

+516
-338
lines changed

5 files changed

+516
-338
lines changed

.changeset/dry-cars-know.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@traversable/zod": patch
3+
---
4+
5+
docs(zod): adds `zx.fold` usage with `z.clone` example to README (thanks @Refzlund!)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@
5757
"typescript": "catalog:",
5858
"vitest": "catalog:"
5959
},
60-
"packageManager": "pnpm@10.15.1"
60+
"packageManager": "pnpm@10.17.1"
6161
}

packages/zod/README.md

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
## Requirements
3232

33-
`@traversable/zod` has a peer dependency on [`zod`](https://zod.dev) (v4).
33+
`@traversable/zod` has a peer dependency on [`Zod`](https://zod.dev) (v4).
3434

3535
## What's it all about?
3636

@@ -434,7 +434,7 @@ deepEqual(
434434

435435
### `zx.convertCaseCodec`
436436

437-
Convert a zod schema into a codec that applies a bi-directional **key transformation** to all object schemas recursively.
437+
Convert a Zod schema into a codec that applies a bi-directional **key transformation** to all object schemas recursively.
438438

439439
#### Example
440440

@@ -516,7 +516,7 @@ console.log(
516516
> [!WARNING]
517517
> Support for this feature is **experimental** (🔬).
518518
519-
Convert a zod schema into a codec that **decodes any objects's keys to camel case** and **encode any object's keys to snake case**, recursively.
519+
Convert a Zod schema into a codec that **decodes any objects's keys to camel case** and **encode any object's keys to snake case**, recursively.
520520

521521
> [!NOTE]
522522
> This feature was implemented in terms of [`zx.convertCaseCodec`](https://github.com/traversable/schema/tree/main/packages/zod#zxconvertcasecodec).
@@ -617,7 +617,7 @@ console.log(
617617
> [!WARNING]
618618
> Support for this feature is **experimental** (🔬).
619619
620-
Convert a zod schema into a codec that **decodes any objects's keys to snake case** and **encode any object's keys to camel case**, recursively.
620+
Convert a Zod schema into a codec that **decodes any objects's keys to snake case** and **encode any object's keys to camel case**, recursively.
621621

622622
> [!NOTE]
623623
> This feature was implemented in terms of [`zx.convertCaseCodec`](https://github.com/traversable/schema/tree/main/packages/zod#zxconvertcasecodec).
@@ -789,7 +789,7 @@ console.log(zx.toString(ex_03))
789789

790790
### `zx.fromJson.writeable`
791791

792-
Convert a blob of JSON data into a _stringified_ zod schema that represents its greatest lower bound.
792+
Convert a blob of JSON data into a _stringified_ Zod schema that represents its greatest lower bound.
793793

794794
#### Example
795795

@@ -867,7 +867,7 @@ console.log(zx.deepPartial.writeable(MySchema))
867867

868868
### `zx.defaultValue`
869869

870-
`zx.defaultValues` converts a zod schema into a "default value' that respects the structure of the schema.
870+
`zx.defaultValues` converts a Zod schema into a "default value' that respects the structure of the schema.
871871

872872
A common use case for `zx.defaultValue` is creating default values for forms.
873873

@@ -916,7 +916,7 @@ console.log(
916916

917917
### `zx.toString`
918918

919-
Convert a zod schema into a string that constructs the same zod schema.
919+
Convert a Zod schema into a string that constructs the same zod schema.
920920

921921
Useful for writing/debugging tests that involve randomly generated schemas.
922922

@@ -950,7 +950,7 @@ console.log(
950950

951951
### `zx.toType`
952952

953-
Convert a zod schema into a string that represents its type.
953+
Convert a Zod schema into a string that represents its type.
954954

955955
To preserve JSDoc annotations for object properties, pass `preserveJsDocs: true` in the options object.
956956
If the property's metadata includes an `example` property, the example will be escaped and included
@@ -1564,7 +1564,7 @@ console.log(zx.deepNonStrict.writeable(MySchema))
15641564

15651565
### `zx.typeof`
15661566

1567-
`zx.typeof` returns the "type" (or _tag_) of a zod schema.
1567+
`zx.typeof` returns the "type" (or _tag_) of a Zod schema.
15681568

15691569
#### Example
15701570

@@ -1577,7 +1577,7 @@ console.log(zx.typeof(z.string())) // => "string"
15771577

15781578
### `zx.tagged`
15791579

1580-
`zx.tagged` lets you construct a type-guard that identifies the type of zod schema you have.
1580+
`zx.tagged` lets you construct a type-guard that identifies the type of Zod schema you have.
15811581

15821582
#### Example
15831583

@@ -1891,15 +1891,59 @@ console.log(ex_03) // => { a: [{ b: [0, 1], c: '' }, { b: [1, 2], c: '' }] }
18911891
> [!NOTE]
18921892
> `zx.fold` is an advanced API.
18931893
1894-
Use `zx.fold` to define a recursive traversal of a zod schema. Useful when building a schema rewriter.
1894+
Use `zx.fold` to define a recursive traversal of a Zod schema. Useful when building a schema rewriter.
18951895

18961896
`zx.fold` is a powertool. Most of `@traversable/zod` uses `zx.fold` under the hood.
18971897

1898-
Compared to the rest of the library, it's fairly "low-level", so unless you're doing something pretty advanced you probably won't need to use it directly.
1898+
Compared to the rest of the library, it's fairly "low-level", so unless you're doing something more advanced you probably won't need to use it directly.
18991899

1900-
#### Example
1900+
#### Examples
1901+
1902+
1. Example: Custom schema rewriter
1903+
1904+
Let's write a schema rewriter that takes an arbitrary Zod schema, and applies a custom transformation to only `z.string` schemas. For this contrived example, we'll be converting string values to uppercase.
1905+
1906+
> [!NOTE]
1907+
>
1908+
> You can play with this example on [StackBlitz](https://stackblitz.com/edit/traversable-zod-fold-example?file=test%2Fexample.test.ts&initialPath=__vitest__/)
1909+
1910+
```typescript
1911+
import * as z from 'zod'
1912+
import { zx } from '@traversable/zod'
1913+
1914+
function rewriter<T extends z.ZodType>(type: T): T
1915+
function rewriter<T>(type: z.ZodType<T>) {
1916+
return fold<z.ZodType>((x) => {
1917+
switch (true) {
1918+
case zx.tagged('string')(x): return x.transform((v) => v.toUpperCase())
1919+
default: return z.clone(x as z.ZodType, x._zod.def as z.core.$ZodTypeDef)
1920+
}
1921+
})(type)
1922+
}
1923+
1924+
const Ex01 = rewriter(z.uuid())
1925+
// ^? const Ex01: z.ZodUUID
1926+
1927+
console.log(Ex01.parse('fdbe3218-bba3-4cf9-95d6-0a0a3770fb64'))
1928+
// => "FDBE3218-BBA3-4CF9-95D6-0A0A3770FB64"
1929+
1930+
const Ex02 = rewriter(z.object({ id: z.uuid() }))
1931+
// ^? const Ex02: z.ZodObject<{ id: z.ZodUUID }>
1932+
1933+
console.log(Ex02.parse({ id: '012f33de-023b-414e-a0a8-0ff9e1e53545' }))
1934+
// => { "id": "012F33DE-023B-414E-A0A8-0FF9E1E53545" }
1935+
```
1936+
1937+
> [!NOTE]
1938+
>
1939+
> Notice the use of `z.clone`: this is only necessary when your target is __also__ a Zod schema. This is to ensure that none of the schema's class properties are lost in the traversal.
1940+
1941+
Thanks to [@Refzlund](https://github.com/Refzlund) for suggesting that we add this example to the docs!
1942+
1943+
1944+
2. Example: Mock data generator
19011945

1902-
Let's write a function that takes an arbitrary zod schema, and generates mock data that satisfies the schema (a.k.a. a "faker").
1946+
Let's write a function that takes an arbitrary Zod schema, and generates mock data that satisfies the schema (a.k.a. a "faker").
19031947

19041948
> [!NOTE]
19051949
> You can play with this example on [StackBlitz](https://stackblitz.com/edit/traversable-zod-faker-example?file=test%2Ffake.test.ts,src%2Ffake.ts&initialPath=__vitest__/)

0 commit comments

Comments
 (0)