@hookform/resolvers 3.7.0 → 3.8.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 +69 -0
- package/ajv/dist/ajv.js.map +1 -1
- package/ajv/dist/ajv.modern.mjs.map +1 -1
- package/ajv/dist/ajv.module.js.map +1 -1
- package/ajv/dist/ajv.umd.js.map +1 -1
- package/ajv/dist/types.d.ts +1 -1
- package/ajv/src/__tests__/ajv.ts +7 -1
- package/ajv/src/ajv.ts +1 -1
- package/ajv/src/types.ts +1 -5
- package/arktype/dist/arktype.js +1 -1
- package/arktype/dist/arktype.js.map +1 -1
- package/arktype/dist/arktype.mjs +1 -1
- package/arktype/dist/arktype.modern.mjs +1 -1
- package/arktype/dist/arktype.modern.mjs.map +1 -1
- package/arktype/dist/arktype.module.js +1 -1
- package/arktype/dist/arktype.module.js.map +1 -1
- package/arktype/dist/arktype.umd.js +1 -1
- package/arktype/dist/arktype.umd.js.map +1 -1
- package/arktype/dist/types.d.ts +1 -1
- package/arktype/package.json +2 -1
- package/arktype/src/__tests__/Form-native-validation.tsx +5 -5
- package/arktype/src/__tests__/Form.tsx +2 -2
- package/arktype/src/__tests__/__fixtures__/data.ts +1 -1
- package/arktype/src/__tests__/__snapshots__/arktype.ts.snap +29 -29
- package/arktype/src/__tests__/arktype.ts +1 -1
- package/arktype/src/arktype.ts +2 -2
- package/arktype/src/types.ts +1 -1
- package/class-validator/dist/class-validator.js.map +1 -1
- package/class-validator/dist/class-validator.modern.mjs.map +1 -1
- package/class-validator/dist/class-validator.module.js.map +1 -1
- package/class-validator/dist/class-validator.umd.js.map +1 -1
- package/class-validator/dist/types.d.ts +2 -2
- package/class-validator/src/__tests__/Form-native-validation.tsx +2 -2
- package/class-validator/src/__tests__/Form.tsx +2 -2
- package/class-validator/src/__tests__/__snapshots__/class-validator.ts.snap +2 -2
- package/class-validator/src/__tests__/class-validator.ts +4 -4
- package/class-validator/src/class-validator.ts +2 -2
- package/class-validator/src/types.ts +2 -2
- package/computed-types/dist/computed-types.js.map +1 -1
- package/computed-types/dist/computed-types.modern.mjs.map +1 -1
- package/computed-types/dist/computed-types.module.js.map +1 -1
- package/computed-types/dist/computed-types.umd.js.map +1 -1
- package/computed-types/dist/types.d.ts +1 -1
- package/computed-types/src/__tests__/Form-native-validation.tsx +2 -2
- package/computed-types/src/__tests__/Form.tsx +2 -2
- package/computed-types/src/__tests__/__fixtures__/data.ts +1 -1
- package/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap +6 -6
- package/computed-types/src/__tests__/computed-types.ts +1 -1
- package/computed-types/src/computed-types.ts +2 -2
- package/computed-types/src/types.ts +1 -1
- package/dist/resolvers.js +1 -1
- package/dist/resolvers.js.map +1 -1
- package/dist/resolvers.mjs +1 -1
- package/dist/resolvers.mjs.map +1 -1
- package/dist/resolvers.module.js +1 -1
- package/dist/resolvers.module.js.map +1 -1
- package/dist/resolvers.umd.js +1 -1
- package/dist/resolvers.umd.js.map +1 -1
- package/dist/toNestErrors.d.ts +1 -6
- package/dist/validateFieldsNatively.d.ts +1 -1
- package/effect-ts/dist/effect-ts.js +1 -1
- package/effect-ts/dist/effect-ts.js.map +1 -1
- package/effect-ts/dist/effect-ts.mjs +1 -1
- package/effect-ts/dist/effect-ts.modern.mjs +1 -1
- package/effect-ts/dist/effect-ts.modern.mjs.map +1 -1
- package/effect-ts/dist/effect-ts.module.js +1 -1
- package/effect-ts/dist/effect-ts.module.js.map +1 -1
- package/effect-ts/dist/effect-ts.umd.js +1 -1
- package/effect-ts/dist/effect-ts.umd.js.map +1 -1
- package/effect-ts/src/__tests__/Form-native-validation.tsx +2 -2
- package/effect-ts/src/__tests__/Form.tsx +2 -2
- package/effect-ts/src/__tests__/__snapshots__/effect-ts.ts.snap +2 -2
- package/effect-ts/src/__tests__/effect-ts.ts +1 -1
- package/effect-ts/src/effect-ts.ts +1 -1
- package/io-ts/dist/errorsToRecord.d.ts +0 -1
- package/io-ts/dist/io-ts.js +1 -1
- package/io-ts/dist/io-ts.js.map +1 -1
- package/io-ts/dist/io-ts.mjs +1 -1
- package/io-ts/dist/io-ts.modern.mjs +1 -1
- package/io-ts/dist/io-ts.modern.mjs.map +1 -1
- package/io-ts/dist/io-ts.module.js +1 -1
- package/io-ts/dist/io-ts.module.js.map +1 -1
- package/io-ts/dist/io-ts.umd.js +1 -1
- package/io-ts/dist/io-ts.umd.js.map +1 -1
- package/io-ts/src/__tests__/Form-native-validation.tsx +2 -2
- package/io-ts/src/__tests__/Form.tsx +2 -2
- package/io-ts/src/__tests__/__snapshots__/io-ts.ts.snap +9 -9
- package/io-ts/src/__tests__/errorsToRecord.ts +29 -19
- package/io-ts/src/__tests__/io-ts.ts +1 -1
- package/io-ts/src/errorsToRecord.ts +19 -10
- package/io-ts/src/io-ts.ts +1 -1
- package/joi/dist/joi.js +1 -1
- package/joi/dist/joi.js.map +1 -1
- package/joi/dist/joi.mjs +1 -1
- package/joi/dist/joi.modern.mjs +1 -1
- package/joi/dist/joi.modern.mjs.map +1 -1
- package/joi/dist/joi.module.js +1 -1
- package/joi/dist/joi.module.js.map +1 -1
- package/joi/dist/joi.umd.js +1 -1
- package/joi/dist/joi.umd.js.map +1 -1
- package/joi/dist/types.d.ts +1 -1
- package/joi/src/__tests__/Form-native-validation.tsx +2 -2
- package/joi/src/__tests__/Form.tsx +2 -2
- package/joi/src/__tests__/__snapshots__/joi.ts.snap +56 -56
- package/joi/src/__tests__/joi.ts +1 -1
- package/joi/src/joi.ts +1 -1
- package/joi/src/types.ts +1 -5
- package/nope/dist/nope.js.map +1 -1
- package/nope/dist/nope.modern.mjs.map +1 -1
- package/nope/dist/nope.module.js.map +1 -1
- package/nope/dist/nope.umd.js.map +1 -1
- package/nope/dist/types.d.ts +1 -1
- package/nope/src/__tests__/Form-native-validation.tsx +2 -2
- package/nope/src/__tests__/Form.tsx +2 -2
- package/nope/src/__tests__/__fixtures__/data.ts +1 -1
- package/nope/src/__tests__/nope.ts +1 -1
- package/nope/src/nope.ts +1 -1
- package/nope/src/types.ts +2 -2
- package/package.json +54 -51
- package/superstruct/dist/superstruct.js.map +1 -1
- package/superstruct/dist/superstruct.modern.mjs.map +1 -1
- package/superstruct/dist/superstruct.module.js.map +1 -1
- package/superstruct/dist/superstruct.umd.js.map +1 -1
- package/superstruct/dist/types.d.ts +1 -1
- package/superstruct/src/__tests__/Form-native-validation.tsx +2 -2
- package/superstruct/src/__tests__/Form.tsx +2 -2
- package/superstruct/src/__tests__/__fixtures__/data.ts +8 -8
- package/superstruct/src/__tests__/__snapshots__/superstruct.ts.snap +4 -4
- package/superstruct/src/__tests__/superstruct.ts +1 -1
- package/superstruct/src/superstruct.ts +1 -1
- package/superstruct/src/types.ts +1 -1
- package/typanion/dist/typanion.js.map +1 -1
- package/typanion/dist/typanion.modern.mjs.map +1 -1
- package/typanion/dist/typanion.module.js.map +1 -1
- package/typanion/dist/typanion.umd.js.map +1 -1
- package/typanion/dist/types.d.ts +1 -1
- package/typanion/src/__tests__/Form-native-validation.tsx +1 -1
- package/typanion/src/__tests__/Form.tsx +1 -1
- package/typanion/src/__tests__/__fixtures__/data.ts +12 -7
- package/typanion/src/__tests__/__snapshots__/typanion.ts.snap +4 -4
- package/typanion/src/__tests__/typanion.ts +1 -1
- package/typanion/src/typanion.ts +1 -1
- package/typanion/src/types.ts +4 -4
- 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/dist/types.d.ts +3 -2
- package/typebox/src/__tests__/Form-compiler.tsx +57 -0
- package/typebox/src/__tests__/Form-native-validation-compiler.tsx +86 -0
- package/typebox/src/__tests__/Form-native-validation.tsx +4 -4
- package/typebox/src/__tests__/Form.tsx +3 -3
- package/typebox/src/__tests__/__fixtures__/data.ts +6 -2
- package/typebox/src/__tests__/__snapshots__/typebox-compiler.ts.snap +188 -0
- package/typebox/src/__tests__/__snapshots__/typebox.ts.snap +13 -13
- package/typebox/src/__tests__/typebox-compiler.ts +37 -0
- package/typebox/src/__tests__/typebox.ts +1 -1
- package/typebox/src/typebox.ts +8 -3
- package/typebox/src/types.ts +3 -2
- package/typeschema/dist/index.d.ts +2 -0
- package/typeschema/dist/types.d.ts +9 -0
- package/typeschema/dist/typeschema.d.ts +2 -0
- package/typeschema/dist/typeschema.js +2 -0
- package/typeschema/dist/typeschema.js.map +1 -0
- package/typeschema/dist/typeschema.mjs +2 -0
- package/typeschema/dist/typeschema.modern.mjs +2 -0
- package/typeschema/dist/typeschema.modern.mjs.map +1 -0
- package/typeschema/dist/typeschema.module.js +2 -0
- package/typeschema/dist/typeschema.module.js.map +1 -0
- package/typeschema/dist/typeschema.umd.js +2 -0
- package/typeschema/dist/typeschema.umd.js.map +1 -0
- package/typeschema/package.json +18 -0
- package/typeschema/src/__tests__/Form-native-validation.tsx +82 -0
- package/typeschema/src/__tests__/Form.tsx +53 -0
- package/typeschema/src/__tests__/__fixtures__/data.ts +88 -0
- package/typeschema/src/__tests__/__snapshots__/typeschema.ts.snap +225 -0
- package/typeschema/src/__tests__/typeschema.ts +70 -0
- package/typeschema/src/index.ts +2 -0
- package/typeschema/src/types.ts +18 -0
- package/typeschema/src/typeschema.ts +70 -0
- package/valibot/dist/types.d.ts +1 -1
- package/valibot/dist/valibot.js +1 -1
- package/valibot/dist/valibot.js.map +1 -1
- package/valibot/dist/valibot.mjs +1 -1
- package/valibot/dist/valibot.modern.mjs +1 -1
- package/valibot/dist/valibot.modern.mjs.map +1 -1
- package/valibot/dist/valibot.module.js +1 -1
- package/valibot/dist/valibot.module.js.map +1 -1
- package/valibot/dist/valibot.umd.js +1 -1
- package/valibot/dist/valibot.umd.js.map +1 -1
- package/valibot/src/__tests__/Form-native-validation.tsx +2 -2
- package/valibot/src/__tests__/Form.tsx +1 -1
- package/valibot/src/__tests__/valibot.ts +4 -4
- package/valibot/src/types.ts +1 -1
- package/valibot/src/valibot.ts +12 -6
- package/vest/dist/types.d.ts +2 -2
- package/vest/dist/vest.js.map +1 -1
- package/vest/dist/vest.modern.mjs.map +1 -1
- package/vest/dist/vest.module.js.map +1 -1
- package/vest/dist/vest.umd.js.map +1 -1
- package/vest/src/__tests__/Form-native-validation.tsx +1 -1
- package/vest/src/__tests__/Form.tsx +1 -1
- package/vest/src/__tests__/__snapshots__/vest.ts.snap +0 -6
- package/vest/src/__tests__/vest.ts +14 -8
- package/vest/src/types.ts +11 -4
- package/vest/src/vest.ts +1 -1
- package/vine/dist/types.d.ts +1 -1
- package/vine/dist/vine.js +1 -1
- package/vine/dist/vine.js.map +1 -1
- package/vine/dist/vine.mjs +1 -1
- package/vine/dist/vine.modern.mjs +1 -1
- package/vine/dist/vine.modern.mjs.map +1 -1
- package/vine/dist/vine.module.js +1 -1
- package/vine/dist/vine.module.js.map +1 -1
- package/vine/dist/vine.umd.js +1 -1
- package/vine/dist/vine.umd.js.map +1 -1
- package/vine/src/__tests__/Form-native-validation.tsx +9 -5
- package/vine/src/__tests__/Form.tsx +9 -5
- package/vine/src/__tests__/__fixtures__/data.ts +4 -2
- package/vine/src/__tests__/vine.ts +1 -1
- package/vine/src/types.ts +1 -1
- package/vine/src/vine.ts +10 -8
- package/yup/dist/yup.d.ts +1 -1
- package/yup/dist/yup.js.map +1 -1
- package/yup/dist/yup.modern.mjs.map +1 -1
- package/yup/dist/yup.module.js.map +1 -1
- package/yup/dist/yup.umd.js.map +1 -1
- package/yup/src/__tests__/Form-native-validation.tsx +1 -1
- package/yup/src/__tests__/Form.tsx +1 -1
- package/yup/src/__tests__/__snapshots__/yup.ts.snap +13 -13
- package/yup/src/__tests__/yup.ts +9 -7
- package/yup/src/yup.ts +2 -2
- package/zod/dist/types.d.ts +1 -1
- package/zod/dist/zod.js +1 -1
- package/zod/dist/zod.js.map +1 -1
- package/zod/dist/zod.mjs +1 -1
- package/zod/dist/zod.modern.mjs +1 -1
- package/zod/dist/zod.modern.mjs.map +1 -1
- package/zod/dist/zod.module.js +1 -1
- package/zod/dist/zod.module.js.map +1 -1
- package/zod/dist/zod.umd.js +1 -1
- package/zod/dist/zod.umd.js.map +1 -1
- package/zod/src/__tests__/Form-native-validation.tsx +2 -2
- package/zod/src/__tests__/Form.tsx +1 -1
- package/zod/src/__tests__/zod.ts +1 -1
- package/zod/src/types.ts +1 -1
- package/zod/src/zod.ts +4 -3
package/typebox/src/types.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
|
-
import {
|
|
2
|
+
import type { TypeCheck } from '@sinclair/typebox/compiler';
|
|
3
|
+
import { FieldValues, ResolverOptions, ResolverResult } from 'react-hook-form';
|
|
3
4
|
|
|
4
5
|
export type Resolver = <T extends ReturnType<typeof Type.Object>>(
|
|
5
|
-
schema: T
|
|
6
|
+
schema: T | TypeCheck<T>,
|
|
6
7
|
) => <TFieldValues extends FieldValues, TContext>(
|
|
7
8
|
values: TFieldValues,
|
|
8
9
|
context: TContext | undefined,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Schema } from '@typeschema/main';
|
|
2
|
+
import { FieldValues, ResolverOptions, ResolverResult } from 'react-hook-form';
|
|
3
|
+
export type Resolver = <T extends Schema>(schema: T, schemaOptions?: never, factoryOptions?: {
|
|
4
|
+
/**
|
|
5
|
+
* Return the raw input values rather than the parsed values.
|
|
6
|
+
* @default false
|
|
7
|
+
*/
|
|
8
|
+
raw?: boolean;
|
|
9
|
+
}) => <TFieldValues extends FieldValues, TContext>(values: TFieldValues, context: TContext | undefined, options: ResolverOptions<TFieldValues>) => Promise<ResolverResult<TFieldValues>>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=require("@hookform/resolvers"),r=require("@typeschema/main"),s=require("react-hook-form"),a=function(e,r){for(var a={};e.length;){var t=e[0];if(t.path){var o=t.path.join(".");if(a[o]||(a[o]={message:t.message,type:""}),r){var i=a[o].types,n=i&&i[""];a[o]=s.appendErrors(o,r,a,"",n?[].concat(n,t.message):t.message)}e.shift()}}return a};exports.typeschemaResolver=function(s,t,o){return void 0===o&&(o={}),function(t,i,n){try{return Promise.resolve(r.validate(s,t)).then(function(r){return n.shouldUseNativeValidation&&e.validateFieldsNatively({},n),r.success?{errors:{},values:o.raw?t:r.data}:{values:{},errors:e.toNestErrors(a(r.issues,!n.shouldUseNativeValidation&&"all"===n.criteriaMode),n)}})}catch(e){return Promise.reject(e)}}};
|
|
2
|
+
//# sourceMappingURL=typeschema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeschema.js","sources":["../src/typeschema.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationIssue } from '@typeschema/core';\nimport { validate } from '@typeschema/main';\nimport { FieldError, FieldErrors, appendErrors } from 'react-hook-form';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n typeschemaErrors: ValidationIssue[],\n validateAllFieldCriteria: boolean,\n): FieldErrors => {\n const errors: Record<string, FieldError> = {};\n\n for (; typeschemaErrors.length; ) {\n const error = typeschemaErrors[0];\n\n if (!error.path) {\n continue;\n }\n const _path = error.path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message: error.message, type: '' };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types[''];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '',\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n typeschemaErrors.shift();\n }\n\n return errors;\n};\n\nexport const typeschemaResolver: Resolver =\n (schema, _, resolverOptions = {}) =>\n async (values, _, options) => {\n const result = await validate(schema, values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (result.success) {\n return {\n errors: {} as FieldErrors,\n values: resolverOptions.raw ? values : (result.data as any),\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n result.issues,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","typeschemaErrors","validateAllFieldCriteria","errors","length","error","path","_path","join","message","type","types","messages","appendErrors","concat","shift","schema","_","resolverOptions","values","options","Promise","resolve","validate","then","result","shouldUseNativeValidation","validateFieldsNatively","success","raw","data","toNestErrors","issues","criteriaMode","e","reject"],"mappings":"gGAMMA,EAAmB,SACvBC,EACAC,GAIA,IAFA,IAAMC,EAAqC,CAAE,EAEtCF,EAAiBG,QAAU,CAChC,IAAMC,EAAQJ,EAAiB,GAE/B,GAAKI,EAAMC,KAAX,CAGA,IAAMC,EAAQF,EAAMC,KAAKE,KAAK,KAM9B,GAJKL,EAAOI,KACVJ,EAAOI,GAAS,CAAEE,QAASJ,EAAMI,QAASC,KAAM,KAG9CR,EAA0B,CAC5B,IAAMS,EAAQR,EAAOI,GAAOI,MACtBC,EAAWD,GAASA,EAAM,IAEhCR,EAAOI,GAASM,EAAYA,aAC1BN,EACAL,EACAC,EACA,GACAS,EACK,GAAgBE,OAAOF,EAAsBP,EAAMI,SACpDJ,EAAMI,QAEd,CAEAR,EAAiBc,OAtBjB,CAuBF,CAEA,OAAOZ,CACT,6BAGE,SAACa,EAAQC,EAAGC,GACLC,YADKD,IAAAA,IAAAA,EAAkB,CAAA,GACvBC,SAAAA,EAAQF,EAAGG,OAAWC,OAAAA,QAAAC,QACNC,EAAQA,SAACP,EAAQG,IAAOK,cAAvCC,GAEmE,OAAzEL,EAAQM,2BAA6BC,EAAsBA,uBAAC,CAAE,EAAEP,GAE5DK,EAAOG,QACF,CACLzB,OAAQ,CAAiB,EACzBgB,OAAQD,EAAgBW,IAAMV,EAAUM,EAAOK,MAI5C,CACLX,OAAQ,CAAE,EACVhB,OAAQ4B,EAAYA,aAClB/B,EACEyB,EAAOO,QACNZ,EAAQM,2BAAsD,QAAzBN,EAAQa,cAEhDb,GAEH,EACH,CAAC,MAAAc,GAAAb,OAAAA,QAAAc,OAAAD,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{validate as o}from"@typeschema/main";import{appendErrors as t}from"react-hook-form";var s=function(r,e){for(var o={};r.length;){var s=r[0];if(s.path){var a=s.path.join(".");if(o[a]||(o[a]={message:s.message,type:""}),e){var i=o[a].types,n=i&&i[""];o[a]=t(a,e,o,"",n?[].concat(n,s.message):s.message)}r.shift()}}return o},a=function(t,a,i){return void 0===i&&(i={}),function(a,n,m){try{return Promise.resolve(o(t,a)).then(function(o){return m.shouldUseNativeValidation&&r({},m),o.success?{errors:{},values:i.raw?a:o.data}:{values:{},errors:e(s(o.issues,!m.shouldUseNativeValidation&&"all"===m.criteriaMode),m)}})}catch(r){return Promise.reject(r)}}};export{a as typeschemaResolver};
|
|
2
|
+
//# sourceMappingURL=typeschema.module.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{validateFieldsNatively as s,toNestErrors as e}from"@hookform/resolvers";import{validate as o}from"@typeschema/main";import{appendErrors as t}from"react-hook-form";const a=(s,e)=>{const o={};for(;s.length;){const a=s[0];if(!a.path)continue;const r=a.path.join(".");if(o[r]||(o[r]={message:a.message,type:""}),e){const s=o[r].types,i=s&&s[""];o[r]=t(r,e,o,"",i?[].concat(i,a.message):a.message)}s.shift()}return o},r=(t,r,i={})=>async(r,n,c)=>{const m=await o(t,r);return c.shouldUseNativeValidation&&s({},c),m.success?{errors:{},values:i.raw?r:m.data}:{values:{},errors:e(a(m.issues,!c.shouldUseNativeValidation&&"all"===c.criteriaMode),c)}};export{r as typeschemaResolver};
|
|
2
|
+
//# sourceMappingURL=typeschema.modern.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeschema.modern.mjs","sources":["../src/typeschema.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationIssue } from '@typeschema/core';\nimport { validate } from '@typeschema/main';\nimport { FieldError, FieldErrors, appendErrors } from 'react-hook-form';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n typeschemaErrors: ValidationIssue[],\n validateAllFieldCriteria: boolean,\n): FieldErrors => {\n const errors: Record<string, FieldError> = {};\n\n for (; typeschemaErrors.length; ) {\n const error = typeschemaErrors[0];\n\n if (!error.path) {\n continue;\n }\n const _path = error.path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message: error.message, type: '' };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types[''];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '',\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n typeschemaErrors.shift();\n }\n\n return errors;\n};\n\nexport const typeschemaResolver: Resolver =\n (schema, _, resolverOptions = {}) =>\n async (values, _, options) => {\n const result = await validate(schema, values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (result.success) {\n return {\n errors: {} as FieldErrors,\n values: resolverOptions.raw ? values : (result.data as any),\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n result.issues,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","typeschemaErrors","validateAllFieldCriteria","errors","length","error","path","_path","join","message","type","types","messages","appendErrors","concat","shift","typeschemaResolver","schema","_","resolverOptions","async","values","options","result","validate","shouldUseNativeValidation","validateFieldsNatively","success","raw","data","toNestErrors","issues","criteriaMode"],"mappings":"0KAMA,MAAMA,EAAmBA,CACvBC,EACAC,KAEA,MAAMC,EAAqC,CAAE,EAE7C,KAAOF,EAAiBG,QAAU,CAChC,MAAMC,EAAQJ,EAAiB,GAE/B,IAAKI,EAAMC,KACT,SAEF,MAAMC,EAAQF,EAAMC,KAAKE,KAAK,KAM9B,GAJKL,EAAOI,KACVJ,EAAOI,GAAS,CAAEE,QAASJ,EAAMI,QAASC,KAAM,KAG9CR,EAA0B,CAC5B,MAAMS,EAAQR,EAAOI,GAAOI,MACtBC,EAAWD,GAASA,EAAM,IAEhCR,EAAOI,GAASM,EACdN,EACAL,EACAC,EACA,GACAS,EACK,GAAgBE,OAAOF,EAAsBP,EAAMI,SACpDJ,EAAMI,QAEd,CAEAR,EAAiBc,OACnB,CAEA,OAAOZ,GAGIa,EACXA,CAACC,EAAQC,EAAGC,EAAkB,CAAE,IAChCC,MAAOC,EAAQH,EAAGI,KAChB,MAAMC,QAAeC,EAASP,EAAQI,GAItC,OAFAC,EAAQG,2BAA6BC,EAAuB,CAAE,EAAEJ,GAE5DC,EAAOI,QACF,CACLxB,OAAQ,CAAiB,EACzBkB,OAAQF,EAAgBS,IAAMP,EAAUE,EAAOM,MAI5C,CACLR,OAAQ,CAAA,EACRlB,OAAQ2B,EACN9B,EACEuB,EAAOQ,QACNT,EAAQG,2BAAsD,QAAzBH,EAAQU,cAEhDV"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{validateFieldsNatively as r,toNestErrors as e}from"@hookform/resolvers";import{validate as o}from"@typeschema/main";import{appendErrors as t}from"react-hook-form";var s=function(r,e){for(var o={};r.length;){var s=r[0];if(s.path){var a=s.path.join(".");if(o[a]||(o[a]={message:s.message,type:""}),e){var i=o[a].types,n=i&&i[""];o[a]=t(a,e,o,"",n?[].concat(n,s.message):s.message)}r.shift()}}return o},a=function(t,a,i){return void 0===i&&(i={}),function(a,n,m){try{return Promise.resolve(o(t,a)).then(function(o){return m.shouldUseNativeValidation&&r({},m),o.success?{errors:{},values:i.raw?a:o.data}:{values:{},errors:e(s(o.issues,!m.shouldUseNativeValidation&&"all"===m.criteriaMode),m)}})}catch(r){return Promise.reject(r)}}};export{a as typeschemaResolver};
|
|
2
|
+
//# sourceMappingURL=typeschema.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeschema.module.js","sources":["../src/typeschema.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationIssue } from '@typeschema/core';\nimport { validate } from '@typeschema/main';\nimport { FieldError, FieldErrors, appendErrors } from 'react-hook-form';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n typeschemaErrors: ValidationIssue[],\n validateAllFieldCriteria: boolean,\n): FieldErrors => {\n const errors: Record<string, FieldError> = {};\n\n for (; typeschemaErrors.length; ) {\n const error = typeschemaErrors[0];\n\n if (!error.path) {\n continue;\n }\n const _path = error.path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message: error.message, type: '' };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types[''];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '',\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n typeschemaErrors.shift();\n }\n\n return errors;\n};\n\nexport const typeschemaResolver: Resolver =\n (schema, _, resolverOptions = {}) =>\n async (values, _, options) => {\n const result = await validate(schema, values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (result.success) {\n return {\n errors: {} as FieldErrors,\n values: resolverOptions.raw ? values : (result.data as any),\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n result.issues,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","typeschemaErrors","validateAllFieldCriteria","errors","length","error","path","_path","join","message","type","types","messages","appendErrors","concat","shift","typeschemaResolver","schema","_","resolverOptions","values","options","Promise","resolve","validate","then","result","shouldUseNativeValidation","validateFieldsNatively","success","raw","data","toNestErrors","issues","criteriaMode","e","reject"],"mappings":"0KAMA,IAAMA,EAAmB,SACvBC,EACAC,GAIA,IAFA,IAAMC,EAAqC,CAAE,EAEtCF,EAAiBG,QAAU,CAChC,IAAMC,EAAQJ,EAAiB,GAE/B,GAAKI,EAAMC,KAAX,CAGA,IAAMC,EAAQF,EAAMC,KAAKE,KAAK,KAM9B,GAJKL,EAAOI,KACVJ,EAAOI,GAAS,CAAEE,QAASJ,EAAMI,QAASC,KAAM,KAG9CR,EAA0B,CAC5B,IAAMS,EAAQR,EAAOI,GAAOI,MACtBC,EAAWD,GAASA,EAAM,IAEhCR,EAAOI,GAASM,EACdN,EACAL,EACAC,EACA,GACAS,EACK,GAAgBE,OAAOF,EAAsBP,EAAMI,SACpDJ,EAAMI,QAEd,CAEAR,EAAiBc,OAtBjB,CAuBF,CAEA,OAAOZ,CACT,EAEaa,EACX,SAACC,EAAQC,EAAGC,GACLC,YADKD,IAAAA,IAAAA,EAAkB,CAAA,GACvBC,SAAAA,EAAQF,EAAGG,OAAWC,OAAAA,QAAAC,QACNC,EAASP,EAAQG,IAAOK,cAAvCC,GAEmE,OAAzEL,EAAQM,2BAA6BC,EAAuB,CAAE,EAAEP,GAE5DK,EAAOG,QACF,CACL1B,OAAQ,CAAiB,EACzBiB,OAAQD,EAAgBW,IAAMV,EAAUM,EAAOK,MAI5C,CACLX,OAAQ,CAAE,EACVjB,OAAQ6B,EACNhC,EACE0B,EAAOO,QACNZ,EAAQM,2BAAsD,QAAzBN,EAAQa,cAEhDb,GAEH,EACH,CAAC,MAAAc,GAAAb,OAAAA,QAAAc,OAAAD,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports,require("@hookform/resolvers"),require("@typeschema/main"),require("react-hook-form")):"function"==typeof define&&define.amd?define(["exports","@hookform/resolvers","@typeschema/main","react-hook-form"],o):o((e||self).hookformResolversTypeschema={},e.hookformResolvers,e.main,e.ReactHookForm)}(this,function(e,o,r,s){var t=function(e,o){for(var r={};e.length;){var t=e[0];if(t.path){var a=t.path.join(".");if(r[a]||(r[a]={message:t.message,type:""}),o){var i=r[a].types,n=i&&i[""];r[a]=s.appendErrors(a,o,r,"",n?[].concat(n,t.message):t.message)}e.shift()}}return r};e.typeschemaResolver=function(e,s,a){return void 0===a&&(a={}),function(s,i,n){try{return Promise.resolve(r.validate(e,s)).then(function(e){return n.shouldUseNativeValidation&&o.validateFieldsNatively({},n),e.success?{errors:{},values:a.raw?s:e.data}:{values:{},errors:o.toNestErrors(t(e.issues,!n.shouldUseNativeValidation&&"all"===n.criteriaMode),n)}})}catch(e){return Promise.reject(e)}}}});
|
|
2
|
+
//# sourceMappingURL=typeschema.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeschema.umd.js","sources":["../src/typeschema.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationIssue } from '@typeschema/core';\nimport { validate } from '@typeschema/main';\nimport { FieldError, FieldErrors, appendErrors } from 'react-hook-form';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n typeschemaErrors: ValidationIssue[],\n validateAllFieldCriteria: boolean,\n): FieldErrors => {\n const errors: Record<string, FieldError> = {};\n\n for (; typeschemaErrors.length; ) {\n const error = typeschemaErrors[0];\n\n if (!error.path) {\n continue;\n }\n const _path = error.path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message: error.message, type: '' };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types[''];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '',\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n typeschemaErrors.shift();\n }\n\n return errors;\n};\n\nexport const typeschemaResolver: Resolver =\n (schema, _, resolverOptions = {}) =>\n async (values, _, options) => {\n const result = await validate(schema, values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (result.success) {\n return {\n errors: {} as FieldErrors,\n values: resolverOptions.raw ? values : (result.data as any),\n };\n }\n\n return {\n values: {},\n errors: toNestErrors(\n parseErrorSchema(\n result.issues,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","typeschemaErrors","validateAllFieldCriteria","errors","length","error","path","_path","join","message","type","types","messages","appendErrors","concat","shift","schema","_","resolverOptions","values","options","Promise","resolve","validate","then","result","shouldUseNativeValidation","validateFieldsNatively","success","raw","data","toNestErrors","issues","criteriaMode","e","reject"],"mappings":"ubAMA,IAAMA,EAAmB,SACvBC,EACAC,GAIA,IAFA,IAAMC,EAAqC,CAAE,EAEtCF,EAAiBG,QAAU,CAChC,IAAMC,EAAQJ,EAAiB,GAE/B,GAAKI,EAAMC,KAAX,CAGA,IAAMC,EAAQF,EAAMC,KAAKE,KAAK,KAM9B,GAJKL,EAAOI,KACVJ,EAAOI,GAAS,CAAEE,QAASJ,EAAMI,QAASC,KAAM,KAG9CR,EAA0B,CAC5B,IAAMS,EAAQR,EAAOI,GAAOI,MACtBC,EAAWD,GAASA,EAAM,IAEhCR,EAAOI,GAASM,EAAYA,aAC1BN,EACAL,EACAC,EACA,GACAS,EACK,GAAgBE,OAAOF,EAAsBP,EAAMI,SACpDJ,EAAMI,QAEd,CAEAR,EAAiBc,OAtBjB,CAuBF,CAEA,OAAOZ,CACT,uBAGE,SAACa,EAAQC,EAAGC,GACLC,YADKD,IAAAA,IAAAA,EAAkB,CAAA,GACvBC,SAAAA,EAAQF,EAAGG,OAAWC,OAAAA,QAAAC,QACNC,EAAQA,SAACP,EAAQG,IAAOK,cAAvCC,GAEmE,OAAzEL,EAAQM,2BAA6BC,EAAsBA,uBAAC,CAAE,EAAEP,GAE5DK,EAAOG,QACF,CACLzB,OAAQ,CAAiB,EACzBgB,OAAQD,EAAgBW,IAAMV,EAAUM,EAAOK,MAI5C,CACLX,OAAQ,CAAE,EACVhB,OAAQ4B,EAAYA,aAClB/B,EACEyB,EAAOO,QACNZ,EAAQM,2BAAsD,QAAzBN,EAAQa,cAEhDb,GAEH,EACH,CAAC,MAAAc,GAAAb,OAAAA,QAAAc,OAAAD,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hookform/resolvers/typeschema",
|
|
3
|
+
"amdName": "hookformResolversTypeschema",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "React Hook Form validation resolver: typeschema",
|
|
7
|
+
"main": "dist/typeschema.js",
|
|
8
|
+
"module": "dist/typeschema.module.js",
|
|
9
|
+
"umd:main": "dist/typeschema.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
|
+
"@typeschema/main": "^0.13.7"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import user from '@testing-library/user-event';
|
|
3
|
+
import type { Infer } from '@typeschema/main';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { useForm } from 'react-hook-form';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { typeschemaResolver } from '..';
|
|
8
|
+
|
|
9
|
+
const USERNAME_REQUIRED_MESSAGE = 'username field is required';
|
|
10
|
+
const PASSWORD_REQUIRED_MESSAGE = 'password field is required';
|
|
11
|
+
|
|
12
|
+
const schema = z.object({
|
|
13
|
+
username: z.string().min(1, { message: USERNAME_REQUIRED_MESSAGE }),
|
|
14
|
+
password: z.string().min(1, { message: PASSWORD_REQUIRED_MESSAGE }),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
type FormData = Infer<typeof schema>;
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
onSubmit: (data: FormData) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function TestComponent({ onSubmit }: Props) {
|
|
24
|
+
const { register, handleSubmit } = useForm<FormData>({
|
|
25
|
+
resolver: typeschemaResolver(schema),
|
|
26
|
+
shouldUseNativeValidation: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
31
|
+
<input {...register('username')} placeholder="username" />
|
|
32
|
+
|
|
33
|
+
<input {...register('password')} placeholder="password" />
|
|
34
|
+
|
|
35
|
+
<button type="submit">submit</button>
|
|
36
|
+
</form>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test("form's native validation with TypeSchema", async () => {
|
|
41
|
+
const handleSubmit = vi.fn();
|
|
42
|
+
render(<TestComponent onSubmit={handleSubmit} />);
|
|
43
|
+
|
|
44
|
+
// username
|
|
45
|
+
let usernameField = screen.getByPlaceholderText(
|
|
46
|
+
/username/i,
|
|
47
|
+
) as HTMLInputElement;
|
|
48
|
+
expect(usernameField.validity.valid).toBe(true);
|
|
49
|
+
expect(usernameField.validationMessage).toBe('');
|
|
50
|
+
|
|
51
|
+
// password
|
|
52
|
+
let passwordField = screen.getByPlaceholderText(
|
|
53
|
+
/password/i,
|
|
54
|
+
) as HTMLInputElement;
|
|
55
|
+
expect(passwordField.validity.valid).toBe(true);
|
|
56
|
+
expect(passwordField.validationMessage).toBe('');
|
|
57
|
+
|
|
58
|
+
await user.click(screen.getByText(/submit/i));
|
|
59
|
+
|
|
60
|
+
// username
|
|
61
|
+
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
62
|
+
expect(usernameField.validity.valid).toBe(false);
|
|
63
|
+
expect(usernameField.validationMessage).toBe(USERNAME_REQUIRED_MESSAGE);
|
|
64
|
+
|
|
65
|
+
// password
|
|
66
|
+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
67
|
+
expect(passwordField.validity.valid).toBe(false);
|
|
68
|
+
expect(passwordField.validationMessage).toBe(PASSWORD_REQUIRED_MESSAGE);
|
|
69
|
+
|
|
70
|
+
await user.type(screen.getByPlaceholderText(/username/i), 'joe');
|
|
71
|
+
await user.type(screen.getByPlaceholderText(/password/i), 'password');
|
|
72
|
+
|
|
73
|
+
// username
|
|
74
|
+
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
75
|
+
expect(usernameField.validity.valid).toBe(true);
|
|
76
|
+
expect(usernameField.validationMessage).toBe('');
|
|
77
|
+
|
|
78
|
+
// password
|
|
79
|
+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
80
|
+
expect(passwordField.validity.valid).toBe(true);
|
|
81
|
+
expect(passwordField.validationMessage).toBe('');
|
|
82
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import user from '@testing-library/user-event';
|
|
3
|
+
import type { Infer } from '@typeschema/main';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { useForm } from 'react-hook-form';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { typeschemaResolver } from '..';
|
|
8
|
+
|
|
9
|
+
const schema = z.object({
|
|
10
|
+
username: z.string().min(1, { message: 'username field is required' }),
|
|
11
|
+
password: z.string().min(1, { message: 'password field is required' }),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type FormData = Infer<typeof schema> & { unusedProperty: string };
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
onSubmit: (data: FormData) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function TestComponent({ onSubmit }: Props) {
|
|
21
|
+
const {
|
|
22
|
+
register,
|
|
23
|
+
handleSubmit,
|
|
24
|
+
formState: { errors },
|
|
25
|
+
} = useForm<FormData>({
|
|
26
|
+
resolver: typeschemaResolver(schema), // Useful to check TypeScript regressions
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
31
|
+
<input {...register('username')} />
|
|
32
|
+
{errors.username && <span role="alert">{errors.username.message}</span>}
|
|
33
|
+
|
|
34
|
+
<input {...register('password')} />
|
|
35
|
+
{errors.password && <span role="alert">{errors.password.message}</span>}
|
|
36
|
+
|
|
37
|
+
<button type="submit">submit</button>
|
|
38
|
+
</form>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
test("form's validation with TypeSchema and TypeScript's integration", async () => {
|
|
43
|
+
const handleSubmit = vi.fn();
|
|
44
|
+
render(<TestComponent onSubmit={handleSubmit} />);
|
|
45
|
+
|
|
46
|
+
expect(screen.queryAllByRole('alert')).toHaveLength(0);
|
|
47
|
+
|
|
48
|
+
await user.click(screen.getByText(/submit/i));
|
|
49
|
+
|
|
50
|
+
expect(screen.getByText(/username field is required/i)).toBeInTheDocument();
|
|
51
|
+
expect(screen.getByText(/password field is required/i)).toBeInTheDocument();
|
|
52
|
+
expect(handleSubmit).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Field, InternalFieldName } from 'react-hook-form';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const schema = z
|
|
5
|
+
.object({
|
|
6
|
+
username: z.string().regex(/^\w+$/).min(3).max(30),
|
|
7
|
+
password: z
|
|
8
|
+
.string()
|
|
9
|
+
.regex(new RegExp('.*[A-Z].*'), 'One uppercase character')
|
|
10
|
+
.regex(new RegExp('.*[a-z].*'), 'One lowercase character')
|
|
11
|
+
.regex(new RegExp('.*\\d.*'), 'One number')
|
|
12
|
+
.regex(
|
|
13
|
+
new RegExp('.*[`~<>?,./!@#$%^&*()\\-_+="\'|{}\\[\\];:\\\\].*'),
|
|
14
|
+
'One special character',
|
|
15
|
+
)
|
|
16
|
+
.min(8, 'Must be at least 8 characters in length'),
|
|
17
|
+
repeatPassword: z.string(),
|
|
18
|
+
accessToken: z.union([z.string(), z.number()]),
|
|
19
|
+
birthYear: z.number().min(1900).max(2013).optional(),
|
|
20
|
+
email: z.string().email().optional(),
|
|
21
|
+
tags: z.array(z.string()),
|
|
22
|
+
enabled: z.boolean(),
|
|
23
|
+
url: z.string().url('Custom error url').or(z.literal('')),
|
|
24
|
+
like: z
|
|
25
|
+
.array(
|
|
26
|
+
z.object({
|
|
27
|
+
id: z.number(),
|
|
28
|
+
name: z.string().length(4),
|
|
29
|
+
}),
|
|
30
|
+
)
|
|
31
|
+
.optional(),
|
|
32
|
+
dateStr: z
|
|
33
|
+
.string()
|
|
34
|
+
.transform((value) => new Date(value))
|
|
35
|
+
.refine((value) => !isNaN(value.getTime()), {
|
|
36
|
+
message: 'Invalid date',
|
|
37
|
+
}),
|
|
38
|
+
})
|
|
39
|
+
.refine((obj) => obj.password === obj.repeatPassword, {
|
|
40
|
+
message: 'Passwords do not match',
|
|
41
|
+
path: ['confirm'],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const validData: z.input<typeof schema> = {
|
|
45
|
+
username: 'Doe',
|
|
46
|
+
password: 'Password123_',
|
|
47
|
+
repeatPassword: 'Password123_',
|
|
48
|
+
birthYear: 2000,
|
|
49
|
+
email: 'john@doe.com',
|
|
50
|
+
tags: ['tag1', 'tag2'],
|
|
51
|
+
enabled: true,
|
|
52
|
+
accessToken: 'accessToken',
|
|
53
|
+
url: 'https://react-hook-form.com/',
|
|
54
|
+
like: [
|
|
55
|
+
{
|
|
56
|
+
id: 1,
|
|
57
|
+
name: 'name',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
dateStr: '2020-01-01',
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const invalidData = {
|
|
64
|
+
password: '___',
|
|
65
|
+
email: '',
|
|
66
|
+
birthYear: 'birthYear',
|
|
67
|
+
like: [{ id: 'z' }],
|
|
68
|
+
url: 'abc',
|
|
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,225 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`typeschemaResolver > should return a single error from typeschemaResolver when validation fails 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"errors": {
|
|
6
|
+
"accessToken": {
|
|
7
|
+
"message": "Invalid input",
|
|
8
|
+
"ref": undefined,
|
|
9
|
+
"type": "",
|
|
10
|
+
},
|
|
11
|
+
"birthYear": {
|
|
12
|
+
"message": "Expected number, received string",
|
|
13
|
+
"ref": undefined,
|
|
14
|
+
"type": "",
|
|
15
|
+
},
|
|
16
|
+
"dateStr": {
|
|
17
|
+
"message": "Required",
|
|
18
|
+
"ref": undefined,
|
|
19
|
+
"type": "",
|
|
20
|
+
},
|
|
21
|
+
"email": {
|
|
22
|
+
"message": "Invalid email",
|
|
23
|
+
"ref": {
|
|
24
|
+
"name": "email",
|
|
25
|
+
},
|
|
26
|
+
"type": "",
|
|
27
|
+
},
|
|
28
|
+
"enabled": {
|
|
29
|
+
"message": "Required",
|
|
30
|
+
"ref": undefined,
|
|
31
|
+
"type": "",
|
|
32
|
+
},
|
|
33
|
+
"like": [
|
|
34
|
+
{
|
|
35
|
+
"id": {
|
|
36
|
+
"message": "Expected number, received string",
|
|
37
|
+
"ref": undefined,
|
|
38
|
+
"type": "",
|
|
39
|
+
},
|
|
40
|
+
"name": {
|
|
41
|
+
"message": "Required",
|
|
42
|
+
"ref": undefined,
|
|
43
|
+
"type": "",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
"password": {
|
|
48
|
+
"message": "One uppercase character",
|
|
49
|
+
"ref": {
|
|
50
|
+
"name": "password",
|
|
51
|
+
},
|
|
52
|
+
"type": "",
|
|
53
|
+
},
|
|
54
|
+
"repeatPassword": {
|
|
55
|
+
"message": "Required",
|
|
56
|
+
"ref": undefined,
|
|
57
|
+
"type": "",
|
|
58
|
+
},
|
|
59
|
+
"tags": {
|
|
60
|
+
"message": "Required",
|
|
61
|
+
"ref": undefined,
|
|
62
|
+
"type": "",
|
|
63
|
+
},
|
|
64
|
+
"url": {
|
|
65
|
+
"message": "Custom error url",
|
|
66
|
+
"ref": undefined,
|
|
67
|
+
"type": "",
|
|
68
|
+
},
|
|
69
|
+
"username": {
|
|
70
|
+
"message": "Required",
|
|
71
|
+
"ref": {
|
|
72
|
+
"name": "username",
|
|
73
|
+
},
|
|
74
|
+
"type": "",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
"values": {},
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
exports[`typeschemaResolver > should return all the errors from typeschemaResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = `
|
|
82
|
+
{
|
|
83
|
+
"errors": {
|
|
84
|
+
"accessToken": {
|
|
85
|
+
"message": "Invalid input",
|
|
86
|
+
"ref": undefined,
|
|
87
|
+
"type": "",
|
|
88
|
+
"types": {
|
|
89
|
+
"": "Invalid input",
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
"birthYear": {
|
|
93
|
+
"message": "Expected number, received string",
|
|
94
|
+
"ref": undefined,
|
|
95
|
+
"type": "",
|
|
96
|
+
"types": {
|
|
97
|
+
"": "Expected number, received string",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
"dateStr": {
|
|
101
|
+
"message": "Required",
|
|
102
|
+
"ref": undefined,
|
|
103
|
+
"type": "",
|
|
104
|
+
"types": {
|
|
105
|
+
"": "Required",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
"email": {
|
|
109
|
+
"message": "Invalid email",
|
|
110
|
+
"ref": {
|
|
111
|
+
"name": "email",
|
|
112
|
+
},
|
|
113
|
+
"type": "",
|
|
114
|
+
"types": {
|
|
115
|
+
"": "Invalid email",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
"enabled": {
|
|
119
|
+
"message": "Required",
|
|
120
|
+
"ref": undefined,
|
|
121
|
+
"type": "",
|
|
122
|
+
"types": {
|
|
123
|
+
"": "Required",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
"like": [
|
|
127
|
+
{
|
|
128
|
+
"id": {
|
|
129
|
+
"message": "Expected number, received string",
|
|
130
|
+
"ref": undefined,
|
|
131
|
+
"type": "",
|
|
132
|
+
"types": {
|
|
133
|
+
"": "Expected number, received string",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
"name": {
|
|
137
|
+
"message": "Required",
|
|
138
|
+
"ref": undefined,
|
|
139
|
+
"type": "",
|
|
140
|
+
"types": {
|
|
141
|
+
"": "Required",
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
"password": {
|
|
147
|
+
"message": "One uppercase character",
|
|
148
|
+
"ref": {
|
|
149
|
+
"name": "password",
|
|
150
|
+
},
|
|
151
|
+
"type": "",
|
|
152
|
+
"types": {
|
|
153
|
+
"": [
|
|
154
|
+
"One uppercase character",
|
|
155
|
+
"One lowercase character",
|
|
156
|
+
"One number",
|
|
157
|
+
"Must be at least 8 characters in length",
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
"repeatPassword": {
|
|
162
|
+
"message": "Required",
|
|
163
|
+
"ref": undefined,
|
|
164
|
+
"type": "",
|
|
165
|
+
"types": {
|
|
166
|
+
"": "Required",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
"tags": {
|
|
170
|
+
"message": "Required",
|
|
171
|
+
"ref": undefined,
|
|
172
|
+
"type": "",
|
|
173
|
+
"types": {
|
|
174
|
+
"": "Required",
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
"url": {
|
|
178
|
+
"message": "Custom error url",
|
|
179
|
+
"ref": undefined,
|
|
180
|
+
"type": "",
|
|
181
|
+
"types": {
|
|
182
|
+
"": "Custom error url",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
"username": {
|
|
186
|
+
"message": "Required",
|
|
187
|
+
"ref": {
|
|
188
|
+
"name": "username",
|
|
189
|
+
},
|
|
190
|
+
"type": "",
|
|
191
|
+
"types": {
|
|
192
|
+
"": "Required",
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
"values": {},
|
|
197
|
+
}
|
|
198
|
+
`;
|
|
199
|
+
|
|
200
|
+
exports[`typeschemaResolver > should return parsed values from typeschemaResolver when validation pass 1`] = `
|
|
201
|
+
{
|
|
202
|
+
"errors": {},
|
|
203
|
+
"values": {
|
|
204
|
+
"accessToken": "accessToken",
|
|
205
|
+
"birthYear": 2000,
|
|
206
|
+
"dateStr": 2020-01-01T00:00:00.000Z,
|
|
207
|
+
"email": "john@doe.com",
|
|
208
|
+
"enabled": true,
|
|
209
|
+
"like": [
|
|
210
|
+
{
|
|
211
|
+
"id": 1,
|
|
212
|
+
"name": "name",
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
"password": "Password123_",
|
|
216
|
+
"repeatPassword": "Password123_",
|
|
217
|
+
"tags": [
|
|
218
|
+
"tag1",
|
|
219
|
+
"tag2",
|
|
220
|
+
],
|
|
221
|
+
"url": "https://react-hook-form.com/",
|
|
222
|
+
"username": "Doe",
|
|
223
|
+
},
|
|
224
|
+
}
|
|
225
|
+
`;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as typeschema from '@typeschema/main';
|
|
2
|
+
import { typeschemaResolver } from '..';
|
|
3
|
+
import { fields, invalidData, schema, validData } from './__fixtures__/data';
|
|
4
|
+
|
|
5
|
+
const shouldUseNativeValidation = false;
|
|
6
|
+
|
|
7
|
+
vi.mock('@typeschema/main', async (importOriginal) => {
|
|
8
|
+
const module: object = await importOriginal();
|
|
9
|
+
return { ...module };
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe('typeschemaResolver', () => {
|
|
13
|
+
it('should return values from typeschemaResolver when validation pass & raw=true', async () => {
|
|
14
|
+
const validateSpy = vi.spyOn(typeschema, 'validate');
|
|
15
|
+
|
|
16
|
+
const result = await typeschemaResolver(schema, undefined, { raw: true })(
|
|
17
|
+
validData,
|
|
18
|
+
undefined,
|
|
19
|
+
{ fields, shouldUseNativeValidation },
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
expect(validateSpy).toHaveBeenCalledTimes(1);
|
|
23
|
+
expect(result).toEqual({ errors: {}, values: validData });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return parsed values from typeschemaResolver when validation pass', async () => {
|
|
27
|
+
const validateSpy = vi.spyOn(typeschema, 'validate');
|
|
28
|
+
|
|
29
|
+
const result = await typeschemaResolver(schema)(validData, undefined, {
|
|
30
|
+
fields,
|
|
31
|
+
shouldUseNativeValidation,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(validateSpy).toHaveBeenCalledTimes(1);
|
|
35
|
+
expect(result.errors).toEqual({});
|
|
36
|
+
expect(result).toMatchSnapshot();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should return a single error from typeschemaResolver when validation fails', async () => {
|
|
40
|
+
const result = await typeschemaResolver(schema)(invalidData, undefined, {
|
|
41
|
+
fields,
|
|
42
|
+
shouldUseNativeValidation,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(result).toMatchSnapshot();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should return all the errors from typeschemaResolver when validation fails with `validateAllFieldCriteria` set to true', async () => {
|
|
49
|
+
const result = await typeschemaResolver(schema)(invalidData, undefined, {
|
|
50
|
+
fields,
|
|
51
|
+
criteriaMode: 'all',
|
|
52
|
+
shouldUseNativeValidation,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(result).toMatchSnapshot();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should throw any error unrelated to TypeSchema', async () => {
|
|
59
|
+
const schemaWithCustomError = schema.refine(() => {
|
|
60
|
+
throw Error('custom error');
|
|
61
|
+
});
|
|
62
|
+
const promise = typeschemaResolver(schemaWithCustomError)(
|
|
63
|
+
validData,
|
|
64
|
+
undefined,
|
|
65
|
+
{ fields, shouldUseNativeValidation },
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
await expect(promise).rejects.toThrow('custom error');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Schema } from '@typeschema/main';
|
|
2
|
+
import { FieldValues, ResolverOptions, ResolverResult } from 'react-hook-form';
|
|
3
|
+
|
|
4
|
+
export type Resolver = <T extends Schema>(
|
|
5
|
+
schema: T,
|
|
6
|
+
schemaOptions?: never,
|
|
7
|
+
factoryOptions?: {
|
|
8
|
+
/**
|
|
9
|
+
* Return the raw input values rather than the parsed values.
|
|
10
|
+
* @default false
|
|
11
|
+
*/
|
|
12
|
+
raw?: boolean;
|
|
13
|
+
},
|
|
14
|
+
) => <TFieldValues extends FieldValues, TContext>(
|
|
15
|
+
values: TFieldValues,
|
|
16
|
+
context: TContext | undefined,
|
|
17
|
+
options: ResolverOptions<TFieldValues>,
|
|
18
|
+
) => Promise<ResolverResult<TFieldValues>>;
|