@hookform/resolvers 6.0.1 → 7.0.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 +16 -21
- package/package.json +7 -7
- package/typebox/dist/typebox.d.ts +8 -9
- 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/package.json +1 -1
- package/typebox/src/__tests__/Form-compiler.tsx +7 -5
- package/typebox/src/__tests__/Form-native-validation-compiler.tsx +5 -5
- package/typebox/src/__tests__/Form-native-validation.tsx +3 -3
- package/typebox/src/__tests__/Form.tsx +2 -2
- package/typebox/src/__tests__/__fixtures__/data.ts +4 -8
- package/typebox/src/__tests__/__snapshots__/typebox-compiler.ts.snap +56 -63
- package/typebox/src/__tests__/__snapshots__/typebox.ts.snap +56 -63
- package/typebox/src/__tests__/special-path-names.ts +137 -6
- package/typebox/src/__tests__/typebox-compiler.ts +2 -2
- package/typebox/src/__tests__/typebox.ts +36 -8
- package/typebox/src/typebox.ts +59 -29
package/README.md
CHANGED
|
@@ -583,14 +583,16 @@ const App = () => {
|
|
|
583
583
|
|
|
584
584
|
JSON Schema Type Builder with Static Type Resolution for TypeScript
|
|
585
585
|
|
|
586
|
-
[](https://bundlephobia.com/result?p=typebox)
|
|
587
587
|
|
|
588
|
-
|
|
588
|
+
> Requires `typebox` 1.x (`npm install typebox`). The legacy `@sinclair/typebox` 0.x package is no longer supported.
|
|
589
|
+
|
|
590
|
+
#### With `Value`
|
|
589
591
|
|
|
590
592
|
```tsx
|
|
591
593
|
import { useForm } from 'react-hook-form';
|
|
592
594
|
import { typeboxResolver } from '@hookform/resolvers/typebox';
|
|
593
|
-
import { Type } from '
|
|
595
|
+
import { Type } from 'typebox';
|
|
594
596
|
|
|
595
597
|
const schema = Type.Object({
|
|
596
598
|
username: Type.String({ minLength: 1 }),
|
|
@@ -612,22 +614,22 @@ const App = () => {
|
|
|
612
614
|
};
|
|
613
615
|
```
|
|
614
616
|
|
|
615
|
-
#### With `
|
|
617
|
+
#### With `Compile`
|
|
616
618
|
|
|
617
|
-
A high-performance JIT of `TypeBox`, [read more](https://github.
|
|
619
|
+
A high-performance JIT of `TypeBox`, [read more](https://sinclairzx81.github.io/typebox/#/docs/compile/overview)
|
|
618
620
|
|
|
619
621
|
```tsx
|
|
620
622
|
import { useForm } from 'react-hook-form';
|
|
621
623
|
import { typeboxResolver } from '@hookform/resolvers/typebox';
|
|
622
|
-
import { Type } from '
|
|
623
|
-
import {
|
|
624
|
+
import { Type } from 'typebox';
|
|
625
|
+
import { Compile } from 'typebox/compile';
|
|
624
626
|
|
|
625
627
|
const schema = Type.Object({
|
|
626
628
|
username: Type.String({ minLength: 1 }),
|
|
627
629
|
password: Type.String({ minLength: 1 }),
|
|
628
630
|
});
|
|
629
631
|
|
|
630
|
-
const typecheck =
|
|
632
|
+
const typecheck = Compile(schema);
|
|
631
633
|
|
|
632
634
|
const App = () => {
|
|
633
635
|
const { register, handleSubmit } = useForm({
|
|
@@ -644,25 +646,18 @@ const App = () => {
|
|
|
644
646
|
};
|
|
645
647
|
```
|
|
646
648
|
|
|
647
|
-
#### Custom
|
|
649
|
+
#### Custom formats
|
|
648
650
|
|
|
649
|
-
`typeboxResolver` validates using
|
|
650
|
-
|
|
651
|
-
must be registered with TypeBox's own `TypeRegistry` (and `FormatRegistry` for string formats) before
|
|
652
|
-
it's used — this is a TypeBox-level extension point, not something `@hookform/resolvers` wraps or needs
|
|
653
|
-
to expose separately:
|
|
651
|
+
`typeboxResolver` validates using `typebox`'s own `Value.Errors` (or the compiled `Validator`), so custom
|
|
652
|
+
string formats must be registered with TypeBox's `Format` registry before they're used:
|
|
654
653
|
|
|
655
654
|
```tsx
|
|
656
|
-
import {
|
|
655
|
+
import { Format } from 'typebox/format';
|
|
657
656
|
|
|
658
|
-
|
|
659
|
-
TypeRegistry.Set('Files', (schema, value) => Array.isArray(value));
|
|
660
|
-
}
|
|
657
|
+
Format.Set('slug', (value) => /^[a-z0-9-]+$/.test(value));
|
|
661
658
|
```
|
|
662
659
|
|
|
663
|
-
Make sure this registration runs against the same
|
|
664
|
-
built with — if a library vendors its own copy of `@sinclair/typebox` instead of relying on the shared
|
|
665
|
-
peer dependency, its registrations won't be visible here, and you'll see a runtime `"Unknown type"` error.
|
|
660
|
+
Make sure this registration runs against the same `typebox` module instance the schema was built with.
|
|
666
661
|
|
|
667
662
|
### [ArkType](https://github.com/arktypeio/arktype)
|
|
668
663
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hookform/resolvers",
|
|
3
3
|
"amdName": "hookformResolvers",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "7.0.0",
|
|
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",
|
|
@@ -222,7 +222,7 @@
|
|
|
222
222
|
"build:computed-types": "microbundle --cwd computed-types --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
|
|
223
223
|
"build:typanion": "microbundle --cwd typanion --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
|
|
224
224
|
"build:ajv": "microbundle --cwd ajv --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
|
|
225
|
-
"build:typebox": "microbundle --cwd typebox --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm
|
|
225
|
+
"build:typebox": "microbundle --cwd typebox --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm,typebox/value=value,typebox/compile=compile,typebox/system=system",
|
|
226
226
|
"build:arktype": "microbundle --cwd arktype --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
|
|
227
227
|
"build:valibot": "microbundle --cwd valibot --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
|
|
228
228
|
"build:typeschema": "microbundle --cwd typeschema --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm,@typeschema/main=main",
|
|
@@ -277,7 +277,6 @@
|
|
|
277
277
|
"homepage": "https://react-hook-form.com",
|
|
278
278
|
"devDependencies": {
|
|
279
279
|
"@biomejs/biome": "^1.9.4",
|
|
280
|
-
"@sinclair/typebox": "^0.34.52",
|
|
281
280
|
"@standard-schema/spec": "^1.1.0",
|
|
282
281
|
"@testing-library/dom": "^10.4.1",
|
|
283
282
|
"@testing-library/jest-dom": "^6.10.0",
|
|
@@ -319,6 +318,7 @@
|
|
|
319
318
|
"reflect-metadata": "^0.2.2",
|
|
320
319
|
"superstruct": "^2.0.2",
|
|
321
320
|
"typanion": "^3.14.0",
|
|
321
|
+
"typebox": "^1.4.3",
|
|
322
322
|
"typescript": "^6.0.3",
|
|
323
323
|
"valibot": "1.0.0-beta.12",
|
|
324
324
|
"vest": "^6.3.2",
|
|
@@ -329,7 +329,6 @@
|
|
|
329
329
|
"zod": "^3.25.76"
|
|
330
330
|
},
|
|
331
331
|
"peerDependencies": {
|
|
332
|
-
"@sinclair/typebox": ">=0.25.24",
|
|
333
332
|
"@standard-schema/spec": "^1.0.0",
|
|
334
333
|
"@vinejs/vine": "^2.0.0 || ^3.0.0 || ^4.0.0",
|
|
335
334
|
"ajv": "^8.12.0",
|
|
@@ -349,15 +348,13 @@
|
|
|
349
348
|
"react-hook-form": "^7.55.0",
|
|
350
349
|
"superstruct": ">=0.12.0",
|
|
351
350
|
"typanion": "^3.3.2",
|
|
351
|
+
"typebox": "^1.0.0",
|
|
352
352
|
"valibot": ">=0.31.0 || ^1.0.0-beta.4 || ^1.0.0-rc",
|
|
353
353
|
"vest": ">=6.0.0",
|
|
354
354
|
"yup": "^1.0.0",
|
|
355
355
|
"zod": "^3.25.0 || ^4.0.0"
|
|
356
356
|
},
|
|
357
357
|
"peerDependenciesMeta": {
|
|
358
|
-
"@sinclair/typebox": {
|
|
359
|
-
"optional": true
|
|
360
|
-
},
|
|
361
358
|
"@standard-schema/spec": {
|
|
362
359
|
"optional": true
|
|
363
360
|
},
|
|
@@ -412,6 +409,9 @@
|
|
|
412
409
|
"typanion": {
|
|
413
410
|
"optional": true
|
|
414
411
|
},
|
|
412
|
+
"typebox": {
|
|
413
|
+
"optional": true
|
|
414
|
+
},
|
|
415
415
|
"valibot": {
|
|
416
416
|
"optional": true
|
|
417
417
|
},
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Static, StaticDecode, TObject } from '@sinclair/typebox';
|
|
2
|
-
import { TypeCheck } from '@sinclair/typebox/compiler';
|
|
3
1
|
import { Resolver } from 'react-hook-form';
|
|
2
|
+
import type { Static, StaticDecode, TObject, TProperties } from 'typebox';
|
|
3
|
+
import { Validator } from 'typebox/compile';
|
|
4
4
|
/**
|
|
5
5
|
* Creates a resolver for react-hook-form using Typebox schema validation
|
|
6
|
-
* @param {Schema |
|
|
6
|
+
* @param {Schema | Validator<TypeContext, Schema>} schema - The Typebox schema to validate against
|
|
7
7
|
* @param {Object} options - Additional resolver configuration
|
|
8
8
|
* @param {string} [options.mode='async'] - Validation mode
|
|
9
|
-
* @returns {Resolver<Static<Schema>>} A resolver function compatible with react-hook-form
|
|
9
|
+
* @returns {Resolver<Static<Schema, TypeContext>>} A resolver function compatible with react-hook-form
|
|
10
10
|
* @example
|
|
11
11
|
* const schema = Type.Object({
|
|
12
12
|
* name: Type.String(),
|
|
@@ -17,9 +17,8 @@ import { Resolver } from 'react-hook-form';
|
|
|
17
17
|
* resolver: typeboxResolver(schema)
|
|
18
18
|
* });
|
|
19
19
|
*
|
|
20
|
-
* //
|
|
21
|
-
* //
|
|
22
|
-
* //
|
|
23
|
-
* // TypeRegistry.Set('Files', (schema, value) => Array.isArray(value));
|
|
20
|
+
* // Custom string formats must be registered with TypeBox's own `Format` registry
|
|
21
|
+
* // before validating, since this resolver validates via `typebox`'s `Value.Errors`:
|
|
22
|
+
* // Format.Set('slug', (value) => /^[a-z0-9-]+$/.test(value));
|
|
24
23
|
*/
|
|
25
|
-
export declare function typeboxResolver<Schema extends TObject, Context
|
|
24
|
+
export declare function typeboxResolver<Schema extends TObject, Context, TypeContext extends TProperties = Record<never, never>>(schema: Schema | Validator<TypeContext, Schema>): Resolver<Static<Schema, TypeContext>, Context, StaticDecode<Schema, TypeContext>>;
|
package/typebox/dist/typebox.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var r=require("@hookform/resolvers"),e=require("react-hook-form"),t=require("typebox/compile"),n=require("typebox/system"),a=require("typebox/value");function o(r,e){(null==e||e>r.length)&&(e=r.length);for(var t=0,n=Array(e);t<e;t++)n[t]=r[t];return n}function i(){return i=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var n in t)({}).hasOwnProperty.call(t,n)&&(r[n]=t[n])}return r},i.apply(null,arguments)}function s(r,t){for(var n,a=Object.create(null),i=function(r){var e="undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(e)return(e=e.call(r)).next.bind(e);if(Array.isArray(r)||(e=function(r,e){if(r){if("string"==typeof r)return o(r,e);var t={}.toString.call(r).slice(8,-1);return"Object"===t&&r.constructor&&(t=r.constructor.name),"Map"===t||"Set"===t?Array.from(r):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?o(r,e):void 0}}(r))){e&&(r=e);var t=0;return function(){return t>=r.length?{done:!0}:{done:!1,value:r[t++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(r);!(n=i()).done;){var s=n.value,l=s.keyword,u=s.message,c=s.instancePath.split("/").slice(1).map(function(r){return r.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(a[c]||(a[c]={message:u,type:l}),t){var p=a[c].types,f=p&&p[l];a[c]=e.appendErrors(c,t,a,l,f?[].concat(f,u):u)}}return a}exports.typeboxResolver=function(e){return function(o,l,u){try{var c=function(r){return r.flatMap(function(r){return"required"===r.keyword?r.params.requiredProperties.map(function(e){var t=i({},r,{instancePath:r.instancePath+"/"+e.replace(/~/g,"~0").replace(/\//g,"~1"),params:{requiredProperties:[e]}});return i({},t,{message:n.Locale.Get()(t)})}):[r]})}(e instanceof t.Validator?e.Errors(o):a.Value.Errors(e,o));return u.shouldUseNativeValidation&&r.validateFieldsNatively({},u),Promise.resolve(c.length?{values:{},errors:r.toNestErrors(s(c,!u.shouldUseNativeValidation&&"all"===u.criteriaMode),u)}:{errors:{},values:o})}catch(r){return Promise.reject(r)}}};
|
|
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 '
|
|
1
|
+
{"version":3,"file":"typebox.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\nimport type { Static, StaticDecode, TObject, TProperties } from 'typebox';\nimport { Validator } from 'typebox/compile';\nimport type { TLocalizedValidationError } from 'typebox/error';\nimport { Locale } from 'typebox/system';\nimport { Value } from 'typebox/value';\n\n// TypeBox reports a single `required` error on the parent object listing every\n// missing property; split it into one error per missing field so each one lands\n// on its own path, re-localizing the message for that single property.\nfunction expandRequiredErrors(\n errors: TLocalizedValidationError[],\n): TLocalizedValidationError[] {\n return errors.flatMap<TLocalizedValidationError>((error) =>\n error.keyword === 'required'\n ? error.params.requiredProperties.map((property) => {\n const single = {\n ...error,\n instancePath: `${error.instancePath}/${property.replace(/~/g, '~0').replace(/\\//g, '~1')}`,\n params: { requiredProperties: [property] },\n };\n return { ...single, message: Locale.Get()(single) };\n })\n : [error],\n );\n}\n\nfunction parseErrorSchema(\n _errors: TLocalizedValidationError[],\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 (const error of _errors) {\n const { keyword: type, message, instancePath } = error;\n const _path = instancePath\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 };\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[], message)\n : message,\n ) as FieldError;\n }\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | Validator<TypeContext, 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, TypeContext>>} 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 * // Custom string formats must be registered with TypeBox's own `Format` registry\n * // before validating, since this resolver validates via `typebox`'s `Value.Errors`:\n * // Format.Set('slug', (value) => /^[a-z0-9-]+$/.test(value));\n */\nexport function typeboxResolver<\n Schema extends TObject,\n Context,\n TypeContext extends TProperties = Record<never, never>,\n>(\n schema: Schema | Validator<TypeContext, Schema>,\n): Resolver<\n Static<Schema, TypeContext>,\n Context,\n StaticDecode<Schema, TypeContext>\n> {\n return async (values: Static<Schema, TypeContext>, _, options) => {\n const errors = expandRequiredErrors(\n schema instanceof Validator\n ? (schema as Validator<TypeContext, 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: values as StaticDecode<Schema, TypeContext>,\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","_step","errors","Object","create","_iterator","_createForOfIteratorHelperLoose","done","error","value","type","keyword","message","_path","instancePath","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","schema","values","_","options","flatMap","params","requiredProperties","property","single","_extends","Locale","Get","expandRequiredErrors","Validator","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","length","toNestErrors","criteriaMode","e","reject"],"mappings":"odA4BA,SAASA,EACPC,EACAC,GAIA,IADA,IAC2BC,EADrBC,EAAqCC,OAAOC,OAAO,MACzDC,2pBAAAC,CAAoBP,KAAOE,EAAAI,KAAAE,MAAE,CAAlB,IAAAC,EAAKP,EAAAQ,MACGC,EAAgCF,EAAzCG,QAAeC,EAA0BJ,EAA1BI,QACjBC,EAD2CL,EAAjBM,aAE7BC,MAAM,KACNC,MAAM,GACNC,IAAI,SAACC,GAAO,OAAKA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,IAAI,GAChEC,KAAK,KAMR,GAJKlB,EAAOW,KACVX,EAAOW,GAAS,CAAED,QAAAA,EAASF,KAAAA,IAGzBV,EAA0B,CAC5B,IAAMqB,EAAQnB,EAAOW,GAAOQ,MACtBC,EAAWD,GAASA,EAAMX,GAEhCR,EAAOW,GAASU,EAAYA,aAC1BV,EACAb,EACAE,EACAQ,EACAY,EACK,GAAgBE,OAAOF,EAAsBV,GAC9CA,EAER,CACF,CAEA,OAAOV,CACT,yBAsBgB,SAKduB,GAMA,OAAcC,SAAAA,EAAqCC,EAAGC,OACpD,IAAM1B,EAtFV,SACEA,GAEA,OAAOA,EAAO2B,QAAmC,SAACrB,GAChD,MAAkB,aAAlBA,EAAMG,QACFH,EAAMsB,OAAOC,mBAAmBd,IAAI,SAACe,GACnC,IAAMC,EAAMC,EACP1B,GAAAA,GACHM,aAAiBN,EAAMM,aAAY,IAAIkB,EAASb,QAAQ,KAAM,MAAMA,QAAQ,MAAO,MACnFW,OAAQ,CAAEC,mBAAoB,CAACC,MAEjC,OAAAE,EAAYD,GAAAA,EAAQrB,CAAAA,QAASuB,EAAAA,OAAOC,KAAPD,CAAaF,IAC5C,GACA,CAACzB,EAAM,EAEf,CAuEmB6B,CACbZ,aAAkBa,EAASA,UACtBb,EAA0Cc,OAAOb,GAClDc,QAAMD,OAAOd,EAAQC,IAK3B,OAFAE,EAAQa,2BAA6BC,yBAAuB,CAAA,EAAId,GAShEe,QAAAC,QAPK1C,EAAO2C,OAOL,CACLnB,OAAQ,CAAA,EACRxB,OAAQ4C,EAAYA,aAClBhD,EACEI,GACC0B,EAAQa,2BAAsD,QAAzBb,EAAQmB,cAEhDnB,IAbK,CACL1B,OAAQ,CAAA,EACRwB,OAAQA,GAcd,CAAC,MAAAsB,GAAA,OAAAL,QAAAM,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{
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{appendErrors as t}from"react-hook-form";import{Validator as n}from"typebox/compile";import{Locale as o}from"typebox/system";import{Value as a}from"typebox/value";function i(r,e){(null==e||e>r.length)&&(e=r.length);for(var t=0,n=Array(e);t<e;t++)n[t]=r[t];return n}function s(){return s=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var n in t)({}).hasOwnProperty.call(t,n)&&(r[n]=t[n])}return r},s.apply(null,arguments)}function l(r,e){for(var n,o=Object.create(null),a=function(r){var e="undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(e)return(e=e.call(r)).next.bind(e);if(Array.isArray(r)||(e=function(r,e){if(r){if("string"==typeof r)return i(r,e);var t={}.toString.call(r).slice(8,-1);return"Object"===t&&r.constructor&&(t=r.constructor.name),"Map"===t||"Set"===t?Array.from(r):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?i(r,e):void 0}}(r))){e&&(r=e);var t=0;return function(){return t>=r.length?{done:!0}:{done:!1,value:r[t++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(r);!(n=a()).done;){var s=n.value,l=s.keyword,u=s.message,c=s.instancePath.split("/").slice(1).map(function(r){return r.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(o[c]||(o[c]={message:u,type:l}),e){var f=o[c].types,m=f&&f[l];o[c]=t(c,e,o,l,m?[].concat(m,u):u)}}return o}function u(t){return function(i,u,c){try{var f=function(r){return r.flatMap(function(r){return"required"===r.keyword?r.params.requiredProperties.map(function(e){var t=s({},r,{instancePath:r.instancePath+"/"+e.replace(/~/g,"~0").replace(/\//g,"~1"),params:{requiredProperties:[e]}});return s({},t,{message:o.Get()(t)})}):[r]})}(t instanceof n?t.Errors(i):a.Errors(t,i));return c.shouldUseNativeValidation&&r({},c),Promise.resolve(f.length?{values:{},errors:e(l(f,!c.shouldUseNativeValidation&&"all"===c.criteriaMode),c)}:{errors:{},values:i})}catch(r){return Promise.reject(r)}}}export{u 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{
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{appendErrors as t}from"react-hook-form";import{Validator as o}from"typebox/compile";import{Locale as a}from"typebox/system";import{Value as n}from"typebox/value";function s(){return s=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var o in t)({}).hasOwnProperty.call(t,o)&&(r[o]=t[o])}return r},s.apply(null,arguments)}function i(r,e){const o=Object.create(null);for(const a of r){const{keyword:r,message:n,instancePath:s}=a,i=s.split("/").slice(1).map(r=>r.replace(/~1/g,"/").replace(/~0/g,"~")).join(".");if(o[i]||(o[i]={message:n,type:r}),e){const a=o[i].types,s=a&&a[r];o[i]=t(i,e,o,r,s?[].concat(s,n):n)}}return o}function c(t){return async(c,l,p)=>{const u=function(r){return r.flatMap(r=>"required"===r.keyword?r.params.requiredProperties.map(e=>{const t=s({},r,{instancePath:`${r.instancePath}/${e.replace(/~/g,"~0").replace(/\//g,"~1")}`,params:{requiredProperties:[e]}});return s({},t,{message:a.Get()(t)})}):[r])}(t instanceof o?t.Errors(c):n.Errors(t,c));return p.shouldUseNativeValidation&&r({},p),u.length?{values:{},errors:e(i(u,!p.shouldUseNativeValidation&&"all"===p.criteriaMode),p)}:{errors:{},values:c}}}export{c 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 '
|
|
1
|
+
{"version":3,"file":"typebox.modern.mjs","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\nimport type { Static, StaticDecode, TObject, TProperties } from 'typebox';\nimport { Validator } from 'typebox/compile';\nimport type { TLocalizedValidationError } from 'typebox/error';\nimport { Locale } from 'typebox/system';\nimport { Value } from 'typebox/value';\n\n// TypeBox reports a single `required` error on the parent object listing every\n// missing property; split it into one error per missing field so each one lands\n// on its own path, re-localizing the message for that single property.\nfunction expandRequiredErrors(\n errors: TLocalizedValidationError[],\n): TLocalizedValidationError[] {\n return errors.flatMap<TLocalizedValidationError>((error) =>\n error.keyword === 'required'\n ? error.params.requiredProperties.map((property) => {\n const single = {\n ...error,\n instancePath: `${error.instancePath}/${property.replace(/~/g, '~0').replace(/\\//g, '~1')}`,\n params: { requiredProperties: [property] },\n };\n return { ...single, message: Locale.Get()(single) };\n })\n : [error],\n );\n}\n\nfunction parseErrorSchema(\n _errors: TLocalizedValidationError[],\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 (const error of _errors) {\n const { keyword: type, message, instancePath } = error;\n const _path = instancePath\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 };\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[], message)\n : message,\n ) as FieldError;\n }\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | Validator<TypeContext, 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, TypeContext>>} 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 * // Custom string formats must be registered with TypeBox's own `Format` registry\n * // before validating, since this resolver validates via `typebox`'s `Value.Errors`:\n * // Format.Set('slug', (value) => /^[a-z0-9-]+$/.test(value));\n */\nexport function typeboxResolver<\n Schema extends TObject,\n Context,\n TypeContext extends TProperties = Record<never, never>,\n>(\n schema: Schema | Validator<TypeContext, Schema>,\n): Resolver<\n Static<Schema, TypeContext>,\n Context,\n StaticDecode<Schema, TypeContext>\n> {\n return async (values: Static<Schema, TypeContext>, _, options) => {\n const errors = expandRequiredErrors(\n schema instanceof Validator\n ? (schema as Validator<TypeContext, 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: values as StaticDecode<Schema, TypeContext>,\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","error","keyword","type","message","instancePath","_path","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","typeboxResolver","schema","values","_","options","flatMap","params","requiredProperties","property","single","_extends","Locale","Get","expandRequiredErrors","Validator","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","length","toNestErrors","criteriaMode"],"mappings":"gdA4BA,SAASA,EACPC,EACAC,GAGA,MAAMC,EAAqCC,OAAOC,OAAO,MACzD,IAAK,MAAMC,KAASL,EAAS,CAC3B,MAAQM,QAASC,EAAIC,QAAEA,EAAOC,aAAEA,GAAiBJ,EAC3CK,EAAQD,EACXE,MAAM,KACNC,MAAM,GACNC,IAAKC,GAAYA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,MAC5DC,KAAK,KAMR,GAJKd,EAAOQ,KACVR,EAAOQ,GAAS,CAAEF,UAASD,SAGzBN,EAA0B,CAC5B,MAAMgB,EAAQf,EAAOQ,GAAOO,MACtBC,EAAWD,GAASA,EAAMV,GAEhCL,EAAOQ,GAASS,EACdT,EACAT,EACAC,EACAK,EACAW,EACK,GAAgBE,OAAOF,EAAsBV,GAC9CA,EAER,CACF,CAEA,OAAON,CACT,CAsBM,SAAUmB,EAKdC,GAMA,aAAcC,EAAqCC,EAAGC,KACpD,MAAMvB,EAtFV,SACEA,GAEA,OAAOA,EAAOwB,QAAoCrB,GAC9B,aAAlBA,EAAMC,QACFD,EAAMsB,OAAOC,mBAAmBf,IAAKgB,IACnC,MAAMC,EAAMC,KACP1B,EAAK,CACRI,aAAc,GAAGJ,EAAMI,gBAAgBoB,EAASd,QAAQ,KAAM,MAAMA,QAAQ,MAAO,QACnFY,OAAQ,CAAEC,mBAAoB,CAACC,MAEjC,OAAAE,EAAYD,GAAAA,GAAQtB,QAASwB,EAAOC,KAAPD,CAAaF,IAAO,GAEnD,CAACzB,GAET,CAuEmB6B,CACbZ,aAAkBa,EACbb,EAA0Cc,OAAOb,GAClDc,EAAMD,OAAOd,EAAQC,IAK3B,OAFAE,EAAQa,2BAA6BC,EAAuB,CAAA,EAAId,GAE3DvB,EAAOsC,OAOL,CACLjB,OAAQ,CAAE,EACVrB,OAAQuC,EACN1C,EACEG,GACCuB,EAAQa,2BAAsD,QAAzBb,EAAQiB,cAEhDjB,IAbK,CACLvB,OAAQ,CAAE,EACVqB,OAAQA,EAaX,CAEL"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{appendErrors as t}from"react-hook-form";import{Validator as n}from"typebox/compile";import{Locale as o}from"typebox/system";import{Value as a}from"typebox/value";function i(r,e){(null==e||e>r.length)&&(e=r.length);for(var t=0,n=Array(e);t<e;t++)n[t]=r[t];return n}function s(){return s=Object.assign?Object.assign.bind():function(r){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var n in t)({}).hasOwnProperty.call(t,n)&&(r[n]=t[n])}return r},s.apply(null,arguments)}function l(r,e){for(var n,o=Object.create(null),a=function(r){var e="undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(e)return(e=e.call(r)).next.bind(e);if(Array.isArray(r)||(e=function(r,e){if(r){if("string"==typeof r)return i(r,e);var t={}.toString.call(r).slice(8,-1);return"Object"===t&&r.constructor&&(t=r.constructor.name),"Map"===t||"Set"===t?Array.from(r):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?i(r,e):void 0}}(r))){e&&(r=e);var t=0;return function(){return t>=r.length?{done:!0}:{done:!1,value:r[t++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(r);!(n=a()).done;){var s=n.value,l=s.keyword,u=s.message,c=s.instancePath.split("/").slice(1).map(function(r){return r.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(o[c]||(o[c]={message:u,type:l}),e){var f=o[c].types,m=f&&f[l];o[c]=t(c,e,o,l,m?[].concat(m,u):u)}}return o}function u(t){return function(i,u,c){try{var f=function(r){return r.flatMap(function(r){return"required"===r.keyword?r.params.requiredProperties.map(function(e){var t=s({},r,{instancePath:r.instancePath+"/"+e.replace(/~/g,"~0").replace(/\//g,"~1"),params:{requiredProperties:[e]}});return s({},t,{message:o.Get()(t)})}):[r]})}(t instanceof n?t.Errors(i):a.Errors(t,i));return c.shouldUseNativeValidation&&r({},c),Promise.resolve(f.length?{values:{},errors:e(l(f,!c.shouldUseNativeValidation&&"all"===c.criteriaMode),c)}:{errors:{},values:i})}catch(r){return Promise.reject(r)}}}export{u 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 '
|
|
1
|
+
{"version":3,"file":"typebox.module.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\nimport type { Static, StaticDecode, TObject, TProperties } from 'typebox';\nimport { Validator } from 'typebox/compile';\nimport type { TLocalizedValidationError } from 'typebox/error';\nimport { Locale } from 'typebox/system';\nimport { Value } from 'typebox/value';\n\n// TypeBox reports a single `required` error on the parent object listing every\n// missing property; split it into one error per missing field so each one lands\n// on its own path, re-localizing the message for that single property.\nfunction expandRequiredErrors(\n errors: TLocalizedValidationError[],\n): TLocalizedValidationError[] {\n return errors.flatMap<TLocalizedValidationError>((error) =>\n error.keyword === 'required'\n ? error.params.requiredProperties.map((property) => {\n const single = {\n ...error,\n instancePath: `${error.instancePath}/${property.replace(/~/g, '~0').replace(/\\//g, '~1')}`,\n params: { requiredProperties: [property] },\n };\n return { ...single, message: Locale.Get()(single) };\n })\n : [error],\n );\n}\n\nfunction parseErrorSchema(\n _errors: TLocalizedValidationError[],\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 (const error of _errors) {\n const { keyword: type, message, instancePath } = error;\n const _path = instancePath\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 };\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[], message)\n : message,\n ) as FieldError;\n }\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | Validator<TypeContext, 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, TypeContext>>} 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 * // Custom string formats must be registered with TypeBox's own `Format` registry\n * // before validating, since this resolver validates via `typebox`'s `Value.Errors`:\n * // Format.Set('slug', (value) => /^[a-z0-9-]+$/.test(value));\n */\nexport function typeboxResolver<\n Schema extends TObject,\n Context,\n TypeContext extends TProperties = Record<never, never>,\n>(\n schema: Schema | Validator<TypeContext, Schema>,\n): Resolver<\n Static<Schema, TypeContext>,\n Context,\n StaticDecode<Schema, TypeContext>\n> {\n return async (values: Static<Schema, TypeContext>, _, options) => {\n const errors = expandRequiredErrors(\n schema instanceof Validator\n ? (schema as Validator<TypeContext, 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: values as StaticDecode<Schema, TypeContext>,\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","_step","errors","Object","create","_iterator","_createForOfIteratorHelperLoose","done","error","value","type","keyword","message","_path","instancePath","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","typeboxResolver","schema","values","_","options","flatMap","params","requiredProperties","property","single","_extends","Locale","Get","expandRequiredErrors","Validator","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","length","toNestErrors","criteriaMode","e","reject"],"mappings":"sjBA4BA,SAASA,EACPC,EACAC,GAIA,IADA,IAC2BC,EADrBC,EAAqCC,OAAOC,OAAO,MACzDC,2pBAAAC,CAAoBP,KAAOE,EAAAI,KAAAE,MAAE,CAAlB,IAAAC,EAAKP,EAAAQ,MACGC,EAAgCF,EAAzCG,QAAeC,EAA0BJ,EAA1BI,QACjBC,EAD2CL,EAAjBM,aAE7BC,MAAM,KACNC,MAAM,GACNC,IAAI,SAACC,GAAO,OAAKA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,IAAI,GAChEC,KAAK,KAMR,GAJKlB,EAAOW,KACVX,EAAOW,GAAS,CAAED,QAAAA,EAASF,KAAAA,IAGzBV,EAA0B,CAC5B,IAAMqB,EAAQnB,EAAOW,GAAOQ,MACtBC,EAAWD,GAASA,EAAMX,GAEhCR,EAAOW,GAASU,EACdV,EACAb,EACAE,EACAQ,EACAY,EACK,GAAgBE,OAAOF,EAAsBV,GAC9CA,EAER,CACF,CAEA,OAAOV,CACT,CAsBgB,SAAAuB,EAKdC,GAMA,OAAcC,SAAAA,EAAqCC,EAAGC,OACpD,IAAM3B,EAtFV,SACEA,GAEA,OAAOA,EAAO4B,QAAmC,SAACtB,GAChD,MAAkB,aAAlBA,EAAMG,QACFH,EAAMuB,OAAOC,mBAAmBf,IAAI,SAACgB,GACnC,IAAMC,EAAMC,EACP3B,GAAAA,GACHM,aAAiBN,EAAMM,aAAY,IAAImB,EAASd,QAAQ,KAAM,MAAMA,QAAQ,MAAO,MACnFY,OAAQ,CAAEC,mBAAoB,CAACC,MAEjC,OAAAE,EAAYD,GAAAA,EAAQtB,CAAAA,QAASwB,EAAOC,KAAPD,CAAaF,IAC5C,GACA,CAAC1B,EAAM,EAEf,CAuEmB8B,CACbZ,aAAkBa,EACbb,EAA0Cc,OAAOb,GAClDc,EAAMD,OAAOd,EAAQC,IAK3B,OAFAE,EAAQa,2BAA6BC,EAAuB,CAAA,EAAId,GAShEe,QAAAC,QAPK3C,EAAO4C,OAOL,CACLnB,OAAQ,CAAA,EACRzB,OAAQ6C,EACNjD,EACEI,GACC2B,EAAQa,2BAAsD,QAAzBb,EAAQmB,cAEhDnB,IAbK,CACL3B,OAAQ,CAAA,EACRyB,OAAQA,GAcd,CAAC,MAAAsB,GAAA,OAAAL,QAAAM,OAAAD,EACH,CAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("@hookform/resolvers"),require("
|
|
1
|
+
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("@hookform/resolvers"),require("react-hook-form"),require("typebox/compile"),require("typebox/system"),require("typebox/value")):"function"==typeof define&&define.amd?define(["exports","@hookform/resolvers","react-hook-form","typebox/compile","typebox/system","typebox/value"],r):r((e||self).hookformResolversTypebox={},e.hookformResolvers,e.ReactHookForm,e.compile,e.system,e.value)}(this,function(e,r,t,o,n,a){function i(e,r){(null==r||r>e.length)&&(r=e.length);for(var t=0,o=Array(r);t<r;t++)o[t]=e[t];return o}function s(){return s=Object.assign?Object.assign.bind():function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var o in t)({}).hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e},s.apply(null,arguments)}function l(e,r){for(var o,n=Object.create(null),a=function(e){var r="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(r)return(r=r.call(e)).next.bind(r);if(Array.isArray(e)||(r=function(e,r){if(e){if("string"==typeof e)return i(e,r);var t={}.toString.call(e).slice(8,-1);return"Object"===t&&e.constructor&&(t=e.constructor.name),"Map"===t||"Set"===t?Array.from(e):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?i(e,r):void 0}}(e))){r&&(e=r);var t=0;return function(){return t>=e.length?{done:!0}:{done:!1,value:e[t++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(e);!(o=a()).done;){var s=o.value,l=s.keyword,u=s.message,c=s.instancePath.split("/").slice(1).map(function(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")}).join(".");if(n[c]||(n[c]={message:u,type:l}),r){var f=n[c].types,p=f&&f[l];n[c]=t.appendErrors(c,r,n,l,p?[].concat(p,u):u)}}return n}e.typeboxResolver=function(e){return function(t,i,u){try{var c=function(e){return e.flatMap(function(e){return"required"===e.keyword?e.params.requiredProperties.map(function(r){var t=s({},e,{instancePath:e.instancePath+"/"+r.replace(/~/g,"~0").replace(/\//g,"~1"),params:{requiredProperties:[r]}});return s({},t,{message:n.Locale.Get()(t)})}):[e]})}(e instanceof o.Validator?e.Errors(t):a.Value.Errors(e,t));return u.shouldUseNativeValidation&&r.validateFieldsNatively({},u),Promise.resolve(c.length?{values:{},errors:r.toNestErrors(l(c,!u.shouldUseNativeValidation&&"all"===u.criteriaMode),u)}:{errors:{},values:t})}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 '
|
|
1
|
+
{"version":3,"file":"typebox.umd.js","sources":["../src/typebox.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, Resolver, appendErrors } from 'react-hook-form';\nimport type { Static, StaticDecode, TObject, TProperties } from 'typebox';\nimport { Validator } from 'typebox/compile';\nimport type { TLocalizedValidationError } from 'typebox/error';\nimport { Locale } from 'typebox/system';\nimport { Value } from 'typebox/value';\n\n// TypeBox reports a single `required` error on the parent object listing every\n// missing property; split it into one error per missing field so each one lands\n// on its own path, re-localizing the message for that single property.\nfunction expandRequiredErrors(\n errors: TLocalizedValidationError[],\n): TLocalizedValidationError[] {\n return errors.flatMap<TLocalizedValidationError>((error) =>\n error.keyword === 'required'\n ? error.params.requiredProperties.map((property) => {\n const single = {\n ...error,\n instancePath: `${error.instancePath}/${property.replace(/~/g, '~0').replace(/\\//g, '~1')}`,\n params: { requiredProperties: [property] },\n };\n return { ...single, message: Locale.Get()(single) };\n })\n : [error],\n );\n}\n\nfunction parseErrorSchema(\n _errors: TLocalizedValidationError[],\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 (const error of _errors) {\n const { keyword: type, message, instancePath } = error;\n const _path = instancePath\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 };\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[], message)\n : message,\n ) as FieldError;\n }\n }\n\n return errors;\n}\n\n/**\n * Creates a resolver for react-hook-form using Typebox schema validation\n * @param {Schema | Validator<TypeContext, 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, TypeContext>>} 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 * // Custom string formats must be registered with TypeBox's own `Format` registry\n * // before validating, since this resolver validates via `typebox`'s `Value.Errors`:\n * // Format.Set('slug', (value) => /^[a-z0-9-]+$/.test(value));\n */\nexport function typeboxResolver<\n Schema extends TObject,\n Context,\n TypeContext extends TProperties = Record<never, never>,\n>(\n schema: Schema | Validator<TypeContext, Schema>,\n): Resolver<\n Static<Schema, TypeContext>,\n Context,\n StaticDecode<Schema, TypeContext>\n> {\n return async (values: Static<Schema, TypeContext>, _, options) => {\n const errors = expandRequiredErrors(\n schema instanceof Validator\n ? (schema as Validator<TypeContext, 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: values as StaticDecode<Schema, TypeContext>,\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","_step","errors","Object","create","_iterator","_createForOfIteratorHelperLoose","done","error","value","type","keyword","message","_path","instancePath","split","slice","map","segment","replace","join","types","messages","appendErrors","concat","schema","values","_","options","flatMap","params","requiredProperties","property","single","_extends","Locale","Get","expandRequiredErrors","Validator","Errors","Value","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","length","toNestErrors","criteriaMode","e","reject"],"mappings":"41BA4BA,SAASA,EACPC,EACAC,GAIA,IADA,IAC2BC,EADrBC,EAAqCC,OAAOC,OAAO,MACzDC,2pBAAAC,CAAoBP,KAAOE,EAAAI,KAAAE,MAAE,CAAlB,IAAAC,EAAKP,EAAAQ,MACGC,EAAgCF,EAAzCG,QAAeC,EAA0BJ,EAA1BI,QACjBC,EAD2CL,EAAjBM,aAE7BC,MAAM,KACNC,MAAM,GACNC,IAAI,SAACC,GAAO,OAAKA,EAAQC,QAAQ,MAAO,KAAKA,QAAQ,MAAO,IAAI,GAChEC,KAAK,KAMR,GAJKlB,EAAOW,KACVX,EAAOW,GAAS,CAAED,QAAAA,EAASF,KAAAA,IAGzBV,EAA0B,CAC5B,IAAMqB,EAAQnB,EAAOW,GAAOQ,MACtBC,EAAWD,GAASA,EAAMX,GAEhCR,EAAOW,GAASU,EAAYA,aAC1BV,EACAb,EACAE,EACAQ,EACAY,EACK,GAAgBE,OAAOF,EAAsBV,GAC9CA,EAER,CACF,CAEA,OAAOV,CACT,mBAsBgB,SAKduB,GAMA,OAAcC,SAAAA,EAAqCC,EAAGC,OACpD,IAAM1B,EAtFV,SACEA,GAEA,OAAOA,EAAO2B,QAAmC,SAACrB,GAChD,MAAkB,aAAlBA,EAAMG,QACFH,EAAMsB,OAAOC,mBAAmBd,IAAI,SAACe,GACnC,IAAMC,EAAMC,EACP1B,GAAAA,GACHM,aAAiBN,EAAMM,aAAY,IAAIkB,EAASb,QAAQ,KAAM,MAAMA,QAAQ,MAAO,MACnFW,OAAQ,CAAEC,mBAAoB,CAACC,MAEjC,OAAAE,EAAYD,GAAAA,EAAQrB,CAAAA,QAASuB,EAAAA,OAAOC,KAAPD,CAAaF,IAC5C,GACA,CAACzB,EAAM,EAEf,CAuEmB6B,CACbZ,aAAkBa,EAASA,UACtBb,EAA0Cc,OAAOb,GAClDc,QAAMD,OAAOd,EAAQC,IAK3B,OAFAE,EAAQa,2BAA6BC,yBAAuB,CAAA,EAAId,GAShEe,QAAAC,QAPK1C,EAAO2C,OAOL,CACLnB,OAAQ,CAAA,EACRxB,OAAQ4C,EAAYA,aAClBhD,EACEI,GACC0B,EAAQa,2BAAsD,QAAzBb,EAAQmB,cAEhDnB,IAbK,CACL1B,OAAQ,CAAA,EACRwB,OAAQA,GAcd,CAAC,MAAAsB,GAAA,OAAAL,QAAAM,OAAAD,EACH,CAAA,CAAA"}
|
package/typebox/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Static, Type } from '@sinclair/typebox';
|
|
2
|
-
import { TypeCompiler } from '@sinclair/typebox/compiler';
|
|
3
1
|
import { render, screen } from '@testing-library/react';
|
|
4
2
|
import user from '@testing-library/user-event';
|
|
5
3
|
import React from 'react';
|
|
6
4
|
import { useForm } from 'react-hook-form';
|
|
5
|
+
import { Static, Type } from 'typebox';
|
|
6
|
+
import { Compile } from 'typebox/compile';
|
|
7
7
|
import { typeboxResolver } from '..';
|
|
8
8
|
|
|
9
9
|
const schema = Type.Object({
|
|
@@ -11,11 +11,13 @@ const schema = Type.Object({
|
|
|
11
11
|
password: Type.String({ minLength: 1 }),
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
const typecheck =
|
|
14
|
+
const typecheck = Compile(schema);
|
|
15
15
|
|
|
16
16
|
function TestComponent({
|
|
17
17
|
onSubmit,
|
|
18
|
-
}: {
|
|
18
|
+
}: {
|
|
19
|
+
onSubmit: (data: Static<typeof schema>) => void;
|
|
20
|
+
}) {
|
|
19
21
|
const {
|
|
20
22
|
register,
|
|
21
23
|
handleSubmit,
|
|
@@ -46,7 +48,7 @@ test("form's validation with Typebox (with compiler) and TypeScript's integratio
|
|
|
46
48
|
await user.click(screen.getByText(/submit/i));
|
|
47
49
|
|
|
48
50
|
expect(
|
|
49
|
-
screen.getAllByText(/
|
|
51
|
+
screen.getAllByText(/must not have fewer than 1 characters/i),
|
|
50
52
|
).toHaveLength(2);
|
|
51
53
|
|
|
52
54
|
expect(handleSubmit).not.toHaveBeenCalled();
|
|
@@ -4,15 +4,15 @@ import React from 'react';
|
|
|
4
4
|
import { useForm } from 'react-hook-form';
|
|
5
5
|
import { typeboxResolver } from '..';
|
|
6
6
|
|
|
7
|
-
import { Static, Type } from '
|
|
8
|
-
import {
|
|
7
|
+
import { Static, Type } from 'typebox';
|
|
8
|
+
import { Compile } from 'typebox/compile';
|
|
9
9
|
|
|
10
10
|
const schema = Type.Object({
|
|
11
11
|
username: Type.String({ minLength: 1 }),
|
|
12
12
|
password: Type.String({ minLength: 1 }),
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
const typecheck =
|
|
15
|
+
const typecheck = Compile(schema);
|
|
16
16
|
|
|
17
17
|
type FormData = Static<typeof schema>;
|
|
18
18
|
|
|
@@ -61,14 +61,14 @@ test("form's native validation with Typebox (with compiler)", async () => {
|
|
|
61
61
|
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
62
62
|
expect(usernameField.validity.valid).toBe(false);
|
|
63
63
|
expect(usernameField.validationMessage).toBe(
|
|
64
|
-
'
|
|
64
|
+
'must not have fewer than 1 characters',
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
// password
|
|
68
68
|
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
69
69
|
expect(passwordField.validity.valid).toBe(false);
|
|
70
70
|
expect(passwordField.validationMessage).toBe(
|
|
71
|
-
'
|
|
71
|
+
'must not have fewer than 1 characters',
|
|
72
72
|
);
|
|
73
73
|
|
|
74
74
|
await user.type(screen.getByPlaceholderText(/username/i), 'joe');
|
|
@@ -4,7 +4,7 @@ import React from 'react';
|
|
|
4
4
|
import { useForm } from 'react-hook-form';
|
|
5
5
|
import { typeboxResolver } from '..';
|
|
6
6
|
|
|
7
|
-
import { Static, Type } from '
|
|
7
|
+
import { Static, Type } from 'typebox';
|
|
8
8
|
|
|
9
9
|
const schema = Type.Object({
|
|
10
10
|
username: Type.String({ minLength: 1 }),
|
|
@@ -58,14 +58,14 @@ test("form's native validation with Typebox", async () => {
|
|
|
58
58
|
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
59
59
|
expect(usernameField.validity.valid).toBe(false);
|
|
60
60
|
expect(usernameField.validationMessage).toBe(
|
|
61
|
-
'
|
|
61
|
+
'must not have fewer than 1 characters',
|
|
62
62
|
);
|
|
63
63
|
|
|
64
64
|
// password
|
|
65
65
|
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
66
66
|
expect(passwordField.validity.valid).toBe(false);
|
|
67
67
|
expect(passwordField.validationMessage).toBe(
|
|
68
|
-
'
|
|
68
|
+
'must not have fewer than 1 characters',
|
|
69
69
|
);
|
|
70
70
|
|
|
71
71
|
await user.type(screen.getByPlaceholderText(/username/i), 'joe');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Static, Type } from '@sinclair/typebox';
|
|
2
1
|
import { render, screen } from '@testing-library/react';
|
|
3
2
|
import user from '@testing-library/user-event';
|
|
4
3
|
import React from 'react';
|
|
5
4
|
import { useForm } from 'react-hook-form';
|
|
5
|
+
import { Static, Type } from 'typebox';
|
|
6
6
|
import { typeboxResolver } from '..';
|
|
7
7
|
|
|
8
8
|
const schema = Type.Object({
|
|
@@ -45,7 +45,7 @@ test("form's validation with Typebox and TypeScript's integration", async () =>
|
|
|
45
45
|
await user.click(screen.getByText(/submit/i));
|
|
46
46
|
|
|
47
47
|
expect(
|
|
48
|
-
screen.getAllByText(/
|
|
48
|
+
screen.getAllByText(/must not have fewer than 1 characters/i),
|
|
49
49
|
).toHaveLength(2);
|
|
50
50
|
|
|
51
51
|
expect(handleSubmit).not.toHaveBeenCalled();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { StaticDecode, Type } from '@sinclair/typebox';
|
|
2
1
|
import { Field, InternalFieldName } from 'react-hook-form';
|
|
2
|
+
import { StaticDecode, Type } from 'typebox';
|
|
3
3
|
|
|
4
4
|
export const schema = Type.Object({
|
|
5
5
|
username: Type.String({
|
|
@@ -19,11 +19,7 @@ export const schema = Type.Object({
|
|
|
19
19
|
maximum: 2013,
|
|
20
20
|
}),
|
|
21
21
|
),
|
|
22
|
-
email: Type.Optional(
|
|
23
|
-
Type.RegExp(
|
|
24
|
-
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
|
|
25
|
-
),
|
|
26
|
-
),
|
|
22
|
+
email: Type.Optional(Type.String({ format: 'email' })),
|
|
27
23
|
tags: Type.Array(Type.String()),
|
|
28
24
|
enabled: Type.Boolean(),
|
|
29
25
|
like: Type.Optional(
|
|
@@ -34,7 +30,7 @@ export const schema = Type.Object({
|
|
|
34
30
|
}),
|
|
35
31
|
),
|
|
36
32
|
),
|
|
37
|
-
dateStr: Type.
|
|
33
|
+
dateStr: Type.String({ format: 'date' }),
|
|
38
34
|
});
|
|
39
35
|
|
|
40
36
|
export const validData: StaticDecode<typeof schema> = {
|
|
@@ -52,7 +48,7 @@ export const validData: StaticDecode<typeof schema> = {
|
|
|
52
48
|
name: 'name',
|
|
53
49
|
},
|
|
54
50
|
],
|
|
55
|
-
dateStr:
|
|
51
|
+
dateStr: '2024-01-01',
|
|
56
52
|
};
|
|
57
53
|
|
|
58
54
|
export const invalidData = {
|