@hookform/resolvers 2.8.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.
Files changed (227) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +420 -0
  3. package/class-validator/dist/class-validator.d.ts +2 -0
  4. package/class-validator/dist/class-validator.js +2 -0
  5. package/class-validator/dist/class-validator.js.map +1 -0
  6. package/class-validator/dist/class-validator.mjs +2 -0
  7. package/class-validator/dist/class-validator.modern.js +2 -0
  8. package/class-validator/dist/class-validator.modern.js.map +1 -0
  9. package/class-validator/dist/class-validator.module.js +2 -0
  10. package/class-validator/dist/class-validator.module.js.map +1 -0
  11. package/class-validator/dist/class-validator.umd.js +2 -0
  12. package/class-validator/dist/class-validator.umd.js.map +1 -0
  13. package/class-validator/dist/index.d.ts +2 -0
  14. package/class-validator/dist/types.d.ts +8 -0
  15. package/class-validator/package.json +19 -0
  16. package/class-validator/src/__tests__/Form-native-validation.tsx +83 -0
  17. package/class-validator/src/__tests__/Form.tsx +55 -0
  18. package/class-validator/src/__tests__/__fixtures__/data.ts +88 -0
  19. package/class-validator/src/__tests__/__snapshots__/class-validator.ts.snap +207 -0
  20. package/class-validator/src/__tests__/class-validator.ts +87 -0
  21. package/class-validator/src/class-validator.ts +62 -0
  22. package/class-validator/src/index.ts +2 -0
  23. package/class-validator/src/types.ts +22 -0
  24. package/computed-types/dist/computed-types.d.ts +2 -0
  25. package/computed-types/dist/computed-types.js +2 -0
  26. package/computed-types/dist/computed-types.js.map +1 -0
  27. package/computed-types/dist/computed-types.mjs +2 -0
  28. package/computed-types/dist/computed-types.modern.js +2 -0
  29. package/computed-types/dist/computed-types.modern.js.map +1 -0
  30. package/computed-types/dist/computed-types.module.js +2 -0
  31. package/computed-types/dist/computed-types.module.js.map +1 -0
  32. package/computed-types/dist/computed-types.umd.js +2 -0
  33. package/computed-types/dist/computed-types.umd.js.map +1 -0
  34. package/computed-types/dist/index.d.ts +2 -0
  35. package/computed-types/dist/types.d.ts +2 -0
  36. package/computed-types/package.json +17 -0
  37. package/computed-types/src/__tests__/Form-native-validation.tsx +85 -0
  38. package/computed-types/src/__tests__/Form.tsx +54 -0
  39. package/computed-types/src/__tests__/__fixtures__/data.ts +72 -0
  40. package/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap +55 -0
  41. package/computed-types/src/__tests__/computed-types.ts +24 -0
  42. package/computed-types/src/computed-types.ts +43 -0
  43. package/computed-types/src/index.ts +2 -0
  44. package/computed-types/src/types.ts +14 -0
  45. package/dist/index.d.ts +2 -0
  46. package/dist/resolvers.js +2 -0
  47. package/dist/resolvers.js.map +1 -0
  48. package/dist/resolvers.mjs +2 -0
  49. package/dist/resolvers.mjs.map +1 -0
  50. package/dist/resolvers.module.js +2 -0
  51. package/dist/resolvers.module.js.map +1 -0
  52. package/dist/resolvers.umd.js +2 -0
  53. package/dist/resolvers.umd.js.map +1 -0
  54. package/dist/toNestError.d.ts +2 -0
  55. package/dist/validateFieldsNatively.d.ts +2 -0
  56. package/io-ts/dist/arrayToPath.d.ts +3 -0
  57. package/io-ts/dist/errorsToRecord.d.ts +5 -0
  58. package/io-ts/dist/index.d.ts +2 -0
  59. package/io-ts/dist/io-ts.d.ts +2 -0
  60. package/io-ts/dist/io-ts.js +2 -0
  61. package/io-ts/dist/io-ts.js.map +1 -0
  62. package/io-ts/dist/io-ts.mjs +2 -0
  63. package/io-ts/dist/io-ts.modern.js +2 -0
  64. package/io-ts/dist/io-ts.modern.js.map +1 -0
  65. package/io-ts/dist/io-ts.module.js +2 -0
  66. package/io-ts/dist/io-ts.module.js.map +1 -0
  67. package/io-ts/dist/io-ts.umd.js +2 -0
  68. package/io-ts/dist/io-ts.umd.js.map +1 -0
  69. package/io-ts/dist/types.d.ts +7 -0
  70. package/io-ts/package.json +19 -0
  71. package/io-ts/src/__tests__/Form-native-validation.tsx +89 -0
  72. package/io-ts/src/__tests__/Form.tsx +65 -0
  73. package/io-ts/src/__tests__/__fixtures__/data.ts +129 -0
  74. package/io-ts/src/__tests__/__snapshots__/io-ts.ts.snap +89 -0
  75. package/io-ts/src/__tests__/io-ts.ts +37 -0
  76. package/io-ts/src/arrayToPath.ts +18 -0
  77. package/io-ts/src/errorsToRecord.ts +131 -0
  78. package/io-ts/src/index.ts +2 -0
  79. package/io-ts/src/io-ts.ts +33 -0
  80. package/io-ts/src/types.ts +23 -0
  81. package/joi/dist/index.d.ts +2 -0
  82. package/joi/dist/joi.d.ts +2 -0
  83. package/joi/dist/joi.js +2 -0
  84. package/joi/dist/joi.js.map +1 -0
  85. package/joi/dist/joi.mjs +2 -0
  86. package/joi/dist/joi.modern.js +2 -0
  87. package/joi/dist/joi.modern.js.map +1 -0
  88. package/joi/dist/joi.module.js +2 -0
  89. package/joi/dist/joi.module.js.map +1 -0
  90. package/joi/dist/joi.umd.js +2 -0
  91. package/joi/dist/joi.umd.js.map +1 -0
  92. package/joi/dist/types.d.ts +5 -0
  93. package/joi/package.json +17 -0
  94. package/joi/src/__tests__/Form-native-validation.tsx +89 -0
  95. package/joi/src/__tests__/Form.tsx +61 -0
  96. package/joi/src/__tests__/__fixtures__/data.ts +85 -0
  97. package/joi/src/__tests__/__snapshots__/joi.ts.snap +293 -0
  98. package/joi/src/__tests__/joi.ts +98 -0
  99. package/joi/src/index.ts +2 -0
  100. package/joi/src/joi.ts +81 -0
  101. package/joi/src/types.ts +16 -0
  102. package/nope/dist/index.d.ts +2 -0
  103. package/nope/dist/nope.d.ts +2 -0
  104. package/nope/dist/nope.js +2 -0
  105. package/nope/dist/nope.js.map +1 -0
  106. package/nope/dist/nope.mjs +2 -0
  107. package/nope/dist/nope.modern.js +2 -0
  108. package/nope/dist/nope.modern.js.map +1 -0
  109. package/nope/dist/nope.module.js +2 -0
  110. package/nope/dist/nope.module.js.map +1 -0
  111. package/nope/dist/nope.umd.js +2 -0
  112. package/nope/dist/nope.umd.js.map +1 -0
  113. package/nope/dist/types.d.ts +6 -0
  114. package/nope/package.json +18 -0
  115. package/nope/src/__tests__/Form-native-validation.tsx +89 -0
  116. package/nope/src/__tests__/Form.tsx +57 -0
  117. package/nope/src/__tests__/__fixtures__/data.ts +70 -0
  118. package/nope/src/__tests__/__snapshots__/nope.ts.snap +43 -0
  119. package/nope/src/__tests__/nope.ts +28 -0
  120. package/nope/src/index.ts +2 -0
  121. package/nope/src/nope.ts +46 -0
  122. package/nope/src/types.ts +22 -0
  123. package/package.json +216 -0
  124. package/superstruct/dist/index.d.ts +2 -0
  125. package/superstruct/dist/superstruct.d.ts +2 -0
  126. package/superstruct/dist/superstruct.js +2 -0
  127. package/superstruct/dist/superstruct.js.map +1 -0
  128. package/superstruct/dist/superstruct.mjs +2 -0
  129. package/superstruct/dist/superstruct.modern.js +2 -0
  130. package/superstruct/dist/superstruct.modern.js.map +1 -0
  131. package/superstruct/dist/superstruct.module.js +2 -0
  132. package/superstruct/dist/superstruct.module.js.map +1 -0
  133. package/superstruct/dist/superstruct.umd.js +2 -0
  134. package/superstruct/dist/superstruct.umd.js.map +1 -0
  135. package/superstruct/dist/types.d.ts +5 -0
  136. package/superstruct/package.json +18 -0
  137. package/superstruct/src/__tests__/Form-native-validation.tsx +86 -0
  138. package/superstruct/src/__tests__/Form.tsx +62 -0
  139. package/superstruct/src/__tests__/__fixtures__/data.ts +75 -0
  140. package/superstruct/src/__tests__/__snapshots__/superstruct.ts.snap +64 -0
  141. package/superstruct/src/__tests__/superstruct.ts +24 -0
  142. package/superstruct/src/index.ts +2 -0
  143. package/superstruct/src/superstruct.ts +37 -0
  144. package/superstruct/src/types.ts +17 -0
  145. package/typanion/dist/index.d.ts +2 -0
  146. package/typanion/dist/typanion.d.ts +2 -0
  147. package/typanion/dist/typanion.js +2 -0
  148. package/typanion/dist/typanion.js.map +1 -0
  149. package/typanion/dist/typanion.mjs +2 -0
  150. package/typanion/dist/typanion.modern.js +2 -0
  151. package/typanion/dist/typanion.modern.js.map +1 -0
  152. package/typanion/dist/typanion.module.js +2 -0
  153. package/typanion/dist/typanion.module.js.map +1 -0
  154. package/typanion/dist/typanion.umd.js +2 -0
  155. package/typanion/dist/typanion.umd.js.map +1 -0
  156. package/typanion/dist/types.d.ts +6 -0
  157. package/typanion/package.json +18 -0
  158. package/typanion/src/__tests__/Form-native-validation.tsx +89 -0
  159. package/typanion/src/__tests__/Form.tsx +61 -0
  160. package/typanion/src/__tests__/__fixtures__/data.ts +77 -0
  161. package/typanion/src/__tests__/__snapshots__/typanion.ts.snap +67 -0
  162. package/typanion/src/__tests__/typanion.ts +31 -0
  163. package/typanion/src/index.ts +2 -0
  164. package/typanion/src/typanion.ts +44 -0
  165. package/typanion/src/types.ts +28 -0
  166. package/vest/dist/index.d.ts +1 -0
  167. package/vest/dist/vest.d.ts +2 -0
  168. package/vest/dist/vest.js +2 -0
  169. package/vest/dist/vest.js.map +1 -0
  170. package/vest/dist/vest.mjs +2 -0
  171. package/vest/dist/vest.modern.js +2 -0
  172. package/vest/dist/vest.modern.js.map +1 -0
  173. package/vest/dist/vest.module.js +2 -0
  174. package/vest/dist/vest.module.js.map +1 -0
  175. package/vest/dist/vest.umd.js +2 -0
  176. package/vest/dist/vest.umd.js.map +1 -0
  177. package/vest/package.json +18 -0
  178. package/vest/src/__tests__/Form-native-validation.tsx +93 -0
  179. package/vest/src/__tests__/Form.tsx +64 -0
  180. package/vest/src/__tests__/__fixtures__/data.ts +67 -0
  181. package/vest/src/__tests__/__snapshots__/vest.ts.snap +141 -0
  182. package/vest/src/__tests__/vest.ts +71 -0
  183. package/vest/src/index.ts +1 -0
  184. package/vest/src/types.ts +20 -0
  185. package/vest/src/vest.ts +51 -0
  186. package/yup/dist/index.d.ts +2 -0
  187. package/yup/dist/types.d.ts +8 -0
  188. package/yup/dist/yup.d.ts +2 -0
  189. package/yup/dist/yup.js +2 -0
  190. package/yup/dist/yup.js.map +1 -0
  191. package/yup/dist/yup.mjs +2 -0
  192. package/yup/dist/yup.modern.js +2 -0
  193. package/yup/dist/yup.modern.js.map +1 -0
  194. package/yup/dist/yup.module.js +2 -0
  195. package/yup/dist/yup.module.js.map +1 -0
  196. package/yup/dist/yup.umd.js +2 -0
  197. package/yup/dist/yup.umd.js.map +1 -0
  198. package/yup/package.json +17 -0
  199. package/yup/src/__tests__/Form-native-validation.tsx +85 -0
  200. package/yup/src/__tests__/Form.tsx +54 -0
  201. package/yup/src/__tests__/__fixtures__/data.ts +72 -0
  202. package/yup/src/__tests__/__snapshots__/yup.ts.snap +231 -0
  203. package/yup/src/__tests__/yup.ts +174 -0
  204. package/yup/src/index.ts +2 -0
  205. package/yup/src/types.ts +21 -0
  206. package/yup/src/yup.ts +75 -0
  207. package/zod/dist/index.d.ts +2 -0
  208. package/zod/dist/types.d.ts +5 -0
  209. package/zod/dist/zod.d.ts +2 -0
  210. package/zod/dist/zod.js +2 -0
  211. package/zod/dist/zod.js.map +1 -0
  212. package/zod/dist/zod.mjs +2 -0
  213. package/zod/dist/zod.modern.js +2 -0
  214. package/zod/dist/zod.modern.js.map +1 -0
  215. package/zod/dist/zod.module.js +2 -0
  216. package/zod/dist/zod.module.js.map +1 -0
  217. package/zod/dist/zod.umd.js +2 -0
  218. package/zod/dist/zod.umd.js.map +1 -0
  219. package/zod/package.json +17 -0
  220. package/zod/src/__tests__/Form-native-validation.tsx +85 -0
  221. package/zod/src/__tests__/Form.tsx +54 -0
  222. package/zod/src/__tests__/__fixtures__/data.ts +81 -0
  223. package/zod/src/__tests__/__snapshots__/zod.ts.snap +377 -0
  224. package/zod/src/__tests__/zod.ts +77 -0
  225. package/zod/src/index.ts +2 -0
  226. package/zod/src/types.ts +16 -0
  227. package/zod/src/zod.ts +85 -0
