Skip to content

Commit 5030a59

Browse files
authored
feat(ajv): Keep original validation type while using errorMessage (#728)
BREAKING CHANGE: The AJV Resolver now unwraps the `errorMessage` object to return the original error types. This update may introduce breaking changes to your projects.
1 parent 985c48d commit 5030a59

File tree

6 files changed

+946
-20
lines changed

6 files changed

+946
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import { JSONSchemaType } from 'ajv';
2+
import { Field, InternalFieldName } from 'react-hook-form';
3+
4+
interface DataA {
5+
username: string;
6+
password: string;
7+
}
8+
9+
export const schemaA: JSONSchemaType<DataA> = {
10+
type: 'object',
11+
properties: {
12+
username: {
13+
type: 'string',
14+
minLength: 3,
15+
errorMessage: {
16+
minLength: 'username should be at least three characters long',
17+
},
18+
},
19+
password: {
20+
type: 'string',
21+
pattern: '.*[A-Z].*',
22+
minLength: 8,
23+
errorMessage: {
24+
pattern: 'One uppercase character',
25+
minLength: 'passwords should be at least eight characters long',
26+
},
27+
},
28+
},
29+
required: ['username', 'password'],
30+
additionalProperties: false,
31+
errorMessage: {
32+
required: {
33+
username: 'username field is required',
34+
password: 'password field is required',
35+
},
36+
},
37+
};
38+
39+
export const validDataA: DataA = {
40+
username: 'kt666',
41+
password: 'validPassword',
42+
};
43+
44+
export const invalidDataA = {
45+
username: 'kt',
46+
password: 'invalid',
47+
};
48+
49+
export const undefinedDataA = {
50+
username: undefined,
51+
password: undefined,
52+
};
53+
54+
export const fieldsA: Record<InternalFieldName, Field['_f']> = {
55+
username: {
56+
ref: { name: 'username' },
57+
name: 'username',
58+
},
59+
password: {
60+
ref: { name: 'password' },
61+
name: 'password',
62+
},
63+
email: {
64+
ref: { name: 'email' },
65+
name: 'email',
66+
},
67+
birthday: {
68+
ref: { name: 'birthday' },
69+
name: 'birthday',
70+
},
71+
};
72+
73+
// examples from [ajv-errors](https://github.com/ajv-validator/ajv-errors)
74+
75+
interface DataB {
76+
foo: number;
77+
}
78+
79+
export const schemaB: JSONSchemaType<DataB> = {
80+
type: 'object',
81+
required: ['foo'],
82+
properties: {
83+
foo: { type: 'integer' },
84+
},
85+
additionalProperties: false,
86+
errorMessage: 'should be an object with an integer property foo only',
87+
};
88+
89+
export const validDataB: DataB = { foo: 666 };
90+
export const invalidDataB = { foo: 'kt', bar: 6 };
91+
export const undefinedDataB = { foo: undefined };
92+
93+
interface DataC {
94+
foo: number;
95+
}
96+
97+
export const schemaC: JSONSchemaType<DataC> = {
98+
type: 'object',
99+
required: ['foo'],
100+
properties: {
101+
foo: { type: 'integer' },
102+
},
103+
additionalProperties: false,
104+
errorMessage: {
105+
type: 'should be an object',
106+
required: 'should have property foo',
107+
additionalProperties: 'should not have properties other than foo',
108+
},
109+
};
110+
111+
export const validDataC: DataC = { foo: 666 };
112+
export const invalidDataC = { foo: 'kt', bar: 6 };
113+
export const undefinedDataC = { foo: undefined };
114+
export const invalidTypeDataC = 'something';
115+
116+
interface DataD {
117+
foo: number;
118+
bar: string;
119+
}
120+
121+
export const schemaD: JSONSchemaType<DataD> = {
122+
type: 'object',
123+
required: ['foo', 'bar'],
124+
properties: {
125+
foo: { type: 'integer' },
126+
bar: { type: 'string' },
127+
},
128+
errorMessage: {
129+
type: 'should be an object', // will not replace internal "type" error for the property "foo"
130+
required: {
131+
foo: 'should have an integer property "foo"',
132+
bar: 'should have a string property "bar"',
133+
},
134+
},
135+
};
136+
137+
export const validDataD: DataD = { foo: 666, bar: 'kt' };
138+
export const invalidDataD = { foo: 'kt', bar: 6 };
139+
export const undefinedDataD = { foo: undefined, bar: undefined };
140+
export const invalidTypeDataD = 'something';
141+
142+
interface DataE {
143+
foo: number;
144+
bar: string;
145+
}
146+
147+
export const schemaE: JSONSchemaType<DataE> = {
148+
type: 'object',
149+
required: ['foo', 'bar'],
150+
allOf: [
151+
{
152+
properties: {
153+
foo: { type: 'integer', minimum: 2 },
154+
bar: { type: 'string', minLength: 2 },
155+
},
156+
additionalProperties: false,
157+
},
158+
],
159+
errorMessage: {
160+
properties: {
161+
foo: 'data.foo should be integer >= 2',
162+
bar: 'data.bar should be string with length >= 2',
163+
},
164+
},
165+
};
166+
167+
export const validDataE: DataE = { foo: 666, bar: 'kt' };
168+
export const invalidDataE = { foo: 1, bar: 'k' };
169+
export const undefinedDataE = { foo: undefined, bar: undefined };
170+
171+
interface DataF {
172+
foo: number;
173+
bar: string;
174+
}
175+
176+
export const schemaF: JSONSchemaType<DataF> = {
177+
type: 'object',
178+
required: ['foo', 'bar'],
179+
allOf: [
180+
{
181+
properties: {
182+
foo: { type: 'integer', minimum: 2 },
183+
bar: { type: 'string', minLength: 2 },
184+
},
185+
additionalProperties: false,
186+
},
187+
],
188+
errorMessage: {
189+
type: 'data should be an object',
190+
properties: {
191+
foo: 'data.foo should be integer >= 2',
192+
bar: 'data.bar should be string with length >= 2',
193+
},
194+
_: 'data should have properties "foo" and "bar" only',
195+
},
196+
};
197+
198+
export const validDataF: DataF = { foo: 666, bar: 'kt' };
199+
export const invalidDataF = {};
200+
export const undefinedDataF = { foo: 1, bar: undefined };
201+
export const invalidTypeDataF = 'something';
202+
203+
export const fieldsRest: Record<InternalFieldName, Field['_f']> = {
204+
foo: {
205+
ref: { name: 'foo' },
206+
name: 'foo',
207+
},
208+
bar: {
209+
ref: { name: 'bar' },
210+
name: 'bar',
211+
},
212+
lorem: {
213+
ref: { name: 'lorem' },
214+
name: 'lorem',
215+
},
216+
};

0 commit comments

Comments
 (0)