@hookform/resolvers 2.9.11 → 3.0.1
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 +51 -5
- package/ajv/dist/ajv.d.ts +2 -2
- package/ajv/dist/ajv.js +1 -7
- package/ajv/dist/ajv.js.map +1 -1
- package/ajv/dist/ajv.mjs +1 -7
- package/ajv/dist/ajv.modern.mjs +2 -0
- package/ajv/dist/ajv.modern.mjs.map +1 -0
- package/ajv/dist/ajv.module.js +1 -7
- package/ajv/dist/ajv.module.js.map +1 -1
- package/ajv/dist/ajv.umd.js +1 -7
- package/ajv/dist/ajv.umd.js.map +1 -1
- package/ajv/dist/index.d.ts +2 -2
- package/ajv/dist/types.d.ts +5 -5
- package/ajv/package.json +3 -1
- package/ajv/src/__tests__/Form-native-validation.tsx +5 -9
- package/ajv/src/__tests__/Form.tsx +4 -6
- package/ajv/src/__tests__/__fixtures__/data.ts +3 -4
- package/ajv/src/__tests__/__snapshots__/ajv.ts.snap +83 -83
- package/ajv/src/ajv.ts +28 -24
- package/class-validator/dist/class-validator.d.ts +2 -2
- package/class-validator/dist/class-validator.js +1 -1
- package/class-validator/dist/class-validator.js.map +1 -1
- package/class-validator/dist/class-validator.mjs +1 -1
- package/class-validator/dist/class-validator.modern.mjs +2 -0
- package/class-validator/dist/class-validator.modern.mjs.map +1 -0
- package/class-validator/dist/class-validator.module.js +1 -1
- package/class-validator/dist/class-validator.module.js.map +1 -1
- package/class-validator/dist/class-validator.umd.js +1 -1
- package/class-validator/dist/class-validator.umd.js.map +1 -1
- package/class-validator/dist/index.d.ts +2 -2
- package/class-validator/dist/types.d.ts +12 -9
- package/class-validator/src/__tests__/Form-native-validation.tsx +5 -9
- package/class-validator/src/__tests__/Form.tsx +4 -6
- package/class-validator/src/__tests__/__snapshots__/class-validator.ts.snap +102 -67
- package/class-validator/src/__tests__/class-validator.ts +66 -6
- package/class-validator/src/class-validator.ts +6 -4
- package/class-validator/src/types.ts +7 -8
- package/computed-types/dist/computed-types.d.ts +2 -2
- package/computed-types/dist/computed-types.js +1 -1
- package/computed-types/dist/computed-types.js.map +1 -1
- package/computed-types/dist/computed-types.mjs +1 -1
- package/computed-types/dist/computed-types.modern.mjs +2 -0
- package/computed-types/dist/computed-types.modern.mjs.map +1 -0
- package/computed-types/dist/computed-types.module.js +1 -1
- package/computed-types/dist/computed-types.module.js.map +1 -1
- package/computed-types/dist/computed-types.umd.js +1 -1
- package/computed-types/dist/computed-types.umd.js.map +1 -1
- package/computed-types/dist/index.d.ts +2 -2
- package/computed-types/dist/types.d.ts +2 -2
- package/computed-types/src/__tests__/Form-native-validation.tsx +5 -9
- package/computed-types/src/__tests__/Form.tsx +4 -6
- package/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap +21 -21
- package/computed-types/src/__tests__/computed-types.ts +16 -0
- package/computed-types/src/computed-types.ts +12 -5
- package/dist/index.d.ts +2 -2
- 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/toNestError.d.ts +2 -2
- package/dist/validateFieldsNatively.d.ts +2 -2
- package/io-ts/dist/arrayToPath.d.ts +3 -3
- package/io-ts/dist/errorsToRecord.d.ts +5 -5
- package/io-ts/dist/index.d.ts +2 -2
- package/io-ts/dist/io-ts.d.ts +2 -2
- 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 +2 -0
- package/io-ts/dist/io-ts.modern.mjs.map +1 -0
- 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/dist/types.d.ts +7 -7
- package/io-ts/src/__tests__/Form-native-validation.tsx +5 -9
- package/io-ts/src/__tests__/Form.tsx +4 -6
- package/io-ts/src/__tests__/__snapshots__/io-ts.ts.snap +28 -28
- package/io-ts/src/__tests__/io-ts.ts +1 -1
- package/joi/dist/index.d.ts +2 -2
- package/joi/dist/joi.d.ts +2 -2
- package/joi/dist/joi.js.map +1 -1
- package/joi/dist/{joi.modern.js → joi.modern.mjs} +1 -1
- package/joi/dist/joi.modern.mjs.map +1 -0
- package/joi/dist/joi.module.js.map +1 -1
- package/joi/dist/joi.umd.js.map +1 -1
- package/joi/dist/types.d.ts +5 -5
- package/joi/src/__tests__/Form-native-validation.tsx +5 -9
- package/joi/src/__tests__/Form.tsx +4 -6
- package/joi/src/__tests__/__snapshots__/joi.ts.snap +87 -87
- package/joi/src/__tests__/joi.ts +8 -8
- package/nope/dist/index.d.ts +2 -2
- package/nope/dist/nope.d.ts +2 -2
- package/nope/dist/nope.js.map +1 -1
- package/nope/dist/{nope.modern.js → nope.modern.mjs} +1 -1
- package/nope/dist/nope.modern.mjs.map +1 -0
- package/nope/dist/nope.module.js.map +1 -1
- package/nope/dist/nope.umd.js.map +1 -1
- package/nope/dist/types.d.ts +9 -9
- package/nope/src/__tests__/Form-native-validation.tsx +5 -9
- package/nope/src/__tests__/Form.tsx +4 -6
- package/nope/src/__tests__/__snapshots__/nope.ts.snap +15 -15
- package/nope/src/__tests__/nope.ts +1 -1
- package/package.json +74 -44
- package/superstruct/dist/index.d.ts +2 -2
- package/superstruct/dist/superstruct.d.ts +2 -2
- package/superstruct/dist/superstruct.js +1 -1
- package/superstruct/dist/superstruct.js.map +1 -1
- package/superstruct/dist/superstruct.mjs +1 -1
- package/superstruct/dist/superstruct.modern.mjs +2 -0
- package/superstruct/dist/superstruct.modern.mjs.map +1 -0
- package/superstruct/dist/superstruct.module.js +1 -1
- package/superstruct/dist/superstruct.module.js.map +1 -1
- package/superstruct/dist/superstruct.umd.js +1 -1
- package/superstruct/dist/superstruct.umd.js.map +1 -1
- package/superstruct/dist/types.d.ts +11 -5
- package/superstruct/src/__tests__/Form-native-validation.tsx +5 -9
- package/superstruct/src/__tests__/Form.tsx +4 -6
- package/superstruct/src/__tests__/__snapshots__/superstruct.ts.snap +19 -19
- package/superstruct/src/__tests__/superstruct.ts +13 -0
- package/superstruct/src/superstruct.ts +4 -3
- package/superstruct/src/types.ts +8 -5
- package/typanion/dist/index.d.ts +2 -2
- package/typanion/dist/typanion.d.ts +2 -2
- package/typanion/dist/typanion.js.map +1 -1
- package/typanion/dist/{typanion.modern.js → typanion.modern.mjs} +1 -1
- package/typanion/dist/typanion.modern.mjs.map +1 -0
- package/typanion/dist/typanion.module.js.map +1 -1
- package/typanion/dist/typanion.umd.js.map +1 -1
- package/typanion/dist/types.d.ts +9 -9
- package/typanion/src/__tests__/Form-native-validation.tsx +7 -10
- package/typanion/src/__tests__/Form.tsx +9 -7
- package/typanion/src/__tests__/__snapshots__/typanion.ts.snap +22 -22
- package/typanion/src/__tests__/typanion.ts +11 -7
- package/typanion/src/typanion.ts +1 -1
- package/typebox/dist/index.d.ts +2 -0
- package/typebox/dist/typebox.d.ts +2 -0
- package/typebox/dist/typebox.js +2 -0
- package/typebox/dist/typebox.js.map +1 -0
- package/typebox/dist/typebox.mjs +2 -0
- package/typebox/dist/typebox.modern.mjs +2 -0
- package/typebox/dist/typebox.modern.mjs.map +1 -0
- package/typebox/dist/typebox.module.js +2 -0
- package/typebox/dist/typebox.module.js.map +1 -0
- package/typebox/dist/typebox.umd.js +2 -0
- package/typebox/dist/typebox.umd.js.map +1 -0
- package/typebox/dist/types.d.ts +3 -0
- package/typebox/package.json +18 -0
- package/typebox/src/__tests__/Form-native-validation.tsx +83 -0
- package/typebox/src/__tests__/Form.tsx +54 -0
- package/typebox/src/__tests__/__fixtures__/data.ts +84 -0
- package/typebox/src/__tests__/__snapshots__/typebox.ts.snap +190 -0
- package/typebox/src/__tests__/typebox.ts +34 -0
- package/typebox/src/index.ts +2 -0
- package/typebox/src/typebox.ts +64 -0
- package/typebox/src/types.ts +10 -0
- package/vest/dist/index.d.ts +2 -2
- package/vest/dist/types.d.ts +8 -8
- package/vest/dist/vest.d.ts +2 -2
- package/vest/dist/vest.js.map +1 -1
- package/vest/dist/{vest.modern.js → vest.modern.mjs} +1 -1
- package/vest/dist/vest.modern.mjs.map +1 -0
- 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 +5 -9
- package/vest/src/__tests__/Form.tsx +6 -10
- package/vest/src/__tests__/__snapshots__/vest.ts.snap +47 -47
- package/yup/dist/index.d.ts +2 -2
- package/yup/dist/types.d.ts +15 -9
- package/yup/dist/yup.d.ts +2 -2
- package/yup/dist/yup.js +1 -1
- package/yup/dist/yup.js.map +1 -1
- package/yup/dist/yup.mjs +1 -1
- package/yup/dist/yup.modern.mjs +2 -0
- package/yup/dist/yup.modern.mjs.map +1 -0
- package/yup/dist/yup.module.js +1 -1
- package/yup/dist/yup.module.js.map +1 -1
- package/yup/dist/yup.umd.js +1 -1
- package/yup/dist/yup.umd.js.map +1 -1
- package/yup/src/__tests__/Form-native-validation.tsx +5 -9
- package/yup/src/__tests__/Form.tsx +4 -6
- package/yup/src/__tests__/__fixtures__/data.ts +2 -3
- package/yup/src/__tests__/__snapshots__/yup.ts.snap +100 -87
- package/yup/src/__tests__/yup.ts +49 -18
- package/yup/src/types.ts +14 -11
- package/yup/src/yup.ts +1 -1
- package/zod/dist/index.d.ts +2 -2
- package/zod/dist/types.d.ts +13 -13
- package/zod/dist/zod.d.ts +2 -2
- 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 +2 -0
- package/zod/dist/zod.modern.mjs.map +1 -0
- 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 +5 -9
- package/zod/src/__tests__/Form.tsx +4 -6
- package/zod/src/__tests__/__snapshots__/zod.ts.snap +120 -120
- package/zod/src/__tests__/zod.ts +19 -7
- package/zod/src/types.ts +2 -6
- package/zod/src/zod.ts +27 -27
- package/ajv/dist/ajv.modern.js +0 -8
- package/ajv/dist/ajv.modern.js.map +0 -1
- package/class-validator/dist/class-validator.modern.js +0 -2
- package/class-validator/dist/class-validator.modern.js.map +0 -1
- package/computed-types/dist/computed-types.modern.js +0 -2
- package/computed-types/dist/computed-types.modern.js.map +0 -1
- package/io-ts/dist/io-ts.modern.js +0 -2
- package/io-ts/dist/io-ts.modern.js.map +0 -1
- package/joi/dist/joi.modern.js.map +0 -1
- package/nope/dist/nope.modern.js.map +0 -1
- package/superstruct/dist/superstruct.modern.js +0 -2
- package/superstruct/dist/superstruct.modern.js.map +0 -1
- package/typanion/dist/typanion.modern.js.map +0 -1
- package/vest/dist/vest.modern.js.map +0 -1
- package/yup/dist/yup.modern.js +0 -2
- package/yup/dist/yup.modern.js.map +0 -1
- package/zod/dist/zod.modern.js +0 -2
- package/zod/dist/zod.modern.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typanion.umd.js","sources":["../src/typanion.ts"],"sourcesContent":["import type {FieldError, FieldErrors} from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { Resolver } from './types';\n\nconst parseErrors = (errors: string[], parsedErrors: FieldErrors = {}) => {\n return errors.reduce((acc, error) => {\n const e = error.split(':');\n\n acc[e[0].slice(1)] = {\n message: e[1].trim(),\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n};\n\nexport const typanionResolver: Resolver =\n (validator, validatorOptions = {}) =>\n (values, _, options) => {\n const rawErrors: string[] = [];\n const isValid = validator(\n values,\n Object.assign(\n {},\n {\n errors: rawErrors,\n },\n validatorOptions,\n ),\n );\n const parsedErrors = parseErrors(rawErrors);\n\n if (isValid) {\n options.shouldUseNativeValidation &&\n validateFieldsNatively(parsedErrors, options);\n\n return { values, errors: {} };\n }\n\n return { values: {}, errors: toNestError(parsedErrors, options) };\n };\n"],"names":["validator","validatorOptions","values","_","options","rawErrors","isValid","Object","assign","errors","parsedErrors","reduce","acc","error","e","split","slice","message","trim","parseErrors","shouldUseNativeValidation","validateFieldsNatively","toNestError"],"mappings":"iVAiBE,SAACA,EAAWC,
|
|
1
|
+
{"version":3,"file":"typanion.umd.js","sources":["../src/typanion.ts"],"sourcesContent":["import type { FieldError, FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { Resolver } from './types';\n\nconst parseErrors = (errors: string[], parsedErrors: FieldErrors = {}) => {\n return errors.reduce((acc, error) => {\n const e = error.split(':');\n\n acc[e[0].slice(1)] = {\n message: e[1].trim(),\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n};\n\nexport const typanionResolver: Resolver =\n (validator, validatorOptions = {}) =>\n (values, _, options) => {\n const rawErrors: string[] = [];\n const isValid = validator(\n values,\n Object.assign(\n {},\n {\n errors: rawErrors,\n },\n validatorOptions,\n ),\n );\n const parsedErrors = parseErrors(rawErrors);\n\n if (isValid) {\n options.shouldUseNativeValidation &&\n validateFieldsNatively(parsedErrors, options);\n\n return { values, errors: {} };\n }\n\n return { values: {}, errors: toNestError(parsedErrors, options) };\n };\n"],"names":["validator","validatorOptions","values","_","options","rawErrors","isValid","Object","assign","errors","parsedErrors","reduce","acc","error","e","split","slice","message","trim","parseErrors","shouldUseNativeValidation","validateFieldsNatively","toNestError"],"mappings":"iVAiBE,SAACA,EAAWC,GAAqB,gBAArBA,IAAAA,EAAmB,CAAA,YAC9BC,EAAQC,EAAGC,GACV,IAAMC,EAAsB,GACtBC,EAAUN,EACdE,EACAK,OAAOC,OACL,CAAA,EACA,CACEC,OAAQJ,GAEVJ,IAGES,EA1BU,SAACD,EAAkBC,GACrC,YADqCA,IAAAA,IAAAA,EAA4B,CAAE,GAC5DD,EAAOE,OAAO,SAACC,EAAKC,GACzB,IAAMC,EAAID,EAAME,MAAM,KAMtB,OAJAH,EAAIE,EAAE,GAAGE,MAAM,IAAM,CACnBC,QAASH,EAAE,GAAGI,QAGTN,CACT,EAAGF,EACL,CAgByBS,CAAYd,GAEjC,OAAIC,GACFF,EAAQgB,2BACNC,EAAsBA,uBAACX,EAAcN,GAEhC,CAAEF,OAAAA,EAAQO,OAAQ,KAGpB,CAAEP,OAAQ,CAAA,EAAIO,OAAQa,cAAYZ,EAAcN,GACzD,CAAC"}
|
package/typanion/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { FieldValues, ResolverOptions, ResolverResult } from 'react-hook-form';
|
|
2
|
-
import { ValidationState, AnyStrictValidator } from 'typanion';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
mode?: 'async' | 'sync';
|
|
7
|
-
rawValues?: boolean;
|
|
8
|
-
}) => RHFResolver;
|
|
9
|
-
export {};
|
|
1
|
+
import type { FieldValues, ResolverOptions, ResolverResult } from 'react-hook-form';
|
|
2
|
+
import { ValidationState, AnyStrictValidator } from 'typanion';
|
|
3
|
+
type ValidateOptions = Pick<ValidationState, 'coercions' | 'coercion'>;
|
|
4
|
+
type RHFResolver = <TFieldValues extends FieldValues, TContext>(values: TFieldValues, context: TContext | undefined, options: ResolverOptions<TFieldValues>) => ResolverResult<TFieldValues>;
|
|
5
|
+
export type Resolver = <UnknownValidator extends AnyStrictValidator>(validator: UnknownValidator, validatorOptions?: ValidateOptions, resolverOptions?: {
|
|
6
|
+
mode?: 'async' | 'sync';
|
|
7
|
+
rawValues?: boolean;
|
|
8
|
+
}) => RHFResolver;
|
|
9
|
+
export {};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import user from '@testing-library/user-event';
|
|
4
4
|
import { useForm } from 'react-hook-form';
|
|
5
5
|
import * as t from 'typanion';
|
|
6
6
|
import { typanionResolver } from '..';
|
|
7
7
|
|
|
8
|
-
const ERROR_MESSAGE =
|
|
8
|
+
const ERROR_MESSAGE =
|
|
9
|
+
'Expected to have a length of at least 1 elements (got 0)';
|
|
9
10
|
|
|
10
11
|
const schema = t.isObject({
|
|
11
12
|
username: t.applyCascade(t.isString(), [t.hasMinLength(1)]),
|
|
@@ -40,7 +41,7 @@ function TestComponent({ onSubmit }: Props) {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
test("form's native validation with Typanion", async () => {
|
|
43
|
-
const handleSubmit =
|
|
44
|
+
const handleSubmit = vi.fn();
|
|
44
45
|
render(<TestComponent onSubmit={handleSubmit} />);
|
|
45
46
|
|
|
46
47
|
// username
|
|
@@ -57,9 +58,7 @@ test("form's native validation with Typanion", async () => {
|
|
|
57
58
|
expect(passwordField.validity.valid).toBe(true);
|
|
58
59
|
expect(passwordField.validationMessage).toBe('');
|
|
59
60
|
|
|
60
|
-
await
|
|
61
|
-
user.click(screen.getByText(/submit/i));
|
|
62
|
-
});
|
|
61
|
+
await user.click(screen.getByText(/submit/i));
|
|
63
62
|
|
|
64
63
|
// username
|
|
65
64
|
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
@@ -71,10 +70,8 @@ test("form's native validation with Typanion", async () => {
|
|
|
71
70
|
expect(passwordField.validity.valid).toBe(false);
|
|
72
71
|
expect(passwordField.validationMessage).toBe(ERROR_MESSAGE);
|
|
73
72
|
|
|
74
|
-
await
|
|
75
|
-
|
|
76
|
-
user.type(screen.getByPlaceholderText(/password/i), 'password');
|
|
77
|
-
});
|
|
73
|
+
await user.type(screen.getByPlaceholderText(/username/i), 'joe');
|
|
74
|
+
await user.type(screen.getByPlaceholderText(/password/i), 'password');
|
|
78
75
|
|
|
79
76
|
// username
|
|
80
77
|
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import user from '@testing-library/user-event';
|
|
4
4
|
import { useForm } from 'react-hook-form';
|
|
5
5
|
import * as t from 'typanion';
|
|
@@ -43,15 +43,17 @@ function TestComponent({ onSubmit }: Props) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
test("form's validation with Typanion and TypeScript's integration", async () => {
|
|
46
|
-
const handleSubmit =
|
|
46
|
+
const handleSubmit = vi.fn();
|
|
47
47
|
render(<TestComponent onSubmit={handleSubmit} />);
|
|
48
48
|
|
|
49
|
-
expect(screen.queryAllByRole(
|
|
49
|
+
expect(screen.queryAllByRole('alert')).toHaveLength(0);
|
|
50
50
|
|
|
51
|
-
await
|
|
52
|
-
user.click(screen.getByText(/submit/i));
|
|
53
|
-
});
|
|
51
|
+
await user.click(screen.getByText(/submit/i));
|
|
54
52
|
|
|
55
|
-
expect(
|
|
53
|
+
expect(
|
|
54
|
+
screen.getAllByText(
|
|
55
|
+
'Expected to have a length of at least 1 elements (got 0)',
|
|
56
|
+
),
|
|
57
|
+
).toHaveLength(2);
|
|
56
58
|
expect(handleSubmit).not.toHaveBeenCalled();
|
|
57
59
|
});
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
-
exports[`typanionResolver should return a single error from typanionResolver when validation fails 1`] = `
|
|
4
|
-
|
|
5
|
-
"errors":
|
|
6
|
-
"accessToken":
|
|
3
|
+
exports[`typanionResolver > should return a single error from typanionResolver when validation fails 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"errors": {
|
|
6
|
+
"accessToken": {
|
|
7
7
|
"message": "Expected a string (got undefined)",
|
|
8
8
|
"ref": undefined,
|
|
9
9
|
},
|
|
10
|
-
"birthYear":
|
|
10
|
+
"birthYear": {
|
|
11
11
|
"message": "Expected a number (got \\"birthYear\\")",
|
|
12
12
|
"ref": undefined,
|
|
13
13
|
},
|
|
14
|
-
"email":
|
|
14
|
+
"email": {
|
|
15
15
|
"message": "Expected to match the pattern /^\\\\S+@\\\\S+$/ (got an empty string)",
|
|
16
|
-
"ref":
|
|
16
|
+
"ref": {
|
|
17
17
|
"name": "email",
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
|
-
"enabled":
|
|
20
|
+
"enabled": {
|
|
21
21
|
"message": "Expected a boolean (got undefined)",
|
|
22
22
|
"ref": undefined,
|
|
23
23
|
},
|
|
24
|
-
"like":
|
|
25
|
-
"id":
|
|
24
|
+
"like": {
|
|
25
|
+
"id": {
|
|
26
26
|
"message": "Expected a number (got \\"z\\")",
|
|
27
27
|
"ref": undefined,
|
|
28
28
|
},
|
|
29
|
-
"name":
|
|
29
|
+
"name": {
|
|
30
30
|
"message": "Expected a string (got undefined)",
|
|
31
31
|
"ref": undefined,
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
|
-
"password":
|
|
34
|
+
"password": {
|
|
35
35
|
"message": "Expected to match the pattern /.*[A-Z].*/ (got \\"___\\")",
|
|
36
|
-
"ref":
|
|
36
|
+
"ref": {
|
|
37
37
|
"name": "password",
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
|
-
"repeatPassword":
|
|
40
|
+
"repeatPassword": {
|
|
41
41
|
"message": "Expected a string (got undefined)",
|
|
42
42
|
"ref": undefined,
|
|
43
43
|
},
|
|
44
|
-
"tags":
|
|
45
|
-
|
|
44
|
+
"tags": [
|
|
45
|
+
{
|
|
46
46
|
"message": "Expected a string (got 1)",
|
|
47
47
|
"ref": undefined,
|
|
48
48
|
},
|
|
49
|
-
|
|
49
|
+
{
|
|
50
50
|
"message": "Expected a string (got 2)",
|
|
51
51
|
"ref": undefined,
|
|
52
52
|
},
|
|
53
|
-
|
|
53
|
+
{
|
|
54
54
|
"message": "Expected a string (got 3)",
|
|
55
55
|
"ref": undefined,
|
|
56
56
|
},
|
|
57
57
|
],
|
|
58
|
-
"username":
|
|
58
|
+
"username": {
|
|
59
59
|
"message": "Expected a string (got undefined)",
|
|
60
|
-
"ref":
|
|
60
|
+
"ref": {
|
|
61
61
|
"name": "username",
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
},
|
|
65
|
-
"values":
|
|
65
|
+
"values": {},
|
|
66
66
|
}
|
|
67
67
|
`;
|
|
@@ -2,19 +2,23 @@ import { typanionResolver } from '..';
|
|
|
2
2
|
import { isSchema, validData, fields, invalidData } from './__fixtures__/data';
|
|
3
3
|
|
|
4
4
|
const tmpObj = {
|
|
5
|
-
validate: isSchema
|
|
6
|
-
}
|
|
5
|
+
validate: isSchema,
|
|
6
|
+
};
|
|
7
7
|
|
|
8
8
|
const shouldUseNativeValidation = false;
|
|
9
9
|
|
|
10
10
|
describe('typanionResolver', () => {
|
|
11
11
|
it('should return values from typanionResolver when validation pass', async () => {
|
|
12
|
-
const schemaSpy =
|
|
12
|
+
const schemaSpy = vi.spyOn(tmpObj, 'validate');
|
|
13
13
|
|
|
14
|
-
const result = await typanionResolver(schemaSpy as any)(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
const result = await typanionResolver(schemaSpy as any)(
|
|
15
|
+
validData,
|
|
16
|
+
undefined,
|
|
17
|
+
{
|
|
18
|
+
fields,
|
|
19
|
+
shouldUseNativeValidation,
|
|
20
|
+
},
|
|
21
|
+
);
|
|
18
22
|
|
|
19
23
|
expect(schemaSpy).toHaveBeenCalledTimes(1);
|
|
20
24
|
expect(result).toEqual({ errors: {}, values: validData });
|
package/typanion/src/typanion.ts
CHANGED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=require("react-hook-form"),r=require("@hookform/resolvers"),a=require("@sinclair/typebox/value"),s=function(r,a){for(var s={};r.length;){var t=r[0],o=t.type,i=t.message,l=t.path.substring(1).replace(/\//g,".");if(s[l]||(s[l]={message:i,type:""+o}),a){var n=s[l].types,u=n&&n[""+o];s[l]=e.appendErrors(l,a,s,""+o,u?[].concat(u,t.message):t.message)}r.shift()}return s};exports.typeboxResolver=function(e){return function(t,o,i){try{var l=Array.from(a.Value.Errors(e,t));return i.shouldUseNativeValidation&&r.validateFieldsNatively({},i),Promise.resolve(l.length?{values:{},errors:r.toNestError(s(l,!i.shouldUseNativeValidation&&"all"===i.criteriaMode),i)}:{errors:{},values:t})}catch(e){return Promise.reject(e)}}};
|
|
2
|
+
//# sourceMappingURL=typebox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typebox.js","sources":["../src/typebox.ts"],"sourcesContent":["import { appendErrors, FieldError, FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport { Value, ValueError } from '@sinclair/typebox/value';\n\nconst parseErrorSchema = (\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.substring(1).replace(/\\//g, '.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n};\n\nexport const typeboxResolver: Resolver =\n (schema) => async (values, _, options) => {\n const errors = Array.from(Value.Errors(schema, values));\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {} as FieldErrors,\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestError(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","length","error","type","message","_path","path","substring","replace","types","messages","appendErrors","concat","shift","schema","values","_","options","Array","from","Value","Errors","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","toNestError","criteriaMode","e","reject"],"mappings":"uGAKMA,EAAmB,SACvBC,EACAC,GAGA,IADA,IAAMC,EAAqC,CAAE,EACtCF,EAAQG,QAAU,CACvB,IAAMC,EAAQJ,EAAQ,GACdK,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KACJC,UAAU,GAAGC,QAAQ,MAAO,KAM/C,GAJKR,EAAOK,KACVL,EAAOK,GAAS,CAAED,QAAAA,EAASD,KAAM,GAAKA,IAGpCJ,EAA0B,CAC5B,IAAMU,EAAQT,EAAOK,GAAOI,MACtBC,EAAWD,GAASA,EAAM,GAAKN,GAErCH,EAAOK,GAASM,EAAYA,aAC1BN,EACAN,EACAC,EACA,GAAKG,EACLO,EACK,GAAgBE,OAAOF,EAAsBR,EAAME,SACpDF,EAAME,QAEb,CAEDN,EAAQe,OACT,CAED,OAAOb,CACT,0BAGE,SAACc,GAAM,OAAA,SAAYC,EAAQC,EAAGC,GAAW,IACvC,IAAMjB,EAASkB,MAAMC,KAAKC,EAAAA,MAAMC,OAAOP,EAAQC,IAI/C,OAFAE,EAAQK,2BAA6BC,EAAAA,uBAAuB,CAAA,EAAIN,GAShEO,QAAAC,QAPKzB,EAAOC,OAOL,CACLc,OAAQ,CAAE,EACVf,OAAQ0B,EAAAA,YACN7B,EACEG,GACCiB,EAAQK,2BAAsD,QAAzBL,EAAQU,cAEhDV,IAbK,CACLjB,OAAQ,GACRe,OAAAA,GAcN,CAAC,MAAAa,GAAAJ,OAAAA,QAAAK,OAAAD,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{appendErrors as r}from"react-hook-form";import{validateFieldsNatively as e,toNestError as o}from"@hookform/resolvers";import{Value as t}from"@sinclair/typebox/value";var a=function(e,o){for(var t={};e.length;){var a=e[0],s=a.type,i=a.message,n=a.path.substring(1).replace(/\//g,".");if(t[n]||(t[n]={message:i,type:""+s}),o){var l=t[n].types,m=l&&l[""+s];t[n]=r(n,o,t,""+s,m?[].concat(m,a.message):a.message)}e.shift()}return t},s=function(r){return function(s,i,n){try{var l=Array.from(t.Errors(r,s));return n.shouldUseNativeValidation&&e({},n),Promise.resolve(l.length?{values:{},errors:o(a(l,!n.shouldUseNativeValidation&&"all"===n.criteriaMode),n)}:{errors:{},values:s})}catch(r){return Promise.reject(r)}}};export{s as typeboxResolver};
|
|
2
|
+
//# sourceMappingURL=typebox.module.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{appendErrors as r}from"react-hook-form";import{validateFieldsNatively as e,toNestError as o}from"@hookform/resolvers";import{Value as s}from"@sinclair/typebox/value";const t=(e,o)=>{const s={};for(;e.length;){const t=e[0],{type:a,message:i,path:n}=t,l=n.substring(1).replace(/\//g,".");if(s[l]||(s[l]={message:i,type:""+a}),o){const e=s[l].types,i=e&&e[""+a];s[l]=r(l,o,s,""+a,i?[].concat(i,t.message):t.message)}e.shift()}return s},a=r=>async(a,i,n)=>{const l=Array.from(s.Errors(r,a));return n.shouldUseNativeValidation&&e({},n),l.length?{values:{},errors:o(t(l,!n.shouldUseNativeValidation&&"all"===n.criteriaMode),n)}:{errors:{},values:a}};export{a as typeboxResolver};
|
|
2
|
+
//# sourceMappingURL=typebox.modern.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typebox.modern.mjs","sources":["../src/typebox.ts"],"sourcesContent":["import { appendErrors, FieldError, FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport { Value, ValueError } from '@sinclair/typebox/value';\n\nconst parseErrorSchema = (\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.substring(1).replace(/\\//g, '.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n};\n\nexport const typeboxResolver: Resolver =\n (schema) => async (values, _, options) => {\n const errors = Array.from(Value.Errors(schema, values));\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {} as FieldErrors,\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestError(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","length","error","type","message","path","_path","substring","replace","types","messages","appendErrors","concat","shift","typeboxResolver","schema","async","values","_","options","Array","from","Value","Errors","shouldUseNativeValidation","validateFieldsNatively","toNestError","criteriaMode"],"mappings":"6KAKA,MAAMA,EAAmBA,CACvBC,EACAC,KAEA,MAAMC,EAAqC,CAAA,EAC3C,KAAOF,EAAQG,QAAU,CACvB,MAAMC,EAAQJ,EAAQ,IAChBK,KAAEA,EAAIC,QAAEA,EAAOC,KAAEA,GAASH,EAC1BI,EAAQD,EAAKE,UAAU,GAAGC,QAAQ,MAAO,KAM/C,GAJKR,EAAOM,KACVN,EAAOM,GAAS,CAAEF,UAASD,KAAM,GAAKA,IAGpCJ,EAA0B,CAC5B,MAAMU,EAAQT,EAAOM,GAAOG,MACtBC,EAAWD,GAASA,EAAM,GAAKN,GAErCH,EAAOM,GAASK,EACdL,EACAP,EACAC,EACA,GAAKG,EACLO,EACK,GAAgBE,OAAOF,EAAsBR,EAAME,SACpDF,EAAME,QAEb,CAEDN,EAAQe,OACT,CAED,OAAOb,GAGIc,EACVC,GAAWC,MAAOC,EAAQC,EAAGC,KAC5B,MAAMnB,EAASoB,MAAMC,KAAKC,EAAMC,OAAOR,EAAQE,IAI/C,OAFAE,EAAQK,2BAA6BC,EAAuB,CAAE,EAAEN,GAE3DnB,EAAOC,OAOL,CACLgB,OAAQ,CAAA,EACRjB,OAAQ0B,EACN7B,EACEG,GACCmB,EAAQK,2BAAsD,QAAzBL,EAAQQ,cAEhDR,IAbK,CACLnB,OAAQ,CAAA,EACRiB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{appendErrors as r}from"react-hook-form";import{validateFieldsNatively as e,toNestError as o}from"@hookform/resolvers";import{Value as t}from"@sinclair/typebox/value";var a=function(e,o){for(var t={};e.length;){var a=e[0],s=a.type,i=a.message,n=a.path.substring(1).replace(/\//g,".");if(t[n]||(t[n]={message:i,type:""+s}),o){var l=t[n].types,m=l&&l[""+s];t[n]=r(n,o,t,""+s,m?[].concat(m,a.message):a.message)}e.shift()}return t},s=function(r){return function(s,i,n){try{var l=Array.from(t.Errors(r,s));return n.shouldUseNativeValidation&&e({},n),Promise.resolve(l.length?{values:{},errors:o(a(l,!n.shouldUseNativeValidation&&"all"===n.criteriaMode),n)}:{errors:{},values:s})}catch(r){return Promise.reject(r)}}};export{s as typeboxResolver};
|
|
2
|
+
//# sourceMappingURL=typebox.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typebox.module.js","sources":["../src/typebox.ts"],"sourcesContent":["import { appendErrors, FieldError, FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport { Value, ValueError } from '@sinclair/typebox/value';\n\nconst parseErrorSchema = (\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.substring(1).replace(/\\//g, '.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n};\n\nexport const typeboxResolver: Resolver =\n (schema) => async (values, _, options) => {\n const errors = Array.from(Value.Errors(schema, values));\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {} as FieldErrors,\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestError(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","length","error","type","message","_path","path","substring","replace","types","messages","appendErrors","concat","shift","typeboxResolver","schema","values","_","options","Array","from","Value","Errors","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","toNestError","criteriaMode","e","reject"],"mappings":"6KAKA,IAAMA,EAAmB,SACvBC,EACAC,GAGA,IADA,IAAMC,EAAqC,CAAE,EACtCF,EAAQG,QAAU,CACvB,IAAMC,EAAQJ,EAAQ,GACdK,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KACJC,UAAU,GAAGC,QAAQ,MAAO,KAM/C,GAJKR,EAAOK,KACVL,EAAOK,GAAS,CAAED,QAAAA,EAASD,KAAM,GAAKA,IAGpCJ,EAA0B,CAC5B,IAAMU,EAAQT,EAAOK,GAAOI,MACtBC,EAAWD,GAASA,EAAM,GAAKN,GAErCH,EAAOK,GAASM,EACdN,EACAN,EACAC,EACA,GAAKG,EACLO,EACK,GAAgBE,OAAOF,EAAsBR,EAAME,SACpDF,EAAME,QAEb,CAEDN,EAAQe,OACT,CAED,OAAOb,CACT,EAEac,EACX,SAACC,GAAM,OAAA,SAAYC,EAAQC,EAAGC,GAAW,IACvC,IAAMlB,EAASmB,MAAMC,KAAKC,EAAMC,OAAOP,EAAQC,IAI/C,OAFAE,EAAQK,2BAA6BC,EAAuB,CAAA,EAAIN,GAShEO,QAAAC,QAPK1B,EAAOC,OAOL,CACLe,OAAQ,CAAE,EACVhB,OAAQ2B,EACN9B,EACEG,GACCkB,EAAQK,2BAAsD,QAAzBL,EAAQU,cAEhDV,IAbK,CACLlB,OAAQ,GACRgB,OAAAA,GAcN,CAAC,MAAAa,GAAAJ,OAAAA,QAAAK,OAAAD,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("react-hook-form"),require("@hookform/resolvers"),require("@sinclair/typebox/value")):"function"==typeof define&&define.amd?define(["exports","react-hook-form","@hookform/resolvers","@sinclair/typebox/value"],r):r((e||self).hookformResolversTypebox={},e.ReactHookForm,e.hookformResolvers,e.value)}(this,function(e,r,o,t){var s=function(e,o){for(var t={};e.length;){var s=e[0],a=s.type,i=s.message,l=s.path.substring(1).replace(/\//g,".");if(t[l]||(t[l]={message:i,type:""+a}),o){var n=t[l].types,f=n&&n[""+a];t[l]=r.appendErrors(l,o,t,""+a,f?[].concat(f,s.message):s.message)}e.shift()}return t};e.typeboxResolver=function(e){return function(r,a,i){try{var l=Array.from(t.Value.Errors(e,r));return i.shouldUseNativeValidation&&o.validateFieldsNatively({},i),Promise.resolve(l.length?{values:{},errors:o.toNestError(s(l,!i.shouldUseNativeValidation&&"all"===i.criteriaMode),i)}:{errors:{},values:r})}catch(e){return Promise.reject(e)}}}});
|
|
2
|
+
//# sourceMappingURL=typebox.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typebox.umd.js","sources":["../src/typebox.ts"],"sourcesContent":["import { appendErrors, FieldError, FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { Resolver } from './types';\nimport { Value, ValueError } from '@sinclair/typebox/value';\n\nconst parseErrorSchema = (\n _errors: ValueError[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; _errors.length; ) {\n const error = _errors[0];\n const { type, message, path } = error;\n const _path = path.substring(1).replace(/\\//g, '.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: '' + type };\n }\n\n if (validateAllFieldCriteria) {\n const types = errors[_path].types;\n const messages = types && types['' + type];\n\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n '' + type,\n messages\n ? ([] as string[]).concat(messages as string[], error.message)\n : error.message,\n ) as FieldError;\n }\n\n _errors.shift();\n }\n\n return errors;\n};\n\nexport const typeboxResolver: Resolver =\n (schema) => async (values, _, options) => {\n const errors = Array.from(Value.Errors(schema, values));\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n if (!errors.length) {\n return {\n errors: {} as FieldErrors,\n values,\n };\n }\n\n return {\n values: {},\n errors: toNestError(\n parseErrorSchema(\n errors,\n !options.shouldUseNativeValidation && options.criteriaMode === 'all',\n ),\n options,\n ),\n };\n };\n"],"names":["parseErrorSchema","_errors","validateAllFieldCriteria","errors","length","error","type","message","_path","path","substring","replace","types","messages","appendErrors","concat","shift","schema","values","_","options","Array","from","Value","Errors","shouldUseNativeValidation","validateFieldsNatively","Promise","resolve","toNestError","criteriaMode","e","reject"],"mappings":"mcAKA,IAAMA,EAAmB,SACvBC,EACAC,GAGA,IADA,IAAMC,EAAqC,CAAE,EACtCF,EAAQG,QAAU,CACvB,IAAMC,EAAQJ,EAAQ,GACdK,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KACJC,UAAU,GAAGC,QAAQ,MAAO,KAM/C,GAJKR,EAAOK,KACVL,EAAOK,GAAS,CAAED,QAAAA,EAASD,KAAM,GAAKA,IAGpCJ,EAA0B,CAC5B,IAAMU,EAAQT,EAAOK,GAAOI,MACtBC,EAAWD,GAASA,EAAM,GAAKN,GAErCH,EAAOK,GAASM,EAAYA,aAC1BN,EACAN,EACAC,EACA,GAAKG,EACLO,EACK,GAAgBE,OAAOF,EAAsBR,EAAME,SACpDF,EAAME,QAEb,CAEDN,EAAQe,OACT,CAED,OAAOb,CACT,oBAGE,SAACc,GAAM,OAAA,SAAYC,EAAQC,EAAGC,GAAW,IACvC,IAAMjB,EAASkB,MAAMC,KAAKC,EAAAA,MAAMC,OAAOP,EAAQC,IAI/C,OAFAE,EAAQK,2BAA6BC,EAAAA,uBAAuB,CAAA,EAAIN,GAShEO,QAAAC,QAPKzB,EAAOC,OAOL,CACLc,OAAQ,CAAE,EACVf,OAAQ0B,EAAAA,YACN7B,EACEG,GACCiB,EAAQK,2BAAsD,QAAzBL,EAAQU,cAEhDV,IAbK,CACLjB,OAAQ,GACRe,OAAAA,GAcN,CAAC,MAAAa,GAAAJ,OAAAA,QAAAK,OAAAD,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Type } from '@sinclair/typebox';
|
|
2
|
+
import { FieldValues, ResolverResult, ResolverOptions } from 'react-hook-form';
|
|
3
|
+
export type Resolver = <T extends ReturnType<typeof Type.Object>>(schema: T) => <TFieldValues extends FieldValues, TContext>(values: TFieldValues, context: TContext | undefined, options: ResolverOptions<TFieldValues>) => Promise<ResolverResult<TFieldValues>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hookform/resolvers/typebox",
|
|
3
|
+
"amdName": "hookformResolversTypebox",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "React Hook Form validation resolver: typebox",
|
|
7
|
+
"main": "dist/typebox.js",
|
|
8
|
+
"module": "dist/typebox.module.js",
|
|
9
|
+
"umd:main": "dist/typebox.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
|
+
"@sinclair/typebox": "^0.25.24"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useForm } from 'react-hook-form';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import user from '@testing-library/user-event';
|
|
5
|
+
import { typeboxResolver } from '..';
|
|
6
|
+
|
|
7
|
+
import { Type, Static } from '@sinclair/typebox';
|
|
8
|
+
|
|
9
|
+
const schema = Type.Object({
|
|
10
|
+
username: Type.String({ minLength: 1 }),
|
|
11
|
+
password: Type.String({ minLength: 1 }),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type FormData = Static<typeof schema>;
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
onSubmit: (data: FormData) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function TestComponent({ onSubmit }: Props) {
|
|
21
|
+
const { register, handleSubmit } = useForm<FormData>({
|
|
22
|
+
resolver: typeboxResolver(schema),
|
|
23
|
+
shouldUseNativeValidation: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
28
|
+
<input {...register('username')} placeholder="username" />
|
|
29
|
+
|
|
30
|
+
<input {...register('password')} placeholder="password" />
|
|
31
|
+
|
|
32
|
+
<button type="submit">submit</button>
|
|
33
|
+
</form>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
test("form's native validation with Zod", async () => {
|
|
38
|
+
const handleSubmit = vi.fn();
|
|
39
|
+
render(<TestComponent onSubmit={handleSubmit} />);
|
|
40
|
+
|
|
41
|
+
// username
|
|
42
|
+
let usernameField = screen.getByPlaceholderText(
|
|
43
|
+
/username/i,
|
|
44
|
+
) as HTMLInputElement;
|
|
45
|
+
expect(usernameField.validity.valid).toBe(true);
|
|
46
|
+
expect(usernameField.validationMessage).toBe('');
|
|
47
|
+
|
|
48
|
+
// password
|
|
49
|
+
let passwordField = screen.getByPlaceholderText(
|
|
50
|
+
/password/i,
|
|
51
|
+
) as HTMLInputElement;
|
|
52
|
+
expect(passwordField.validity.valid).toBe(true);
|
|
53
|
+
expect(passwordField.validationMessage).toBe('');
|
|
54
|
+
|
|
55
|
+
await user.click(screen.getByText(/submit/i));
|
|
56
|
+
|
|
57
|
+
// username
|
|
58
|
+
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
59
|
+
expect(usernameField.validity.valid).toBe(false);
|
|
60
|
+
expect(usernameField.validationMessage).toBe(
|
|
61
|
+
'Expected string length greater or equal to 1',
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// password
|
|
65
|
+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
66
|
+
expect(passwordField.validity.valid).toBe(false);
|
|
67
|
+
expect(passwordField.validationMessage).toBe(
|
|
68
|
+
'Expected string length greater or equal to 1',
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
await user.type(screen.getByPlaceholderText(/username/i), 'joe');
|
|
72
|
+
await user.type(screen.getByPlaceholderText(/password/i), 'password');
|
|
73
|
+
|
|
74
|
+
// username
|
|
75
|
+
usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
|
|
76
|
+
expect(usernameField.validity.valid).toBe(true);
|
|
77
|
+
expect(usernameField.validationMessage).toBe('');
|
|
78
|
+
|
|
79
|
+
// password
|
|
80
|
+
passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
|
|
81
|
+
expect(passwordField.validity.valid).toBe(true);
|
|
82
|
+
expect(passwordField.validationMessage).toBe('');
|
|
83
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import user from '@testing-library/user-event';
|
|
4
|
+
import { useForm } from 'react-hook-form';
|
|
5
|
+
import { typeboxResolver } from '..';
|
|
6
|
+
import { Type, Static } from '@sinclair/typebox';
|
|
7
|
+
|
|
8
|
+
const schema = Type.Object({
|
|
9
|
+
username: Type.String({ minLength: 1 }),
|
|
10
|
+
password: Type.String({ minLength: 1 }),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
type FormData = Static<typeof schema> & { unusedProperty: string };
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
onSubmit: (data: FormData) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function TestComponent({ onSubmit }: Props) {
|
|
20
|
+
const {
|
|
21
|
+
register,
|
|
22
|
+
handleSubmit,
|
|
23
|
+
formState: { errors },
|
|
24
|
+
} = useForm<FormData>({
|
|
25
|
+
resolver: typeboxResolver(schema), // Useful to check TypeScript regressions
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
30
|
+
<input {...register('username')} />
|
|
31
|
+
{errors.username && <span role="alert">{errors.username.message}</span>}
|
|
32
|
+
|
|
33
|
+
<input {...register('password')} />
|
|
34
|
+
{errors.password && <span role="alert">{errors.password.message}</span>}
|
|
35
|
+
|
|
36
|
+
<button type="submit">submit</button>
|
|
37
|
+
</form>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
test("form's validation with Zod and TypeScript's integration", async () => {
|
|
42
|
+
const handleSubmit = vi.fn();
|
|
43
|
+
render(<TestComponent onSubmit={handleSubmit} />);
|
|
44
|
+
|
|
45
|
+
expect(screen.queryAllByRole('alert')).toHaveLength(0);
|
|
46
|
+
|
|
47
|
+
await user.click(screen.getByText(/submit/i));
|
|
48
|
+
|
|
49
|
+
expect(
|
|
50
|
+
screen.getAllByText(/Expected string length greater or equal to 1/i),
|
|
51
|
+
).toHaveLength(2);
|
|
52
|
+
|
|
53
|
+
expect(handleSubmit).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Field, InternalFieldName } from 'react-hook-form';
|
|
2
|
+
import { Static, Type } from '@sinclair/typebox';
|
|
3
|
+
import { TypeSystem } from '@sinclair/typebox/system';
|
|
4
|
+
|
|
5
|
+
TypeSystem.CreateFormat('email', (value: string) => {
|
|
6
|
+
return /^\S+@\S+$/.test(value);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const schema = Type.Object({
|
|
10
|
+
username: Type.String({
|
|
11
|
+
minLength: 3,
|
|
12
|
+
maxLength: 30,
|
|
13
|
+
pattern: '^[a-zA-Z0-9]+$',
|
|
14
|
+
}),
|
|
15
|
+
password: Type.String({
|
|
16
|
+
minLength: 8,
|
|
17
|
+
pattern: '^(.*[A-Za-z\\d].*)$',
|
|
18
|
+
}),
|
|
19
|
+
repeatPassword: Type.String(),
|
|
20
|
+
accessToken: Type.Union([Type.String(), Type.Number()]),
|
|
21
|
+
birthYear: Type.Optional(
|
|
22
|
+
Type.Number({
|
|
23
|
+
minimum: 1900,
|
|
24
|
+
maximum: 2013,
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
email: Type.Optional(Type.String({ format: 'email' })),
|
|
28
|
+
tags: Type.Array(Type.String()),
|
|
29
|
+
enabled: Type.Boolean(),
|
|
30
|
+
like: Type.Optional(
|
|
31
|
+
Type.Array(
|
|
32
|
+
Type.Object({
|
|
33
|
+
id: Type.Number(),
|
|
34
|
+
name: Type.String({ minLength: 4, maxLength: 4 }),
|
|
35
|
+
}),
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
dateStr: Type.Date(),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const validData: Static<typeof schema> = {
|
|
42
|
+
username: 'Doe',
|
|
43
|
+
password: 'Password123_',
|
|
44
|
+
repeatPassword: 'Password123_',
|
|
45
|
+
birthYear: 2000,
|
|
46
|
+
email: 'tsulatsitamim@gmail.com',
|
|
47
|
+
tags: ['tag1', 'tag2'],
|
|
48
|
+
enabled: true,
|
|
49
|
+
accessToken: 'accessToken',
|
|
50
|
+
like: [
|
|
51
|
+
{
|
|
52
|
+
id: 1,
|
|
53
|
+
name: 'name',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
dateStr: new Date(),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const invalidData = {
|
|
60
|
+
password: '___',
|
|
61
|
+
email: '',
|
|
62
|
+
birthYear: 'birthYear',
|
|
63
|
+
like: [{ id: 'z' }],
|
|
64
|
+
url: 'abc',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const fields: Record<InternalFieldName, Field['_f']> = {
|
|
68
|
+
username: {
|
|
69
|
+
ref: { name: 'username' },
|
|
70
|
+
name: 'username',
|
|
71
|
+
},
|
|
72
|
+
password: {
|
|
73
|
+
ref: { name: 'password' },
|
|
74
|
+
name: 'password',
|
|
75
|
+
},
|
|
76
|
+
email: {
|
|
77
|
+
ref: { name: 'email' },
|
|
78
|
+
name: 'email',
|
|
79
|
+
},
|
|
80
|
+
birthday: {
|
|
81
|
+
ref: { name: 'birthday' },
|
|
82
|
+
name: 'birthday',
|
|
83
|
+
},
|
|
84
|
+
};
|