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