@@ -0,0 +1,55 @@
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 { classValidatorResolver } from '..';
6
+ import { IsNotEmpty } from 'class-validator';
7
+
8
+ class Schema {
9
+ @IsNotEmpty()
10
+ username: string;
11
+
12
+ @IsNotEmpty()
13
+ password: string;
14
+ }
15
+
16
+ interface Props {
17
+ onSubmit: (data: Schema) => void;
18
+ }
19
+
20
+ function TestComponent({ onSubmit }: Props) {
21
+ const {
22
+ register,
23
+ formState: { errors },
24
+ handleSubmit,
25
+ } = useForm<Schema>({
26
+ resolver: classValidatorResolver(Schema),
27
+ });
28
+
29
+ return (
30
+ <form onSubmit={handleSubmit(onSubmit)}>
31
+ <input {...register('username')} />
32
+ {errors.username && <span role="alert">{errors.username.message}</span>}
33
+
34
+ <input {...register('password')} />
35
+ {errors.password && <span role="alert">{errors.password.message}</span>}
36
+
37
+ <button type="submit">submit</button>
38
+ </form>
39
+ );
40
+ }
41
+
42
+ test("form's validation with Class Validator and TypeScript's integration", async () => {
43
+ const handleSubmit = jest.fn();
44
+ render(<TestComponent onSubmit={handleSubmit} />);
45
+
46
+ expect(screen.queryAllByRole(/alert/i)).toHaveLength(0);
47
+
48
+ await act(async () => {
49
+ user.click(screen.getByText(/submit/i));
50
+ });
51
+
52
+ expect(screen.getByText(/username should not be empty/i)).toBeInTheDocument();
53
+ expect(screen.getByText(/password should not be empty/i)).toBeInTheDocument();
54
+ expect(handleSubmit).not.toHaveBeenCalled();
55
+ });
@@ -0,0 +1,88 @@
1
+ import 'reflect-metadata';
2
+ import { Type } from 'class-transformer';
3
+ import {
4
+ IsEmail,
5
+ IsNotEmpty,
6
+ Length,
7
+ Matches,
8
+ Max,
9
+ Min,
10
+ ValidateNested,
11
+ } from 'class-validator';
12
+ import { Field, InternalFieldName } from 'react-hook-form';
13
+
14
+ class Like {
15
+ @IsNotEmpty()
16
+ id: number;
17
+
18
+ @Length(4)
19
+ name: string;
20
+ }
21
+
22
+ export class Schema {
23
+ @Matches(/^\w+$/)
24
+ @Length(3, 30)
25
+ username: string;
26
+
27
+ @Matches(/^[a-zA-Z0-9]{3,30}/)
28
+ password: string;
29
+
30
+ @Min(1900)
31
+ @Max(2013)
32
+ birthYear: number;
33
+
34
+ @IsEmail()
35
+ email: string;
36
+
37
+ accessToken: string;
38
+
39
+ tags: string[];
40
+
41
+ enabled: boolean;
42
+
43
+ @ValidateNested({ each: true })
44
+ @Type(() => Like)
45
+ like: Like[];
46
+ }
47
+
48
+ export const validData: Schema = {
49
+ username: 'Doe',
50
+ password: 'Password123',
51
+ birthYear: 2000,
52
+ email: 'john@doe.com',
53
+ tags: ['tag1', 'tag2'],
54
+ enabled: true,
55
+ accessToken: 'accessToken',
56
+ like: [
57
+ {
58
+ id: 1,
59
+ name: 'name',
60
+ },
61
+ ],
62
+ };
63
+
64
+ export const invalidData = {
65
+ password: '___',
66
+ email: '',
67
+ birthYear: 'birthYear',
68
+ like: [{ id: 'z' }],
69
+ };
70
+
71
+ export const fields: Record<InternalFieldName, Field['_f']> = {
72
+ username: {
73
+ ref: { name: 'username' },
74
+ name: 'username',
75
+ },
76
+ password: {
77
+ ref: { name: 'password' },
78
+ name: 'password',
79
+ },
80
+ email: {
81
+ ref: { name: 'email' },
82
+ name: 'email',
83
+ },
84
+ birthday: {
85
+ ref: { name: 'birthday' },
86
+ name: 'birthday',
87
+ },
88
+ };
@@ -0,0 +1,207 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`classValidatorResolver should return a single error from classValidatorResolver when validation fails 1`] = `
4
+ Object {
5
+ "errors": Object {
6
+ "birthYear": Object {
7
+ "message": "birthYear must not be greater than 2013",
8
+ "ref": undefined,
9
+ "type": "max",
10
+ },
11
+ "email": Object {
12
+ "message": "email must be an email",
13
+ "ref": Object {
14
+ "name": "email",
15
+ },
16
+ "type": "isEmail",
17
+ },
18
+ "like": Array [
19
+ Object {
20
+ "name": Object {
21
+ "message": "name must be longer than or equal to 4 characters",
22
+ "ref": undefined,
23
+ "type": "isLength",
24
+ },
25
+ },
26
+ ],
27
+ "password": Object {
28
+ "message": "password must match /^[a-zA-Z0-9]{3,30}/ regular expression",
29
+ "ref": Object {
30
+ "name": "password",
31
+ },
32
+ "type": "matches",
33
+ },
34
+ "username": Object {
35
+ "message": "username must be longer than or equal to 3 characters",
36
+ "ref": Object {
37
+ "name": "username",
38
+ },
39
+ "type": "isLength",
40
+ },
41
+ },
42
+ "values": Object {},
43
+ }
44
+ `;
45
+
46
+ exports[`classValidatorResolver should return a single error from classValidatorResolver with \`mode: sync\` when validation fails 1`] = `
47
+ Object {
48
+ "errors": Object {
49
+ "birthYear": Object {
50
+ "message": "birthYear must not be greater than 2013",
51
+ "ref": undefined,
52
+ "type": "max",
53
+ },
54
+ "email": Object {
55
+ "message": "email must be an email",
56
+ "ref": Object {
57
+ "name": "email",
58
+ },
59
+ "type": "isEmail",
60
+ },
61
+ "like": Array [
62
+ Object {
63
+ "name": Object {
64
+ "message": "name must be longer than or equal to 4 characters",
65
+ "ref": undefined,
66
+ "type": "isLength",
67
+ },
68
+ },
69
+ ],
70
+ "password": Object {
71
+ "message": "password must match /^[a-zA-Z0-9]{3,30}/ regular expression",
72
+ "ref": Object {
73
+ "name": "password",
74
+ },
75
+ "type": "matches",
76
+ },
77
+ "username": Object {
78
+ "message": "username must be longer than or equal to 3 characters",
79
+ "ref": Object {
80
+ "name": "username",
81
+ },
82
+ "type": "isLength",
83
+ },
84
+ },
85
+ "values": Object {},
86
+ }
87
+ `;
88
+
89
+ exports[`classValidatorResolver should return all the errors from classValidatorResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = `
90
+ Object {
91
+ "errors": Object {
92
+ "birthYear": Object {
93
+ "message": "birthYear must not be greater than 2013",
94
+ "ref": undefined,
95
+ "type": "max",
96
+ "types": Object {
97
+ "max": "birthYear must not be greater than 2013",
98
+ "min": "birthYear must not be less than 1900",
99
+ },
100
+ },
101
+ "email": Object {
102
+ "message": "email must be an email",
103
+ "ref": Object {
104
+ "name": "email",
105
+ },
106
+ "type": "isEmail",
107
+ "types": Object {
108
+ "isEmail": "email must be an email",
109
+ },
110
+ },
111
+ "like": Array [
112
+ Object {
113
+ "name": Object {
114
+ "message": "name must be longer than or equal to 4 characters",
115
+ "ref": undefined,
116
+ "type": "isLength",
117
+ "types": Object {
118
+ "isLength": "name must be longer than or equal to 4 characters",
119
+ },
120
+ },
121
+ },
122
+ ],
123
+ "password": Object {
124
+ "message": "password must match /^[a-zA-Z0-9]{3,30}/ regular expression",
125
+ "ref": Object {
126
+ "name": "password",
127
+ },
128
+ "type": "matches",
129
+ "types": Object {
130
+ "matches": "password must match /^[a-zA-Z0-9]{3,30}/ regular expression",
131
+ },
132
+ },
133
+ "username": Object {
134
+ "message": "username must be longer than or equal to 3 characters",
135
+ "ref": Object {
136
+ "name": "username",
137
+ },
138
+ "type": "isLength",
139
+ "types": Object {
140
+ "isLength": "username must be longer than or equal to 3 characters",
141
+ "matches": "username must match /^\\\\w+$/ regular expression",
142
+ },
143
+ },
144
+ },
145
+ "values": Object {},
146
+ }
147
+ `;
148
+
149
+ exports[`classValidatorResolver should return all the errors from classValidatorResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = `
150
+ Object {
151
+ "errors": Object {
152
+ "birthYear": Object {
153
+ "message": "birthYear must not be greater than 2013",
154
+ "ref": undefined,
155
+ "type": "max",
156
+ "types": Object {
157
+ "max": "birthYear must not be greater than 2013",
158
+ "min": "birthYear must not be less than 1900",
159
+ },
160
+ },
161
+ "email": Object {
162
+ "message": "email must be an email",
163
+ "ref": Object {
164
+ "name": "email",
165
+ },
166
+ "type": "isEmail",
167
+ "types": Object {
168
+ "isEmail": "email must be an email",
169
+ },
170
+ },
171
+ "like": Array [
172
+ Object {
173
+ "name": Object {
174
+ "message": "name must be longer than or equal to 4 characters",
175
+ "ref": undefined,
176
+ "type": "isLength",
177
+ "types": Object {
178
+ "isLength": "name must be longer than or equal to 4 characters",
179
+ },
180
+ },
181
+ },
182
+ ],
183
+ "password": Object {
184
+ "message": "password must match /^[a-zA-Z0-9]{3,30}/ regular expression",
185
+ "ref": Object {
186
+ "name": "password",
187
+ },
188
+ "type": "matches",
189
+ "types": Object {
190
+ "matches": "password must match /^[a-zA-Z0-9]{3,30}/ regular expression",
191
+ },
192
+ },
193
+ "username": Object {
194
+ "message": "username must be longer than or equal to 3 characters",
195
+ "ref": Object {
196
+ "name": "username",
197
+ },
198
+ "type": "isLength",
199
+ "types": Object {
200
+ "isLength": "username must be longer than or equal to 3 characters",
201
+ "matches": "username must match /^\\\\w+$/ regular expression",
202
+ },
203
+ },
204
+ },
205
+ "values": Object {},
206
+ }
207
+ `;
@@ -0,0 +1,87 @@
1
+ /* eslint-disable no-console, @typescript-eslint/ban-ts-comment */
2
+ import { classValidatorResolver } from '..';
3
+ import { Schema, validData, fields, invalidData } from './__fixtures__/data';
4
+ import * as classValidator from 'class-validator';
5
+
6
+ const shouldUseNativeValidation = false;
7
+
8
+ describe('classValidatorResolver', () => {
9
+ it('should return values from classValidatorResolver when validation pass', async () => {
10
+ const schemaSpy = jest.spyOn(classValidator, 'validate');
11
+ const schemaSyncSpy = jest.spyOn(classValidator, 'validateSync');
12
+
13
+ const result = await classValidatorResolver(Schema)(validData, undefined, {
14
+ fields,
15
+ shouldUseNativeValidation,
16
+ });
17
+
18
+ expect(schemaSpy).toHaveBeenCalledTimes(1);
19
+ expect(schemaSyncSpy).not.toHaveBeenCalled();
20
+ expect(result).toEqual({ errors: {}, values: validData });
21
+ });
22
+
23
+ it('should return values from classValidatorResolver with `mode: sync` when validation pass', async () => {
24
+ const validateSyncSpy = jest.spyOn(classValidator, 'validateSync');
25
+ const validateSpy = jest.spyOn(classValidator, 'validate');
26
+
27
+ const result = await classValidatorResolver(Schema, undefined, {
28
+ mode: 'sync',
29
+ })(validData, undefined, { fields, shouldUseNativeValidation });
30
+
31
+ expect(validateSyncSpy).toHaveBeenCalledTimes(1);
32
+ expect(validateSpy).not.toHaveBeenCalled();
33
+ expect(result).toEqual({ errors: {}, values: validData });
34
+ });
35
+
36
+ it('should return a single error from classValidatorResolver when validation fails', async () => {
37
+ const result = await classValidatorResolver(Schema)(
38
+ invalidData,
39
+ undefined,
40
+ {
41
+ fields,
42
+ shouldUseNativeValidation,
43
+ },
44
+ );
45
+
46
+ expect(result).toMatchSnapshot();
47
+ });
48
+
49
+ it('should return a single error from classValidatorResolver with `mode: sync` when validation fails', async () => {
50
+ const validateSyncSpy = jest.spyOn(classValidator, 'validateSync');
51
+ const validateSpy = jest.spyOn(classValidator, 'validate');
52
+
53
+ const result = await classValidatorResolver(Schema, undefined, {
54
+ mode: 'sync',
55
+ })(invalidData, undefined, { fields, shouldUseNativeValidation });
56
+
57
+ expect(validateSyncSpy).toHaveBeenCalledTimes(1);
58
+ expect(validateSpy).not.toHaveBeenCalled();
59
+ expect(result).toMatchSnapshot();
60
+ });
61
+
62
+ it('should return all the errors from classValidatorResolver when validation fails with `validateAllFieldCriteria` set to true', async () => {
63
+ const result = await classValidatorResolver(Schema)(
64
+ invalidData,
65
+ undefined,
66
+ {
67
+ fields,
68
+ criteriaMode: 'all',
69
+ shouldUseNativeValidation,
70
+ },
71
+ );
72
+
73
+ expect(result).toMatchSnapshot();
74
+ });
75
+
76
+ it('should return all the errors from classValidatorResolver when validation fails with `validateAllFieldCriteria` set to true and `mode: sync`', async () => {
77
+ const result = await classValidatorResolver(Schema, undefined, {
78
+ mode: 'sync',
79
+ })(invalidData, undefined, {
80
+ fields,
81
+ criteriaMode: 'all',
82
+ shouldUseNativeValidation,
83
+ });
84
+
85
+ expect(result).toMatchSnapshot();
86
+ });
87
+ });
@@ -0,0 +1,62 @@
1
+ import { FieldErrors } from 'react-hook-form';
2
+ import { toNestError, validateFieldsNatively } from '@hookform/resolvers';
3
+ import { plainToClass } from 'class-transformer';
4
+ import { validate, validateSync, ValidationError } from 'class-validator';
5
+ import type { Resolver } from './types';
6
+
7
+ const parseErrors = (
8
+ errors: ValidationError[],
9
+ validateAllFieldCriteria: boolean,
10
+ parsedErrors: FieldErrors = {},
11
+ path = '',
12
+ ) => {
13
+ return errors.reduce((acc, error) => {
14
+ const _path = path ? `${path}.${error.property}` : error.property;
15
+
16
+ if (error.constraints) {
17
+ const key = Object.keys(error.constraints)[0];
18
+ acc[_path] = {
19
+ type: key,
20
+ message: error.constraints[key],
21
+ };
22
+
23
+ if (validateAllFieldCriteria && acc[_path]) {
24
+ Object.assign(acc[_path], { types: error.constraints });
25
+ }
26
+ }
27
+
28
+ if (error.children && error.children.length) {
29
+ parseErrors(error.children, validateAllFieldCriteria, acc, _path);
30
+ }
31
+
32
+ return acc;
33
+ }, parsedErrors);
34
+ };
35
+
36
+ export const classValidatorResolver: Resolver =
37
+ (schema, schemaOptions = {}, resolverOptions = {}) =>
38
+ async (values, _, options) => {
39
+ const user = plainToClass(schema, values);
40
+
41
+ const rawErrors = await (resolverOptions.mode === 'sync'
42
+ ? validateSync
43
+ : validate)(user, schemaOptions);
44
+
45
+ if (rawErrors.length) {
46
+ return {
47
+ values: {},
48
+ errors: toNestError(
49
+ parseErrors(
50
+ rawErrors,
51
+ !options.shouldUseNativeValidation &&
52
+ options.criteriaMode === 'all',
53
+ ),
54
+ options,
55
+ ),
56
+ };
57
+ }
58
+
59
+ options.shouldUseNativeValidation && validateFieldsNatively({}, options);
60
+
61
+ return { values, errors: {} };
62
+ };
@@ -0,0 +1,2 @@
1
+ export * from './class-validator';
2
+ export * from './types';
@@ -0,0 +1,22 @@
1
+ import {
2
+ FieldValues,
3
+ ResolverOptions,
4
+ ResolverResult,
5
+ UnpackNestedValue,
6
+ } from 'react-hook-form';
7
+ import { ValidatorOptions } from 'class-validator';
8
+ import { ClassConstructor } from 'class-transformer';
9
+
10
+ export type Resolver = <
11
+ T extends { [_: string]: any },
12
+ TFieldValues extends FieldValues,
13
+ TContext,
14
+ >(
15
+ schema: ClassConstructor<T>,
16
+ schemaOptions?: ValidatorOptions,
17
+ resolverOptions?: { mode?: 'async' | 'sync' },
18
+ ) => (
19
+ values: UnpackNestedValue<TFieldValues>,
20
+ context: TContext | undefined,
21
+ options: ResolverOptions<TFieldValues>,
22
+ ) => Promise<ResolverResult<TFieldValues>>;
@@ -0,0 +1,2 @@
1
+ import type { Resolver } from './types';
2
+ export declare const computedTypesResolver: Resolver;
@@ -0,0 +1,2 @@
1
+ var r=require("@hookform/resolvers"),e=function r(e,t,o){return void 0===t&&(t={}),void 0===o&&(o=""),(e.errors||[]).reduce(function(e,t){var n=String(t.path[0]),s=o?o+"."+n:n;return e[s]={type:t.error.name,message:t.error.message},r(t.error,e,s),e},t)};exports.computedTypesResolver=function(t){return function(o,n,s){try{return Promise.resolve(function(e,n){try{var u=Promise.resolve(t(o)).then(function(e){return s.shouldUseNativeValidation&&r.validateFieldsNatively({},s),{errors:{},values:e}})}catch(r){return n(r)}return u&&u.then?u.then(void 0,n):u}(0,function(t){return{values:{},errors:r.toNestError(e(t),s)}}))}catch(r){return Promise.reject(r)}}};
2
+ //# sourceMappingURL=computed-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed-types.js","sources":["../src/computed-types.ts"],"sourcesContent":["import type { FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationError } from 'computed-types';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n computedTypesError: ValidationError,\n parsedErrors: FieldErrors = {},\n path = '',\n) => {\n return (computedTypesError.errors || []).reduce((acc, error) => {\n const _currentPath = String(error.path[0]);\n const _path = path ? `${path}.${_currentPath}` : _currentPath;\n\n acc[_path] = {\n type: error.error.name,\n message: error.error.message,\n };\n\n parseErrorSchema(error.error, acc, _path);\n\n return acc;\n }, parsedErrors);\n};\n\nexport const computedTypesResolver: Resolver =\n (schema) => async (values, _, options) => {\n try {\n const data = await schema(values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n errors: {},\n values: data,\n };\n } catch (error) {\n return {\n values: {},\n errors: toNestError(parseErrorSchema(error), options),\n };\n }\n };\n"],"names":["parseErrorSchema","computedTypesError","parsedErrors","path","errors","reduce","acc","error","_currentPath","String","_path","type","name","message","schema","values","_","options","data","shouldUseNativeValidation","validateFieldsNatively","toNestError"],"mappings":"qCAKMA,EAAmB,SAAnBA,EACJC,EACAC,EACAC,GAEA,gBAHAD,IAAAA,EAA4B,aAC5BC,IAAAA,EAAO,KAECF,EAAmBG,QAAU,IAAIC,OAAO,SAACC,EAAKC,GACpD,IAAMC,EAAeC,OAAOF,EAAMJ,KAAK,IACjCO,EAAQP,EAAUA,MAAQK,EAAiBA,EASjD,OAPAF,EAAII,GAAS,CACXC,KAAMJ,EAAMA,MAAMK,KAClBC,QAASN,EAAMA,MAAMM,SAGvBb,EAAiBO,EAAMA,MAAOD,EAAKI,GAE5BJ,GACNJ,kCAIH,SAACY,mBAAkBC,EAAQC,EAAGC,sEAEPH,EAAOC,kBAApBG,GAIN,OAFAD,EAAQE,2BAA6BC,yBAAuB,GAAIH,GAEzD,CACLb,OAAQ,GACRW,OAAQG,0EAEHX,GACP,MAAO,CACLQ,OAAQ,GACRX,OAAQiB,cAAYrB,EAAiBO,GAAQU,OAbnD"}
@@ -0,0 +1,2 @@
1
+ import{validateFieldsNatively as r,toNestError as e}from"@hookform/resolvers";var t=function r(e,t,o){return void 0===t&&(t={}),void 0===o&&(o=""),(e.errors||[]).reduce(function(e,t){var n=String(t.path[0]),u=o?o+"."+n:n;return e[u]={type:t.error.name,message:t.error.message},r(t.error,e,u),e},t)},o=function(o){return function(n,u,i){try{return Promise.resolve(function(e,t){try{var u=Promise.resolve(o(n)).then(function(e){return i.shouldUseNativeValidation&&r({},i),{errors:{},values:e}})}catch(r){return t(r)}return u&&u.then?u.then(void 0,t):u}(0,function(r){return{values:{},errors:e(t(r),i)}}))}catch(r){return Promise.reject(r)}}};export{o as computedTypesResolver};
2
+ //# sourceMappingURL=computed-types.module.js.map
@@ -0,0 +1,2 @@
1
+ import{validateFieldsNatively as r,toNestError as e}from"@hookform/resolvers";const o=(r,e={},s="")=>(r.errors||[]).reduce((r,e)=>{const t=String(e.path[0]),a=s?`${s}.${t}`:t;return r[a]={type:e.error.name,message:e.error.message},o(e.error,r,a),r},e),s=s=>async(t,a,n)=>{try{const e=await s(t);return n.shouldUseNativeValidation&&r({},n),{errors:{},values:e}}catch(r){return{values:{},errors:e(o(r),n)}}};export{s as computedTypesResolver};
2
+ //# sourceMappingURL=computed-types.modern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed-types.modern.js","sources":["../src/computed-types.ts"],"sourcesContent":["import type { FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationError } from 'computed-types';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n computedTypesError: ValidationError,\n parsedErrors: FieldErrors = {},\n path = '',\n) => {\n return (computedTypesError.errors || []).reduce((acc, error) => {\n const _currentPath = String(error.path[0]);\n const _path = path ? `${path}.${_currentPath}` : _currentPath;\n\n acc[_path] = {\n type: error.error.name,\n message: error.error.message,\n };\n\n parseErrorSchema(error.error, acc, _path);\n\n return acc;\n }, parsedErrors);\n};\n\nexport const computedTypesResolver: Resolver =\n (schema) => async (values, _, options) => {\n try {\n const data = await schema(values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n errors: {},\n values: data,\n };\n } catch (error) {\n return {\n values: {},\n errors: toNestError(parseErrorSchema(error), options),\n };\n }\n };\n"],"names":["parseErrorSchema","computedTypesError","parsedErrors","path","errors","reduce","acc","error","_currentPath","String","_path","type","name","message","computedTypesResolver","schema","async","values","_","options","data","shouldUseNativeValidation","validateFieldsNatively","toNestError"],"mappings":"8EAKA,MAAMA,EAAmB,CACvBC,EACAC,EAA4B,GAC5BC,EAAO,MAECF,EAAmBG,QAAU,IAAIC,OAAO,CAACC,EAAKC,KACpD,MAAMC,EAAeC,OAAOF,EAAMJ,KAAK,IACjCO,EAAQP,KAAUA,KAAQK,IAAiBA,EASjD,OAPAF,EAAII,GAAS,CACXC,KAAMJ,EAAMA,MAAMK,KAClBC,QAASN,EAAMA,MAAMM,SAGvBb,EAAiBO,EAAMA,MAAOD,EAAKI,GAE5BJ,GACNJ,GAGQY,EACVC,GAAWC,MAAOC,EAAQC,EAAGC,KAC5B,IACE,MAAMC,QAAaL,EAAOE,GAI1B,OAFAE,EAAQE,2BAA6BC,EAAuB,GAAIH,GAEzD,CACLf,OAAQ,GACRa,OAAQG,GAEV,MAAOb,GACP,MAAO,CACLU,OAAQ,GACRb,OAAQmB,EAAYvB,EAAiBO,GAAQY"}
@@ -0,0 +1,2 @@
1
+ import{validateFieldsNatively as r,toNestError as e}from"@hookform/resolvers";var t=function r(e,t,o){return void 0===t&&(t={}),void 0===o&&(o=""),(e.errors||[]).reduce(function(e,t){var n=String(t.path[0]),u=o?o+"."+n:n;return e[u]={type:t.error.name,message:t.error.message},r(t.error,e,u),e},t)},o=function(o){return function(n,u,i){try{return Promise.resolve(function(e,t){try{var u=Promise.resolve(o(n)).then(function(e){return i.shouldUseNativeValidation&&r({},i),{errors:{},values:e}})}catch(r){return t(r)}return u&&u.then?u.then(void 0,t):u}(0,function(r){return{values:{},errors:e(t(r),i)}}))}catch(r){return Promise.reject(r)}}};export{o as computedTypesResolver};
2
+ //# sourceMappingURL=computed-types.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed-types.module.js","sources":["../src/computed-types.ts"],"sourcesContent":["import type { FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationError } from 'computed-types';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n computedTypesError: ValidationError,\n parsedErrors: FieldErrors = {},\n path = '',\n) => {\n return (computedTypesError.errors || []).reduce((acc, error) => {\n const _currentPath = String(error.path[0]);\n const _path = path ? `${path}.${_currentPath}` : _currentPath;\n\n acc[_path] = {\n type: error.error.name,\n message: error.error.message,\n };\n\n parseErrorSchema(error.error, acc, _path);\n\n return acc;\n }, parsedErrors);\n};\n\nexport const computedTypesResolver: Resolver =\n (schema) => async (values, _, options) => {\n try {\n const data = await schema(values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n errors: {},\n values: data,\n };\n } catch (error) {\n return {\n values: {},\n errors: toNestError(parseErrorSchema(error), options),\n };\n }\n };\n"],"names":["parseErrorSchema","computedTypesError","parsedErrors","path","errors","reduce","acc","error","_currentPath","String","_path","type","name","message","computedTypesResolver","schema","values","_","options","data","shouldUseNativeValidation","validateFieldsNatively","toNestError"],"mappings":"8EAKA,IAAMA,EAAmB,SAAnBA,EACJC,EACAC,EACAC,GAEA,gBAHAD,IAAAA,EAA4B,aAC5BC,IAAAA,EAAO,KAECF,EAAmBG,QAAU,IAAIC,OAAO,SAACC,EAAKC,GACpD,IAAMC,EAAeC,OAAOF,EAAMJ,KAAK,IACjCO,EAAQP,EAAUA,MAAQK,EAAiBA,EASjD,OAPAF,EAAII,GAAS,CACXC,KAAMJ,EAAMA,MAAMK,KAClBC,QAASN,EAAMA,MAAMM,SAGvBb,EAAiBO,EAAMA,MAAOD,EAAKI,GAE5BJ,GACNJ,IAGQY,EACX,SAACC,mBAAkBC,EAAQC,EAAGC,sEAEPH,EAAOC,kBAApBG,GAIN,OAFAD,EAAQE,2BAA6BC,EAAuB,GAAIH,GAEzD,CACLd,OAAQ,GACRY,OAAQG,0EAEHZ,GACP,MAAO,CACLS,OAAQ,GACRZ,OAAQkB,EAAYtB,EAAiBO,GAAQW,OAbnD"}
@@ -0,0 +1,2 @@
1
+ !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("@hookform/resolvers")):"function"==typeof define&&define.amd?define(["exports","@hookform/resolvers"],r):r((e||self).hookformResolversComputedTypes={},e.hookformResolvers)}(this,function(e,r){var o=function e(r,o,t){return void 0===o&&(o={}),void 0===t&&(t=""),(r.errors||[]).reduce(function(r,o){var n=String(o.path[0]),s=t?t+"."+n:n;return r[s]={type:o.error.name,message:o.error.message},e(o.error,r,s),r},o)};e.computedTypesResolver=function(e){return function(t,n,s){try{return Promise.resolve(function(o,n){try{var i=Promise.resolve(e(t)).then(function(e){return s.shouldUseNativeValidation&&r.validateFieldsNatively({},s),{errors:{},values:e}})}catch(e){return n(e)}return i&&i.then?i.then(void 0,n):i}(0,function(e){return{values:{},errors:r.toNestError(o(e),s)}}))}catch(e){return Promise.reject(e)}}}});
2
+ //# sourceMappingURL=computed-types.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed-types.umd.js","sources":["../src/computed-types.ts"],"sourcesContent":["import type { FieldErrors } from 'react-hook-form';\nimport { toNestError, validateFieldsNatively } from '@hookform/resolvers';\nimport type { ValidationError } from 'computed-types';\nimport type { Resolver } from './types';\n\nconst parseErrorSchema = (\n computedTypesError: ValidationError,\n parsedErrors: FieldErrors = {},\n path = '',\n) => {\n return (computedTypesError.errors || []).reduce((acc, error) => {\n const _currentPath = String(error.path[0]);\n const _path = path ? `${path}.${_currentPath}` : _currentPath;\n\n acc[_path] = {\n type: error.error.name,\n message: error.error.message,\n };\n\n parseErrorSchema(error.error, acc, _path);\n\n return acc;\n }, parsedErrors);\n};\n\nexport const computedTypesResolver: Resolver =\n (schema) => async (values, _, options) => {\n try {\n const data = await schema(values);\n\n options.shouldUseNativeValidation && validateFieldsNatively({}, options);\n\n return {\n errors: {},\n values: data,\n };\n } catch (error) {\n return {\n values: {},\n errors: toNestError(parseErrorSchema(error), options),\n };\n }\n };\n"],"names":["parseErrorSchema","computedTypesError","parsedErrors","path","errors","reduce","acc","error","_currentPath","String","_path","type","name","message","schema","values","_","options","data","shouldUseNativeValidation","validateFieldsNatively","toNestError"],"mappings":"mUAKA,IAAMA,EAAmB,SAAnBA,EACJC,EACAC,EACAC,GAEA,gBAHAD,IAAAA,EAA4B,aAC5BC,IAAAA,EAAO,KAECF,EAAmBG,QAAU,IAAIC,OAAO,SAACC,EAAKC,GACpD,IAAMC,EAAeC,OAAOF,EAAMJ,KAAK,IACjCO,EAAQP,EAAUA,MAAQK,EAAiBA,EASjD,OAPAF,EAAII,GAAS,CACXC,KAAMJ,EAAMA,MAAMK,KAClBC,QAASN,EAAMA,MAAMM,SAGvBb,EAAiBO,EAAMA,MAAOD,EAAKI,GAE5BJ,GACNJ,4BAIH,SAACY,mBAAkBC,EAAQC,EAAGC,sEAEPH,EAAOC,kBAApBG,GAIN,OAFAD,EAAQE,2BAA6BC,yBAAuB,GAAIH,GAEzD,CACLb,OAAQ,GACRW,OAAQG,0EAEHX,GACP,MAAO,CACLQ,OAAQ,GACRX,OAAQiB,cAAYrB,EAAiBO,GAAQU,OAbnD"}
@@ -0,0 +1,2 @@
1
+ export * from './computed-types';
2
+ export * from './types';
@@ -0,0 +1,2 @@
1
+ import type { FieldValues, ResolverResult, UnpackNestedValue, ResolverOptions } from 'react-hook-form';
2
+ export declare type Resolver = (schema: any) => <TFieldValues extends FieldValues, TContext>(values: UnpackNestedValue<TFieldValues>, context: TContext | undefined, options: ResolverOptions<TFieldValues>) => Promise<ResolverResult<TFieldValues>>;
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "computed-types",
3
+ "amdName": "hookformResolversComputedTypes",
4
+ "version": "1.0.0",
5
+ "private": true,
6
+ "description": "React Hook Form validation resolver: computed-types",
7
+ "main": "dist/computed-types.js",
8
+ "module": "dist/computed-types.module.js",
9
+ "umd:main": "dist/computed-types.umd.js",
10
+ "source": "src/index.ts",
11
+ "types": "dist/index.d.ts",
12
+ "license": "MIT",
13
+ "peerDependencies": {
14
+ "react-hook-form": "^7.0.0",
15
+ "@hookform/resolvers": "^2.0.0"
16
+ }
17
+ }