@umpire/zod 0.1.0-alpha.6 → 0.1.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +100 -0
  2. package/package.json +3 -3
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # @umpire/zod
2
+
3
+ Availability-aware Zod validation for forms powered by [@umpire/core](https://www.npmjs.com/package/@umpire/core). Disabled fields produce no validation errors. Required/optional follows Umpire's availability map.
4
+
5
+ [Docs](https://sdougbrown.github.io/umpire/examples/signup/) · [Quick Start](https://sdougbrown.github.io/umpire/learn/)
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @umpire/core @umpire/zod zod
11
+ ```
12
+
13
+ `zod` is a peer dependency — bring your own version (v3 or v4).
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ import { z } from 'zod'
19
+ import { umpire, enabledWhen, requires } from '@umpire/core'
20
+ import { activeSchema, activeErrors, zodErrors } from '@umpire/zod'
21
+
22
+ // 1. Define availability rules
23
+ const ump = umpire({
24
+ fields: {
25
+ email: { required: true, isEmpty: (v) => !v },
26
+ companyName: { required: true, isEmpty: (v) => !v },
27
+ },
28
+ rules: [
29
+ enabledWhen('companyName', (_v, c) => c.plan === 'business', {
30
+ reason: 'business plan required',
31
+ }),
32
+ ],
33
+ })
34
+
35
+ // 2. Define per-field Zod schemas
36
+ const fieldSchemas = {
37
+ email: z.string().email('Enter a valid email'),
38
+ companyName: z.string().min(1, 'Company name is required'),
39
+ }
40
+
41
+ // 3. Compose at render time
42
+ const availability = ump.check(values, { plan })
43
+
44
+ const schema = activeSchema(availability, fieldSchemas, z)
45
+ const result = schema.safeParse(values)
46
+
47
+ if (!result.success) {
48
+ const errors = activeErrors(availability, zodErrors(result.error))
49
+ // errors.email → 'Enter a valid email' (only if email is enabled)
50
+ // errors.companyName → undefined (disabled on personal plan)
51
+ }
52
+ ```
53
+
54
+ ## API
55
+
56
+ ### `activeSchema(availability, schemas, z)`
57
+
58
+ Builds a `z.object()` from the availability map:
59
+ - **Disabled fields** are excluded entirely
60
+ - **Enabled + required** fields use the base schema
61
+ - **Enabled + optional** fields get `.optional()`
62
+
63
+ Pass per-field schemas directly, or use `formSchema.shape` to extract from an existing `z.object()`.
64
+
65
+ Throws if you accidentally pass a `z.object()` instead of its `.shape` — the error message tells you what to do.
66
+
67
+ ### `activeErrors(availability, errors)`
68
+
69
+ Filters normalized field errors to only include enabled fields. Returns `Partial<Record<field, message>>`.
70
+
71
+ ### `zodErrors(error)`
72
+
73
+ Normalizes a Zod error's `issues` array into `{ field, message }[]` pairs for use with `activeErrors`.
74
+
75
+ ## The Render Loop
76
+
77
+ The payoff — one loop renders every field regardless of availability, validation, or fouls:
78
+
79
+ ```tsx
80
+ {fields.map((field) => {
81
+ const av = availability[field]
82
+ const error = validationErrors[field]
83
+
84
+ return (
85
+ <div className={av.enabled ? '' : 'disabled'}>
86
+ <input disabled={!av.enabled} value={values[field]} />
87
+ {!av.enabled && <span>{av.reason}</span>}
88
+ {av.enabled && error && <span className="error">{error}</span>}
89
+ </div>
90
+ )
91
+ })}
92
+ ```
93
+
94
+ No per-field branching. No `if (field === 'companyName' && plan === 'business')`. The rules and schemas declare everything upfront. The render loop just reads.
95
+
96
+ ## Docs
97
+
98
+ - [Signup Form + Zod demo](https://sdougbrown.github.io/umpire/examples/signup/) — live interactive example
99
+ - [Composing with Validation](https://sdougbrown.github.io/umpire/concepts/validation/) — patterns and boundary guide
100
+ - [Quick Start](https://sdougbrown.github.io/umpire/learn/) — learn each rule primitive
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umpire/zod",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.1.0-alpha.7",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,7 +21,7 @@
21
21
  ".claude"
22
22
  ],
23
23
  "dependencies": {
24
- "@umpire/core": "workspace:^"
24
+ "@umpire/core": "^0.1.0-alpha.7"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "zod": "^3.0.0 || ^4.0.0"
@@ -37,4 +37,4 @@
37
37
  "devDependencies": {
38
38
  "zod": "^3.23.8"
39
39
  }
40
- }
40
+ }