Skip to content

Commit 43561e2

Browse files
committed
feat: add field-level support to global rules
1 parent 58b470f commit 43561e2

File tree

5 files changed

+86
-21
lines changed

5 files changed

+86
-21
lines changed

packages/rules/src/toTypedSchema.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,12 @@ export function toTypedSchema<TOutput = any, TInput extends Optional<TOutput> =
3535
};
3636
},
3737
describe(path) {
38-
if (isObject(rawSchema) && path in rawSchema) {
39-
const rules = (rawSchema as any)[path];
40-
if (typeof rules === 'string') {
41-
return {
42-
exists: true,
43-
required: rules.includes('required'),
44-
};
45-
}
38+
if (!path) {
39+
return getDescriptionFromExpression(rawSchema);
40+
}
4641

47-
if (isObject(rules)) {
48-
return {
49-
exists: true,
50-
required: !!rules.required,
51-
};
52-
}
42+
if (isObject(rawSchema) && path in rawSchema) {
43+
return getDescriptionFromExpression((rawSchema as any)[path]);
5344
}
5445

5546
return {
@@ -61,3 +52,24 @@ export function toTypedSchema<TOutput = any, TInput extends Optional<TOutput> =
6152

6253
return schema;
6354
}
55+
56+
function getDescriptionFromExpression(rules: string | Record<string, any>) {
57+
if (typeof rules === 'string') {
58+
return {
59+
exists: true,
60+
required: rules.includes('required'),
61+
};
62+
}
63+
64+
if (isObject(rules)) {
65+
return {
66+
exists: true,
67+
required: !!rules.required,
68+
};
69+
}
70+
71+
return {
72+
required: false,
73+
exists: true,
74+
};
75+
}

packages/rules/tests/toTypedSchema.spec.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ test('reports required state on fields', async () => {
142142
);
143143
});
144144

145-
test('reports required state on fields', async () => {
145+
test('reports required false for non-existent fields', async () => {
146146
const metaSpy = vi.fn();
147147
mountWithHoc({
148148
setup() {
@@ -177,3 +177,56 @@ test('reports required state on fields', async () => {
177177
}),
178178
);
179179
});
180+
181+
test('reports required state for field-level schemas', async () => {
182+
const metaSpy = vi.fn();
183+
mountWithHoc({
184+
setup() {
185+
useForm();
186+
const { meta: req } = useField('req', toTypedSchema('required'));
187+
const { meta: nreq } = useField('nreq', toTypedSchema('email'));
188+
189+
metaSpy({
190+
req: req.required,
191+
nreq: nreq.required,
192+
});
193+
194+
return {};
195+
},
196+
template: `<div></div>`,
197+
});
198+
199+
await flushPromises();
200+
await expect(metaSpy).toHaveBeenLastCalledWith(
201+
expect.objectContaining({
202+
req: true,
203+
nreq: false,
204+
}),
205+
);
206+
});
207+
208+
test('reports required state for field-level schemas without a form context', async () => {
209+
const metaSpy = vi.fn();
210+
mountWithHoc({
211+
setup() {
212+
const { meta: req } = useField('req', toTypedSchema('required'));
213+
const { meta: nreq } = useField('nreq', toTypedSchema('email'));
214+
215+
metaSpy({
216+
req: req.required,
217+
nreq: nreq.required,
218+
});
219+
220+
return {};
221+
},
222+
template: `<div></div>`,
223+
});
224+
225+
await flushPromises();
226+
await expect(metaSpy).toHaveBeenLastCalledWith(
227+
expect.objectContaining({
228+
req: true,
229+
nreq: false,
230+
}),
231+
);
232+
});

packages/valibot/tests/valibot.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ test('reports required false for non-existent fields', async () => {
473473
);
474474
});
475475

476-
test('reports required state single field schemas', async () => {
476+
test('reports required state for field-level schemas', async () => {
477477
const metaSpy = vi.fn();
478478
mountWithHoc({
479479
setup() {
@@ -500,7 +500,7 @@ test('reports required state single field schemas', async () => {
500500
);
501501
});
502502

503-
test('reports required state single field schemas without a form context', async () => {
503+
test('reports required state for field-level schemas without a form context', async () => {
504504
const metaSpy = vi.fn();
505505
mountWithHoc({
506506
setup() {

packages/yup/tests/yup.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ test('reports required false for non-existent fields', async () => {
430430
);
431431
});
432432

433-
test('reports required state single field schemas', async () => {
433+
test('reports required state for field-level schemas', async () => {
434434
const metaSpy = vi.fn();
435435
mountWithHoc({
436436
setup() {
@@ -457,7 +457,7 @@ test('reports required state single field schemas', async () => {
457457
);
458458
});
459459

460-
test('reports required state single field schemas without a form context', async () => {
460+
test('reports required state for field-level schemas without a form context', async () => {
461461
const metaSpy = vi.fn();
462462
mountWithHoc({
463463
setup() {

packages/zod/tests/zod.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ test('reports required false for non-existent fields', async () => {
524524
);
525525
});
526526

527-
test('reports required state single field schemas', async () => {
527+
test('reports required state for field-level schemas', async () => {
528528
const metaSpy = vi.fn();
529529
mountWithHoc({
530530
setup() {
@@ -551,7 +551,7 @@ test('reports required state single field schemas', async () => {
551551
);
552552
});
553553

554-
test('reports required state single field schemas without a form context', async () => {
554+
test('reports required state for field-level schemas without a form context', async () => {
555555
const metaSpy = vi.fn();
556556
mountWithHoc({
557557
setup() {

0 commit comments

Comments
 (0)