@hookform/resolvers
Version:
React Hook Form validation resolvers: Yup, Joi, Superstruct, Zod, Vest, Class Validator, io-ts, Nope, computed-types, TypeBox, arktype, Typanion, Effect-TS and VineJS
119 lines (105 loc) • 3.51 kB
text/typescript
import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';
import { SimpleErrorReporter, VineValidator, errors } from '@vinejs/vine';
import {
ConstructableSchema,
ValidationOptions,
} from '@vinejs/vine/build/src/types';
import {
FieldError,
FieldErrors,
FieldValues,
Resolver,
appendErrors,
} from 'react-hook-form';
function parseErrorSchema(
vineErrors: SimpleErrorReporter['errors'],
validateAllFieldCriteria: boolean,
) {
const schemaErrors: Record<string, FieldError> = {};
for (; vineErrors.length; ) {
const error = vineErrors[0];
const path = error.field;
if (!(path in schemaErrors)) {
schemaErrors[path] = { message: error.message, type: error.rule };
}
if (validateAllFieldCriteria) {
const { types } = schemaErrors[path];
const messages = types && types[error.rule];
schemaErrors[path] = appendErrors(
path,
validateAllFieldCriteria,
schemaErrors,
error.rule,
messages ? [...(messages as string[]), error.message] : error.message,
) as FieldError;
}
vineErrors.shift();
}
return schemaErrors;
}
export function vineResolver<Input extends FieldValues, Context, Output>(
schema: VineValidator<ConstructableSchema<Input, Output, Output>, any>,
schemaOptions?: ValidationOptions<any>,
resolverOptions?: {
mode?: 'async' | 'sync';
raw?: false;
},
): Resolver<Input, Context, Output>;
export function vineResolver<Input extends FieldValues, Context, Output>(
schema: VineValidator<ConstructableSchema<Input, Output, Output>, any>,
schemaOptions: ValidationOptions<any> | undefined,
resolverOptions: {
mode?: 'async' | 'sync';
raw: true;
},
): Resolver<Input, Context, Input>;
/**
* Creates a resolver for react-hook-form using VineJS schema validation
* @param {T} schema - The VineJS schema to validate against
* @param {ValidationOptions<any>} [schemaOptions] - Optional VineJS validation options
* @param {Object} [resolverOptions] - Optional resolver configuration
* @param {boolean} [resolverOptions.raw=false] - If true, returns raw values instead of validated results
* @returns {Resolver<Infer<typeof schema>>} A resolver function compatible with react-hook-form
* @example
* const schema = vine.compile(
* vine.object({
* name: vine.string().minLength(2),
* age: vine.number().min(18)
* })
* );
*
* useForm({
* resolver: vineResolver(schema)
* });
*/
export function vineResolver<Input extends FieldValues, Context, Output>(
schema: VineValidator<ConstructableSchema<Input, Output, Output>, any>,
schemaOptions?: ValidationOptions<any>,
resolverOptions: { raw?: boolean } = {},
): Resolver<Input, Context, Output | Input> {
return async (values, _, options) => {
try {
const data = await schema.validate(values, schemaOptions);
options.shouldUseNativeValidation && validateFieldsNatively({}, options);
return {
errors: {} as FieldErrors,
values: resolverOptions.raw ? Object.assign({}, values) : data,
};
} catch (error: any) {
if (error instanceof errors.E_VALIDATION_ERROR) {
return {
values: {},
errors: toNestErrors(
parseErrorSchema(
error.messages,
!options.shouldUseNativeValidation &&
options.criteriaMode === 'all',
),
options,
),
};
}
throw error;
}
};
}