@hookform/resolvers 3.1.1 → 3.2.0

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.
package/README.md CHANGED
@@ -26,18 +26,28 @@
26
26
 
27
27
  ### Supported resolvers
28
28
 
29
- - [Yup](#Yup)
30
- - [Zod](#Zod)
31
- - [Superstruct](#Superstruct)
32
- - [Joi](#Joi)
33
- - [Class Validator](#Class-Validator)
34
- - [io-ts](#io-ts)
35
- - [Nope](#Nope)
36
- - [computed-types](#computed-types)
37
- - [typanion](#typanion)
38
- - [Ajv](#Ajv)
39
- - [TypeBox](#TypeBox)
40
- - [ArkType](#ArkType)
29
+ - [Install](#install)
30
+ - [Links](#links)
31
+ - [Supported resolvers](#supported-resolvers)
32
+ - [API](#api)
33
+ - [Quickstart](#quickstart)
34
+ - [Yup](#yup)
35
+ - [Zod](#zod)
36
+ - [Superstruct](#superstruct)
37
+ - [Joi](#joi)
38
+ - [Vest](#vest)
39
+ - [Class Validator](#class-validator)
40
+ - [io-ts](#io-ts)
41
+ - [Nope](#nope)
42
+ - [computed-types](#computed-types)
43
+ - [typanion](#typanion)
44
+ - [Ajv](#ajv)
45
+ - [TypeBox](#typebox)
46
+ - [ArkType](#arktype)
47
+ - [Valibot](#valibot)
48
+ - [Backers](#backers)
49
+ - [Sponsors](#sponsors)
50
+ - [Contributors](#contributors)
41
51
 
42
52
  ## API
43
53
 
@@ -532,6 +542,40 @@ const App = () => {
532
542
  };
533
543
  ```
534
544
 
545
+ ### [Valibot](https://github.com/fabian-hiller/valibot)
546
+
547
+ The modular and type safe schema library for validating structural data
548
+
549
+ [![npm](https://img.shields.io/bundlephobia/minzip/valibot?style=for-the-badge)](https://bundlephobia.com/result?p=valibot)
550
+
551
+ ```typescript jsx
552
+ import { useForm } from 'react-hook-form';
553
+ import { valibotResolver } from '@hookform/resolvers/valibot';
554
+ import { object, string, minLength, endsWith } from 'valibot';
555
+
556
+ const schema = object({
557
+ username: string('username is required', [
558
+ minLength(3, 'Needs to be at least 3 characters'),
559
+ endsWith('cool', 'Needs to end with `cool`'),
560
+ ]),
561
+ password: string('password is required'),
562
+ });
563
+
564
+ const App = () => {
565
+ const { register, handleSubmit } = useForm({
566
+ resolver: valibotResolver(schema),
567
+ });
568
+
569
+ return (
570
+ <form onSubmit={handleSubmit((d) => console.log(d))}>
571
+ <input {...register('username')} />
572
+ <input type="password" {...register('password')} />
573
+ <input type="submit" />
574
+ </form>
575
+ );
576
+ };
577
+ ```
578
+
535
579
  ## Backers
536
580
 
537
581
  Thanks goes to all our backers! [[Become a backer](https://opencollective.com/react-hook-form#backer)].
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hookform/resolvers",
3
3
  "amdName": "hookformResolvers",
4
- "version": "3.1.1",
4
+ "version": "3.2.0",
5
5
  "description": "React Hook Form validation resolvers: Yup, Joi, Superstruct, Zod, Vest, Class Validator, io-ts, Nope, computed-types, TypeBox, arktype and Typanion",
6
6
  "main": "dist/resolvers.js",
7
7
  "module": "dist/resolvers.module.js",
@@ -93,6 +93,12 @@
93
93
  "import": "./arktype/dist/arktype.mjs",
94
94
  "require": "./arktype/dist/arktype.js"
95
95
  },
96
+ "./valibot": {
97
+ "types": "./valibot/dist/index.d.ts",
98
+ "umd": "./valibot/dist/valibot.umd.js",
99
+ "import": "./valibot/dist/valibot.mjs",
100
+ "require": "./valibot/dist/valibot.js"
101
+ },
96
102
  "./package.json": "./package.json",
97
103
  "./*": "./*"
98
104
  },
@@ -136,7 +142,10 @@
136
142
  "typebox/dist",
137
143
  "arktype/package.json",
138
144
  "arktype/src",
139
- "arktype/dist"
145
+ "arktype/dist",
146
+ "valibot/package.json",
147
+ "valibot/src",
148
+ "valibot/dist"
140
149
  ],
141
150
  "publishConfig": {
142
151
  "access": "public"
@@ -158,6 +167,7 @@
158
167
  "build:ajv": "microbundle --cwd ajv --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
159
168
  "build:typebox": "microbundle --cwd typebox --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm,@sinclair/typebox/value=value",
160
169
  "build:arktype": "microbundle --cwd arktype --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
170
+ "build:valibot": "microbundle --cwd valibot --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
161
171
  "postbuild": "node ./config/node-13-exports.js",
162
172
  "lint": "eslint . --ext .ts,.js --ignore-path .gitignore",
163
173
  "lint:types": "tsc",
@@ -238,6 +248,7 @@
238
248
  "superstruct": "^1.0.3",
239
249
  "typanion": "^3.12.1",
240
250
  "typescript": "^5.0.4",
251
+ "valibot": "^0.8.0",
241
252
  "vest": "^4.6.9",
242
253
  "vite": "^4.2.1",
243
254
  "vite-tsconfig-paths": "^4.2.0",
@@ -0,0 +1,2 @@
1
+ export * from './valibot';
2
+ export * from './types';
@@ -0,0 +1,13 @@
1
+ import { FieldValues, ResolverResult, ResolverOptions } from 'react-hook-form';
2
+ import { BaseSchema, BaseSchemaAsync, ParseInfo } from 'valibot';
3
+ export type Resolver = <T extends BaseSchema | BaseSchemaAsync>(schema: T, schemaOptions?: Partial<Pick<ParseInfo, 'abortEarly' | 'abortPipeEarly'>>, resolverOptions?: {
4
+ /**
5
+ * @default async
6
+ */
7
+ mode?: 'sync' | 'async';
8
+ /**
9
+ * Return the raw input values rather than the parsed values.
10
+ * @default false
11
+ */
12
+ raw?: boolean;
13
+ }) => <TFieldValues extends FieldValues, TContext>(values: TFieldValues, context: TContext | undefined, options: ResolverOptions<TFieldValues>) => Promise<ResolverResult<TFieldValues>>;
@@ -0,0 +1,2 @@
1
+ import type { Resolver } from './types';
2
+ export declare const valibotResolver: Resolver;
@@ -0,0 +1,2 @@
1
+ var r=require("@hookform/resolvers"),e=require("valibot"),t=function(r){var e=r.issues.reduce(function(r,e){if(e.path){var t=e.path.map(function(r){return r.key}).join(".");r[t]=[].concat(r[t]||[],[{message:e.message,type:e.validation}])}return r},{});return Object.entries(e).reduce(function(r,e){var t=e[1][0];return r[e[0]]={message:t.message,type:t.type},r},{})};exports.valibotResolver=function(n,o,s){return void 0===o&&(o={abortEarly:!1,abortPipeEarly:!1}),void 0===s&&(s={mode:"async",raw:!1}),function(a,i,u){try{return Promise.resolve(function(r,t){try{var i=function(){function r(r){return{values:i?a:r,errors:{}}}var t=s.mode,i=s.raw;return"sync"===t?r("sync"===t?e.parse(n,a,o):e.parseAsync(n,a,o)):Promise.resolve("sync"===t?e.parse(n,a,o):e.parseAsync(n,a,o)).then(r)}()}catch(r){return t(r)}return i&&i.then?i.then(void 0,t):i}(0,function(n){if(n instanceof e.ValiError)return{values:{},errors:r.toNestError(t(n),u)};throw n}))}catch(r){return Promise.reject(r)}}};
2
+ //# sourceMappingURL=valibot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valibot.js","sources":["../src/valibot.ts"],"sourcesContent":["import { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport {\n BaseSchema,\n BaseSchemaAsync,\n ValiError,\n parse,\n parseAsync,\n} from 'valibot';\nimport { FieldErrors, FieldError } from 'react-hook-form';\n\ntype FlatErrors = Record<string, [FieldError, ...FieldError[]]>;\n\nconst parseErrors = (error: ValiError): FieldErrors => {\n const errors = error.issues.reduce<FlatErrors>((flatErrors, issue) => {\n if (issue.path) {\n const path = issue.path.map(({ key }) => key).join('.');\n flatErrors[path] = [\n ...(flatErrors[path] || []),\n {\n message: issue.message,\n type: issue.validation,\n },\n ];\n }\n\n return flatErrors;\n }, {});\n\n return Object.entries(errors).reduce<FieldErrors>((acc, [path, errors]) => {\n const [firstError] = errors;\n acc[path] = {\n message: firstError.message,\n type: firstError.type,\n };\n\n return acc;\n }, {});\n};\n\nexport const valibotResolver: Resolver =\n (\n schema,\n schemaOptions = {\n abortEarly: false,\n abortPipeEarly: false,\n },\n resolverOptions = {\n mode: 'async',\n raw: false,\n },\n ) =>\n async (values, _, options) => {\n try {\n const { mode, raw } = resolverOptions;\n const parsed =\n mode === 'sync'\n ? parse(schema as BaseSchema, values, schemaOptions)\n : await parseAsync(\n schema as BaseSchema | BaseSchemaAsync,\n values,\n schemaOptions,\n );\n\n return { values: raw ? values : parsed, errors: {} as FieldErrors };\n } catch (error) {\n if (error instanceof ValiError) {\n return {\n values: {},\n errors: toNestError(parseErrors(error), options),\n };\n }\n\n throw error;\n }\n };\n"],"names":["parseErrors","error","errors","issues","reduce","flatErrors","issue","path","map","_ref","key","join","concat","message","type","validation","Object","entries","acc","_ref2","firstError","schema","schemaOptions","resolverOptions","values","abortEarly","abortPipeEarly","mode","raw","_","options","Promise","resolve","_temp","parsed","parse","parseAsync","then","_catch","ValiError","toNestError","e","reject"],"mappings":"0DAaMA,EAAc,SAACC,GACnB,IAAMC,EAASD,EAAME,OAAOC,OAAmB,SAACC,EAAYC,GAC1D,GAAIA,EAAMC,KAAM,CACd,IAAMA,EAAOD,EAAMC,KAAKC,IAAI,SAAAC,UAAMA,EAAHC,GAAa,GAAEC,KAAK,KACnDN,EAAWE,GAAKK,GAAAA,OACVP,EAAWE,IAAS,GAAE,CAC1B,CACEM,QAASP,EAAMO,QACfC,KAAMR,EAAMS,aAGjB,CAED,OAAOV,CACT,EAAG,CAAA,GAEH,OAAOW,OAAOC,QAAQf,GAAQE,OAAoB,SAACc,EAAGC,GAAoB,IACjEC,EAD4DD,KACxC,GAM3B,OALAD,EAF2DC,EAAA,IAE/C,CACVN,QAASO,EAAWP,QACpBC,KAAMM,EAAWN,MAGZI,CACT,EAAG,GACL,0BAGE,SACEG,EACAC,EAIAC,GAKKC,YATQ,IAAbF,IAAAA,EAAgB,CACdG,YAAY,EACZC,gBAAgB,SAEH,IAAfH,IAAAA,EAAkB,CAChBI,KAAM,QACNC,KAAK,IAGFJ,SAAAA,EAAQK,EAAGC,GAAO,IAAIC,OAAAA,QAAAC,gCAAA,WACvBC,SAAAA,EAEIC,GASN,MAAO,CAAEV,OAAQI,EAAMJ,EAASU,EAAQhC,OAAQ,GAAoB,CAVpE,IAAQyB,EAAcJ,EAAdI,KAAMC,EAAQL,EAARK,IAAwB,MAE3B,SAATD,EAAeM,EAAN,SAATN,EACIQ,EAAAA,MAAMd,EAAsBG,EAAQF,GAC9Bc,EAAAA,WACJf,EACAG,EACAF,IACDS,QAAAC,QANI,SAATL,EACIQ,EAAAA,MAAMd,EAAsBG,EAAQF,GAC9Bc,EAAAA,WACJf,EACAG,EACAF,IACDe,KAAAJ,EAGR,6DAb0BK,CAAA,EAa1B,SAAQrC,GACP,GAAIA,aAAiBsC,YACnB,MAAO,CACLf,OAAQ,GACRtB,OAAQsC,EAAAA,YAAYxC,EAAYC,GAAQ6B,IAI5C,MAAM7B,CACP,GACH,CAAC,MAAAwC,UAAAV,QAAAW,OAAAD,EAAA,CAAA,CAAA"}
@@ -0,0 +1,2 @@
1
+ import{toNestError as r}from"@hookform/resolvers";import{parse as e,parseAsync as t,ValiError as n}from"valibot";var o=function(r){var e=r.issues.reduce(function(r,e){if(e.path){var t=e.path.map(function(r){return r.key}).join(".");r[t]=[].concat(r[t]||[],[{message:e.message,type:e.validation}])}return r},{});return Object.entries(e).reduce(function(r,e){var t=e[1][0];return r[e[0]]={message:t.message,type:t.type},r},{})},a=function(a,i,s){return void 0===i&&(i={abortEarly:!1,abortPipeEarly:!1}),void 0===s&&(s={mode:"async",raw:!1}),function(u,c,f){try{return Promise.resolve(function(r,n){try{var o=function(){function r(r){return{values:o?u:r,errors:{}}}var n=s.mode,o=s.raw;return"sync"===n?r("sync"===n?e(a,u,i):t(a,u,i)):Promise.resolve("sync"===n?e(a,u,i):t(a,u,i)).then(r)}()}catch(r){return n(r)}return o&&o.then?o.then(void 0,n):o}(0,function(e){if(e instanceof n)return{values:{},errors:r(o(e),f)};throw e}))}catch(r){return Promise.reject(r)}}};export{a as valibotResolver};
2
+ //# sourceMappingURL=valibot.module.js.map
@@ -0,0 +1,2 @@
1
+ import{toNestError as e}from"@hookform/resolvers";import{parse as r,parseAsync as t,ValiError as s}from"valibot";const o=e=>{const r=e.issues.reduce((e,r)=>{if(r.path){const t=r.path.map(({key:e})=>e).join(".");e[t]=[...e[t]||[],{message:r.message,type:r.validation}]}return e},{});return Object.entries(r).reduce((e,[r,t])=>{const[s]=t;return e[r]={message:s.message,type:s.type},e},{})},a=(a,n={abortEarly:!1,abortPipeEarly:!1},c={mode:"async",raw:!1})=>async(i,m,p)=>{try{const{mode:e,raw:s}=c,o="sync"===e?r(a,i,n):await t(a,i,n);return{values:s?i:o,errors:{}}}catch(r){if(r instanceof s)return{values:{},errors:e(o(r),p)};throw r}};export{a as valibotResolver};
2
+ //# sourceMappingURL=valibot.modern.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valibot.modern.mjs","sources":["../src/valibot.ts"],"sourcesContent":["import { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport {\n BaseSchema,\n BaseSchemaAsync,\n ValiError,\n parse,\n parseAsync,\n} from 'valibot';\nimport { FieldErrors, FieldError } from 'react-hook-form';\n\ntype FlatErrors = Record<string, [FieldError, ...FieldError[]]>;\n\nconst parseErrors = (error: ValiError): FieldErrors => {\n const errors = error.issues.reduce<FlatErrors>((flatErrors, issue) => {\n if (issue.path) {\n const path = issue.path.map(({ key }) => key).join('.');\n flatErrors[path] = [\n ...(flatErrors[path] || []),\n {\n message: issue.message,\n type: issue.validation,\n },\n ];\n }\n\n return flatErrors;\n }, {});\n\n return Object.entries(errors).reduce<FieldErrors>((acc, [path, errors]) => {\n const [firstError] = errors;\n acc[path] = {\n message: firstError.message,\n type: firstError.type,\n };\n\n return acc;\n }, {});\n};\n\nexport const valibotResolver: Resolver =\n (\n schema,\n schemaOptions = {\n abortEarly: false,\n abortPipeEarly: false,\n },\n resolverOptions = {\n mode: 'async',\n raw: false,\n },\n ) =>\n async (values, _, options) => {\n try {\n const { mode, raw } = resolverOptions;\n const parsed =\n mode === 'sync'\n ? parse(schema as BaseSchema, values, schemaOptions)\n : await parseAsync(\n schema as BaseSchema | BaseSchemaAsync,\n values,\n schemaOptions,\n );\n\n return { values: raw ? values : parsed, errors: {} as FieldErrors };\n } catch (error) {\n if (error instanceof ValiError) {\n return {\n values: {},\n errors: toNestError(parseErrors(error), options),\n };\n }\n\n throw error;\n }\n };\n"],"names":["parseErrors","error","errors","issues","reduce","flatErrors","issue","path","map","key","join","message","type","validation","Object","entries","acc","firstError","valibotResolver","schema","schemaOptions","abortEarly","abortPipeEarly","resolverOptions","mode","raw","async","values","_","options","parsed","parse","parseAsync","ValiError","toNestError"],"mappings":"iHAaA,MAAMA,EAAeC,IACnB,MAAMC,EAASD,EAAME,OAAOC,OAAmB,CAACC,EAAYC,KAC1D,GAAIA,EAAMC,KAAM,CACd,MAAMA,EAAOD,EAAMC,KAAKC,IAAI,EAAGC,SAAUA,GAAKC,KAAK,KACnDL,EAAWE,GAAQ,IACbF,EAAWE,IAAS,GACxB,CACEI,QAASL,EAAMK,QACfC,KAAMN,EAAMO,YAGjB,CAED,OAAOR,GACN,CAAE,GAEL,OAAOS,OAAOC,QAAQb,GAAQE,OAAoB,CAACY,GAAMT,EAAML,MAC7D,MAAOe,GAAcf,EAMrB,OALAc,EAAIT,GAAQ,CACVI,QAASM,EAAWN,QACpBC,KAAMK,EAAWL,MAGZI,GACN,CAAA,EAAE,EAGME,EACXA,CACEC,EACAC,EAAgB,CACdC,YAAY,EACZC,gBAAgB,GAElBC,EAAkB,CAChBC,KAAM,QACNC,KAAK,KAGTC,MAAOC,EAAQC,EAAGC,KAChB,IACE,MAAML,KAAEA,EAAIC,IAAEA,GAAQF,EAChBO,EACK,SAATN,EACIO,EAAMZ,EAAsBQ,EAAQP,SAC9BY,EACJb,EACAQ,EACAP,GAGR,MAAO,CAAEO,OAAQF,EAAME,EAASG,EAAQ5B,OAAQ,GACjD,CAAC,MAAOD,GACP,GAAIA,aAAiBgC,EACnB,MAAO,CACLN,OAAQ,CAAE,EACVzB,OAAQgC,EAAYlC,EAAYC,GAAQ4B,IAI5C,MAAM5B,CACP"}
@@ -0,0 +1,2 @@
1
+ import{toNestError as r}from"@hookform/resolvers";import{parse as e,parseAsync as t,ValiError as n}from"valibot";var o=function(r){var e=r.issues.reduce(function(r,e){if(e.path){var t=e.path.map(function(r){return r.key}).join(".");r[t]=[].concat(r[t]||[],[{message:e.message,type:e.validation}])}return r},{});return Object.entries(e).reduce(function(r,e){var t=e[1][0];return r[e[0]]={message:t.message,type:t.type},r},{})},a=function(a,i,s){return void 0===i&&(i={abortEarly:!1,abortPipeEarly:!1}),void 0===s&&(s={mode:"async",raw:!1}),function(u,c,f){try{return Promise.resolve(function(r,n){try{var o=function(){function r(r){return{values:o?u:r,errors:{}}}var n=s.mode,o=s.raw;return"sync"===n?r("sync"===n?e(a,u,i):t(a,u,i)):Promise.resolve("sync"===n?e(a,u,i):t(a,u,i)).then(r)}()}catch(r){return n(r)}return o&&o.then?o.then(void 0,n):o}(0,function(e){if(e instanceof n)return{values:{},errors:r(o(e),f)};throw e}))}catch(r){return Promise.reject(r)}}};export{a as valibotResolver};
2
+ //# sourceMappingURL=valibot.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valibot.module.js","sources":["../src/valibot.ts"],"sourcesContent":["import { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport {\n BaseSchema,\n BaseSchemaAsync,\n ValiError,\n parse,\n parseAsync,\n} from 'valibot';\nimport { FieldErrors, FieldError } from 'react-hook-form';\n\ntype FlatErrors = Record<string, [FieldError, ...FieldError[]]>;\n\nconst parseErrors = (error: ValiError): FieldErrors => {\n const errors = error.issues.reduce<FlatErrors>((flatErrors, issue) => {\n if (issue.path) {\n const path = issue.path.map(({ key }) => key).join('.');\n flatErrors[path] = [\n ...(flatErrors[path] || []),\n {\n message: issue.message,\n type: issue.validation,\n },\n ];\n }\n\n return flatErrors;\n }, {});\n\n return Object.entries(errors).reduce<FieldErrors>((acc, [path, errors]) => {\n const [firstError] = errors;\n acc[path] = {\n message: firstError.message,\n type: firstError.type,\n };\n\n return acc;\n }, {});\n};\n\nexport const valibotResolver: Resolver =\n (\n schema,\n schemaOptions = {\n abortEarly: false,\n abortPipeEarly: false,\n },\n resolverOptions = {\n mode: 'async',\n raw: false,\n },\n ) =>\n async (values, _, options) => {\n try {\n const { mode, raw } = resolverOptions;\n const parsed =\n mode === 'sync'\n ? parse(schema as BaseSchema, values, schemaOptions)\n : await parseAsync(\n schema as BaseSchema | BaseSchemaAsync,\n values,\n schemaOptions,\n );\n\n return { values: raw ? values : parsed, errors: {} as FieldErrors };\n } catch (error) {\n if (error instanceof ValiError) {\n return {\n values: {},\n errors: toNestError(parseErrors(error), options),\n };\n }\n\n throw error;\n }\n };\n"],"names":["parseErrors","error","errors","issues","reduce","flatErrors","issue","path","map","_ref","key","join","concat","message","type","validation","Object","entries","acc","_ref2","firstError","valibotResolver","schema","schemaOptions","resolverOptions","values","abortEarly","abortPipeEarly","mode","raw","_","options","Promise","resolve","_temp","parsed","parse","parseAsync","then","_catch","ValiError","toNestError","e","reject"],"mappings":"iHAaA,IAAMA,EAAc,SAACC,GACnB,IAAMC,EAASD,EAAME,OAAOC,OAAmB,SAACC,EAAYC,GAC1D,GAAIA,EAAMC,KAAM,CACd,IAAMA,EAAOD,EAAMC,KAAKC,IAAI,SAAAC,UAAMA,EAAHC,GAAa,GAAEC,KAAK,KACnDN,EAAWE,GAAKK,GAAAA,OACVP,EAAWE,IAAS,GAAE,CAC1B,CACEM,QAASP,EAAMO,QACfC,KAAMR,EAAMS,aAGjB,CAED,OAAOV,CACT,EAAG,CAAA,GAEH,OAAOW,OAAOC,QAAQf,GAAQE,OAAoB,SAACc,EAAGC,GAAoB,IACjEC,EAD4DD,KACxC,GAM3B,OALAD,EAF2DC,EAAA,IAE/C,CACVN,QAASO,EAAWP,QACpBC,KAAMM,EAAWN,MAGZI,CACT,EAAG,GACL,EAEaG,EACX,SACEC,EACAC,EAIAC,GAKKC,YATQ,IAAbF,IAAAA,EAAgB,CACdG,YAAY,EACZC,gBAAgB,SAEH,IAAfH,IAAAA,EAAkB,CAChBI,KAAM,QACNC,KAAK,IAGFJ,SAAAA,EAAQK,EAAGC,GAAO,IAAIC,OAAAA,QAAAC,gCAAA,WACvBC,SAAAA,EAEIC,GASN,MAAO,CAAEV,OAAQI,EAAMJ,EAASU,EAAQjC,OAAQ,GAAoB,CAVpE,IAAQ0B,EAAcJ,EAAdI,KAAMC,EAAQL,EAARK,IAAwB,MAE3B,SAATD,EAAeM,EAAN,SAATN,EACIQ,EAAMd,EAAsBG,EAAQF,GAC9Bc,EACJf,EACAG,EACAF,IACDS,QAAAC,QANI,SAATL,EACIQ,EAAMd,EAAsBG,EAAQF,GAC9Bc,EACJf,EACAG,EACAF,IACDe,KAAAJ,EAGR,6DAb0BK,CAAA,EAa1B,SAAQtC,GACP,GAAIA,aAAiBuC,EACnB,MAAO,CACLf,OAAQ,GACRvB,OAAQuC,EAAYzC,EAAYC,GAAQ8B,IAI5C,MAAM9B,CACP,GACH,CAAC,MAAAyC,UAAAV,QAAAW,OAAAD,EAAA,CAAA,CAAA"}
@@ -0,0 +1,2 @@
1
+ !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("@hookform/resolvers"),require("valibot")):"function"==typeof define&&define.amd?define(["exports","@hookform/resolvers","valibot"],r):r((e||self).hookformResolversValibot={},e.hookformResolvers,e.valibot)}(this,function(e,r,o){var t=function(e){var r=e.issues.reduce(function(e,r){if(r.path){var o=r.path.map(function(e){return e.key}).join(".");e[o]=[].concat(e[o]||[],[{message:r.message,type:r.validation}])}return e},{});return Object.entries(r).reduce(function(e,r){var o=r[1][0];return e[r[0]]={message:o.message,type:o.type},e},{})};e.valibotResolver=function(e,n,s){return void 0===n&&(n={abortEarly:!1,abortPipeEarly:!1}),void 0===s&&(s={mode:"async",raw:!1}),function(i,a,u){try{return Promise.resolve(function(r,t){try{var a=function(){function r(e){return{values:a?i:e,errors:{}}}var t=s.mode,a=s.raw;return"sync"===t?r("sync"===t?o.parse(e,i,n):o.parseAsync(e,i,n)):Promise.resolve("sync"===t?o.parse(e,i,n):o.parseAsync(e,i,n)).then(r)}()}catch(e){return t(e)}return a&&a.then?a.then(void 0,t):a}(0,function(e){if(e instanceof o.ValiError)return{values:{},errors:r.toNestError(t(e),u)};throw e}))}catch(e){return Promise.reject(e)}}}});
2
+ //# sourceMappingURL=valibot.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valibot.umd.js","sources":["../src/valibot.ts"],"sourcesContent":["import { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport {\n BaseSchema,\n BaseSchemaAsync,\n ValiError,\n parse,\n parseAsync,\n} from 'valibot';\nimport { FieldErrors, FieldError } from 'react-hook-form';\n\ntype FlatErrors = Record<string, [FieldError, ...FieldError[]]>;\n\nconst parseErrors = (error: ValiError): FieldErrors => {\n const errors = error.issues.reduce<FlatErrors>((flatErrors, issue) => {\n if (issue.path) {\n const path = issue.path.map(({ key }) => key).join('.');\n flatErrors[path] = [\n ...(flatErrors[path] || []),\n {\n message: issue.message,\n type: issue.validation,\n },\n ];\n }\n\n return flatErrors;\n }, {});\n\n return Object.entries(errors).reduce<FieldErrors>((acc, [path, errors]) => {\n const [firstError] = errors;\n acc[path] = {\n message: firstError.message,\n type: firstError.type,\n };\n\n return acc;\n }, {});\n};\n\nexport const valibotResolver: Resolver =\n (\n schema,\n schemaOptions = {\n abortEarly: false,\n abortPipeEarly: false,\n },\n resolverOptions = {\n mode: 'async',\n raw: false,\n },\n ) =>\n async (values, _, options) => {\n try {\n const { mode, raw } = resolverOptions;\n const parsed =\n mode === 'sync'\n ? parse(schema as BaseSchema, values, schemaOptions)\n : await parseAsync(\n schema as BaseSchema | BaseSchemaAsync,\n values,\n schemaOptions,\n );\n\n return { values: raw ? values : parsed, errors: {} as FieldErrors };\n } catch (error) {\n if (error instanceof ValiError) {\n return {\n values: {},\n errors: toNestError(parseErrors(error), options),\n };\n }\n\n throw error;\n }\n };\n"],"names":["parseErrors","error","errors","issues","reduce","flatErrors","issue","path","map","_ref","key","join","concat","message","type","validation","Object","entries","acc","_ref2","firstError","schema","schemaOptions","resolverOptions","values","abortEarly","abortPipeEarly","mode","raw","_","options","Promise","resolve","_temp","parsed","parse","parseAsync","then","_catch","ValiError","toNestError","e","reject"],"mappings":"sWAaA,IAAMA,EAAc,SAACC,GACnB,IAAMC,EAASD,EAAME,OAAOC,OAAmB,SAACC,EAAYC,GAC1D,GAAIA,EAAMC,KAAM,CACd,IAAMA,EAAOD,EAAMC,KAAKC,IAAI,SAAAC,UAAMA,EAAHC,GAAa,GAAEC,KAAK,KACnDN,EAAWE,GAAKK,GAAAA,OACVP,EAAWE,IAAS,GAAE,CAC1B,CACEM,QAASP,EAAMO,QACfC,KAAMR,EAAMS,aAGjB,CAED,OAAOV,CACT,EAAG,CAAA,GAEH,OAAOW,OAAOC,QAAQf,GAAQE,OAAoB,SAACc,EAAGC,GAAoB,IACjEC,EAD4DD,KACxC,GAM3B,OALAD,EAF2DC,EAAA,IAE/C,CACVN,QAASO,EAAWP,QACpBC,KAAMM,EAAWN,MAGZI,CACT,EAAG,GACL,oBAGE,SACEG,EACAC,EAIAC,GAKKC,YATQ,IAAbF,IAAAA,EAAgB,CACdG,YAAY,EACZC,gBAAgB,SAEH,IAAfH,IAAAA,EAAkB,CAChBI,KAAM,QACNC,KAAK,IAGFJ,SAAAA,EAAQK,EAAGC,GAAO,IAAIC,OAAAA,QAAAC,gCAAA,WACvBC,SAAAA,EAEIC,GASN,MAAO,CAAEV,OAAQI,EAAMJ,EAASU,EAAQhC,OAAQ,GAAoB,CAVpE,IAAQyB,EAAcJ,EAAdI,KAAMC,EAAQL,EAARK,IAAwB,MAE3B,SAATD,EAAeM,EAAN,SAATN,EACIQ,EAAAA,MAAMd,EAAsBG,EAAQF,GAC9Bc,EAAAA,WACJf,EACAG,EACAF,IACDS,QAAAC,QANI,SAATL,EACIQ,EAAAA,MAAMd,EAAsBG,EAAQF,GAC9Bc,EAAAA,WACJf,EACAG,EACAF,IACDe,KAAAJ,EAGR,6DAb0BK,CAAA,EAa1B,SAAQrC,GACP,GAAIA,aAAiBsC,YACnB,MAAO,CACLf,OAAQ,GACRtB,OAAQsC,EAAAA,YAAYxC,EAAYC,GAAQ6B,IAI5C,MAAM7B,CACP,GACH,CAAC,MAAAwC,UAAAV,QAAAW,OAAAD,EAAA,CAAA,CAAA"}
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@hookform/resolvers/valibot",
3
+ "amdName": "hookformResolversValibot",
4
+ "version": "1.0.0",
5
+ "private": true,
6
+ "description": "React Hook Form validation resolver: valibot",
7
+ "main": "dist/valibot.js",
8
+ "module": "dist/valibot.module.js",
9
+ "umd:main": "dist/valibot.umd.js",
10
+ "source": "src/index.ts",
11
+ "types": "dist/index.d.ts",
12
+ "license": "MIT",
13
+ "peerDependencies": {
14
+ "react-hook-form": "^7.0.0",
15
+ "@hookform/resolvers": "^2.0.0",
16
+ "valibot": ">=0.8"
17
+ }
18
+ }
@@ -0,0 +1,88 @@
1
+ import { Field, InternalFieldName } from 'react-hook-form';
2
+ import {
3
+ object,
4
+ string,
5
+ minLength,
6
+ maxLength,
7
+ regex,
8
+ number,
9
+ minValue,
10
+ maxValue,
11
+ email,
12
+ array,
13
+ boolean,
14
+ required,
15
+ } from 'valibot';
16
+
17
+ export const schema = required(
18
+ object({
19
+ username: string([minLength(2), maxLength(30), regex(/^\w+$/)]),
20
+ password: string('New Password is required', [
21
+ regex(new RegExp('.*[A-Z].*'), 'One uppercase character'),
22
+ regex(new RegExp('.*[a-z].*'), 'One lowercase character'),
23
+ regex(new RegExp('.*\\d.*'), 'One number'),
24
+ regex(
25
+ new RegExp('.*[`~<>?,./!@#$%^&*()\\-_+="\'|{}\\[\\];:\\\\].*'),
26
+ 'One special character',
27
+ ),
28
+ minLength(8, 'Must be at least 8 characters in length'),
29
+ ]),
30
+ repeatPassword: string('Repeat Password is required'),
31
+ accessToken: string('Access token is required'),
32
+ birthYear: number('Please enter your birth year', [
33
+ minValue(1900),
34
+ maxValue(2013),
35
+ ]),
36
+ email: string([email('Invalid email address')]),
37
+ tags: array(string('Tags should be strings')),
38
+ enabled: boolean(),
39
+ like: required(
40
+ object({
41
+ id: number('Like id is required'),
42
+ name: string('Like name is required', [minLength(4, 'Too short')]),
43
+ }),
44
+ ),
45
+ }),
46
+ );
47
+
48
+ export const validData = {
49
+ username: 'Doe',
50
+ password: 'Password123_',
51
+ repeatPassword: 'Password123_',
52
+ birthYear: 2000,
53
+ email: 'john@doe.com',
54
+ tags: ['tag1', 'tag2'],
55
+ enabled: true,
56
+ accessToken: 'accessToken',
57
+ like: {
58
+ id: 1,
59
+ name: 'name',
60
+ },
61
+ };
62
+
63
+ export const invalidData = {
64
+ password: '___',
65
+ email: '',
66
+ birthYear: 'birthYear',
67
+ like: { id: 'z' },
68
+ tags: [1, 2, 3],
69
+ };
70
+
71
+ export const fields: Record<InternalFieldName, Field['_f']> = {
72
+ username: {
73
+ ref: { name: 'username' },
74
+ name: 'username',
75
+ },
76
+ password: {
77
+ ref: { name: 'password' },
78
+ name: 'password',
79
+ },
80
+ email: {
81
+ ref: { name: 'email' },
82
+ name: 'email',
83
+ },
84
+ birthday: {
85
+ ref: { name: 'birthday' },
86
+ name: 'birthday',
87
+ },
88
+ };
@@ -0,0 +1,79 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`valibotResolver > should return a single error from valibotResolver when validation fails 1`] = `
4
+ {
5
+ "errors": {
6
+ "accessToken": {
7
+ "message": "Invalid type",
8
+ "ref": undefined,
9
+ "type": "non_optional",
10
+ },
11
+ "birthYear": {
12
+ "message": "Please enter your birth year",
13
+ "ref": undefined,
14
+ "type": "number",
15
+ },
16
+ "email": {
17
+ "message": "Invalid email address",
18
+ "ref": {
19
+ "name": "email",
20
+ },
21
+ "type": "email",
22
+ },
23
+ "enabled": {
24
+ "message": "Invalid type",
25
+ "ref": undefined,
26
+ "type": "non_optional",
27
+ },
28
+ "like": {
29
+ "id": {
30
+ "message": "Like id is required",
31
+ "ref": undefined,
32
+ "type": "number",
33
+ },
34
+ "name": {
35
+ "message": "Invalid type",
36
+ "ref": undefined,
37
+ "type": "non_optional",
38
+ },
39
+ },
40
+ "password": {
41
+ "message": "One uppercase character",
42
+ "ref": {
43
+ "name": "password",
44
+ },
45
+ "type": "regex",
46
+ },
47
+ "repeatPassword": {
48
+ "message": "Invalid type",
49
+ "ref": undefined,
50
+ "type": "non_optional",
51
+ },
52
+ "tags": [
53
+ {
54
+ "message": "Tags should be strings",
55
+ "ref": undefined,
56
+ "type": "string",
57
+ },
58
+ {
59
+ "message": "Tags should be strings",
60
+ "ref": undefined,
61
+ "type": "string",
62
+ },
63
+ {
64
+ "message": "Tags should be strings",
65
+ "ref": undefined,
66
+ "type": "string",
67
+ },
68
+ ],
69
+ "username": {
70
+ "message": "Invalid type",
71
+ "ref": {
72
+ "name": "username",
73
+ },
74
+ "type": "non_optional",
75
+ },
76
+ },
77
+ "values": {},
78
+ }
79
+ `;
@@ -0,0 +1,24 @@
1
+ /* eslint-disable no-console, @typescript-eslint/ban-ts-comment */
2
+ import { valibotResolver } from '..';
3
+ import { schema, validData, fields, invalidData } from './__fixtures__/data';
4
+
5
+ const shouldUseNativeValidation = false;
6
+ describe('valibotResolver', () => {
7
+ it('should return values from valibotResolver when validation pass', async () => {
8
+ const result = await valibotResolver(schema)(validData, undefined, {
9
+ fields,
10
+ shouldUseNativeValidation,
11
+ });
12
+
13
+ expect(result).toEqual({ errors: {}, values: validData });
14
+ });
15
+
16
+ it('should return a single error from valibotResolver when validation fails', async () => {
17
+ const result = await valibotResolver(schema)(invalidData, undefined, {
18
+ fields,
19
+ shouldUseNativeValidation,
20
+ });
21
+
22
+ expect(result).toMatchSnapshot();
23
+ });
24
+ });
@@ -0,0 +1,2 @@
1
+ export * from './valibot';
2
+ export * from './types';
@@ -0,0 +1,22 @@
1
+ import { FieldValues, ResolverResult, ResolverOptions } from 'react-hook-form';
2
+ import { BaseSchema, BaseSchemaAsync, ParseInfo } from 'valibot';
3
+
4
+ export type Resolver = <T extends BaseSchema | BaseSchemaAsync>(
5
+ schema: T,
6
+ schemaOptions?: Partial<Pick<ParseInfo, 'abortEarly' | 'abortPipeEarly'>>,
7
+ resolverOptions?: {
8
+ /**
9
+ * @default async
10
+ */
11
+ mode?: 'sync' | 'async';
12
+ /**
13
+ * Return the raw input values rather than the parsed values.
14
+ * @default false
15
+ */
16
+ raw?: boolean;
17
+ },
18
+ ) => <TFieldValues extends FieldValues, TContext>(
19
+ values: TFieldValues,
20
+ context: TContext | undefined,
21
+ options: ResolverOptions<TFieldValues>,
22
+ ) => Promise<ResolverResult<TFieldValues>>;
@@ -0,0 +1,76 @@
1
+ import { toNestError } from '@hookform/resolvers';
2
+ import type { Resolver } from './types';
3
+ import {
4
+ BaseSchema,
5
+ BaseSchemaAsync,
6
+ ValiError,
7
+ parse,
8
+ parseAsync,
9
+ } from 'valibot';
10
+ import { FieldErrors, FieldError } from 'react-hook-form';
11
+
12
+ type FlatErrors = Record<string, [FieldError, ...FieldError[]]>;
13
+
14
+ const parseErrors = (error: ValiError): FieldErrors => {
15
+ const errors = error.issues.reduce<FlatErrors>((flatErrors, issue) => {
16
+ if (issue.path) {
17
+ const path = issue.path.map(({ key }) => key).join('.');
18
+ flatErrors[path] = [
19
+ ...(flatErrors[path] || []),
20
+ {
21
+ message: issue.message,
22
+ type: issue.validation,
23
+ },
24
+ ];
25
+ }
26
+
27
+ return flatErrors;
28
+ }, {});
29
+
30
+ return Object.entries(errors).reduce<FieldErrors>((acc, [path, errors]) => {
31
+ const [firstError] = errors;
32
+ acc[path] = {
33
+ message: firstError.message,
34
+ type: firstError.type,
35
+ };
36
+
37
+ return acc;
38
+ }, {});
39
+ };
40
+
41
+ export const valibotResolver: Resolver =
42
+ (
43
+ schema,
44
+ schemaOptions = {
45
+ abortEarly: false,
46
+ abortPipeEarly: false,
47
+ },
48
+ resolverOptions = {
49
+ mode: 'async',
50
+ raw: false,
51
+ },
52
+ ) =>
53
+ async (values, _, options) => {
54
+ try {
55
+ const { mode, raw } = resolverOptions;
56
+ const parsed =
57
+ mode === 'sync'
58
+ ? parse(schema as BaseSchema, values, schemaOptions)
59
+ : await parseAsync(
60
+ schema as BaseSchema | BaseSchemaAsync,
61
+ values,
62
+ schemaOptions,
63
+ );
64
+
65
+ return { values: raw ? values : parsed, errors: {} as FieldErrors };
66
+ } catch (error) {
67
+ if (error instanceof ValiError) {
68
+ return {
69
+ values: {},
70
+ errors: toNestError(parseErrors(error), options),
71
+ };
72
+ }
73
+
74
+ throw error;
75
+ }
76
+ };