Skip to content

Commit e436b75

Browse files
committed
feat: added built-in support for yup validation schema
1 parent 0802512 commit e436b75

2 files changed

Lines changed: 60 additions & 4 deletions

File tree

packages/core/src/useField.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ type RuleExpression = MaybeReactive<string | Record<string, any> | GenericValida
2626
export function useField(fieldName: MaybeReactive<string>, rules: RuleExpression, opts?: Partial<FieldOptions>) {
2727
const { value, form, immediate, bails, disabled } = normalizeOptions(opts);
2828
const { meta, errors, failedRules, onBlur, handleChange, reset, patch } = useValidationState(value);
29-
let schemaValidation: GenericValidateFunction | string | Record<string, any>;
29+
// eslint-disable-next-line prefer-const
30+
let schemaValidation: GenericValidateFunction | string | Record<string, any> | undefined;
3031
const normalizedRules = computed(() => {
3132
return normalizeRules(schemaValidation || unwrap(rules));
3233
});
@@ -97,9 +98,7 @@ export function useField(fieldName: MaybeReactive<string>, rules: RuleExpression
9798
form.register(field);
9899

99100
// set the rules if present in schema
100-
if (form.schema?.[unwrap(fieldName)]) {
101-
schemaValidation = form.schema[unwrap(fieldName)];
102-
}
101+
schemaValidation = extractRuleFromSchema(form.schema, unwrap(fieldName));
103102

104103
// extract cross-field dependencies in a computed prop
105104
const dependencies = computed(() => {
@@ -270,3 +269,25 @@ function useAriAttrs(fieldName: MaybeReactive<string>, meta: Record<Flag, Ref<bo
270269
};
271270
});
272271
}
272+
273+
/**
274+
* Extracts the validation rules from a schema
275+
*/
276+
function extractRuleFromSchema(schema: Record<string, any> | undefined, fieldName: string) {
277+
// no schema at all
278+
if (!schema) {
279+
return undefined;
280+
}
281+
282+
// a yup schema
283+
if (schema.fields?.[fieldName]) {
284+
return schema.fields?.[fieldName];
285+
}
286+
287+
// there is a key on the schema object for this field
288+
if (schema[fieldName]) {
289+
return schema[fieldName];
290+
}
291+
292+
return undefined;
293+
}

packages/core/tests/Form.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import flushPromises from 'flush-promises';
22
import { defineRule } from '@vee-validate/core';
33
import { mountWithHoc, setValue } from './helpers';
4+
import * as yup from 'yup';
45

56
describe('<Form />', () => {
67
const REQUIRED_MESSAGE = `This field is required`;
@@ -245,6 +246,40 @@ describe('<Form />', () => {
245246
expect(submitMock).toHaveBeenCalledTimes(1);
246247
});
247248

249+
// test('validation schema with yup', async () => {
250+
// const wrapper = mountWithHoc({
251+
// setup() {
252+
// const schema = yup.object().shape({
253+
// email: yup.string().email(),
254+
// password: yup.string().required().min(8),
255+
// });
256+
257+
// return {
258+
// schema,
259+
// };
260+
// },
261+
// template: `
262+
// <VForm @submit="submit" as="form" :validationSchema="schema" v-slot="{ errors }">
263+
// <Field name="field" as="input" />
264+
// <span id="field">{{ errors.field }}</span>
265+
266+
// <Field name="other" as="input" />
267+
// <span id="other">{{ errors.other }}</span>
268+
269+
// <button>Validate</button>
270+
// </VForm>
271+
// `,
272+
// });
273+
274+
// const first = wrapper.$el.querySelector('#field');
275+
// const second = wrapper.$el.querySelector('#other');
276+
277+
// await flushPromises();
278+
279+
// expect(first.textContent).toBe('this is required');
280+
// expect(second.textContent).toBe('this is required');
281+
// });
282+
248283
test('validation schema to validate form', async () => {
249284
const wrapper = mountWithHoc({
250285
setup() {

0 commit comments

Comments
 (0)