@conform-to/zod
Advanced tools
Comparing version 0.1.1 to 0.2.0
@@ -1,4 +0,4 @@ | ||
import { type Schema, type FormResult } from '@conform-to/dom'; | ||
import { type Schema, type Submission } from '@conform-to/dom'; | ||
import * as z from 'zod'; | ||
export declare function parse<T>(payload: FormData | URLSearchParams, schema: z.ZodType<T>): FormResult<T>; | ||
export declare function parse<T extends Record<string, unknown>>(payload: FormData | URLSearchParams, schema: z.ZodType<T>): Submission<T>; | ||
export declare function resolve<T extends Record<string, any>>(schema: z.ZodType<T>): Schema<T>; |
120
index.js
@@ -5,2 +5,3 @@ 'use strict'; | ||
var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js'); | ||
var dom = require('@conform-to/dom'); | ||
@@ -30,13 +31,21 @@ var z = require('zod'); | ||
function inferConstraint(schema) { | ||
var def = schema; | ||
var constraint = { | ||
required: !def.isOptional() | ||
required: true | ||
}; | ||
if (schema instanceof z__namespace.ZodArray) { | ||
constraint.multiple = true; | ||
def = schema.element; | ||
} | ||
if (schema instanceof z__namespace.ZodString) { | ||
if (schema instanceof z__namespace.ZodEffects) { | ||
return inferConstraint(schema.innerType()); | ||
} else if (schema instanceof z__namespace.ZodOptional) { | ||
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, inferConstraint(schema.unwrap())), {}, { | ||
required: false | ||
}); | ||
} else if (schema instanceof z__namespace.ZodDefault) { | ||
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, inferConstraint(schema.removeDefault())), {}, { | ||
required: false | ||
}); | ||
} else if (schema instanceof z__namespace.ZodArray) { | ||
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, inferConstraint(schema.element)), {}, { | ||
multiple: true | ||
}); | ||
} else if (schema instanceof z__namespace.ZodString) { | ||
for (var check of schema._def.checks) { | ||
@@ -82,11 +91,7 @@ switch (check.kind) { | ||
break; | ||
case 'multipleOf': | ||
if (!constraint.step) { | ||
constraint.step = _check.value; | ||
} | ||
break; | ||
} | ||
} | ||
} else if (schema instanceof z__namespace.ZodEnum) { | ||
constraint.pattern = schema.options.map(option => // To escape unsafe characters on regex | ||
option.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')).join('|'); | ||
} | ||
@@ -100,15 +105,15 @@ | ||
return schema.shape; | ||
} | ||
if (schema instanceof z__namespace.ZodEffects) { | ||
} else if (schema instanceof z__namespace.ZodEffects) { | ||
return getSchemaShape(schema.innerType()); | ||
} else if (schema instanceof z__namespace.ZodOptional) { | ||
return getSchemaShape(schema.unwrap()); | ||
} | ||
throw new Error('Unknown schema provided; The schema could be either ZodObject or ZodEffects only'); | ||
return null; | ||
} | ||
function createParser(schema) { | ||
if (schema instanceof z__namespace.ZodString || schema instanceof z__namespace.ZodEnum) { | ||
if (schema instanceof z__namespace.ZodString || schema instanceof z__namespace.ZodEnum || schema instanceof z__namespace.ZodNumber || schema instanceof z__namespace.ZodDate || schema instanceof z__namespace.ZodBoolean) { | ||
return value => { | ||
if (typeof value !== 'string' || value === '') { | ||
if (value === '') { | ||
return; | ||
@@ -119,36 +124,22 @@ } | ||
}; | ||
} else if (schema instanceof z__namespace.ZodNumber) { | ||
return value => { | ||
if (typeof value !== 'string' || value === '') { | ||
return; | ||
} | ||
} else if (schema instanceof z__namespace.ZodDefault) { | ||
var def = schema.removeDefault(); | ||
return Number(value); | ||
}; | ||
} else if (schema instanceof z__namespace.ZodDate) { | ||
return value => { | ||
if (typeof value !== 'string' || value === '') { | ||
return; | ||
} | ||
var _parse = createParser(def); | ||
return new Date(value); | ||
}; | ||
} else if (schema instanceof z__namespace.ZodBoolean) { | ||
return value => { | ||
return value === 'on'; | ||
}; | ||
return _parse; | ||
} else if (schema instanceof z__namespace.ZodOptional) { | ||
var def = schema.unwrap(); | ||
var _def = schema.unwrap(); | ||
var _parse = createParser(def); | ||
var _parse2 = createParser(_def); | ||
return _parse; | ||
return _parse2; | ||
} else if (schema instanceof z__namespace.ZodEffects) { | ||
var _def = schema.innerType(); | ||
var _def2 = schema.innerType(); | ||
var _parse2 = createParser(_def); | ||
var _parse3 = createParser(_def2); | ||
return _parse2; | ||
return _parse3; | ||
} else if (schema instanceof z__namespace.ZodArray) { | ||
var _parse3 = createParser(schema.element); | ||
var _parse4 = createParser(schema.element); | ||
@@ -160,3 +151,3 @@ return value => { | ||
return value.map(_parse3); | ||
return value.map(_parse4); | ||
}; | ||
@@ -166,5 +157,5 @@ } else if (schema instanceof z__namespace.ZodObject) { | ||
for (var [key, _def2] of Object.entries(schema.shape)) { | ||
for (var [key, _def3] of Object.entries(schema.shape)) { | ||
// @ts-expect-error | ||
shape[key] = createParser(_def2); | ||
shape[key] = createParser(_def3); | ||
} | ||
@@ -180,4 +171,4 @@ | ||
for (var [_key, _parse4] of Object.entries(shape)) { | ||
var item = _parse4(object[_key]); | ||
for (var [_key, _parse5] of Object.entries(shape)) { | ||
var item = _parse5(object[_key]); | ||
@@ -202,9 +193,12 @@ if (typeof item !== 'undefined') { | ||
var parse = createParser(schema); | ||
var formResult = dom.parse(payload); | ||
var value = parse(formResult.value); | ||
var submission = dom.parse(payload); | ||
var value = parse(submission.form.value); | ||
var result = schema.safeParse(value); | ||
if (formResult.state === 'processed') { | ||
// @ts-expect-error | ||
return formResult; | ||
if (submission.state === 'modified') { | ||
return { | ||
state: 'modified', | ||
// @ts-expect-error | ||
form: submission.form | ||
}; | ||
} | ||
@@ -215,3 +209,5 @@ | ||
state: 'accepted', | ||
value: result.data | ||
data: result.data, | ||
// @ts-expect-error | ||
form: submission.form | ||
}; | ||
@@ -222,4 +218,5 @@ } else { | ||
// @ts-expect-error | ||
value: formResult.value, | ||
error: formatError(result.error) | ||
form: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, submission.form), {}, { | ||
error: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, submission.form.error), formatError(result.error)) | ||
}) | ||
}; | ||
@@ -231,2 +228,7 @@ } | ||
var shape = getSchemaShape(schema); | ||
if (!shape) { | ||
throw new Error('Unknown schema provided; The schema must have an object shape'); | ||
} | ||
return { | ||
@@ -233,0 +235,0 @@ // @ts-expect-error |
@@ -0,1 +1,2 @@ | ||
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js'; | ||
import { parse as parse$1, transform, getName, getFieldElements } from '@conform-to/dom'; | ||
@@ -5,13 +6,21 @@ import * as z from 'zod'; | ||
function inferConstraint(schema) { | ||
var def = schema; | ||
var constraint = { | ||
required: !def.isOptional() | ||
required: true | ||
}; | ||
if (schema instanceof z.ZodArray) { | ||
constraint.multiple = true; | ||
def = schema.element; | ||
} | ||
if (schema instanceof z.ZodString) { | ||
if (schema instanceof z.ZodEffects) { | ||
return inferConstraint(schema.innerType()); | ||
} else if (schema instanceof z.ZodOptional) { | ||
return _objectSpread2(_objectSpread2({}, inferConstraint(schema.unwrap())), {}, { | ||
required: false | ||
}); | ||
} else if (schema instanceof z.ZodDefault) { | ||
return _objectSpread2(_objectSpread2({}, inferConstraint(schema.removeDefault())), {}, { | ||
required: false | ||
}); | ||
} else if (schema instanceof z.ZodArray) { | ||
return _objectSpread2(_objectSpread2({}, inferConstraint(schema.element)), {}, { | ||
multiple: true | ||
}); | ||
} else if (schema instanceof z.ZodString) { | ||
for (var check of schema._def.checks) { | ||
@@ -57,11 +66,7 @@ switch (check.kind) { | ||
break; | ||
case 'multipleOf': | ||
if (!constraint.step) { | ||
constraint.step = _check.value; | ||
} | ||
break; | ||
} | ||
} | ||
} else if (schema instanceof z.ZodEnum) { | ||
constraint.pattern = schema.options.map(option => // To escape unsafe characters on regex | ||
option.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')).join('|'); | ||
} | ||
@@ -75,15 +80,15 @@ | ||
return schema.shape; | ||
} | ||
if (schema instanceof z.ZodEffects) { | ||
} else if (schema instanceof z.ZodEffects) { | ||
return getSchemaShape(schema.innerType()); | ||
} else if (schema instanceof z.ZodOptional) { | ||
return getSchemaShape(schema.unwrap()); | ||
} | ||
throw new Error('Unknown schema provided; The schema could be either ZodObject or ZodEffects only'); | ||
return null; | ||
} | ||
function createParser(schema) { | ||
if (schema instanceof z.ZodString || schema instanceof z.ZodEnum) { | ||
if (schema instanceof z.ZodString || schema instanceof z.ZodEnum || schema instanceof z.ZodNumber || schema instanceof z.ZodDate || schema instanceof z.ZodBoolean) { | ||
return value => { | ||
if (typeof value !== 'string' || value === '') { | ||
if (value === '') { | ||
return; | ||
@@ -94,36 +99,22 @@ } | ||
}; | ||
} else if (schema instanceof z.ZodNumber) { | ||
return value => { | ||
if (typeof value !== 'string' || value === '') { | ||
return; | ||
} | ||
} else if (schema instanceof z.ZodDefault) { | ||
var def = schema.removeDefault(); | ||
return Number(value); | ||
}; | ||
} else if (schema instanceof z.ZodDate) { | ||
return value => { | ||
if (typeof value !== 'string' || value === '') { | ||
return; | ||
} | ||
var _parse = createParser(def); | ||
return new Date(value); | ||
}; | ||
} else if (schema instanceof z.ZodBoolean) { | ||
return value => { | ||
return value === 'on'; | ||
}; | ||
return _parse; | ||
} else if (schema instanceof z.ZodOptional) { | ||
var def = schema.unwrap(); | ||
var _def = schema.unwrap(); | ||
var _parse = createParser(def); | ||
var _parse2 = createParser(_def); | ||
return _parse; | ||
return _parse2; | ||
} else if (schema instanceof z.ZodEffects) { | ||
var _def = schema.innerType(); | ||
var _def2 = schema.innerType(); | ||
var _parse2 = createParser(_def); | ||
var _parse3 = createParser(_def2); | ||
return _parse2; | ||
return _parse3; | ||
} else if (schema instanceof z.ZodArray) { | ||
var _parse3 = createParser(schema.element); | ||
var _parse4 = createParser(schema.element); | ||
@@ -135,3 +126,3 @@ return value => { | ||
return value.map(_parse3); | ||
return value.map(_parse4); | ||
}; | ||
@@ -141,5 +132,5 @@ } else if (schema instanceof z.ZodObject) { | ||
for (var [key, _def2] of Object.entries(schema.shape)) { | ||
for (var [key, _def3] of Object.entries(schema.shape)) { | ||
// @ts-expect-error | ||
shape[key] = createParser(_def2); | ||
shape[key] = createParser(_def3); | ||
} | ||
@@ -155,4 +146,4 @@ | ||
for (var [_key, _parse4] of Object.entries(shape)) { | ||
var item = _parse4(object[_key]); | ||
for (var [_key, _parse5] of Object.entries(shape)) { | ||
var item = _parse5(object[_key]); | ||
@@ -177,9 +168,12 @@ if (typeof item !== 'undefined') { | ||
var parse = createParser(schema); | ||
var formResult = parse$1(payload); | ||
var value = parse(formResult.value); | ||
var submission = parse$1(payload); | ||
var value = parse(submission.form.value); | ||
var result = schema.safeParse(value); | ||
if (formResult.state === 'processed') { | ||
// @ts-expect-error | ||
return formResult; | ||
if (submission.state === 'modified') { | ||
return { | ||
state: 'modified', | ||
// @ts-expect-error | ||
form: submission.form | ||
}; | ||
} | ||
@@ -190,3 +184,5 @@ | ||
state: 'accepted', | ||
value: result.data | ||
data: result.data, | ||
// @ts-expect-error | ||
form: submission.form | ||
}; | ||
@@ -197,4 +193,5 @@ } else { | ||
// @ts-expect-error | ||
value: formResult.value, | ||
error: formatError(result.error) | ||
form: _objectSpread2(_objectSpread2({}, submission.form), {}, { | ||
error: _objectSpread2(_objectSpread2({}, submission.form.error), formatError(result.error)) | ||
}) | ||
}; | ||
@@ -206,2 +203,7 @@ } | ||
var shape = getSchemaShape(schema); | ||
if (!shape) { | ||
throw new Error('Unknown schema provided; The schema must have an object shape'); | ||
} | ||
return { | ||
@@ -208,0 +210,0 @@ // @ts-expect-error |
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"main": "index.js", | ||
@@ -18,3 +18,3 @@ "module": "module/index.js", | ||
"peerDependencies": { | ||
"@conform-to/dom": "0.1.1", | ||
"@conform-to/dom": "0.2.0", | ||
"zod": "^3.0.0" | ||
@@ -21,0 +21,0 @@ }, |
# @conform-to/zod | ||
> Schema resolver integrating [zod](https://github.com/colinhacks/zod) for end-to-end type safety | ||
> [Zod](https://github.com/colinhacks/zod) schema resolver for [conform](https://github.com/edmundhung/conform) | ||
## API Reference | ||
- [resolve](#resolve) | ||
- [parse](#parse) | ||
- [resolve](#resolve) | ||
### resolve | ||
This resolves zod schema to a conform schema: | ||
```tsx | ||
import { useFieldset } from '@conform-to/react'; | ||
import { resolve } from '@conform-to/zod'; | ||
import { z } from 'zod'; | ||
// Define the schema with zod | ||
const schema = z.object({ | ||
email: z.string(), | ||
password: z.string(), | ||
}); | ||
// When used with `@conform-to/react`: | ||
function RandomForm() { | ||
const [setupFieldset, { email, password }] = useFieldset(resolve(schema)); | ||
// ... | ||
} | ||
``` | ||
### parse | ||
### resolve | ||
The `parse` function could be used to parse the FormData on client side: | ||
```tsx | ||
const schema = z.object({ | ||
// Define the schema with zod | ||
}); | ||
form.addEventListener('submit', (e) => { | ||
e.preventDefault(); | ||
// Read the FormData from the from | ||
const formData = new FormData(e.target); | ||
// Parse the data against the zod schema | ||
const result = parse(formData, schema); | ||
console.log(result.state); | ||
// It could be accepted / rejected / processed | ||
console.log(result.value); | ||
// Parsed value (if accepted) | ||
// or Fieldset data in schema structure (if not) | ||
console.log(result.error); | ||
// Fieldset error in schema structure (if rejected) | ||
}); | ||
``` | ||
Or parse the request payload on server side (e.g. Remix): | ||
```tsx | ||
import { parse } from '@conform-to/zod'; | ||
import { z } from 'zod'; | ||
const schema = z.object({ | ||
// Define the schema with zod | ||
}); | ||
export let action = async ({ request }) => { | ||
const formData = await request.formData(); | ||
const result = parse(formData, schema); | ||
// Depends on the usecase, you can also do this: | ||
// const url = new URL(request.url) | ||
// const result = parse(url.searchParams, schema) | ||
// Return the current result if not accepted | ||
if (result.state !== 'accepted') { | ||
return json(result); | ||
} | ||
// Do something else | ||
}; | ||
export default function SomeRoute() { | ||
const result = useActionData(); | ||
// You can then use result.value / result.error | ||
// to populate inital value of each fields and | ||
// its corresponding error | ||
} | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20796
8
488
97