@hookform/resolvers 6.0.0 → 6.0.2
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 +1 -1
- package/package.json +1 -5
- package/typebox/dist/typebox.js +1 -1
- package/typebox/dist/typebox.js.map +1 -1
- package/typebox/dist/typebox.mjs +1 -1
- package/typebox/dist/typebox.modern.mjs +1 -1
- package/typebox/dist/typebox.modern.mjs.map +1 -1
- package/typebox/dist/typebox.module.js +1 -1
- package/typebox/dist/typebox.module.js.map +1 -1
- package/typebox/dist/typebox.umd.js +1 -1
- package/typebox/dist/typebox.umd.js.map +1 -1
- package/typebox/src/__tests__/special-path-names.ts +102 -0
- package/typebox/src/typebox.ts +5 -1
- package/typeschema/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<p align="center">
|
|
3
3
|
<a href="https://react-hook-form.com" title="React Hook Form - Simple React forms validation">
|
|
4
|
-
<img src="https://
|
|
4
|
+
<img src="https://react-hook-form.com/images/react-hook-form-og.png" alt="React Hook Form Logo - React hook custom hook for form validation" />
|
|
5
5
|
</a>
|
|
6
6
|
</p>
|
|
7
7
|
</div>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hookform/resolvers",
|
|
3
3
|
"amdName": "hookformResolvers",
|
|
4
|
-
"version": "6.0.
|
|
4
|
+
"version": "6.0.2",
|
|
5
5
|
"description": "React Hook Form validation resolvers: Yup, Joi, Superstruct, Zod, Vest, Class Validator, io-ts, Nope, computed-types, TypeBox, arktype, Typanion, Effect-TS and VineJS",
|
|
6
6
|
"main": "dist/resolvers.js",
|
|
7
7
|
"module": "dist/resolvers.module.js",
|
|
@@ -331,7 +331,6 @@
|
|
|
331
331
|
"peerDependencies": {
|
|
332
332
|
"@sinclair/typebox": ">=0.25.24",
|
|
333
333
|
"@standard-schema/spec": "^1.0.0",
|
|
334
|
-
"@typeschema/main": ">=0.13.7",
|
|
335
334
|
"@vinejs/vine": "^2.0.0 || ^3.0.0 || ^4.0.0",
|
|
336
335
|
"ajv": "^8.12.0",
|
|
337
336
|
"ajv-errors": "^3.0.0",
|
|
@@ -362,9 +361,6 @@
|
|
|
362
361
|
"@standard-schema/spec": {
|
|
363
362
|
"optional": true
|
|
364
363
|
},
|
|
365
|
-
"@typeschema/main": {
|
|
366
|
-
"optional": true
|
|
367
|
-
},
|
|
368
364
|
"@vinejs/vine": {
|
|
369
365
|
"optional": true
|
|
370
366
|
},
|
package/typebox/dist/typebox.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=require("@hookform/resolvers"),r=require("@sinclair/typebox/compiler"),
|
|
1
|
+
var e=require("@hookform/resolvers"),r=require("@sinclair/typebox/compiler"),t=require("@sinclair/typebox/value"),a=require("react-hook-form");function o(e,r){for(var t=Object.create(null);e.length;){var o=e[0],s=o.type,i=o.message,l=o.path.split("/").slice(1).map(function(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(t[l]||(t[l]={message:i,type:""+s}),r){var n=t[l].types,c=n&&n[""+s];t[l]=a.appendErrors(l,r,t,""+s,c?[].concat(c,o.message):o.message)}e.shift()}return t}exports.typeboxResolver=function(a){return function(s,i,l){try{var n=Array.from(a instanceof r.TypeCheck?a.Errors(s):t.Value.Errors(a,s));return l.shouldUseNativeValidation&&e.validateFieldsNatively({},l),Promise.resolve(n.length?{values:{},errors:e.toNestErrors(o(n,!l.shouldUseNativeValidation&&"all"===l.criteriaMode),l)}:{errors:{},values:s})}catch(e){return Promise.reject(e)}}};
|
|
2
2
|
//# sourceMappingURL=typebox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typebox.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.
|
|
1
|
+
{"version":3,"file":"typebox.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path\n .split('/')\n .slice(1)\n .map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'))\n .join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | TypeCheck<Schema>} schema - The Typebox schema to validate against\n * @param {Object} options - Additional resolver configuration\n * @param {string} [options.mode='async'] - Validation mode\n * @returns {Resolver<Static<Schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = Type.Object({\n * name: Type.String(),\n * age: Type.Number()\n * });\n *\n * useForm({\n * resolver: typeboxResolver(schema)\n * });\n *\n * // Schemas using a custom/third-party `Kind` (e.g. ElysiaJS's `t.Files()`) must have\n * // that kind registered with TypeBox's own `TypeRegistry` before validating, since\n * // this resolver validates via `@sinclair/typebox`'s `Value.Errors`/`Value.Check`:\n * // TypeRegistry.Set('Files', (schema, value) => Array.isArray(value));\n */\nexport function typeboxResolver<Schema extends TObject, Context>(\n schema: Schema | TypeCheck<Schema>,\n): Resolver<Static<Schema>, Context, StaticDecode<Schema>> {\n return async (values: Static<Schema>, _, options) => {\n const errors = Array.from(\n schema instanceof TypeCheck\n ? schema.Errors(values)\n : Value.Errors(schema, values),\n );\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {},\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n}\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","Object","create","length","error","type","message","_path","path","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","shift","schema","values","_","options","Array","from","TypeCheck","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","toNestErrors","criteriaMode","e","reject"],"mappings":"+IAMA,SAASA,EACPC,EACAC,GAIA,IADA,IAAMC,EAAqCC,OAAOC,OAAO,MAClDJ,EAAQK,QAAU,CACvB,IAAMC,EAAQN,EAAQ,GACdO,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KAEpBC,MAAM,KACNC,MAAM,GACNC,IAAI,SAACC,GAAO,OAAKA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,IAAI,GAChEC,KAAK,KAMR,GAJKd,EAAOO,KACVP,EAAOO,GAAS,CAAED,QAAAA,EAASD,KAAM,GAAKA,IAGpCN,EAA0B,CAC5B,IAAMgB,EAAQf,EAAOO,GAAOQ,MACtBC,EAAWD,GAASA,EAAM,GAAKV,GAErCL,EAAOO,GAASU,eACdV,EACAR,EACAC,EACA,GAAKK,EACLW,EACK,GAAgBE,OAAOF,EAAsBZ,EAAME,SACpDF,EAAME,QAEd,CAEAR,EAAQqB,OACV,CAEA,OAAOnB,CACT,kCAwBEoB,GAEA,OAAA,SAAcC,EAAwBC,EAAGC,GAAO,IAC9C,IAAMvB,EAASwB,MAAMC,KACnBL,aAAkBM,EAASA,UACvBN,EAAOO,OAAON,GACdO,QAAMD,OAAOP,EAAQC,IAK3B,OAFAE,EAAQM,2BAA6BC,EAAsBA,uBAAC,GAAIP,GAShEQ,QAAAC,QAPKhC,EAAOG,OAOL,CACLkB,OAAQ,CAAE,EACVrB,OAAQiC,eACNpC,EACEG,GACCuB,EAAQM,2BAAsD,QAAzBN,EAAQW,cAEhDX,IAbK,CACLvB,OAAQ,GACRqB,OAAAA,GAcN,CAAC,MAAAc,GAAAJ,OAAAA,QAAAK,OAAAD,EACH,CAAA,CAAA"}
|
package/typebox/dist/typebox.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{TypeCheck as o}from"@sinclair/typebox/compiler";import{Value as t}from"@sinclair/typebox/value";import{appendErrors as
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{TypeCheck as o}from"@sinclair/typebox/compiler";import{Value as t}from"@sinclair/typebox/value";import{appendErrors as a}from"react-hook-form";function s(r,e){for(var o=Object.create(null);r.length;){var t=r[0],s=t.type,i=t.message,n=t.path.split("/").slice(1).map(function(r){return r.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(o[n]||(o[n]={message:i,type:""+s}),e){var l=o[n].types,c=l&&l[""+s];o[n]=a(n,e,o,""+s,c?[].concat(c,t.message):t.message)}r.shift()}return o}function i(a){return function(i,n,l){try{var c=Array.from(a instanceof o?a.Errors(i):t.Errors(a,i));return l.shouldUseNativeValidation&&r({},l),Promise.resolve(c.length?{values:{},errors:e(s(c,!l.shouldUseNativeValidation&&"all"===l.criteriaMode),l)}:{errors:{},values:i})}catch(r){return Promise.reject(r)}}}export{i as typeboxResolver};
|
|
2
2
|
//# sourceMappingURL=typebox.module.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{TypeCheck as o}from"@sinclair/typebox/compiler";import{Value as t}from"@sinclair/typebox/value";import{appendErrors as s}from"react-hook-form";function a(r,e){const o=Object.create(null);for(;r.length;){const t=r[0],{type:a,message:i,path:n}=t,
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{TypeCheck as o}from"@sinclair/typebox/compiler";import{Value as t}from"@sinclair/typebox/value";import{appendErrors as s}from"react-hook-form";function a(r,e){const o=Object.create(null);for(;r.length;){const t=r[0],{type:a,message:i,path:n}=t,l=n.split("/").slice(1).map(r=>r.replace(/~1/g,"/").replace(/~0/g,"~")).join(".");if(o[l]||(o[l]={message:i,type:""+a}),e){const r=o[l].types,i=r&&r[""+a];o[l]=s(l,e,o,""+a,i?[].concat(i,t.message):t.message)}r.shift()}return o}function i(s){return async(i,n,l)=>{const c=Array.from(s instanceof o?s.Errors(i):t.Errors(s,i));return l.shouldUseNativeValidation&&r({},l),c.length?{values:{},errors:e(a(c,!l.shouldUseNativeValidation&&"all"===l.criteriaMode),l)}:{errors:{},values:i}}}export{i as typeboxResolver};
|
|
2
2
|
//# sourceMappingURL=typebox.modern.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typebox.modern.mjs","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.
|
|
1
|
+
{"version":3,"file":"typebox.modern.mjs","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path\n .split('/')\n .slice(1)\n .map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'))\n .join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | TypeCheck<Schema>} schema - The Typebox schema to validate against\n * @param {Object} options - Additional resolver configuration\n * @param {string} [options.mode='async'] - Validation mode\n * @returns {Resolver<Static<Schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = Type.Object({\n * name: Type.String(),\n * age: Type.Number()\n * });\n *\n * useForm({\n * resolver: typeboxResolver(schema)\n * });\n *\n * // Schemas using a custom/third-party `Kind` (e.g. ElysiaJS's `t.Files()`) must have\n * // that kind registered with TypeBox's own `TypeRegistry` before validating, since\n * // this resolver validates via `@sinclair/typebox`'s `Value.Errors`/`Value.Check`:\n * // TypeRegistry.Set('Files', (schema, value) => Array.isArray(value));\n */\nexport function typeboxResolver<Schema extends TObject, Context>(\n schema: Schema | TypeCheck<Schema>,\n): Resolver<Static<Schema>, Context, StaticDecode<Schema>> {\n return async (values: Static<Schema>, _, options) => {\n const errors = Array.from(\n schema instanceof TypeCheck\n ? schema.Errors(values)\n : Value.Errors(schema, values),\n );\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {},\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n}\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","Object","create","length","error","type","message","path","_path","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","shift","typeboxResolver","schema","async","values","_","options","Array","from","TypeCheck","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","toNestErrors","criteriaMode"],"mappings":"qOAMA,SAASA,EACPC,EACAC,GAGA,MAAMC,EAAqCC,OAAOC,OAAO,MACzD,KAAOJ,EAAQK,QAAU,CACvB,MAAMC,EAAQN,EAAQ,IAChBO,KAAEA,EAAIC,QAAEA,EAAOC,KAAEA,GAASH,EAC1BI,EAAQD,EACXE,MAAM,KACNC,MAAM,GACNC,IAAKC,GAAYA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,MAC5DC,KAAK,KAMR,GAJKd,EAAOQ,KACVR,EAAOQ,GAAS,CAAEF,UAASD,KAAM,GAAKA,IAGpCN,EAA0B,CAC5B,MAAMgB,EAAQf,EAAOQ,GAAOO,MACtBC,EAAWD,GAASA,EAAM,GAAKV,GAErCL,EAAOQ,GAASS,EACdT,EACAT,EACAC,EACA,GAAKK,EACLW,EACK,GAAgBE,OAAOF,EAAsBZ,EAAME,SACpDF,EAAME,QAEd,CAEAR,EAAQqB,OACV,CAEA,OAAOnB,CACT,CAuBM,SAAUoB,EACdC,GAEA,OAAOC,MAAOC,EAAwBC,EAAGC,KACvC,MAAMzB,EAAS0B,MAAMC,KACnBN,aAAkBO,EACdP,EAAOQ,OAAON,GACdO,EAAMD,OAAOR,EAAQE,IAK3B,OAFAE,EAAQM,2BAA6BC,EAAuB,CAAA,EAAIP,GAE3DzB,EAAOG,OAOL,CACLoB,OAAQ,CAAE,EACVvB,OAAQiC,EACNpC,EACEG,GACCyB,EAAQM,2BAAsD,QAAzBN,EAAQS,cAEhDT,IAbK,CACLzB,OAAQ,GACRuB,SAaH,CAEL"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{TypeCheck as o}from"@sinclair/typebox/compiler";import{Value as t}from"@sinclair/typebox/value";import{appendErrors as
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{TypeCheck as o}from"@sinclair/typebox/compiler";import{Value as t}from"@sinclair/typebox/value";import{appendErrors as a}from"react-hook-form";function s(r,e){for(var o=Object.create(null);r.length;){var t=r[0],s=t.type,i=t.message,n=t.path.split("/").slice(1).map(function(r){return r.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(o[n]||(o[n]={message:i,type:""+s}),e){var l=o[n].types,c=l&&l[""+s];o[n]=a(n,e,o,""+s,c?[].concat(c,t.message):t.message)}r.shift()}return o}function i(a){return function(i,n,l){try{var c=Array.from(a instanceof o?a.Errors(i):t.Errors(a,i));return l.shouldUseNativeValidation&&r({},l),Promise.resolve(c.length?{values:{},errors:e(s(c,!l.shouldUseNativeValidation&&"all"===l.criteriaMode),l)}:{errors:{},values:i})}catch(r){return Promise.reject(r)}}}export{i as typeboxResolver};
|
|
2
2
|
//# sourceMappingURL=typebox.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typebox.module.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.
|
|
1
|
+
{"version":3,"file":"typebox.module.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path\n .split('/')\n .slice(1)\n .map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'))\n .join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | TypeCheck<Schema>} schema - The Typebox schema to validate against\n * @param {Object} options - Additional resolver configuration\n * @param {string} [options.mode='async'] - Validation mode\n * @returns {Resolver<Static<Schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = Type.Object({\n * name: Type.String(),\n * age: Type.Number()\n * });\n *\n * useForm({\n * resolver: typeboxResolver(schema)\n * });\n *\n * // Schemas using a custom/third-party `Kind` (e.g. ElysiaJS's `t.Files()`) must have\n * // that kind registered with TypeBox's own `TypeRegistry` before validating, since\n * // this resolver validates via `@sinclair/typebox`'s `Value.Errors`/`Value.Check`:\n * // TypeRegistry.Set('Files', (schema, value) => Array.isArray(value));\n */\nexport function typeboxResolver<Schema extends TObject, Context>(\n schema: Schema | TypeCheck<Schema>,\n): Resolver<Static<Schema>, Context, StaticDecode<Schema>> {\n return async (values: Static<Schema>, _, options) => {\n const errors = Array.from(\n schema instanceof TypeCheck\n ? schema.Errors(values)\n : Value.Errors(schema, values),\n );\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {},\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n}\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","Object","create","length","error","type","message","_path","path","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","shift","typeboxResolver","schema","values","_","options","Array","from","TypeCheck","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","toNestErrors","criteriaMode","e","reject"],"mappings":"qOAMA,SAASA,EACPC,EACAC,GAIA,IADA,IAAMC,EAAqCC,OAAOC,OAAO,MAClDJ,EAAQK,QAAU,CACvB,IAAMC,EAAQN,EAAQ,GACdO,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KAEpBC,MAAM,KACNC,MAAM,GACNC,IAAI,SAACC,GAAO,OAAKA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,IAAI,GAChEC,KAAK,KAMR,GAJKd,EAAOO,KACVP,EAAOO,GAAS,CAAED,QAAAA,EAASD,KAAM,GAAKA,IAGpCN,EAA0B,CAC5B,IAAMgB,EAAQf,EAAOO,GAAOQ,MACtBC,EAAWD,GAASA,EAAM,GAAKV,GAErCL,EAAOO,GAASU,EACdV,EACAR,EACAC,EACA,GAAKK,EACLW,EACK,GAAgBE,OAAOF,EAAsBZ,EAAME,SACpDF,EAAME,QAEd,CAEAR,EAAQqB,OACV,CAEA,OAAOnB,CACT,UAuBgBoB,EACdC,GAEA,OAAA,SAAcC,EAAwBC,EAAGC,GAAO,IAC9C,IAAMxB,EAASyB,MAAMC,KACnBL,aAAkBM,EACdN,EAAOO,OAAON,GACdO,EAAMD,OAAOP,EAAQC,IAK3B,OAFAE,EAAQM,2BAA6BC,EAAuB,GAAIP,GAShEQ,QAAAC,QAPKjC,EAAOG,OAOL,CACLmB,OAAQ,CAAE,EACVtB,OAAQkC,EACNrC,EACEG,GACCwB,EAAQM,2BAAsD,QAAzBN,EAAQW,cAEhDX,IAbK,CACLxB,OAAQ,GACRsB,OAAAA,GAcN,CAAC,MAAAc,GAAAJ,OAAAA,QAAAK,OAAAD,EACH,CAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("@hookform/resolvers"),require("@sinclair/typebox/compiler"),require("@sinclair/typebox/value"),require("react-hook-form")):"function"==typeof define&&define.amd?define(["exports","@hookform/resolvers","@sinclair/typebox/compiler","@sinclair/typebox/value","react-hook-form"],r):r((e||self).hookformResolversTypebox={},e.hookformResolvers,e.compiler,e.value,e.ReactHookForm)}(this,function(e,r,o,t,s){function i(e,r){for(var o=Object.create(null);e.length;){var t=e[0],i=t.type,a=t.message,l=t.path.
|
|
1
|
+
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("@hookform/resolvers"),require("@sinclair/typebox/compiler"),require("@sinclair/typebox/value"),require("react-hook-form")):"function"==typeof define&&define.amd?define(["exports","@hookform/resolvers","@sinclair/typebox/compiler","@sinclair/typebox/value","react-hook-form"],r):r((e||self).hookformResolversTypebox={},e.hookformResolvers,e.compiler,e.value,e.ReactHookForm)}(this,function(e,r,o,t,s){function i(e,r){for(var o=Object.create(null);e.length;){var t=e[0],i=t.type,a=t.message,l=t.path.split("/").slice(1).map(function(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(o[l]||(o[l]={message:a,type:""+i}),r){var n=o[l].types,c=n&&n[""+i];o[l]=s.appendErrors(l,r,o,""+i,c?[].concat(c,t.message):t.message)}e.shift()}return o}e.typeboxResolver=function(e){return function(s,a,l){try{var n=Array.from(e instanceof o.TypeCheck?e.Errors(s):t.Value.Errors(e,s));return l.shouldUseNativeValidation&&r.validateFieldsNatively({},l),Promise.resolve(n.length?{values:{},errors:r.toNestErrors(i(n,!l.shouldUseNativeValidation&&"all"===l.criteriaMode),l)}:{errors:{},values:s})}catch(e){return Promise.reject(e)}}}});
|
|
2
2
|
//# sourceMappingURL=typebox.umd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typebox.umd.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.
|
|
1
|
+
{"version":3,"file":"typebox.umd.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { Static, StaticDecode, TObject } from '@sinclair/typebox';\nimport { TypeCheck } from '@sinclair/typebox/compiler';\nimport { Value, type ValueError } from '@sinclair/typebox/value';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\n\nfunction parseErrorSchema(\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) {\n // See the matching comment in the zod resolver's `parseZod3Issues`.\n const errors: Record<string, FieldError> = Object.create(null);\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path\n .split('/')\n .slice(1)\n .map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'))\n .join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | TypeCheck<Schema>} schema - The Typebox schema to validate against\n * @param {Object} options - Additional resolver configuration\n * @param {string} [options.mode='async'] - Validation mode\n * @returns {Resolver<Static<Schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = Type.Object({\n * name: Type.String(),\n * age: Type.Number()\n * });\n *\n * useForm({\n * resolver: typeboxResolver(schema)\n * });\n *\n * // Schemas using a custom/third-party `Kind` (e.g. ElysiaJS's `t.Files()`) must have\n * // that kind registered with TypeBox's own `TypeRegistry` before validating, since\n * // this resolver validates via `@sinclair/typebox`'s `Value.Errors`/`Value.Check`:\n * // TypeRegistry.Set('Files', (schema, value) => Array.isArray(value));\n */\nexport function typeboxResolver<Schema extends TObject, Context>(\n schema: Schema | TypeCheck<Schema>,\n): Resolver<Static<Schema>, Context, StaticDecode<Schema>> {\n return async (values: Static<Schema>, _, options) => {\n const errors = Array.from(\n schema instanceof TypeCheck\n ? schema.Errors(values)\n : Value.Errors(schema, values),\n );\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {},\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n}\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","Object","create","length","error","type","message","_path","path","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","shift","schema","values","_","options","Array","from","TypeCheck","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","toNestErrors","criteriaMode","e","reject"],"mappings":"mhBAMA,SAASA,EACPC,EACAC,GAIA,IADA,IAAMC,EAAqCC,OAAOC,OAAO,MAClDJ,EAAQK,QAAU,CACvB,IAAMC,EAAQN,EAAQ,GACdO,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KAEpBC,MAAM,KACNC,MAAM,GACNC,IAAI,SAACC,GAAO,OAAKA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,IAAI,GAChEC,KAAK,KAMR,GAJKd,EAAOO,KACVP,EAAOO,GAAS,CAAED,QAAAA,EAASD,KAAM,GAAKA,IAGpCN,EAA0B,CAC5B,IAAMgB,EAAQf,EAAOO,GAAOQ,MACtBC,EAAWD,GAASA,EAAM,GAAKV,GAErCL,EAAOO,GAASU,eACdV,EACAR,EACAC,EACA,GAAKK,EACLW,EACK,GAAgBE,OAAOF,EAAsBZ,EAAME,SACpDF,EAAME,QAEd,CAEAR,EAAQqB,OACV,CAEA,OAAOnB,CACT,4BAwBEoB,GAEA,OAAA,SAAcC,EAAwBC,EAAGC,GAAO,IAC9C,IAAMvB,EAASwB,MAAMC,KACnBL,aAAkBM,EAASA,UACvBN,EAAOO,OAAON,GACdO,QAAMD,OAAOP,EAAQC,IAK3B,OAFAE,EAAQM,2BAA6BC,EAAsBA,uBAAC,GAAIP,GAShEQ,QAAAC,QAPKhC,EAAOG,OAOL,CACLkB,OAAQ,CAAE,EACVrB,OAAQiC,eACNpC,EACEG,GACCuB,EAAQM,2BAAsD,QAAzBN,EAAQW,cAEhDX,IAbK,CACLvB,OAAQ,GACRqB,OAAAA,GAcN,CAAC,MAAAc,GAAAJ,OAAAA,QAAAK,OAAAD,EACH,CAAA,CAAA"}
|
|
@@ -1,8 +1,110 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
|
+
import { TypeCompiler } from '@sinclair/typebox/compiler';
|
|
3
|
+
import { ValueErrorType } from '@sinclair/typebox/errors';
|
|
4
|
+
import { createFormControl } from 'react-hook-form';
|
|
2
5
|
import { typeboxResolver } from '..';
|
|
3
6
|
|
|
4
7
|
const shouldUseNativeValidation = false;
|
|
5
8
|
|
|
9
|
+
describe.each([false, true])('typeboxResolver with compiler=%s', (compiled) => {
|
|
10
|
+
it.each(
|
|
11
|
+
['a/b', 'a~b', 'a~1b'].flatMap((name) =>
|
|
12
|
+
(['firstError', 'all'] as const).map((criteriaMode) => ({
|
|
13
|
+
name,
|
|
14
|
+
criteriaMode,
|
|
15
|
+
})),
|
|
16
|
+
),
|
|
17
|
+
)(
|
|
18
|
+
'preserves $name with criteriaMode=$criteriaMode',
|
|
19
|
+
async ({ name, criteriaMode }) => {
|
|
20
|
+
const schema = Type.Object({ [name]: Type.String({ minLength: 1 }) });
|
|
21
|
+
const ref = { name };
|
|
22
|
+
const type = String(ValueErrorType.StringMinLength);
|
|
23
|
+
const message = 'Expected string length greater or equal to 1';
|
|
24
|
+
const result = await typeboxResolver(
|
|
25
|
+
compiled ? TypeCompiler.Compile(schema) : schema,
|
|
26
|
+
)({ [name]: '' }, undefined, {
|
|
27
|
+
fields: { [name]: { name, ref } },
|
|
28
|
+
criteriaMode,
|
|
29
|
+
shouldUseNativeValidation,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
expect(result).toEqual({
|
|
33
|
+
values: {},
|
|
34
|
+
errors: {
|
|
35
|
+
[name]: {
|
|
36
|
+
type,
|
|
37
|
+
message,
|
|
38
|
+
ref,
|
|
39
|
+
...(criteriaMode === 'all' ? { types: { [type]: message } } : {}),
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
expect(result.errors[name]?.ref).toBe(ref);
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
it('preserves escaped array paths and all error messages', async () => {
|
|
48
|
+
const schema = Type.Object({
|
|
49
|
+
'parent/~1': Type.Array(
|
|
50
|
+
Type.Object({
|
|
51
|
+
'a~1/b': Type.String({ minLength: 1, pattern: '^a' }),
|
|
52
|
+
}),
|
|
53
|
+
),
|
|
54
|
+
});
|
|
55
|
+
const name = 'parent/~1.0.a~1/b';
|
|
56
|
+
const ref = { name };
|
|
57
|
+
const type = String(ValueErrorType.StringMinLength);
|
|
58
|
+
const message = 'Expected string length greater or equal to 1';
|
|
59
|
+
const result = await typeboxResolver(
|
|
60
|
+
compiled ? TypeCompiler.Compile(schema) : schema,
|
|
61
|
+
)({ 'parent/~1': [{ 'a~1/b': '' }] }, undefined, {
|
|
62
|
+
names: [name],
|
|
63
|
+
fields: { [name]: { name, ref } },
|
|
64
|
+
criteriaMode: 'all',
|
|
65
|
+
shouldUseNativeValidation,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(result.errors).toEqual({
|
|
69
|
+
'parent/~1': [
|
|
70
|
+
{
|
|
71
|
+
'a~1/b': {
|
|
72
|
+
type,
|
|
73
|
+
message,
|
|
74
|
+
types: {
|
|
75
|
+
[type]: message,
|
|
76
|
+
[ValueErrorType.StringPattern]: "Expected string to match '^a'",
|
|
77
|
+
},
|
|
78
|
+
ref,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
});
|
|
83
|
+
expect(result.errors['parent/~1']?.[0]?.['a~1/b']?.ref).toBe(ref);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('fails field validation for a registered escaped name', async () => {
|
|
87
|
+
const schema = Type.Object({
|
|
88
|
+
'profile/name': Type.String({ minLength: 1 }),
|
|
89
|
+
});
|
|
90
|
+
const form = createFormControl({
|
|
91
|
+
defaultValues: { 'profile/name': '' },
|
|
92
|
+
resolver: typeboxResolver(
|
|
93
|
+
compiled ? TypeCompiler.Compile(schema) : schema,
|
|
94
|
+
),
|
|
95
|
+
});
|
|
96
|
+
form.register('profile/name');
|
|
97
|
+
|
|
98
|
+
expect(await form.trigger('profile/name')).toBe(false);
|
|
99
|
+
expect(form.getFieldState('profile/name').invalid).toBe(true);
|
|
100
|
+
|
|
101
|
+
form.setValue('profile/name', 'Alice');
|
|
102
|
+
|
|
103
|
+
expect(await form.trigger('profile/name')).toBe(true);
|
|
104
|
+
expect(form.getFieldState('profile/name').invalid).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
6
108
|
describe('typeboxResolver special path names', () => {
|
|
7
109
|
it.each(['hasOwnProperty', 'toString'])(
|
|
8
110
|
'reports a validation error for a field named "%s"',
|
package/typebox/src/typebox.ts
CHANGED
|
@@ -13,7 +13,11 @@ function parseErrorSchema(
|
|
|
13
13
|
for (; _errors.length; ) {
|
|
14
14
|
const error = _errors[0];
|
|
15
15
|
const { type, message, path } = error;
|
|
16
|
-
const _path = path
|
|
16
|
+
const _path = path
|
|
17
|
+
.split('/')
|
|
18
|
+
.slice(1)
|
|
19
|
+
.map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'))
|
|
20
|
+
.join('.');
|
|
17
21
|
|
|
18
22
|
if (!errors[_path]) {
|
|
19
23
|
errors[_path] = { message, type: '' + type };
|