@hookform/resolvers 6.0.1 → 7.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.
@@ -4,69 +4,69 @@ exports[`typeboxResolver (with compiler) > should return a single error from typ
4
4
  {
5
5
  "errors": {
6
6
  "accessToken": {
7
- "message": "Expected required property",
7
+ "message": "must have required properties accessToken",
8
8
  "ref": undefined,
9
- "type": "45",
9
+ "type": "required",
10
10
  },
11
11
  "birthYear": {
12
- "message": "Expected number",
12
+ "message": "must be number",
13
13
  "ref": undefined,
14
- "type": "41",
14
+ "type": "type",
15
15
  },
16
16
  "dateStr": {
17
- "message": "Expected required property",
17
+ "message": "must have required properties dateStr",
18
18
  "ref": undefined,
19
- "type": "45",
19
+ "type": "required",
20
20
  },
21
21
  "email": {
22
- "message": "Expected string to match regular expression",
22
+ "message": "must match format "email"",
23
23
  "ref": {
24
24
  "name": "email",
25
25
  },
26
- "type": "48",
26
+ "type": "format",
27
27
  },
28
28
  "enabled": {
29
- "message": "Expected required property",
29
+ "message": "must have required properties enabled",
30
30
  "ref": undefined,
31
- "type": "45",
31
+ "type": "required",
32
32
  },
33
33
  "like": [
34
34
  {
35
35
  "id": {
36
- "message": "Expected number",
36
+ "message": "must be number",
37
37
  "ref": undefined,
38
- "type": "41",
38
+ "type": "type",
39
39
  },
40
40
  "name": {
41
- "message": "Expected required property",
41
+ "message": "must have required properties name",
42
42
  "ref": undefined,
43
- "type": "45",
43
+ "type": "required",
44
44
  },
45
45
  },
46
46
  ],
47
47
  "password": {
48
- "message": "Expected string length greater or equal to 8",
48
+ "message": "must not have fewer than 8 characters",
49
49
  "ref": {
50
50
  "name": "password",
51
51
  },
52
- "type": "52",
52
+ "type": "minLength",
53
53
  },
54
54
  "repeatPassword": {
55
- "message": "Expected required property",
55
+ "message": "must have required properties repeatPassword",
56
56
  "ref": undefined,
57
- "type": "45",
57
+ "type": "required",
58
58
  },
59
59
  "tags": {
60
- "message": "Expected required property",
60
+ "message": "must have required properties tags",
61
61
  "ref": undefined,
62
- "type": "45",
62
+ "type": "required",
63
63
  },
64
64
  "username": {
65
- "message": "Expected required property",
65
+ "message": "must have required properties username",
66
66
  "ref": {
67
67
  "name": "username",
68
68
  },
69
- "type": "45",
69
+ "type": "required",
70
70
  },
71
71
  },
72
72
  "values": {},
@@ -77,109 +77,102 @@ exports[`typeboxResolver (with compiler) > should return all the errors from typ
77
77
  {
78
78
  "errors": {
79
79
  "accessToken": {
80
- "message": "Expected required property",
80
+ "message": "must have required properties accessToken",
81
81
  "ref": undefined,
82
- "type": "45",
82
+ "type": "required",
83
83
  "types": {
84
- "45": "Expected required property",
85
- "62": "Expected union value",
84
+ "required": "must have required properties accessToken",
86
85
  },
87
86
  },
88
87
  "birthYear": {
89
- "message": "Expected number",
88
+ "message": "must be number",
90
89
  "ref": undefined,
91
- "type": "41",
90
+ "type": "type",
92
91
  "types": {
93
- "41": "Expected number",
92
+ "type": "must be number",
94
93
  },
95
94
  },
96
95
  "dateStr": {
97
- "message": "Expected required property",
96
+ "message": "must have required properties dateStr",
98
97
  "ref": undefined,
99
- "type": "45",
98
+ "type": "required",
100
99
  "types": {
101
- "20": "Expected Date",
102
- "45": "Expected required property",
100
+ "required": "must have required properties dateStr",
103
101
  },
104
102
  },
105
103
  "email": {
106
- "message": "Expected string to match regular expression",
104
+ "message": "must match format "email"",
107
105
  "ref": {
108
106
  "name": "email",
109
107
  },
110
- "type": "48",
108
+ "type": "format",
111
109
  "types": {
112
- "48": "Expected string to match regular expression",
110
+ "format": "must match format "email"",
113
111
  },
114
112
  },
115
113
  "enabled": {
116
- "message": "Expected required property",
114
+ "message": "must have required properties enabled",
117
115
  "ref": undefined,
118
- "type": "45",
116
+ "type": "required",
119
117
  "types": {
120
- "14": "Expected boolean",
121
- "45": "Expected required property",
118
+ "required": "must have required properties enabled",
122
119
  },
123
120
  },
124
121
  "like": [
125
122
  {
126
123
  "id": {
127
- "message": "Expected number",
124
+ "message": "must be number",
128
125
  "ref": undefined,
129
- "type": "41",
126
+ "type": "type",
130
127
  "types": {
131
- "41": "Expected number",
128
+ "type": "must be number",
132
129
  },
133
130
  },
134
131
  "name": {
135
- "message": "Expected required property",
132
+ "message": "must have required properties name",
136
133
  "ref": undefined,
137
- "type": "45",
134
+ "type": "required",
138
135
  "types": {
139
- "45": "Expected required property",
140
- "54": "Expected string",
136
+ "required": "must have required properties name",
141
137
  },
142
138
  },
143
139
  },
144
140
  ],
145
141
  "password": {
146
- "message": "Expected string length greater or equal to 8",
142
+ "message": "must not have fewer than 8 characters",
147
143
  "ref": {
148
144
  "name": "password",
149
145
  },
150
- "type": "52",
146
+ "type": "minLength",
151
147
  "types": {
152
- "52": "Expected string length greater or equal to 8",
153
- "53": "Expected string to match '^(.*[A-Za-z\\d].*)$'",
148
+ "minLength": "must not have fewer than 8 characters",
149
+ "pattern": "must match pattern "^(.*[A-Za-z\\d].*)$"",
154
150
  },
155
151
  },
156
152
  "repeatPassword": {
157
- "message": "Expected required property",
153
+ "message": "must have required properties repeatPassword",
158
154
  "ref": undefined,
159
- "type": "45",
155
+ "type": "required",
160
156
  "types": {
161
- "45": "Expected required property",
162
- "54": "Expected string",
157
+ "required": "must have required properties repeatPassword",
163
158
  },
164
159
  },
165
160
  "tags": {
166
- "message": "Expected required property",
161
+ "message": "must have required properties tags",
167
162
  "ref": undefined,
168
- "type": "45",
163
+ "type": "required",
169
164
  "types": {
170
- "45": "Expected required property",
171
- "6": "Expected array",
165
+ "required": "must have required properties tags",
172
166
  },
173
167
  },
174
168
  "username": {
175
- "message": "Expected required property",
169
+ "message": "must have required properties username",
176
170
  "ref": {
177
171
  "name": "username",
178
172
  },
179
- "type": "45",
173
+ "type": "required",
180
174
  "types": {
181
- "45": "Expected required property",
182
- "54": "Expected string",
175
+ "required": "must have required properties username",
183
176
  },
184
177
  },
185
178
  },
@@ -4,69 +4,69 @@ exports[`typeboxResolver > should return a single error from typeboxResolver whe
4
4
  {
5
5
  "errors": {
6
6
  "accessToken": {
7
- "message": "Expected required property",
7
+ "message": "must have required properties accessToken",
8
8
  "ref": undefined,
9
- "type": "45",
9
+ "type": "required",
10
10
  },
11
11
  "birthYear": {
12
- "message": "Expected number",
12
+ "message": "must be number",
13
13
  "ref": undefined,
14
- "type": "41",
14
+ "type": "type",
15
15
  },
16
16
  "dateStr": {
17
- "message": "Expected required property",
17
+ "message": "must have required properties dateStr",
18
18
  "ref": undefined,
19
- "type": "45",
19
+ "type": "required",
20
20
  },
21
21
  "email": {
22
- "message": "Expected string to match regular expression",
22
+ "message": "must match format "email"",
23
23
  "ref": {
24
24
  "name": "email",
25
25
  },
26
- "type": "48",
26
+ "type": "format",
27
27
  },
28
28
  "enabled": {
29
- "message": "Expected required property",
29
+ "message": "must have required properties enabled",
30
30
  "ref": undefined,
31
- "type": "45",
31
+ "type": "required",
32
32
  },
33
33
  "like": [
34
34
  {
35
35
  "id": {
36
- "message": "Expected number",
36
+ "message": "must be number",
37
37
  "ref": undefined,
38
- "type": "41",
38
+ "type": "type",
39
39
  },
40
40
  "name": {
41
- "message": "Expected required property",
41
+ "message": "must have required properties name",
42
42
  "ref": undefined,
43
- "type": "45",
43
+ "type": "required",
44
44
  },
45
45
  },
46
46
  ],
47
47
  "password": {
48
- "message": "Expected string length greater or equal to 8",
48
+ "message": "must not have fewer than 8 characters",
49
49
  "ref": {
50
50
  "name": "password",
51
51
  },
52
- "type": "52",
52
+ "type": "minLength",
53
53
  },
54
54
  "repeatPassword": {
55
- "message": "Expected required property",
55
+ "message": "must have required properties repeatPassword",
56
56
  "ref": undefined,
57
- "type": "45",
57
+ "type": "required",
58
58
  },
59
59
  "tags": {
60
- "message": "Expected required property",
60
+ "message": "must have required properties tags",
61
61
  "ref": undefined,
62
- "type": "45",
62
+ "type": "required",
63
63
  },
64
64
  "username": {
65
- "message": "Expected required property",
65
+ "message": "must have required properties username",
66
66
  "ref": {
67
67
  "name": "username",
68
68
  },
69
- "type": "45",
69
+ "type": "required",
70
70
  },
71
71
  },
72
72
  "values": {},
@@ -77,109 +77,102 @@ exports[`typeboxResolver > should return all the errors from typeboxResolver whe
77
77
  {
78
78
  "errors": {
79
79
  "accessToken": {
80
- "message": "Expected required property",
80
+ "message": "must have required properties accessToken",
81
81
  "ref": undefined,
82
- "type": "45",
82
+ "type": "required",
83
83
  "types": {
84
- "45": "Expected required property",
85
- "62": "Expected union value",
84
+ "required": "must have required properties accessToken",
86
85
  },
87
86
  },
88
87
  "birthYear": {
89
- "message": "Expected number",
88
+ "message": "must be number",
90
89
  "ref": undefined,
91
- "type": "41",
90
+ "type": "type",
92
91
  "types": {
93
- "41": "Expected number",
92
+ "type": "must be number",
94
93
  },
95
94
  },
96
95
  "dateStr": {
97
- "message": "Expected required property",
96
+ "message": "must have required properties dateStr",
98
97
  "ref": undefined,
99
- "type": "45",
98
+ "type": "required",
100
99
  "types": {
101
- "20": "Expected Date",
102
- "45": "Expected required property",
100
+ "required": "must have required properties dateStr",
103
101
  },
104
102
  },
105
103
  "email": {
106
- "message": "Expected string to match regular expression",
104
+ "message": "must match format "email"",
107
105
  "ref": {
108
106
  "name": "email",
109
107
  },
110
- "type": "48",
108
+ "type": "format",
111
109
  "types": {
112
- "48": "Expected string to match regular expression",
110
+ "format": "must match format "email"",
113
111
  },
114
112
  },
115
113
  "enabled": {
116
- "message": "Expected required property",
114
+ "message": "must have required properties enabled",
117
115
  "ref": undefined,
118
- "type": "45",
116
+ "type": "required",
119
117
  "types": {
120
- "14": "Expected boolean",
121
- "45": "Expected required property",
118
+ "required": "must have required properties enabled",
122
119
  },
123
120
  },
124
121
  "like": [
125
122
  {
126
123
  "id": {
127
- "message": "Expected number",
124
+ "message": "must be number",
128
125
  "ref": undefined,
129
- "type": "41",
126
+ "type": "type",
130
127
  "types": {
131
- "41": "Expected number",
128
+ "type": "must be number",
132
129
  },
133
130
  },
134
131
  "name": {
135
- "message": "Expected required property",
132
+ "message": "must have required properties name",
136
133
  "ref": undefined,
137
- "type": "45",
134
+ "type": "required",
138
135
  "types": {
139
- "45": "Expected required property",
140
- "54": "Expected string",
136
+ "required": "must have required properties name",
141
137
  },
142
138
  },
143
139
  },
144
140
  ],
145
141
  "password": {
146
- "message": "Expected string length greater or equal to 8",
142
+ "message": "must not have fewer than 8 characters",
147
143
  "ref": {
148
144
  "name": "password",
149
145
  },
150
- "type": "52",
146
+ "type": "minLength",
151
147
  "types": {
152
- "52": "Expected string length greater or equal to 8",
153
- "53": "Expected string to match '^(.*[A-Za-z\\d].*)$'",
148
+ "minLength": "must not have fewer than 8 characters",
149
+ "pattern": "must match pattern "^(.*[A-Za-z\\d].*)$"",
154
150
  },
155
151
  },
156
152
  "repeatPassword": {
157
- "message": "Expected required property",
153
+ "message": "must have required properties repeatPassword",
158
154
  "ref": undefined,
159
- "type": "45",
155
+ "type": "required",
160
156
  "types": {
161
- "45": "Expected required property",
162
- "54": "Expected string",
157
+ "required": "must have required properties repeatPassword",
163
158
  },
164
159
  },
165
160
  "tags": {
166
- "message": "Expected required property",
161
+ "message": "must have required properties tags",
167
162
  "ref": undefined,
168
- "type": "45",
163
+ "type": "required",
169
164
  "types": {
170
- "45": "Expected required property",
171
- "6": "Expected array",
165
+ "required": "must have required properties tags",
172
166
  },
173
167
  },
174
168
  "username": {
175
- "message": "Expected required property",
169
+ "message": "must have required properties username",
176
170
  "ref": {
177
171
  "name": "username",
178
172
  },
179
- "type": "45",
173
+ "type": "required",
180
174
  "types": {
181
- "45": "Expected required property",
182
- "54": "Expected string",
175
+ "required": "must have required properties username",
183
176
  },
184
177
  },
185
178
  },
@@ -1,19 +1,150 @@
1
- import { Type } from '@sinclair/typebox';
1
+ import { createFormControl } from 'react-hook-form';
2
+ import { Type } from 'typebox';
3
+ import { Compile } from 'typebox/compile';
2
4
  import { typeboxResolver } from '..';
3
5
 
4
6
  const shouldUseNativeValidation = false;
5
7
 
8
+ describe.each([false, true])('typeboxResolver with compiler=%s', (compiled) => {
9
+ it.each(
10
+ ['a/b', 'a~b', 'a~1b'].flatMap((name) =>
11
+ (['firstError', 'all'] as const).map((criteriaMode) => ({
12
+ name,
13
+ criteriaMode,
14
+ })),
15
+ ),
16
+ )(
17
+ 'preserves $name with criteriaMode=$criteriaMode',
18
+ async ({ name, criteriaMode }) => {
19
+ const schema = Type.Object({ [name]: Type.String({ minLength: 1 }) });
20
+ const ref = { name };
21
+ const type = 'minLength';
22
+ const message = 'must not have fewer than 1 characters';
23
+ const result = await typeboxResolver(compiled ? Compile(schema) : schema)(
24
+ { [name]: '' },
25
+ undefined,
26
+ {
27
+ fields: { [name]: { name, ref } },
28
+ criteriaMode,
29
+ shouldUseNativeValidation,
30
+ },
31
+ );
32
+
33
+ expect(result).toEqual({
34
+ values: {},
35
+ errors: {
36
+ [name]: {
37
+ type,
38
+ message,
39
+ ref,
40
+ ...(criteriaMode === 'all' ? { types: { [type]: message } } : {}),
41
+ },
42
+ },
43
+ });
44
+ expect(result.errors[name]?.ref).toBe(ref);
45
+ },
46
+ );
47
+
48
+ it('preserves escaped array paths and all error messages', async () => {
49
+ const schema = Type.Object({
50
+ 'parent/~1': Type.Array(
51
+ Type.Object({
52
+ 'a~1/b': Type.String({ minLength: 1, pattern: '^a' }),
53
+ }),
54
+ ),
55
+ });
56
+ const name = 'parent/~1.0.a~1/b';
57
+ const ref = { name };
58
+ const type = 'minLength';
59
+ const message = 'must not have fewer than 1 characters';
60
+ const result = await typeboxResolver(compiled ? Compile(schema) : schema)(
61
+ { 'parent/~1': [{ 'a~1/b': '' }] },
62
+ undefined,
63
+ {
64
+ names: [name],
65
+ fields: { [name]: { name, ref } },
66
+ criteriaMode: 'all',
67
+ shouldUseNativeValidation,
68
+ },
69
+ );
70
+
71
+ expect(result.errors).toEqual({
72
+ 'parent/~1': [
73
+ {
74
+ 'a~1/b': {
75
+ type,
76
+ message,
77
+ types: {
78
+ [type]: message,
79
+ pattern: 'must match pattern "^a"',
80
+ },
81
+ ref,
82
+ },
83
+ },
84
+ ],
85
+ });
86
+ expect(result.errors['parent/~1']?.[0]?.['a~1/b']?.ref).toBe(ref);
87
+ });
88
+
89
+ it('reports each missing required property at its own escaped path', async () => {
90
+ const schema = Type.Object({
91
+ nested: Type.Object({
92
+ 'a/b': Type.String(),
93
+ 'c~d': Type.String(),
94
+ }),
95
+ });
96
+ const result = await typeboxResolver(compiled ? Compile(schema) : schema)(
97
+ { nested: {} } as any,
98
+ undefined,
99
+ { fields: {}, shouldUseNativeValidation },
100
+ );
101
+
102
+ expect(result.errors).toEqual({
103
+ nested: {
104
+ 'a/b': {
105
+ type: 'required',
106
+ message: 'must have required properties a/b',
107
+ ref: undefined,
108
+ },
109
+ 'c~d': {
110
+ type: 'required',
111
+ message: 'must have required properties c~d',
112
+ ref: undefined,
113
+ },
114
+ },
115
+ });
116
+ });
117
+
118
+ it('fails field validation for a registered escaped name', async () => {
119
+ const schema = Type.Object({
120
+ 'profile/name': Type.String({ minLength: 1 }),
121
+ });
122
+ const form = createFormControl({
123
+ defaultValues: { 'profile/name': '' },
124
+ resolver: typeboxResolver(compiled ? Compile(schema) : schema),
125
+ });
126
+ form.register('profile/name');
127
+
128
+ expect(await form.trigger('profile/name')).toBe(false);
129
+ expect(form.getFieldState('profile/name').invalid).toBe(true);
130
+
131
+ form.setValue('profile/name', 'Alice');
132
+
133
+ expect(await form.trigger('profile/name')).toBe(true);
134
+ expect(form.getFieldState('profile/name').invalid).toBe(false);
135
+ });
136
+ });
137
+
6
138
  describe('typeboxResolver special path names', () => {
7
139
  it.each(['hasOwnProperty', 'toString'])(
8
140
  'reports a validation error for a field named "%s"',
9
141
  async (name) => {
10
142
  const schema = Type.Object({ [name]: Type.String({ minLength: 1 }) });
11
143
 
12
- const result = await typeboxResolver(schema as any)(
13
- { [name]: '' } as any,
14
- undefined,
15
- { fields: {}, shouldUseNativeValidation } as any,
16
- );
144
+ const result = await typeboxResolver(schema)({ [name]: '' }, undefined, {
145
+ fields: {},
146
+ shouldUseNativeValidation,
147
+ });
17
148
 
18
149
  expect(result.errors[name]).toBeDefined();
19
150
  },
@@ -1,11 +1,11 @@
1
- import { TypeCompiler } from '@sinclair/typebox/compiler';
1
+ import { Compile } from 'typebox/compile';
2
2
  import { typeboxResolver } from '..';
3
3
  import { fields, invalidData, schema, validData } from './__fixtures__/data';
4
4
 
5
5
  const shouldUseNativeValidation = false;
6
6
 
7
7
  describe('typeboxResolver (with compiler)', () => {
8
- const typecheck = TypeCompiler.Compile(schema);
8
+ const typecheck = Compile(schema);
9
9
 
10
10
  it('should return a single error from typeboxResolver when validation fails', async () => {
11
11
  const result = await typeboxResolver(typecheck)(invalidData, undefined, {