@hookform/resolvers 4.1.3 → 5.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 +30 -0
- package/ajv/package.json +1 -1
- package/arktype/dist/arktype.d.ts +8 -20
- 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/package.json +1 -1
- package/arktype/src/__tests__/Form.tsx +0 -28
- package/arktype/src/__tests__/arktype.ts +56 -0
- package/arktype/src/arktype.ts +58 -22
- package/class-validator/src/__tests__/Form.tsx +0 -26
- package/computed-types/dist/computed-types.d.ts +2 -3
- 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/package.json +1 -1
- package/computed-types/src/__tests__/Form.tsx +0 -28
- package/computed-types/src/__tests__/computed-types.ts +55 -1
- package/computed-types/src/computed-types.ts +7 -5
- package/effect-ts/dist/effect-ts.d.ts +8 -16
- package/effect-ts/dist/effect-ts.js.map +1 -1
- package/effect-ts/dist/effect-ts.modern.mjs.map +1 -1
- package/effect-ts/dist/effect-ts.module.js.map +1 -1
- package/effect-ts/dist/effect-ts.umd.js.map +1 -1
- package/effect-ts/package.json +1 -1
- package/effect-ts/src/__tests__/effect-ts.ts +61 -0
- package/effect-ts/src/effect-ts.ts +21 -3
- package/fluentvalidation-ts/package.json +1 -1
- package/io-ts/dist/io-ts.d.ts +8 -17
- package/io-ts/dist/io-ts.js.map +1 -1
- package/io-ts/dist/io-ts.modern.mjs.map +1 -1
- package/io-ts/dist/io-ts.module.js.map +1 -1
- package/io-ts/dist/io-ts.umd.js.map +1 -1
- package/io-ts/package.json +1 -1
- package/io-ts/src/__tests__/__fixtures__/data.ts +3 -3
- package/io-ts/src/__tests__/io-ts.ts +54 -0
- package/io-ts/src/io-ts.ts +35 -8
- package/joi/package.json +1 -1
- package/nope/package.json +1 -1
- package/package.json +13 -13
- package/standard-schema/dist/standard-schema.d.ts +6 -23
- package/standard-schema/dist/standard-schema.js +1 -1
- package/standard-schema/dist/standard-schema.js.map +1 -1
- package/standard-schema/dist/standard-schema.mjs +1 -1
- package/standard-schema/dist/standard-schema.modern.mjs +1 -1
- package/standard-schema/dist/standard-schema.modern.mjs.map +1 -1
- package/standard-schema/dist/standard-schema.module.js +1 -1
- package/standard-schema/dist/standard-schema.module.js.map +1 -1
- package/standard-schema/dist/standard-schema.umd.js +1 -1
- package/standard-schema/dist/standard-schema.umd.js.map +1 -1
- package/standard-schema/package.json +1 -1
- package/standard-schema/src/__tests__/Form.tsx +0 -28
- package/standard-schema/src/__tests__/__fixtures__/data.ts +2 -2
- package/standard-schema/src/__tests__/standard-schema.ts +78 -1
- package/standard-schema/src/standard-schema.ts +32 -5
- package/superstruct/dist/superstruct.d.ts +6 -20
- 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/package.json +1 -1
- package/superstruct/src/__tests__/superstruct.ts +60 -0
- package/superstruct/src/superstruct.ts +20 -4
- package/typanion/dist/typanion.d.ts +8 -16
- 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/package.json +1 -1
- package/typanion/src/__tests__/Form.tsx +0 -32
- package/typanion/src/__tests__/typanion.ts +49 -0
- package/typanion/src/typanion.ts +22 -4
- package/typebox/dist/typebox.d.ts +3 -3
- package/typebox/dist/typebox.js.map +1 -1
- package/typebox/dist/typebox.modern.mjs.map +1 -1
- package/typebox/dist/typebox.module.js.map +1 -1
- package/typebox/dist/typebox.umd.js.map +1 -1
- package/typebox/package.json +1 -1
- package/typebox/src/__tests__/Form-native-validation-compiler.tsx +1 -1
- package/typebox/src/__tests__/Form.tsx +0 -28
- package/typebox/src/__tests__/__fixtures__/data.ts +3 -3
- package/typebox/src/__tests__/typebox.ts +98 -0
- package/typebox/src/typebox.ts +7 -14
- package/typeschema/dist/index.d.ts +0 -1
- package/typeschema/dist/typeschema.d.ts +8 -19
- package/typeschema/dist/typeschema.js +1 -1
- package/typeschema/dist/typeschema.js.map +1 -1
- package/typeschema/dist/typeschema.mjs +1 -1
- package/typeschema/dist/typeschema.modern.mjs +1 -1
- package/typeschema/dist/typeschema.modern.mjs.map +1 -1
- package/typeschema/dist/typeschema.module.js +1 -1
- package/typeschema/dist/typeschema.module.js.map +1 -1
- package/typeschema/dist/typeschema.umd.js +1 -1
- package/typeschema/dist/typeschema.umd.js.map +1 -1
- package/typeschema/package.json +1 -1
- package/typeschema/src/__tests__/Form.tsx +2 -4
- package/typeschema/src/__tests__/__fixtures__/data.ts +1 -1
- package/typeschema/src/__tests__/typeschema.ts +77 -0
- package/typeschema/src/index.ts +0 -1
- package/typeschema/src/typeschema.ts +52 -25
- package/valibot/dist/valibot.d.ts +9 -30
- package/valibot/dist/valibot.js.map +1 -1
- package/valibot/dist/valibot.modern.mjs.map +1 -1
- package/valibot/dist/valibot.module.js.map +1 -1
- package/valibot/dist/valibot.umd.js.map +1 -1
- package/valibot/package.json +1 -1
- package/valibot/src/__tests__/valibot.ts +69 -3
- package/valibot/src/valibot.ts +29 -13
- package/vest/package.json +1 -1
- package/vine/dist/vine.d.ts +10 -24
- package/vine/dist/vine.js.map +1 -1
- package/vine/dist/vine.modern.mjs.map +1 -1
- package/vine/dist/vine.module.js.map +1 -1
- package/vine/dist/vine.umd.js.map +1 -1
- package/vine/package.json +1 -1
- package/vine/src/__tests__/Form.tsx +0 -28
- package/vine/src/__tests__/__fixtures__/data.ts +4 -4
- package/vine/src/__tests__/vine.ts +69 -0
- package/vine/src/vine.ts +26 -4
- package/yup/dist/yup.d.ts +7 -21
- 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 +1 -1
- package/yup/dist/yup.modern.mjs.map +1 -1
- 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/package.json +1 -1
- package/yup/src/__tests__/yup.ts +66 -0
- package/yup/src/yup.ts +30 -8
- package/zod/dist/zod.d.ts +7 -22
- package/zod/dist/zod.js.map +1 -1
- package/zod/dist/zod.modern.mjs.map +1 -1
- package/zod/dist/zod.module.js.map +1 -1
- package/zod/dist/zod.umd.js.map +1 -1
- package/zod/package.json +1 -1
- package/zod/src/__tests__/Form.tsx +0 -28
- package/zod/src/__tests__/__fixtures__/data.ts +2 -2
- package/zod/src/__tests__/zod.ts +69 -0
- package/zod/src/zod.ts +29 -9
- package/typeschema/dist/types.d.ts +0 -9
- package/typeschema/src/types.ts +0 -18
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Resolver, SubmitHandler, useForm } from 'react-hook-form';
|
|
2
|
+
import { z } from 'zod';
|
|
1
3
|
import { standardSchemaResolver } from '..';
|
|
2
4
|
import {
|
|
3
5
|
customSchema,
|
|
@@ -49,7 +51,7 @@ describe('standardSchemaResolver', () => {
|
|
|
49
51
|
it('should return values from standardSchemaResolver when validation pass & raw=true', async () => {
|
|
50
52
|
const validateSpy = vi.spyOn(schema['~standard'], 'validate');
|
|
51
53
|
|
|
52
|
-
const result = await standardSchemaResolver(schema, {
|
|
54
|
+
const result = await standardSchemaResolver(schema, undefined, {
|
|
53
55
|
raw: true,
|
|
54
56
|
})(validData, undefined, {
|
|
55
57
|
fields,
|
|
@@ -71,4 +73,79 @@ describe('standardSchemaResolver', () => {
|
|
|
71
73
|
|
|
72
74
|
expect(result).toMatchSnapshot();
|
|
73
75
|
});
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Type inference tests
|
|
79
|
+
*/
|
|
80
|
+
it('should correctly infer the output type from a standardSchema schema', () => {
|
|
81
|
+
const resolver = standardSchemaResolver(z.object({ id: z.number() }));
|
|
82
|
+
|
|
83
|
+
expectTypeOf(resolver).toEqualTypeOf<
|
|
84
|
+
Resolver<{ id: number }, unknown, { id: number }>
|
|
85
|
+
>();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should correctly infer the output type from a standardSchema schema using a transform', () => {
|
|
89
|
+
const resolver = standardSchemaResolver(
|
|
90
|
+
z.object({ id: z.number().transform((val) => String(val)) }),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expectTypeOf(resolver).toEqualTypeOf<
|
|
94
|
+
Resolver<{ id: number }, unknown, { id: string }>
|
|
95
|
+
>();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should correctly infer the output type from a standardSchema schema when a different input type is specified', () => {
|
|
99
|
+
const schema = z.object({ id: z.number() }).transform(({ id }) => {
|
|
100
|
+
return { id: String(id) };
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const resolver = standardSchemaResolver<
|
|
104
|
+
{ id: number },
|
|
105
|
+
any,
|
|
106
|
+
z.output<typeof schema>
|
|
107
|
+
>(schema);
|
|
108
|
+
|
|
109
|
+
expectTypeOf(resolver).toEqualTypeOf<
|
|
110
|
+
Resolver<{ id: number }, any, { id: string }>
|
|
111
|
+
>();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should correctly infer the output type from a standardSchema schema for the handleSubmit function in useForm', () => {
|
|
115
|
+
const schema = z.object({ id: z.number() });
|
|
116
|
+
|
|
117
|
+
const form = useForm({
|
|
118
|
+
resolver: standardSchemaResolver(schema),
|
|
119
|
+
defaultValues: {
|
|
120
|
+
id: 3,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
125
|
+
|
|
126
|
+
expectTypeOf(form.handleSubmit).parameter(0).toEqualTypeOf<
|
|
127
|
+
SubmitHandler<{
|
|
128
|
+
id: number;
|
|
129
|
+
}>
|
|
130
|
+
>();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should correctly infer the output type from a standardSchema schema with a transform for the handleSubmit function in useForm', () => {
|
|
134
|
+
const schema = z.object({ id: z.number().transform((val) => String(val)) });
|
|
135
|
+
|
|
136
|
+
const form = useForm({
|
|
137
|
+
resolver: standardSchemaResolver(schema),
|
|
138
|
+
defaultValues: {
|
|
139
|
+
id: 3,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
144
|
+
|
|
145
|
+
expectTypeOf(form.handleSubmit).parameter(0).toEqualTypeOf<
|
|
146
|
+
SubmitHandler<{
|
|
147
|
+
id: string;
|
|
148
|
+
}>
|
|
149
|
+
>();
|
|
150
|
+
});
|
|
74
151
|
});
|
|
@@ -3,7 +3,7 @@ import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
|
3
3
|
import { getDotPath } from '@standard-schema/utils';
|
|
4
4
|
import { FieldError, FieldValues, Resolver } from 'react-hook-form';
|
|
5
5
|
|
|
6
|
-
function
|
|
6
|
+
function parseErrorSchema(
|
|
7
7
|
issues: readonly StandardSchemaV1.Issue[],
|
|
8
8
|
validateAllFieldCriteria: boolean,
|
|
9
9
|
) {
|
|
@@ -32,6 +32,30 @@ function parseIssues(
|
|
|
32
32
|
return errors;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
export function standardSchemaResolver<
|
|
36
|
+
Input extends FieldValues,
|
|
37
|
+
Context,
|
|
38
|
+
Output,
|
|
39
|
+
>(
|
|
40
|
+
schema: StandardSchemaV1<Input, Output>,
|
|
41
|
+
_schemaOptions?: never,
|
|
42
|
+
resolverOptions?: {
|
|
43
|
+
raw?: false;
|
|
44
|
+
},
|
|
45
|
+
): Resolver<Input, Context, Output>;
|
|
46
|
+
|
|
47
|
+
export function standardSchemaResolver<
|
|
48
|
+
Input extends FieldValues,
|
|
49
|
+
Context,
|
|
50
|
+
Output,
|
|
51
|
+
>(
|
|
52
|
+
schema: StandardSchemaV1<Input, Output>,
|
|
53
|
+
_schemaOptions: never | undefined,
|
|
54
|
+
resolverOptions: {
|
|
55
|
+
raw: true;
|
|
56
|
+
},
|
|
57
|
+
): Resolver<Input, Context, Input>;
|
|
58
|
+
|
|
35
59
|
/**
|
|
36
60
|
* Creates a resolver for react-hook-form that validates data using a Standard Schema.
|
|
37
61
|
*
|
|
@@ -53,13 +77,16 @@ function parseIssues(
|
|
|
53
77
|
* ```
|
|
54
78
|
*/
|
|
55
79
|
export function standardSchemaResolver<
|
|
56
|
-
|
|
80
|
+
Input extends FieldValues,
|
|
81
|
+
Context,
|
|
82
|
+
Output,
|
|
57
83
|
>(
|
|
58
|
-
schema:
|
|
84
|
+
schema: StandardSchemaV1<Input, Output>,
|
|
85
|
+
_schemaOptions?: never,
|
|
59
86
|
resolverOptions: {
|
|
60
87
|
raw?: boolean;
|
|
61
88
|
} = {},
|
|
62
|
-
): Resolver<
|
|
89
|
+
): Resolver<Input, Context, Output | Input> {
|
|
63
90
|
return async (values, _, options) => {
|
|
64
91
|
let result = schema['~standard'].validate(values);
|
|
65
92
|
if (result instanceof Promise) {
|
|
@@ -67,7 +94,7 @@ export function standardSchemaResolver<
|
|
|
67
94
|
}
|
|
68
95
|
|
|
69
96
|
if (result.issues) {
|
|
70
|
-
const errors =
|
|
97
|
+
const errors = parseErrorSchema(
|
|
71
98
|
result.issues,
|
|
72
99
|
!options.shouldUseNativeValidation && options.criteriaMode === 'all',
|
|
73
100
|
);
|
|
@@ -1,22 +1,8 @@
|
|
|
1
1
|
import { FieldValues, Resolver } from 'react-hook-form';
|
|
2
2
|
import { Infer, Struct, validate } from 'superstruct';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form
|
|
10
|
-
* @example
|
|
11
|
-
* const schema = struct({
|
|
12
|
-
* name: string(),
|
|
13
|
-
* age: number()
|
|
14
|
-
* });
|
|
15
|
-
*
|
|
16
|
-
* useForm({
|
|
17
|
-
* resolver: superstructResolver(schema)
|
|
18
|
-
* });
|
|
19
|
-
*/
|
|
20
|
-
export declare function superstructResolver<TFieldValues extends FieldValues>(schema: Struct<TFieldValues, any>, schemaOptions?: Parameters<typeof validate>[2], resolverOptions?: {
|
|
21
|
-
raw?: boolean;
|
|
22
|
-
}): Resolver<Infer<typeof schema>>;
|
|
3
|
+
export declare function superstructResolver<Input extends FieldValues, Context, Output>(schema: Struct<Input, any>, schemaOptions?: Parameters<typeof validate>[2], resolverOptions?: {
|
|
4
|
+
raw?: false;
|
|
5
|
+
}): Resolver<Input, Context, Infer<typeof schema>>;
|
|
6
|
+
export declare function superstructResolver<Input extends FieldValues, Context, Output>(schema: Struct<Input, any>, schemaOptions: Parameters<typeof validate>[2] | undefined, resolverOptions: {
|
|
7
|
+
raw: true;
|
|
8
|
+
}): Resolver<Input, Context, Input>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"superstruct.js","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<
|
|
1
|
+
{"version":3,"file":"superstruct.js","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions?: {\n raw?: false;\n },\n): Resolver<Input, Context, Infer<typeof schema>>;\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions: Parameters<typeof validate>[2] | undefined,\n resolverOptions: {\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions: {\n raw?: boolean;\n } = {},\n): Resolver<Input, Context, Input | Output> {\n return (values: Input, _, options) => {\n const result = validate(values, schema, schemaOptions);\n\n if (result[0]) {\n return {\n values: {},\n errors: toNestErrors(parseErrorSchema(result[0]), options),\n };\n }\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n values: resolverOptions.raw ? Object.assign({}, values) : result[1],\n errors: {},\n };\n };\n}\n"],"names":["schema","schemaOptions","resolverOptions","values","_","options","error","result","validate","errors","toNestErrors","failures","reduce","previous","path","join","message","type","shouldUseNativeValidation","validateFieldsNatively","raw","Object","assign"],"mappings":"mGAiDEA,EACAC,EACAC,GAIA,gBAJAA,IAAAA,EAEI,CAAE,GAEEC,SAAAA,EAAeC,EAAGC,GACxB,IApDsBC,EAoDhBC,EAASC,EAAAA,SAASL,EAAQH,EAAQC,GAExC,OAAIM,EAAO,GACF,CACLJ,OAAQ,CAAA,EACRM,OAAQC,EAAYA,cAzDFJ,EAyDoBC,EAAO,GAxD5CD,EAAMK,WAAWC,OACtB,SAACC,EAAUP,GACT,OAACO,EAASP,EAAMQ,KAAKC,KAAK,MAAQ,CAChCC,QAASV,EAAMU,QACfC,KAAMX,EAAMW,QACRJ,CAAQ,EAChB,CAAA,IAkDsDR,KAItDA,EAAQa,2BAA6BC,yBAAuB,CAAA,EAAId,GAEzD,CACLF,OAAQD,EAAgBkB,IAAMC,OAAOC,OAAO,CAAE,EAAEnB,GAAUI,EAAO,GACjEE,OAAQ,CAAA,GAEZ,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"superstruct.modern.mjs","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<
|
|
1
|
+
{"version":3,"file":"superstruct.modern.mjs","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions?: {\n raw?: false;\n },\n): Resolver<Input, Context, Infer<typeof schema>>;\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions: Parameters<typeof validate>[2] | undefined,\n resolverOptions: {\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions: {\n raw?: boolean;\n } = {},\n): Resolver<Input, Context, Input | Output> {\n return (values: Input, _, options) => {\n const result = validate(values, schema, schemaOptions);\n\n if (result[0]) {\n return {\n values: {},\n errors: toNestErrors(parseErrorSchema(result[0]), options),\n };\n }\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n values: resolverOptions.raw ? Object.assign({}, values) : result[1],\n errors: {},\n };\n };\n}\n"],"names":["superstructResolver","schema","schemaOptions","resolverOptions","values","_","options","result","validate","errors","toNestErrors","error","failures","reduce","previous","path","join","message","type","shouldUseNativeValidation","validateFieldsNatively","raw","Object","assign"],"mappings":"sHAgDgB,SAAAA,EACdC,EACAC,EACAC,EAEI,CAAE,GAEN,MAAO,CAACC,EAAeC,EAAGC,KACxB,MAAMC,EAASC,EAASJ,EAAQH,EAAQC,GAExC,OAAIK,EAAO,GACF,CACLH,OAAQ,CAAA,EACRK,OAAQC,GAzDUC,EAyDoBJ,EAAO,GAxD5CI,EAAMC,WAAWC,OACtB,CAACC,EAAUH,KACRG,EAASH,EAAMI,KAAKC,KAAK,MAAQ,CAChCC,QAASN,EAAMM,QACfC,KAAMP,EAAMO,QACRJ,EACR,KAkDsDR,KAItDA,EAAQa,2BAA6BC,EAAuB,GAAId,GAEzD,CACLF,OAAQD,EAAgBkB,IAAMC,OAAOC,OAAO,CAAA,EAAInB,GAAUG,EAAO,GACjEE,OAAQ,CAAA,IAjEd,IAA0BE,EAoE1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"superstruct.module.js","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<
|
|
1
|
+
{"version":3,"file":"superstruct.module.js","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions?: {\n raw?: false;\n },\n): Resolver<Input, Context, Infer<typeof schema>>;\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions: Parameters<typeof validate>[2] | undefined,\n resolverOptions: {\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions: {\n raw?: boolean;\n } = {},\n): Resolver<Input, Context, Input | Output> {\n return (values: Input, _, options) => {\n const result = validate(values, schema, schemaOptions);\n\n if (result[0]) {\n return {\n values: {},\n errors: toNestErrors(parseErrorSchema(result[0]), options),\n };\n }\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n values: resolverOptions.raw ? Object.assign({}, values) : result[1],\n errors: {},\n };\n };\n}\n"],"names":["superstructResolver","schema","schemaOptions","resolverOptions","values","_","options","error","result","validate","errors","toNestErrors","failures","reduce","previous","path","join","message","type","shouldUseNativeValidation","validateFieldsNatively","raw","Object","assign"],"mappings":"+HAgDgBA,EACdC,EACAC,EACAC,GAIA,gBAJAA,IAAAA,EAEI,CAAE,GAEEC,SAAAA,EAAeC,EAAGC,GACxB,IApDsBC,EAoDhBC,EAASC,EAASL,EAAQH,EAAQC,GAExC,OAAIM,EAAO,GACF,CACLJ,OAAQ,CAAA,EACRM,OAAQC,GAzDUJ,EAyDoBC,EAAO,GAxD5CD,EAAMK,WAAWC,OACtB,SAACC,EAAUP,GACT,OAACO,EAASP,EAAMQ,KAAKC,KAAK,MAAQ,CAChCC,QAASV,EAAMU,QACfC,KAAMX,EAAMW,QACRJ,CAAQ,EAChB,CAAA,IAkDsDR,KAItDA,EAAQa,2BAA6BC,EAAuB,CAAA,EAAId,GAEzD,CACLF,OAAQD,EAAgBkB,IAAMC,OAAOC,OAAO,CAAE,EAAEnB,GAAUI,EAAO,GACjEE,OAAQ,CAAA,GAEZ,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"superstruct.umd.js","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<
|
|
1
|
+
{"version":3,"file":"superstruct.umd.js","sources":["../src/superstruct.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport { FieldError, FieldValues, Resolver } from 'react-hook-form';\nimport { Infer, Struct, StructError, validate } from 'superstruct';\n\nfunction parseErrorSchema(error: StructError) {\n return error.failures().reduce<Record<string, FieldError>>(\n (previous, error) =>\n (previous[error.path.join('.')] = {\n message: error.message,\n type: error.type,\n }) && previous,\n {},\n );\n}\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions?: {\n raw?: false;\n },\n): Resolver<Input, Context, Infer<typeof schema>>;\n\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions: Parameters<typeof validate>[2] | undefined,\n resolverOptions: {\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Superstruct schema validation\n * @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against\n * @param {Parameters<typeof validate>[2]} [schemaOptions] - Optional Superstruct validation options\n * @param {Object} resolverOptions - Additional resolver configuration\n * @param {boolean} [resolverOptions.raw=false] - If true, returns raw values rather than validated results\n * @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = struct({\n * name: string(),\n * age: number()\n * });\n *\n * useForm({\n * resolver: superstructResolver(schema)\n * });\n */\nexport function superstructResolver<Input extends FieldValues, Context, Output>(\n schema: Struct<Input, any>,\n schemaOptions?: Parameters<typeof validate>[2],\n resolverOptions: {\n raw?: boolean;\n } = {},\n): Resolver<Input, Context, Input | Output> {\n return (values: Input, _, options) => {\n const result = validate(values, schema, schemaOptions);\n\n if (result[0]) {\n return {\n values: {},\n errors: toNestErrors(parseErrorSchema(result[0]), options),\n };\n }\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n values: resolverOptions.raw ? Object.assign({}, values) : result[1],\n errors: {},\n };\n };\n}\n"],"names":["schema","schemaOptions","resolverOptions","values","_","options","error","result","validate","errors","toNestErrors","failures","reduce","previous","path","join","message","type","shouldUseNativeValidation","validateFieldsNatively","raw","Object","assign"],"mappings":"qZAiDEA,EACAC,EACAC,GAIA,gBAJAA,IAAAA,EAEI,CAAE,GAEEC,SAAAA,EAAeC,EAAGC,GACxB,IApDsBC,EAoDhBC,EAASC,EAAAA,SAASL,EAAQH,EAAQC,GAExC,OAAIM,EAAO,GACF,CACLJ,OAAQ,CAAA,EACRM,OAAQC,EAAYA,cAzDFJ,EAyDoBC,EAAO,GAxD5CD,EAAMK,WAAWC,OACtB,SAACC,EAAUP,GACT,OAACO,EAASP,EAAMQ,KAAKC,KAAK,MAAQ,CAChCC,QAASV,EAAMU,QACfC,KAAMX,EAAMW,QACRJ,CAAQ,EAChB,CAAA,IAkDsDR,KAItDA,EAAQa,2BAA6BC,yBAAuB,CAAA,EAAId,GAEzD,CACLF,OAAQD,EAAgBkB,IAAMC,OAAOC,OAAO,CAAE,EAAEnB,GAAUI,EAAO,GACjEE,OAAQ,CAAA,GAEZ,CACF"}
|
package/superstruct/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Resolver, SubmitHandler, useForm } from 'react-hook-form';
|
|
2
|
+
import * as s from 'superstruct';
|
|
1
3
|
import { superstructResolver } from '..';
|
|
2
4
|
import { fields, invalidData, schema, validData } from './__fixtures__/data';
|
|
3
5
|
|
|
@@ -13,6 +15,19 @@ describe('superstructResolver', () => {
|
|
|
13
15
|
expect(result).toEqual({ errors: {}, values: validData });
|
|
14
16
|
});
|
|
15
17
|
|
|
18
|
+
it('should return values from superstructResolver with coerced values', async () => {
|
|
19
|
+
const result = await superstructResolver(
|
|
20
|
+
s.object({
|
|
21
|
+
id: s.coerce(s.number(), s.string(), (val) => String(val)),
|
|
22
|
+
}),
|
|
23
|
+
)({ id: 1 }, undefined, {
|
|
24
|
+
fields,
|
|
25
|
+
shouldUseNativeValidation,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(result).toEqual({ errors: {}, values: { id: '1' } });
|
|
29
|
+
});
|
|
30
|
+
|
|
16
31
|
it('should return a single error from superstructResolver when validation fails', async () => {
|
|
17
32
|
const result = await superstructResolver(schema)(invalidData, undefined, {
|
|
18
33
|
fields,
|
|
@@ -34,4 +49,49 @@ describe('superstructResolver', () => {
|
|
|
34
49
|
|
|
35
50
|
expect(result).toEqual({ errors: {}, values: validData });
|
|
36
51
|
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Type inference tests
|
|
55
|
+
*/
|
|
56
|
+
it('should correctly infer the output type from a superstruct schema', () => {
|
|
57
|
+
const resolver = superstructResolver(s.object({ id: s.number() }));
|
|
58
|
+
|
|
59
|
+
expectTypeOf(resolver).toEqualTypeOf<
|
|
60
|
+
Resolver<{ id: number }, unknown, { id: number }>
|
|
61
|
+
>();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should correctly infer the output type from a superstruct schema for the handleSubmit function in useForm', () => {
|
|
65
|
+
const schema = s.object({ id: s.number() });
|
|
66
|
+
|
|
67
|
+
const form = useForm({
|
|
68
|
+
resolver: superstructResolver(schema),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
72
|
+
|
|
73
|
+
expectTypeOf(form.handleSubmit).parameter(0).toEqualTypeOf<
|
|
74
|
+
SubmitHandler<{
|
|
75
|
+
id: number;
|
|
76
|
+
}>
|
|
77
|
+
>();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should correctly infer the output type from a superstruct schema with a transform for the handleSubmit function in useForm', () => {
|
|
81
|
+
const schema = s.object({
|
|
82
|
+
id: s.coerce(s.string(), s.number(), (val) => String(val)),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const form = useForm({
|
|
86
|
+
resolver: superstructResolver(schema),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expectTypeOf(form.watch('id')).toEqualTypeOf<string>();
|
|
90
|
+
|
|
91
|
+
expectTypeOf(form.handleSubmit).parameter(0).toEqualTypeOf<
|
|
92
|
+
SubmitHandler<{
|
|
93
|
+
id: string;
|
|
94
|
+
}>
|
|
95
|
+
>();
|
|
96
|
+
});
|
|
37
97
|
});
|
|
@@ -13,6 +13,22 @@ function parseErrorSchema(error: StructError) {
|
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export function superstructResolver<Input extends FieldValues, Context, Output>(
|
|
17
|
+
schema: Struct<Input, any>,
|
|
18
|
+
schemaOptions?: Parameters<typeof validate>[2],
|
|
19
|
+
resolverOptions?: {
|
|
20
|
+
raw?: false;
|
|
21
|
+
},
|
|
22
|
+
): Resolver<Input, Context, Infer<typeof schema>>;
|
|
23
|
+
|
|
24
|
+
export function superstructResolver<Input extends FieldValues, Context, Output>(
|
|
25
|
+
schema: Struct<Input, any>,
|
|
26
|
+
schemaOptions: Parameters<typeof validate>[2] | undefined,
|
|
27
|
+
resolverOptions: {
|
|
28
|
+
raw: true;
|
|
29
|
+
},
|
|
30
|
+
): Resolver<Input, Context, Input>;
|
|
31
|
+
|
|
16
32
|
/**
|
|
17
33
|
* Creates a resolver for react-hook-form using Superstruct schema validation
|
|
18
34
|
* @param {Struct<TFieldValues, any>} schema - The Superstruct schema to validate against
|
|
@@ -30,14 +46,14 @@ function parseErrorSchema(error: StructError) {
|
|
|
30
46
|
* resolver: superstructResolver(schema)
|
|
31
47
|
* });
|
|
32
48
|
*/
|
|
33
|
-
export function superstructResolver<
|
|
34
|
-
schema: Struct<
|
|
49
|
+
export function superstructResolver<Input extends FieldValues, Context, Output>(
|
|
50
|
+
schema: Struct<Input, any>,
|
|
35
51
|
schemaOptions?: Parameters<typeof validate>[2],
|
|
36
52
|
resolverOptions: {
|
|
37
53
|
raw?: boolean;
|
|
38
54
|
} = {},
|
|
39
|
-
): Resolver<
|
|
40
|
-
return (values, _, options) => {
|
|
55
|
+
): Resolver<Input, Context, Input | Output> {
|
|
56
|
+
return (values: Input, _, options) => {
|
|
41
57
|
const result = validate(values, schema, schemaOptions);
|
|
42
58
|
|
|
43
59
|
if (result[0]) {
|
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
import type { FieldValues, Resolver } from 'react-hook-form';
|
|
2
2
|
import * as t from 'typanion';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* age: t.isInteger()
|
|
12
|
-
* });
|
|
13
|
-
*
|
|
14
|
-
* useForm({
|
|
15
|
-
* resolver: typanionResolver(schema)
|
|
16
|
-
* });
|
|
17
|
-
*/
|
|
18
|
-
export declare function typanionResolver<TFieldValues extends FieldValues>(schema: t.StrictValidator<TFieldValues, TFieldValues>, schemaOptions?: Pick<t.ValidationState, 'coercions' | 'coercion'>): Resolver<t.InferType<typeof schema>>;
|
|
3
|
+
export declare function typanionResolver<Input extends FieldValues, Context, Output>(schema: t.StrictValidator<Input, Input>, schemaOptions?: Pick<t.ValidationState, 'coercions' | 'coercion'>, resolverOptions?: {
|
|
4
|
+
mode?: 'async' | 'sync';
|
|
5
|
+
raw?: false;
|
|
6
|
+
}): Resolver<Input, Context, t.InferType<typeof schema>>;
|
|
7
|
+
export declare function typanionResolver<Input extends FieldValues, Context, Output>(schema: t.StrictValidator<Input, Input>, schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> | undefined, resolverOptions: {
|
|
8
|
+
mode?: 'async' | 'sync';
|
|
9
|
+
raw: true;
|
|
10
|
+
}): Resolver<Input, Context, Input>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typanion.js","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<
|
|
1
|
+
{"version":3,"file":"typanion.js","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions?: Pick<t.ValidationState, 'coercions' | 'coercion'>,\n resolverOptions?: {\n mode?: 'async' | 'sync';\n raw?: false;\n },\n): Resolver<Input, Context, t.InferType<typeof schema>>;\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> | undefined,\n resolverOptions: {\n mode?: 'async' | 'sync';\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> = {},\n): Resolver<Input, Context, Output | Input> {\n return (values: Input, _, options) => {\n const rawErrors: string[] = [];\n const isValid = schema(\n values,\n Object.assign(\n {},\n {\n errors: rawErrors,\n },\n schemaOptions,\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: toNestErrors(parsedErrors, options) };\n };\n}\n"],"names":["schema","schemaOptions","values","_","options","rawErrors","isValid","Object","assign","errors","parsedErrors","reduce","acc","error","fieldIndex","indexOf","field","slice","message","trim","parseErrors","shouldUseNativeValidation","validateFieldsNatively","toNestErrors"],"mappings":"8DAyDgB,SACdA,EACAC,GAEA,YAFAA,IAAAA,IAAAA,EAAmE,CAAE,GAE7DC,SAAAA,EAAeC,EAAGC,GACxB,IAAMC,EAAsB,GACtBC,EAAUN,EACdE,EACAK,OAAOC,OACL,CAAE,EACF,CACEC,OAAQJ,GAEVJ,IAGES,EAhEV,SAAqBD,EAAkBC,GACrC,gBADqCA,IAAAA,EAA4B,IAC1DD,EAAOE,OAAO,SAACC,EAAKC,GACzB,IAAMC,EAAaD,EAAME,QAAQ,KAE3BC,EAAQH,EAAMI,MAAM,EAAGH,GACvBI,EAAUL,EAAMI,MAAMH,EAAa,GAAGK,OAM5C,OAJAP,EAAII,GAAS,CACXE,QAAAA,GAGKN,CACT,EAAGF,EACL,CAmDyBU,CAAYf,GAEjC,OAAIC,GACFF,EAAQiB,2BACNC,EAAAA,uBAAuBZ,EAAcN,GAEhC,CAAEF,OAAAA,EAAQO,OAAQ,CAAA,IAGpB,CAAEP,OAAQ,GAAIO,OAAQc,EAAYA,aAACb,EAAcN,GAC1D,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typanion.modern.mjs","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<
|
|
1
|
+
{"version":3,"file":"typanion.modern.mjs","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions?: Pick<t.ValidationState, 'coercions' | 'coercion'>,\n resolverOptions?: {\n mode?: 'async' | 'sync';\n raw?: false;\n },\n): Resolver<Input, Context, t.InferType<typeof schema>>;\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> | undefined,\n resolverOptions: {\n mode?: 'async' | 'sync';\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> = {},\n): Resolver<Input, Context, Output | Input> {\n return (values: Input, _, options) => {\n const rawErrors: string[] = [];\n const isValid = schema(\n values,\n Object.assign(\n {},\n {\n errors: rawErrors,\n },\n schemaOptions,\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: toNestErrors(parsedErrors, options) };\n };\n}\n"],"names":["typanionResolver","schema","schemaOptions","values","_","options","rawErrors","isValid","Object","assign","errors","parsedErrors","reduce","acc","error","fieldIndex","indexOf","field","slice","message","trim","parseErrors","shouldUseNativeValidation","validateFieldsNatively","toNestErrors"],"mappings":"+EAyDgB,SAAAA,EACdC,EACAC,EAAmE,IAEnE,MAAO,CAACC,EAAeC,EAAGC,KACxB,MAAMC,EAAsB,GACtBC,EAAUN,EACdE,EACAK,OAAOC,OACL,CAAA,EACA,CACEC,OAAQJ,GAEVJ,IAGES,EAhEV,SAAqBD,EAAkBC,EAA4B,CAAE,GACnE,OAAOD,EAAOE,OAAO,CAACC,EAAKC,KACzB,MAAMC,EAAaD,EAAME,QAAQ,KAE3BC,EAAQH,EAAMI,MAAM,EAAGH,GACvBI,EAAUL,EAAMI,MAAMH,EAAa,GAAGK,OAM5C,OAJAP,EAAII,GAAS,CACXE,WAGKN,GACNF,EACL,CAmDyBU,CAAYf,GAEjC,OAAIC,GACFF,EAAQiB,2BACNC,EAAuBZ,EAAcN,GAEhC,CAAEF,SAAQO,OAAQ,KAGpB,CAAEP,OAAQ,CAAE,EAAEO,OAAQc,EAAab,EAAcN,IAE5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typanion.module.js","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<
|
|
1
|
+
{"version":3,"file":"typanion.module.js","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions?: Pick<t.ValidationState, 'coercions' | 'coercion'>,\n resolverOptions?: {\n mode?: 'async' | 'sync';\n raw?: false;\n },\n): Resolver<Input, Context, t.InferType<typeof schema>>;\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> | undefined,\n resolverOptions: {\n mode?: 'async' | 'sync';\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> = {},\n): Resolver<Input, Context, Output | Input> {\n return (values: Input, _, options) => {\n const rawErrors: string[] = [];\n const isValid = schema(\n values,\n Object.assign(\n {},\n {\n errors: rawErrors,\n },\n schemaOptions,\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: toNestErrors(parsedErrors, options) };\n };\n}\n"],"names":["typanionResolver","schema","schemaOptions","values","_","options","rawErrors","isValid","Object","assign","errors","parsedErrors","reduce","acc","error","fieldIndex","indexOf","field","slice","message","trim","parseErrors","shouldUseNativeValidation","validateFieldsNatively","toNestErrors"],"mappings":"+EAyDgB,SAAAA,EACdC,EACAC,GAEA,YAFAA,IAAAA,IAAAA,EAAmE,CAAE,GAE7DC,SAAAA,EAAeC,EAAGC,GACxB,IAAMC,EAAsB,GACtBC,EAAUN,EACdE,EACAK,OAAOC,OACL,CAAE,EACF,CACEC,OAAQJ,GAEVJ,IAGES,EAhEV,SAAqBD,EAAkBC,GACrC,gBADqCA,IAAAA,EAA4B,IAC1DD,EAAOE,OAAO,SAACC,EAAKC,GACzB,IAAMC,EAAaD,EAAME,QAAQ,KAE3BC,EAAQH,EAAMI,MAAM,EAAGH,GACvBI,EAAUL,EAAMI,MAAMH,EAAa,GAAGK,OAM5C,OAJAP,EAAII,GAAS,CACXE,QAAAA,GAGKN,CACT,EAAGF,EACL,CAmDyBU,CAAYf,GAEjC,OAAIC,GACFF,EAAQiB,2BACNC,EAAuBZ,EAAcN,GAEhC,CAAEF,OAAAA,EAAQO,OAAQ,CAAA,IAGpB,CAAEP,OAAQ,GAAIO,OAAQc,EAAab,EAAcN,GAC1D,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typanion.umd.js","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<
|
|
1
|
+
{"version":3,"file":"typanion.umd.js","sources":["../src/typanion.ts"],"sourcesContent":["import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';\nimport type {\n FieldError,\n FieldErrors,\n FieldValues,\n Resolver,\n} from 'react-hook-form';\nimport * as t from 'typanion';\n\nfunction parseErrors(errors: string[], parsedErrors: FieldErrors = {}) {\n return errors.reduce((acc, error) => {\n const fieldIndex = error.indexOf(':');\n\n const field = error.slice(1, fieldIndex);\n const message = error.slice(fieldIndex + 1).trim();\n\n acc[field] = {\n message,\n } as FieldError;\n\n return acc;\n }, parsedErrors);\n}\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions?: Pick<t.ValidationState, 'coercions' | 'coercion'>,\n resolverOptions?: {\n mode?: 'async' | 'sync';\n raw?: false;\n },\n): Resolver<Input, Context, t.InferType<typeof schema>>;\n\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> | undefined,\n resolverOptions: {\n mode?: 'async' | 'sync';\n raw: true;\n },\n): Resolver<Input, Context, Input>;\n\n/**\n * Creates a resolver for react-hook-form using Typanion schema validation\n * @param {t.StrictValidator<TFieldValues, TFieldValues>} schema - The Typanion schema to validate against\n * @param {Pick<t.ValidationState, 'coercions' | 'coercion'>} [schemaOptions] - Optional Typanion validation options\n * @returns {Resolver<t.InferType<typeof schema>>} A resolver function compatible with react-hook-form\n * @example\n * const schema = t.isObject({\n * name: t.isString(),\n * age: t.isInteger()\n * });\n *\n * useForm({\n * resolver: typanionResolver(schema)\n * });\n */\nexport function typanionResolver<Input extends FieldValues, Context, Output>(\n schema: t.StrictValidator<Input, Input>,\n schemaOptions: Pick<t.ValidationState, 'coercions' | 'coercion'> = {},\n): Resolver<Input, Context, Output | Input> {\n return (values: Input, _, options) => {\n const rawErrors: string[] = [];\n const isValid = schema(\n values,\n Object.assign(\n {},\n {\n errors: rawErrors,\n },\n schemaOptions,\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: toNestErrors(parsedErrors, options) };\n };\n}\n"],"names":["schema","schemaOptions","values","_","options","rawErrors","isValid","Object","assign","errors","parsedErrors","reduce","acc","error","fieldIndex","indexOf","field","slice","message","trim","parseErrors","shouldUseNativeValidation","validateFieldsNatively","toNestErrors"],"mappings":"iVAyDgB,SACdA,EACAC,GAEA,YAFAA,IAAAA,IAAAA,EAAmE,CAAE,GAE7DC,SAAAA,EAAeC,EAAGC,GACxB,IAAMC,EAAsB,GACtBC,EAAUN,EACdE,EACAK,OAAOC,OACL,CAAE,EACF,CACEC,OAAQJ,GAEVJ,IAGES,EAhEV,SAAqBD,EAAkBC,GACrC,gBADqCA,IAAAA,EAA4B,IAC1DD,EAAOE,OAAO,SAACC,EAAKC,GACzB,IAAMC,EAAaD,EAAME,QAAQ,KAE3BC,EAAQH,EAAMI,MAAM,EAAGH,GACvBI,EAAUL,EAAMI,MAAMH,EAAa,GAAGK,OAM5C,OAJAP,EAAII,GAAS,CACXE,QAAAA,GAGKN,CACT,EAAGF,EACL,CAmDyBU,CAAYf,GAEjC,OAAIC,GACFF,EAAQiB,2BACNC,EAAAA,uBAAuBZ,EAAcN,GAEhC,CAAEF,OAAAA,EAAQO,OAAQ,CAAA,IAGpB,CAAEP,OAAQ,GAAIO,OAAQc,EAAYA,aAACb,EAAcN,GAC1D,CACF"}
|
package/typanion/package.json
CHANGED
|
@@ -10,12 +10,6 @@ const schema = t.isObject({
|
|
|
10
10
|
password: t.cascade(t.isString(), [t.hasMinLength(1)]),
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
interface FormData {
|
|
14
|
-
unusedProperty: string;
|
|
15
|
-
username: string;
|
|
16
|
-
password: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
13
|
function TestComponent({
|
|
20
14
|
onSubmit,
|
|
21
15
|
}: { onSubmit: (data: t.InferType<typeof schema>) => void }) {
|
|
@@ -55,29 +49,3 @@ test("form's validation with Typanion and TypeScript's integration", async () =>
|
|
|
55
49
|
).toHaveLength(2);
|
|
56
50
|
expect(handleSubmit).not.toHaveBeenCalled();
|
|
57
51
|
});
|
|
58
|
-
|
|
59
|
-
export function TestComponentManualType({
|
|
60
|
-
onSubmit,
|
|
61
|
-
}: {
|
|
62
|
-
onSubmit: (data: FormData) => void;
|
|
63
|
-
}) {
|
|
64
|
-
const {
|
|
65
|
-
register,
|
|
66
|
-
handleSubmit,
|
|
67
|
-
formState: { errors },
|
|
68
|
-
} = useForm<t.InferType<typeof schema>, undefined, FormData>({
|
|
69
|
-
resolver: typanionResolver(schema), // Useful to check TypeScript regressions
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<form onSubmit={handleSubmit(onSubmit)}>
|
|
74
|
-
<input {...register('username')} />
|
|
75
|
-
{errors.username && <span role="alert">{errors.username.message}</span>}
|
|
76
|
-
|
|
77
|
-
<input {...register('password')} />
|
|
78
|
-
{errors.password && <span role="alert">{errors.password.message}</span>}
|
|
79
|
-
|
|
80
|
-
<button type="submit">submit</button>
|
|
81
|
-
</form>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { SubmitHandler } from 'react-hook-form';
|
|
2
|
+
import { useForm } from 'react-hook-form';
|
|
3
|
+
import { Resolver } from 'react-hook-form';
|
|
4
|
+
import * as t from 'typanion';
|
|
1
5
|
import { typanionResolver } from '..';
|
|
2
6
|
import { fields, invalidData, schema, validData } from './__fixtures__/data';
|
|
3
7
|
|
|
@@ -32,4 +36,49 @@ describe('typanionResolver', () => {
|
|
|
32
36
|
|
|
33
37
|
expect(result).toMatchSnapshot();
|
|
34
38
|
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Type inference tests
|
|
42
|
+
*/
|
|
43
|
+
it('should correctly infer the output type from a typanion schema', () => {
|
|
44
|
+
const resolver = typanionResolver(t.isObject({ id: t.isNumber() }));
|
|
45
|
+
|
|
46
|
+
expectTypeOf(resolver).toEqualTypeOf<
|
|
47
|
+
Resolver<ObjectType<{ id: number }>, unknown, ObjectType<{ id: number }>>
|
|
48
|
+
>();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should correctly infer the output type from a typanion schema for the handleSubmit function in useForm', () => {
|
|
52
|
+
const schema = t.isObject({ id: t.isNumber() });
|
|
53
|
+
|
|
54
|
+
const form = useForm({
|
|
55
|
+
resolver: typanionResolver(schema),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
59
|
+
|
|
60
|
+
expectTypeOf(form.handleSubmit)
|
|
61
|
+
.parameter(0)
|
|
62
|
+
.toEqualTypeOf<SubmitHandler<ObjectType<{ id: number }>>>();
|
|
63
|
+
});
|
|
35
64
|
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Copied from Typanion source code because it's not exported
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
declare type ExtractIndex<T> = {
|
|
71
|
+
// biome-ignore lint/complexity/noBannedTypes: for testing purposes
|
|
72
|
+
[K in keyof T as {} extends Record<K, 1> ? K : never]: T[K];
|
|
73
|
+
};
|
|
74
|
+
declare type RemoveIndex<T> = {
|
|
75
|
+
// biome-ignore lint/complexity/noBannedTypes: for testing purposes
|
|
76
|
+
[K in keyof T as {} extends Record<K, 1> ? never : K]: T[K];
|
|
77
|
+
};
|
|
78
|
+
declare type UndefinedProperties<T> = {
|
|
79
|
+
[P in keyof T]-?: undefined extends T[P] ? P : never;
|
|
80
|
+
}[keyof T];
|
|
81
|
+
declare type UndefinedToOptional<T> = Partial<Pick<T, UndefinedProperties<T>>> &
|
|
82
|
+
Pick<T, Exclude<keyof T, UndefinedProperties<T>>>;
|
|
83
|
+
declare type ObjectType<T> = UndefinedToOptional<RemoveIndex<T>> &
|
|
84
|
+
ExtractIndex<T>;
|