@hookform/resolvers 2.0.0-rc.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +115 -18
- package/dist/index.d.ts +1 -0
- package/dist/resolvers.js +2 -0
- package/dist/resolvers.js.map +1 -0
- package/dist/resolvers.mjs +2 -0
- package/dist/resolvers.modern.js +2 -0
- package/dist/resolvers.modern.js.map +1 -0
- package/dist/resolvers.module.js +2 -0
- package/dist/resolvers.module.js.map +1 -0
- package/dist/resolvers.umd.js +2 -0
- package/dist/resolvers.umd.js.map +1 -0
- package/dist/toNestError.d.ts +2 -0
- package/joi/dist/index.d.ts +2 -0
- package/joi/dist/joi.d.ts +2 -0
- package/joi/dist/joi.js +2 -0
- package/joi/dist/joi.js.map +1 -0
- package/joi/dist/joi.mjs +2 -0
- package/joi/dist/joi.modern.js +2 -0
- package/joi/dist/joi.modern.js.map +1 -0
- package/joi/dist/joi.module.js +2 -0
- package/joi/dist/joi.module.js.map +1 -0
- package/joi/dist/joi.umd.js +2 -0
- package/joi/dist/joi.umd.js.map +1 -0
- package/joi/dist/types.d.ts +5 -0
- package/joi/package.json +17 -0
- package/joi/src/__tests__/Form.tsx +61 -0
- package/joi/src/__tests__/__fixtures__/data.ts +76 -0
- package/joi/src/__tests__/__snapshots__/joi.ts.snap +283 -0
- package/joi/src/__tests__/joi.ts +89 -0
- package/joi/src/index.ts +2 -0
- package/joi/src/joi.ts +63 -0
- package/joi/src/types.ts +17 -0
- package/package.json +111 -55
- package/superstruct/dist/index.d.ts +2 -0
- package/superstruct/dist/superstruct.d.ts +2 -0
- package/superstruct/dist/superstruct.js +2 -0
- package/superstruct/dist/superstruct.js.map +1 -0
- package/superstruct/dist/superstruct.mjs +2 -0
- package/superstruct/dist/superstruct.modern.js +2 -0
- package/superstruct/dist/superstruct.modern.js.map +1 -0
- package/superstruct/dist/superstruct.module.js +2 -0
- package/superstruct/dist/superstruct.module.js.map +1 -0
- package/superstruct/dist/superstruct.umd.js +2 -0
- package/superstruct/dist/superstruct.umd.js.map +1 -0
- package/superstruct/dist/types.d.ts +5 -0
- package/superstruct/package.json +18 -0
- package/superstruct/src/__tests__/Form.tsx +62 -0
- package/superstruct/src/__tests__/__fixtures__/data.ts +73 -0
- package/superstruct/src/__tests__/__snapshots__/superstruct.ts.snap +64 -0
- package/superstruct/src/__tests__/superstruct.ts +20 -0
- package/superstruct/src/index.ts +2 -0
- package/superstruct/src/superstruct.ts +30 -0
- package/superstruct/src/types.ts +18 -0
- package/vest/dist/index.d.ts +1 -0
- package/vest/dist/vest.d.ts +2 -0
- package/vest/dist/vest.js +2 -0
- package/vest/dist/vest.js.map +1 -0
- package/vest/dist/vest.mjs +2 -0
- package/vest/dist/vest.modern.js +2 -0
- package/vest/dist/vest.modern.js.map +1 -0
- package/vest/dist/vest.module.js +2 -0
- package/vest/dist/vest.module.js.map +1 -0
- package/vest/dist/vest.umd.js +2 -0
- package/vest/dist/vest.umd.js.map +1 -0
- package/vest/package.json +18 -0
- package/vest/src/__tests__/Form.tsx +64 -0
- package/vest/src/__tests__/__fixtures__/data.ts +67 -0
- package/vest/src/__tests__/__snapshots__/vest.ts.snap +141 -0
- package/vest/src/__tests__/vest.ts +65 -0
- package/vest/src/index.ts +1 -0
- package/vest/src/types.ts +21 -0
- package/vest/src/vest.ts +45 -0
- package/yup/dist/index.d.ts +2 -0
- package/yup/dist/types.d.ts +8 -0
- package/yup/dist/yup.d.ts +2 -0
- package/yup/dist/yup.js +2 -0
- package/yup/dist/yup.js.map +1 -0
- package/yup/dist/yup.mjs +2 -0
- package/yup/dist/yup.modern.js +2 -0
- package/yup/dist/yup.modern.js.map +1 -0
- package/yup/dist/yup.module.js +2 -0
- package/yup/dist/yup.module.js.map +1 -0
- package/yup/dist/yup.umd.js +2 -0
- package/yup/dist/yup.umd.js.map +1 -0
- package/yup/package.json +17 -0
- package/yup/src/__tests__/Form.tsx +54 -0
- package/yup/src/__tests__/__fixtures__/data.ts +65 -0
- package/yup/src/__tests__/__snapshots__/yup.ts.snap +221 -0
- package/yup/src/__tests__/yup.ts +150 -0
- package/yup/src/index.ts +2 -0
- package/yup/src/types.ts +22 -0
- package/yup/src/yup.ts +65 -0
- package/zod/dist/index.d.ts +2 -0
- package/zod/dist/types.d.ts +6 -0
- package/zod/dist/zod.d.ts +2 -0
- package/zod/dist/zod.js +2 -0
- package/zod/dist/zod.js.map +1 -0
- package/zod/dist/zod.mjs +2 -0
- package/zod/dist/zod.modern.js +2 -0
- package/zod/dist/zod.modern.js.map +1 -0
- package/zod/dist/zod.module.js +2 -0
- package/zod/dist/zod.module.js.map +1 -0
- package/zod/dist/zod.umd.js +2 -0
- package/zod/dist/zod.umd.js.map +1 -0
- package/zod/package.json +17 -0
- package/zod/src/__tests__/Form.tsx +54 -0
- package/zod/src/__tests__/__fixtures__/data.ts +68 -0
- package/zod/src/__tests__/__snapshots__/zod.ts.snap +355 -0
- package/zod/src/__tests__/zod.ts +71 -0
- package/zod/src/index.ts +2 -0
- package/zod/src/types.ts +18 -0
- package/zod/src/zod.ts +65 -0
- package/dist/ie11/joi.d.ts +0 -3
- package/dist/ie11/joi.js +0 -104
- package/dist/ie11/joi.js.map +0 -1
- package/dist/ie11/superstruct.d.ts +0 -3
- package/dist/ie11/superstruct.js +0 -95
- package/dist/ie11/superstruct.js.map +0 -1
- package/dist/ie11/utils/convertArrayToPathName.d.ts +0 -2
- package/dist/ie11/utils/convertArrayToPathName.js +0 -12
- package/dist/ie11/utils/convertArrayToPathName.js.map +0 -1
- package/dist/ie11/yup.d.ts +0 -3
- package/dist/ie11/yup.js +0 -132
- package/dist/ie11/yup.js.map +0 -1
- package/dist/joi.d.ts +0 -3
- package/dist/joi.js +0 -41
- package/dist/joi.js.map +0 -1
- package/dist/superstruct.d.ts +0 -3
- package/dist/superstruct.js +0 -39
- package/dist/superstruct.js.map +0 -1
- package/dist/umd/index.js +0 -2
- package/dist/umd/index.js.map +0 -1
- package/dist/utils/convertArrayToPathName.d.ts +0 -2
- package/dist/utils/convertArrayToPathName.js +0 -8
- package/dist/utils/convertArrayToPathName.js.map +0 -1
- package/dist/yup.d.ts +0 -3
- package/dist/yup.js +0 -49
- package/dist/yup.js.map +0 -1
- package/joi.d.ts +0 -1
- package/joi.js +0 -1
- package/superstruct.js +0 -1
- package/yup.d.ts +0 -1
- package/yup.js +0 -1
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`yupResolver should return a single error from yupResolver when validation fails 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"errors": Object {
|
|
6
|
+
"birthYear": Object {
|
|
7
|
+
"message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
|
|
8
|
+
"ref": undefined,
|
|
9
|
+
"type": "typeError",
|
|
10
|
+
},
|
|
11
|
+
"like": Array [
|
|
12
|
+
Object {
|
|
13
|
+
"id": Object {
|
|
14
|
+
"message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
|
|
15
|
+
"ref": undefined,
|
|
16
|
+
"type": "typeError",
|
|
17
|
+
},
|
|
18
|
+
"name": Object {
|
|
19
|
+
"message": "like[0].name is a required field",
|
|
20
|
+
"ref": undefined,
|
|
21
|
+
"type": "required",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
"password": Object {
|
|
26
|
+
"message": "password must match the following: \\"/^[a-zA-Z0-9]{3,30}/\\"",
|
|
27
|
+
"ref": Object {
|
|
28
|
+
"name": "password",
|
|
29
|
+
},
|
|
30
|
+
"type": "matches",
|
|
31
|
+
},
|
|
32
|
+
"username": Object {
|
|
33
|
+
"message": "username is a required field",
|
|
34
|
+
"ref": Object {
|
|
35
|
+
"name": "username",
|
|
36
|
+
},
|
|
37
|
+
"type": "required",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
"values": Object {},
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
exports[`yupResolver should return a single error from yupResolver with \`mode: sync\` when validation fails 1`] = `
|
|
45
|
+
Object {
|
|
46
|
+
"errors": Object {
|
|
47
|
+
"birthYear": Object {
|
|
48
|
+
"message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
|
|
49
|
+
"ref": undefined,
|
|
50
|
+
"type": "typeError",
|
|
51
|
+
},
|
|
52
|
+
"like": Array [
|
|
53
|
+
Object {
|
|
54
|
+
"id": Object {
|
|
55
|
+
"message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
|
|
56
|
+
"ref": undefined,
|
|
57
|
+
"type": "typeError",
|
|
58
|
+
},
|
|
59
|
+
"name": Object {
|
|
60
|
+
"message": "like[0].name is a required field",
|
|
61
|
+
"ref": undefined,
|
|
62
|
+
"type": "required",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
"password": Object {
|
|
67
|
+
"message": "password must match the following: \\"/^[a-zA-Z0-9]{3,30}/\\"",
|
|
68
|
+
"ref": Object {
|
|
69
|
+
"name": "password",
|
|
70
|
+
},
|
|
71
|
+
"type": "matches",
|
|
72
|
+
},
|
|
73
|
+
"username": Object {
|
|
74
|
+
"message": "username is a required field",
|
|
75
|
+
"ref": Object {
|
|
76
|
+
"name": "username",
|
|
77
|
+
},
|
|
78
|
+
"type": "required",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
"values": Object {},
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
exports[`yupResolver should return all the errors from yupResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = `
|
|
86
|
+
Object {
|
|
87
|
+
"errors": Object {
|
|
88
|
+
"birthYear": Object {
|
|
89
|
+
"message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
|
|
90
|
+
"ref": undefined,
|
|
91
|
+
"type": "typeError",
|
|
92
|
+
"types": Object {
|
|
93
|
+
"typeError": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
"like": Array [
|
|
97
|
+
Object {
|
|
98
|
+
"id": Object {
|
|
99
|
+
"message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
|
|
100
|
+
"ref": undefined,
|
|
101
|
+
"type": "typeError",
|
|
102
|
+
"types": Object {
|
|
103
|
+
"typeError": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
"name": Object {
|
|
107
|
+
"message": "like[0].name is a required field",
|
|
108
|
+
"ref": undefined,
|
|
109
|
+
"type": "required",
|
|
110
|
+
"types": Object {
|
|
111
|
+
"required": "like[0].name is a required field",
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
"password": Object {
|
|
117
|
+
"message": "password must match the following: \\"/^[a-zA-Z0-9]{3,30}/\\"",
|
|
118
|
+
"ref": Object {
|
|
119
|
+
"name": "password",
|
|
120
|
+
},
|
|
121
|
+
"type": "matches",
|
|
122
|
+
"types": Object {
|
|
123
|
+
"matches": "password must match the following: \\"/^[a-zA-Z0-9]{3,30}/\\"",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
"username": Object {
|
|
127
|
+
"message": "username is a required field",
|
|
128
|
+
"ref": Object {
|
|
129
|
+
"name": "username",
|
|
130
|
+
},
|
|
131
|
+
"type": "required",
|
|
132
|
+
"types": Object {
|
|
133
|
+
"required": "username is a required field",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
"values": Object {},
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
exports[`yupResolver should return all the errors from yupResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = `
|
|
142
|
+
Object {
|
|
143
|
+
"errors": Object {
|
|
144
|
+
"birthYear": Object {
|
|
145
|
+
"message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
|
|
146
|
+
"ref": undefined,
|
|
147
|
+
"type": "typeError",
|
|
148
|
+
"types": Object {
|
|
149
|
+
"typeError": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
"like": Array [
|
|
153
|
+
Object {
|
|
154
|
+
"id": Object {
|
|
155
|
+
"message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
|
|
156
|
+
"ref": undefined,
|
|
157
|
+
"type": "typeError",
|
|
158
|
+
"types": Object {
|
|
159
|
+
"typeError": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
"name": Object {
|
|
163
|
+
"message": "like[0].name is a required field",
|
|
164
|
+
"ref": undefined,
|
|
165
|
+
"type": "required",
|
|
166
|
+
"types": Object {
|
|
167
|
+
"required": "like[0].name is a required field",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
"password": Object {
|
|
173
|
+
"message": "password must match the following: \\"/^[a-zA-Z0-9]{3,30}/\\"",
|
|
174
|
+
"ref": Object {
|
|
175
|
+
"name": "password",
|
|
176
|
+
},
|
|
177
|
+
"type": "matches",
|
|
178
|
+
"types": Object {
|
|
179
|
+
"matches": "password must match the following: \\"/^[a-zA-Z0-9]{3,30}/\\"",
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
"username": Object {
|
|
183
|
+
"message": "username is a required field",
|
|
184
|
+
"ref": Object {
|
|
185
|
+
"name": "username",
|
|
186
|
+
},
|
|
187
|
+
"type": "required",
|
|
188
|
+
"types": Object {
|
|
189
|
+
"required": "username is a required field",
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
"values": Object {},
|
|
194
|
+
}
|
|
195
|
+
`;
|
|
196
|
+
|
|
197
|
+
exports[`yupResolver should return an error from yupResolver when validation fails and pass down the yup context 1`] = `
|
|
198
|
+
Object {
|
|
199
|
+
"errors": Object {
|
|
200
|
+
"name": Object {
|
|
201
|
+
"message": "name must be at least 6 characters",
|
|
202
|
+
"ref": undefined,
|
|
203
|
+
"type": "min",
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
"values": Object {},
|
|
207
|
+
}
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
exports[`yupResolver should return correct error message with using yup.test 1`] = `
|
|
211
|
+
Object {
|
|
212
|
+
"errors": Object {
|
|
213
|
+
"": Object {
|
|
214
|
+
"message": "Email or name are required",
|
|
215
|
+
"ref": undefined,
|
|
216
|
+
"type": "name",
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
"values": Object {},
|
|
220
|
+
}
|
|
221
|
+
`;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* eslint-disable no-console, @typescript-eslint/ban-ts-comment */
|
|
2
|
+
import * as yup from 'yup';
|
|
3
|
+
import { yupResolver } from '..';
|
|
4
|
+
import { schema, validData, fields, invalidData } from './__fixtures__/data';
|
|
5
|
+
|
|
6
|
+
describe('yupResolver', () => {
|
|
7
|
+
it('should return values from yupResolver when validation pass', async () => {
|
|
8
|
+
const schemaSpy = jest.spyOn(schema, 'validate');
|
|
9
|
+
const schemaSyncSpy = jest.spyOn(schema, 'validateSync');
|
|
10
|
+
|
|
11
|
+
const result = await yupResolver(schema)(validData, undefined, {
|
|
12
|
+
fields,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
expect(schemaSpy).toHaveBeenCalledTimes(1);
|
|
16
|
+
expect(schemaSyncSpy).not.toHaveBeenCalled();
|
|
17
|
+
expect(result).toEqual({ errors: {}, values: validData });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should return values from yupResolver with `mode: sync` when validation pass', async () => {
|
|
21
|
+
const validateSyncSpy = jest.spyOn(schema, 'validateSync');
|
|
22
|
+
const validateSpy = jest.spyOn(schema, 'validate');
|
|
23
|
+
|
|
24
|
+
const result = await yupResolver(schema, undefined, {
|
|
25
|
+
mode: 'sync',
|
|
26
|
+
})(validData, undefined, { fields });
|
|
27
|
+
|
|
28
|
+
expect(validateSyncSpy).toHaveBeenCalledTimes(1);
|
|
29
|
+
expect(validateSpy).not.toHaveBeenCalled();
|
|
30
|
+
expect(result).toEqual({ errors: {}, values: validData });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should return a single error from yupResolver when validation fails', async () => {
|
|
34
|
+
const result = await yupResolver(schema)(invalidData, undefined, {
|
|
35
|
+
fields,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(result).toMatchSnapshot();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should return a single error from yupResolver with `mode: sync` when validation fails', async () => {
|
|
42
|
+
const validateSyncSpy = jest.spyOn(schema, 'validateSync');
|
|
43
|
+
const validateSpy = jest.spyOn(schema, 'validate');
|
|
44
|
+
|
|
45
|
+
const result = await yupResolver(schema, undefined, {
|
|
46
|
+
mode: 'sync',
|
|
47
|
+
})(invalidData, undefined, { fields });
|
|
48
|
+
|
|
49
|
+
expect(validateSyncSpy).toHaveBeenCalledTimes(1);
|
|
50
|
+
expect(validateSpy).not.toHaveBeenCalled();
|
|
51
|
+
expect(result).toMatchSnapshot();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return all the errors from yupResolver when validation fails with `validateAllFieldCriteria` set to true', async () => {
|
|
55
|
+
const result = await yupResolver(schema)(invalidData, undefined, {
|
|
56
|
+
fields,
|
|
57
|
+
criteriaMode: 'all',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(result).toMatchSnapshot();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should return all the errors from yupResolver when validation fails with `validateAllFieldCriteria` set to true and `mode: sync`', async () => {
|
|
64
|
+
const result = await yupResolver(schema, undefined, { mode: 'sync' })(
|
|
65
|
+
invalidData,
|
|
66
|
+
undefined,
|
|
67
|
+
{
|
|
68
|
+
fields,
|
|
69
|
+
criteriaMode: 'all',
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(result).toMatchSnapshot();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should return an error from yupResolver when validation fails and pass down the yup context', async () => {
|
|
77
|
+
const data = { name: 'eric' };
|
|
78
|
+
const context = { min: true };
|
|
79
|
+
const schemaWithContext = yup.object({
|
|
80
|
+
name: yup
|
|
81
|
+
.string()
|
|
82
|
+
.required()
|
|
83
|
+
.when('$min', (min: boolean, schema: yup.StringSchema) => {
|
|
84
|
+
return min ? schema.min(6) : schema;
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const validateSpy = jest.spyOn(schemaWithContext, 'validate');
|
|
89
|
+
|
|
90
|
+
const result = await yupResolver(schemaWithContext)(data, context, {
|
|
91
|
+
fields,
|
|
92
|
+
});
|
|
93
|
+
expect(validateSpy).toHaveBeenCalledTimes(1);
|
|
94
|
+
expect(validateSpy).toHaveBeenCalledWith(
|
|
95
|
+
data,
|
|
96
|
+
expect.objectContaining({
|
|
97
|
+
abortEarly: false,
|
|
98
|
+
context,
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
expect(result).toMatchSnapshot();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should show a warning log if yup context is used instead only on dev environment', async () => {
|
|
105
|
+
jest.spyOn(console, 'warn').mockImplementation(jest.fn);
|
|
106
|
+
process.env.NODE_ENV = 'development';
|
|
107
|
+
|
|
108
|
+
await yupResolver(yup.object(), { context: { noContext: true } })(
|
|
109
|
+
{},
|
|
110
|
+
undefined,
|
|
111
|
+
{
|
|
112
|
+
fields,
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
expect(console.warn).toHaveBeenCalledWith(
|
|
116
|
+
"You should not used the yup options context. Please, use the 'useForm' context object instead",
|
|
117
|
+
);
|
|
118
|
+
process.env.NODE_ENV = 'test';
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should not show a warning log if yup context is used instead only on production environment', async () => {
|
|
122
|
+
jest.spyOn(console, 'warn').mockImplementation(jest.fn);
|
|
123
|
+
process.env.NODE_ENV = 'production';
|
|
124
|
+
|
|
125
|
+
await yupResolver(yup.object(), { context: { noContext: true } })(
|
|
126
|
+
{},
|
|
127
|
+
undefined,
|
|
128
|
+
{ fields },
|
|
129
|
+
);
|
|
130
|
+
expect(console.warn).not.toHaveBeenCalled();
|
|
131
|
+
process.env.NODE_ENV = 'test';
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should return correct error message with using yup.test', async () => {
|
|
135
|
+
const result = await yupResolver(
|
|
136
|
+
yup
|
|
137
|
+
.object({
|
|
138
|
+
name: yup.string(),
|
|
139
|
+
email: yup.string(),
|
|
140
|
+
})
|
|
141
|
+
.test(
|
|
142
|
+
'name',
|
|
143
|
+
'Email or name are required',
|
|
144
|
+
(value) => !!(value && (value.name || value.email)),
|
|
145
|
+
),
|
|
146
|
+
)({ name: '', email: '' }, undefined, { fields });
|
|
147
|
+
|
|
148
|
+
expect(result).toMatchSnapshot();
|
|
149
|
+
});
|
|
150
|
+
});
|
package/yup/src/index.ts
ADDED
package/yup/src/types.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FieldValues,
|
|
3
|
+
ResolverOptions,
|
|
4
|
+
ResolverResult,
|
|
5
|
+
UnpackNestedValue,
|
|
6
|
+
} from 'react-hook-form';
|
|
7
|
+
import * as Yup from 'yup';
|
|
8
|
+
import type Lazy from 'yup/lib/Lazy';
|
|
9
|
+
|
|
10
|
+
type Options<T extends Yup.AnyObjectSchema | Lazy<any>> = Parameters<
|
|
11
|
+
T['validate']
|
|
12
|
+
>[1];
|
|
13
|
+
|
|
14
|
+
export type Resolver = <T extends Yup.AnyObjectSchema | Lazy<any>>(
|
|
15
|
+
schema: T,
|
|
16
|
+
schemaOptions?: Options<T>,
|
|
17
|
+
factoryOptions?: { mode?: 'async' | 'sync' },
|
|
18
|
+
) => <TFieldValues extends FieldValues, TContext>(
|
|
19
|
+
values: UnpackNestedValue<TFieldValues>,
|
|
20
|
+
context: TContext | undefined,
|
|
21
|
+
options: ResolverOptions<TFieldValues>,
|
|
22
|
+
) => Promise<ResolverResult<TFieldValues>>;
|
package/yup/src/yup.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import Yup from 'yup';
|
|
2
|
+
import { toNestError } from '@hookform/resolvers';
|
|
3
|
+
import { appendErrors, FieldError } from 'react-hook-form';
|
|
4
|
+
import { Resolver } from './types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Why `path!` ? because it could be `undefined` in some case
|
|
8
|
+
* https://github.com/jquense/yup#validationerrorerrors-string--arraystring-value-any-path-string
|
|
9
|
+
*/
|
|
10
|
+
const parseErrorSchema = (
|
|
11
|
+
error: Yup.ValidationError,
|
|
12
|
+
validateAllFieldCriteria: boolean,
|
|
13
|
+
) => {
|
|
14
|
+
return error.inner.reduce<Record<string, FieldError>>((previous, error) => {
|
|
15
|
+
if (!previous[error.path!]) {
|
|
16
|
+
previous[error.path!] = { message: error.message, type: error.type! };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (validateAllFieldCriteria) {
|
|
20
|
+
previous[error.path!] = appendErrors(
|
|
21
|
+
error.path!,
|
|
22
|
+
validateAllFieldCriteria,
|
|
23
|
+
previous,
|
|
24
|
+
error.type!,
|
|
25
|
+
error.message,
|
|
26
|
+
) as FieldError;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return previous;
|
|
30
|
+
}, {});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const yupResolver: Resolver = (
|
|
34
|
+
schema,
|
|
35
|
+
schemaOptions = {
|
|
36
|
+
abortEarly: false,
|
|
37
|
+
},
|
|
38
|
+
resolverOptions = {},
|
|
39
|
+
) => async (values, context, options) => {
|
|
40
|
+
try {
|
|
41
|
+
if (schemaOptions.context && process.env.NODE_ENV === 'development') {
|
|
42
|
+
// eslint-disable-next-line no-console
|
|
43
|
+
console.warn(
|
|
44
|
+
"You should not used the yup options context. Please, use the 'useForm' context object instead",
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = await schema[
|
|
49
|
+
resolverOptions.mode === 'sync' ? 'validateSync' : 'validate'
|
|
50
|
+
](values, Object.assign({}, schemaOptions, { context }));
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
values: result,
|
|
54
|
+
errors: {},
|
|
55
|
+
};
|
|
56
|
+
} catch (e) {
|
|
57
|
+
return {
|
|
58
|
+
values: {},
|
|
59
|
+
errors: toNestError(
|
|
60
|
+
parseErrorSchema(e, options.criteriaMode === 'all'),
|
|
61
|
+
options.fields,
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { FieldValues, ResolverResult, UnpackNestedValue, ResolverOptions } from 'react-hook-form';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import type { ParseParams } from 'zod/lib/src/parser';
|
|
4
|
+
export declare type Resolver = <T extends z.ZodSchema<any, any>>(schema: T, schemaOptions?: ParseParams, factoryOptions?: {
|
|
5
|
+
mode?: 'async' | 'sync';
|
|
6
|
+
}) => <TFieldValues extends FieldValues, TContext>(values: UnpackNestedValue<TFieldValues>, context: TContext | undefined, options: ResolverOptions<TFieldValues>) => Promise<ResolverResult<TFieldValues>>;
|
package/zod/dist/zod.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var r=require("react-hook-form"),e=require("@hookform/resolvers"),o=function(e,o){for(var n={};e.length;){var t=e[0],s=t.code,u=t.message,i=t.path.join(".");n[i]||(n[i]={message:u,type:s}),"unionErrors"in t&&t.unionErrors.forEach(function(r){return r.errors.forEach(function(r){return e.push(r)})}),o&&(n[i]=r.appendErrors(i,o,n,s,u)),e.shift()}return n};exports.zodResolver=function(r,n,t){return void 0===t&&(t={}),function(s,u,i){try{return Promise.resolve(function(e,o){try{var u=Promise.resolve(r["sync"===t.mode?"parse":"parseAsync"](s,n)).then(function(r){return{errors:{},values:r}})}catch(r){return o(r)}return u&&u.then?u.then(void 0,o):u}(0,function(r){return{values:{},errors:r.isEmpty?{}:e.toNestError(o(r.errors,"all"===i.criteriaMode),i.fields)}}))}catch(r){return Promise.reject(r)}}};
|
|
2
|
+
//# sourceMappingURL=zod.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.js","sources":["../src/zod.ts"],"sourcesContent":["import { appendErrors, FieldError } from 'react-hook-form';\nimport * as z from 'zod';\nimport { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n zodErrors: z.ZodSuberror[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; zodErrors.length; ) {\n const error = zodErrors[0];\n const { code, message, path } = error;\n const _path = path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: code };\n }\n\n if ('unionErrors' in error) {\n error.unionErrors.forEach((unionError) =>\n unionError.errors.forEach((e) => zodErrors.push(e)),\n );\n }\n\n if (validateAllFieldCriteria) {\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n code,\n message,\n ) as FieldError;\n }\n\n zodErrors.shift();\n }\n\n return errors;\n};\n\nexport const zodResolver: Resolver = (\n schema,\n schemaOptions,\n resolverOptions = {},\n) => async (values, _, options) => {\n try {\n return {\n errors: {},\n values: await schema[\n resolverOptions.mode === 'sync' ? 'parse' : 'parseAsync'\n ](values, schemaOptions),\n };\n } catch (error) {\n return {\n values: {},\n errors: error.isEmpty\n ? {}\n : toNestError(\n parseErrorSchema(error.errors, options.criteriaMode === 'all'),\n options.fields,\n ),\n };\n }\n};\n"],"names":["parseErrorSchema","zodErrors","validateAllFieldCriteria","errors","length","error","code","message","_path","path","join","type","unionErrors","forEach","unionError","e","push","appendErrors","shift","schema","schemaOptions","resolverOptions","values","_","options","mode","isEmpty","toNestError","criteriaMode","fields"],"mappings":"kEAKMA,EAAmB,SACvBC,EACAC,GAGA,IADA,IAAMC,EAAqC,GACpCF,EAAUG,QAAU,CACzB,IAAMC,EAAQJ,EAAU,GAChBK,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KACJC,KAAK,KAEnBP,EAAOK,KACVL,EAAOK,GAAS,CAAED,QAAAA,EAASI,KAAML,IAG/B,gBAAiBD,GACnBA,EAAMO,YAAYC,QAAQ,SAACC,UACzBA,EAAWX,OAAOU,QAAQ,SAACE,UAAMd,EAAUe,KAAKD,OAIhDb,IACFC,EAAOK,GAASS,eACdT,EACAN,EACAC,EACAG,EACAC,IAIJN,EAAUiB,QAGZ,OAAOf,uBAG4B,SACnCgB,EACAC,EACAC,mBAAAA,IAAAA,EAAkB,aACRC,EAAQC,EAAGC,sEAIHL,EACa,SAAzBE,EAAgBI,KAAkB,QAAU,cAC5CH,EAAQF,qBAJZ,MAAO,CACLjB,OAAQ,GACRmB,iFAIKjB,GACP,MAAO,CACLiB,OAAQ,GACRnB,OAAQE,EAAMqB,QACV,GACAC,cACE3B,EAAiBK,EAAMF,OAAiC,QAAzBqB,EAAQI,cACvCJ,EAAQK,YAnBiB"}
|
package/zod/dist/zod.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{appendErrors as r}from"react-hook-form";import{toNestError as e}from"@hookform/resolvers";var o=function(e,o){for(var n={};e.length;){var t=e[0],s=t.code,i=t.message,u=t.path.join(".");n[u]||(n[u]={message:i,type:s}),"unionErrors"in t&&t.unionErrors.forEach(function(r){return r.errors.forEach(function(r){return e.push(r)})}),o&&(n[u]=r(u,o,n,s,i)),e.shift()}return n},n=function(r,n,t){return void 0===t&&(t={}),function(s,i,u){try{return Promise.resolve(function(e,o){try{var i=Promise.resolve(r["sync"===t.mode?"parse":"parseAsync"](s,n)).then(function(r){return{errors:{},values:r}})}catch(r){return o(r)}return i&&i.then?i.then(void 0,o):i}(0,function(r){return{values:{},errors:r.isEmpty?{}:e(o(r.errors,"all"===u.criteriaMode),u.fields)}}))}catch(r){return Promise.reject(r)}}};export{n as zodResolver};
|
|
2
|
+
//# sourceMappingURL=zod.module.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{appendErrors as r}from"react-hook-form";import{toNestError as o}from"@hookform/resolvers";const e=(o,e)=>{const s={};for(;o.length;){const t=o[0],{code:a,message:n,path:c}=t,i=c.join(".");s[i]||(s[i]={message:n,type:a}),"unionErrors"in t&&t.unionErrors.forEach(r=>r.errors.forEach(r=>o.push(r))),e&&(s[i]=r(i,e,s,a,n)),o.shift()}return s},s=(r,s,t={})=>async(a,n,c)=>{try{return{errors:{},values:await r["sync"===t.mode?"parse":"parseAsync"](a,s)}}catch(r){return{values:{},errors:r.isEmpty?{}:o(e(r.errors,"all"===c.criteriaMode),c.fields)}}};export{s as zodResolver};
|
|
2
|
+
//# sourceMappingURL=zod.modern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.modern.js","sources":["../src/zod.ts"],"sourcesContent":["import { appendErrors, FieldError } from 'react-hook-form';\nimport * as z from 'zod';\nimport { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n zodErrors: z.ZodSuberror[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; zodErrors.length; ) {\n const error = zodErrors[0];\n const { code, message, path } = error;\n const _path = path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: code };\n }\n\n if ('unionErrors' in error) {\n error.unionErrors.forEach((unionError) =>\n unionError.errors.forEach((e) => zodErrors.push(e)),\n );\n }\n\n if (validateAllFieldCriteria) {\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n code,\n message,\n ) as FieldError;\n }\n\n zodErrors.shift();\n }\n\n return errors;\n};\n\nexport const zodResolver: Resolver = (\n schema,\n schemaOptions,\n resolverOptions = {},\n) => async (values, _, options) => {\n try {\n return {\n errors: {},\n values: await schema[\n resolverOptions.mode === 'sync' ? 'parse' : 'parseAsync'\n ](values, schemaOptions),\n };\n } catch (error) {\n return {\n values: {},\n errors: error.isEmpty\n ? {}\n : toNestError(\n parseErrorSchema(error.errors, options.criteriaMode === 'all'),\n options.fields,\n ),\n };\n }\n};\n"],"names":["parseErrorSchema","zodErrors","validateAllFieldCriteria","errors","length","error","code","message","path","_path","join","type","unionErrors","forEach","unionError","e","push","appendErrors","shift","zodResolver","schema","schemaOptions","resolverOptions","async","values","_","options","mode","isEmpty","toNestError","criteriaMode","fields"],"mappings":"iGAKA,MAAMA,EAAmB,CACvBC,EACAC,KAEA,MAAMC,EAAqC,GAC3C,KAAOF,EAAUG,QAAU,CACzB,MAAMC,EAAQJ,EAAU,IAClBK,KAAEA,EAAFC,QAAQA,EAARC,KAAiBA,GAASH,EAC1BI,EAAQD,EAAKE,KAAK,KAEnBP,EAAOM,KACVN,EAAOM,GAAS,CAAEF,QAAAA,EAASI,KAAML,IAG/B,gBAAiBD,GACnBA,EAAMO,YAAYC,QAASC,GACzBA,EAAWX,OAAOU,QAASE,GAAMd,EAAUe,KAAKD,KAIhDb,IACFC,EAAOM,GAASQ,EACdR,EACAP,EACAC,EACAG,EACAC,IAIJN,EAAUiB,QAGZ,OAAOf,GAGIgB,EAAwB,CACnCC,EACAC,EACAC,EAAkB,KACfC,MAAOC,EAAQC,EAAGC,KACrB,IACE,MAAO,CACLvB,OAAQ,GACRqB,aAAcJ,EACa,SAAzBE,EAAgBK,KAAkB,QAAU,cAC5CH,EAAQH,IAEZ,MAAOhB,GACP,MAAO,CACLmB,OAAQ,GACRrB,OAAQE,EAAMuB,QACV,GACAC,EACE7B,EAAiBK,EAAMF,OAAiC,QAAzBuB,EAAQI,cACvCJ,EAAQK"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{appendErrors as r}from"react-hook-form";import{toNestError as e}from"@hookform/resolvers";var o=function(e,o){for(var n={};e.length;){var t=e[0],s=t.code,i=t.message,u=t.path.join(".");n[u]||(n[u]={message:i,type:s}),"unionErrors"in t&&t.unionErrors.forEach(function(r){return r.errors.forEach(function(r){return e.push(r)})}),o&&(n[u]=r(u,o,n,s,i)),e.shift()}return n},n=function(r,n,t){return void 0===t&&(t={}),function(s,i,u){try{return Promise.resolve(function(e,o){try{var i=Promise.resolve(r["sync"===t.mode?"parse":"parseAsync"](s,n)).then(function(r){return{errors:{},values:r}})}catch(r){return o(r)}return i&&i.then?i.then(void 0,o):i}(0,function(r){return{values:{},errors:r.isEmpty?{}:e(o(r.errors,"all"===u.criteriaMode),u.fields)}}))}catch(r){return Promise.reject(r)}}};export{n as zodResolver};
|
|
2
|
+
//# sourceMappingURL=zod.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.module.js","sources":["../src/zod.ts"],"sourcesContent":["import { appendErrors, FieldError } from 'react-hook-form';\nimport * as z from 'zod';\nimport { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n zodErrors: z.ZodSuberror[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; zodErrors.length; ) {\n const error = zodErrors[0];\n const { code, message, path } = error;\n const _path = path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: code };\n }\n\n if ('unionErrors' in error) {\n error.unionErrors.forEach((unionError) =>\n unionError.errors.forEach((e) => zodErrors.push(e)),\n );\n }\n\n if (validateAllFieldCriteria) {\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n code,\n message,\n ) as FieldError;\n }\n\n zodErrors.shift();\n }\n\n return errors;\n};\n\nexport const zodResolver: Resolver = (\n schema,\n schemaOptions,\n resolverOptions = {},\n) => async (values, _, options) => {\n try {\n return {\n errors: {},\n values: await schema[\n resolverOptions.mode === 'sync' ? 'parse' : 'parseAsync'\n ](values, schemaOptions),\n };\n } catch (error) {\n return {\n values: {},\n errors: error.isEmpty\n ? {}\n : toNestError(\n parseErrorSchema(error.errors, options.criteriaMode === 'all'),\n options.fields,\n ),\n };\n }\n};\n"],"names":["parseErrorSchema","zodErrors","validateAllFieldCriteria","errors","length","error","code","message","_path","path","join","type","unionErrors","forEach","unionError","e","push","appendErrors","shift","zodResolver","schema","schemaOptions","resolverOptions","values","_","options","mode","isEmpty","toNestError","criteriaMode","fields"],"mappings":"iGAKA,IAAMA,EAAmB,SACvBC,EACAC,GAGA,IADA,IAAMC,EAAqC,GACpCF,EAAUG,QAAU,CACzB,IAAMC,EAAQJ,EAAU,GAChBK,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KACJC,KAAK,KAEnBP,EAAOK,KACVL,EAAOK,GAAS,CAAED,QAAAA,EAASI,KAAML,IAG/B,gBAAiBD,GACnBA,EAAMO,YAAYC,QAAQ,SAACC,UACzBA,EAAWX,OAAOU,QAAQ,SAACE,UAAMd,EAAUe,KAAKD,OAIhDb,IACFC,EAAOK,GAASS,EACdT,EACAN,EACAC,EACAG,EACAC,IAIJN,EAAUiB,QAGZ,OAAOf,GAGIgB,EAAwB,SACnCC,EACAC,EACAC,mBAAAA,IAAAA,EAAkB,aACRC,EAAQC,EAAGC,sEAIHL,EACa,SAAzBE,EAAgBI,KAAkB,QAAU,cAC5CH,EAAQF,qBAJZ,MAAO,CACLlB,OAAQ,GACRoB,iFAIKlB,GACP,MAAO,CACLkB,OAAQ,GACRpB,OAAQE,EAAMsB,QACV,GACAC,EACE5B,EAAiBK,EAAMF,OAAiC,QAAzBsB,EAAQI,cACvCJ,EAAQK,YAnBiB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react-hook-form"),require("@hookform/resolvers")):"function"==typeof define&&define.amd?define(["exports","react-hook-form","@hookform/resolvers"],e):e((r||self).hookformResolversZod={},r.reactHookForm,r.hookformResolvers)}(this,function(r,e,o){var n=function(r,o){for(var n={};r.length;){var t=r[0],s=t.code,i=t.message,f=t.path.join(".");n[f]||(n[f]={message:i,type:s}),"unionErrors"in t&&t.unionErrors.forEach(function(e){return e.errors.forEach(function(e){return r.push(e)})}),o&&(n[f]=e.appendErrors(f,o,n,s,i)),r.shift()}return n};r.zodResolver=function(r,e,t){return void 0===t&&(t={}),function(s,i,f){try{return Promise.resolve(function(o,n){try{var i=Promise.resolve(r["sync"===t.mode?"parse":"parseAsync"](s,e)).then(function(r){return{errors:{},values:r}})}catch(r){return n(r)}return i&&i.then?i.then(void 0,n):i}(0,function(r){return{values:{},errors:r.isEmpty?{}:o.toNestError(n(r.errors,"all"===f.criteriaMode),f.fields)}}))}catch(r){return Promise.reject(r)}}}});
|
|
2
|
+
//# sourceMappingURL=zod.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.umd.js","sources":["../src/zod.ts"],"sourcesContent":["import { appendErrors, FieldError } from 'react-hook-form';\nimport * as z from 'zod';\nimport { toNestError } from '@hookform/resolvers';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n zodErrors: z.ZodSuberror[],\n validateAllFieldCriteria: boolean,\n) => {\n const errors: Record<string, FieldError> = {};\n for (; zodErrors.length; ) {\n const error = zodErrors[0];\n const { code, message, path } = error;\n const _path = path.join('.');\n\n if (!errors[_path]) {\n errors[_path] = { message, type: code };\n }\n\n if ('unionErrors' in error) {\n error.unionErrors.forEach((unionError) =>\n unionError.errors.forEach((e) => zodErrors.push(e)),\n );\n }\n\n if (validateAllFieldCriteria) {\n errors[_path] = appendErrors(\n _path,\n validateAllFieldCriteria,\n errors,\n code,\n message,\n ) as FieldError;\n }\n\n zodErrors.shift();\n }\n\n return errors;\n};\n\nexport const zodResolver: Resolver = (\n schema,\n schemaOptions,\n resolverOptions = {},\n) => async (values, _, options) => {\n try {\n return {\n errors: {},\n values: await schema[\n resolverOptions.mode === 'sync' ? 'parse' : 'parseAsync'\n ](values, schemaOptions),\n };\n } catch (error) {\n return {\n values: {},\n errors: error.isEmpty\n ? {}\n : toNestError(\n parseErrorSchema(error.errors, options.criteriaMode === 'all'),\n options.fields,\n ),\n };\n }\n};\n"],"names":["parseErrorSchema","zodErrors","validateAllFieldCriteria","errors","length","error","code","message","_path","path","join","type","unionErrors","forEach","unionError","e","push","appendErrors","shift","schema","schemaOptions","resolverOptions","values","_","options","mode","isEmpty","toNestError","criteriaMode","fields"],"mappings":"wXAKA,IAAMA,EAAmB,SACvBC,EACAC,GAGA,IADA,IAAMC,EAAqC,GACpCF,EAAUG,QAAU,CACzB,IAAMC,EAAQJ,EAAU,GAChBK,EAAwBD,EAAxBC,KAAMC,EAAkBF,EAAlBE,QACRC,EAD0BH,EAATI,KACJC,KAAK,KAEnBP,EAAOK,KACVL,EAAOK,GAAS,CAAED,QAAAA,EAASI,KAAML,IAG/B,gBAAiBD,GACnBA,EAAMO,YAAYC,QAAQ,SAACC,UACzBA,EAAWX,OAAOU,QAAQ,SAACE,UAAMd,EAAUe,KAAKD,OAIhDb,IACFC,EAAOK,GAASS,eACdT,EACAN,EACAC,EACAG,EACAC,IAIJN,EAAUiB,QAGZ,OAAOf,iBAG4B,SACnCgB,EACAC,EACAC,mBAAAA,IAAAA,EAAkB,aACRC,EAAQC,EAAGC,sEAIHL,EACa,SAAzBE,EAAgBI,KAAkB,QAAU,cAC5CH,EAAQF,qBAJZ,MAAO,CACLjB,OAAQ,GACRmB,iFAIKjB,GACP,MAAO,CACLiB,OAAQ,GACRnB,OAAQE,EAAMqB,QACV,GACAC,cACE3B,EAAiBK,EAAMF,OAAiC,QAAzBqB,EAAQI,cACvCJ,EAAQK,YAnBiB"}
|
package/zod/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zod",
|
|
3
|
+
"amdName": "hookformResolversZod",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "React Hook Form validation resolver: zod",
|
|
7
|
+
"main": "dist/zod.js",
|
|
8
|
+
"module": "dist/zod.module.js",
|
|
9
|
+
"umd:main": "dist/zod.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": "^1.0.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, act } from '@testing-library/react';
|
|
3
|
+
import user from '@testing-library/user-event';
|
|
4
|
+
import { useForm } from 'react-hook-form';
|
|
5
|
+
import * as Zod from 'zod';
|
|
6
|
+
import { zodResolver } from '..';
|
|
7
|
+
|
|
8
|
+
const schema = Zod.object({
|
|
9
|
+
username: Zod.string().nonempty({ message: 'username field is required' }),
|
|
10
|
+
password: Zod.string().nonempty({ message: 'password field is required' }),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
type FormData = Zod.infer<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: zodResolver(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 = jest.fn();
|
|
43
|
+
render(<TestComponent onSubmit={handleSubmit} />);
|
|
44
|
+
|
|
45
|
+
expect(screen.queryAllByRole(/alert/i)).toHaveLength(0);
|
|
46
|
+
|
|
47
|
+
await act(async () => {
|
|
48
|
+
user.click(screen.getByText(/submit/i));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(screen.getByText(/username field is required/i)).toBeInTheDocument();
|
|
52
|
+
expect(screen.getByText(/password field is required/i)).toBeInTheDocument();
|
|
53
|
+
expect(handleSubmit).not.toHaveBeenCalled();
|
|
54
|
+
});
|