@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
117 lines (101 loc) • 3.1 kB
text/typescript
import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';
import { StandardSchemaV1 } from '@standard-schema/spec';
import {
FieldError,
FieldErrors,
FieldValues,
Resolver,
appendErrors,
} from 'react-hook-form';
const parseErrorSchema = (
typeschemaErrors: readonly StandardSchemaV1.Issue[],
validateAllFieldCriteria: boolean,
): FieldErrors => {
const schemaErrors = Object.assign([], typeschemaErrors);
const errors: Record<string, FieldError> = {};
for (; schemaErrors.length; ) {
const error = typeschemaErrors[0];
if (!error.path) {
continue;
}
const _path = error.path.join('.');
if (!errors[_path]) {
errors[_path] = { message: error.message, type: '' };
}
if (validateAllFieldCriteria) {
const types = errors[_path].types;
const messages = types && types[''];
errors[_path] = appendErrors(
_path,
validateAllFieldCriteria,
errors,
'',
messages
? ([] as string[]).concat(messages as string[], error.message)
: error.message,
) as FieldError;
}
schemaErrors.shift();
}
return errors;
};
export function typeschemaResolver<Input extends FieldValues, Context, Output>(
schema: StandardSchemaV1<Input, Output>,
_schemaOptions?: never,
resolverOptions?: {
raw?: false;
},
): Resolver<Input, Context, Output>;
export function typeschemaResolver<Input extends FieldValues, Context, Output>(
schema: StandardSchemaV1<Input, Output>,
_schemaOptions: never | undefined,
resolverOptions: {
raw: true;
},
): Resolver<Input, Context, Input>;
/**
* Creates a resolver for react-hook-form using TypeSchema validation
* @param {any} schema - The TypeSchema to validate against
* @param {any} _ - Unused parameter
* @param {Object} resolverOptions - Additional resolver configuration
* @param {string} [resolverOptions.mode='async'] - Validation mode
* @returns {Resolver} A resolver function compatible with react-hook-form
* @example
* const schema = z.object({
* name: z.string().required(),
* age: z.number().required(),
* });
*
* useForm({
* resolver: typeschemaResolver(schema)
* });
*/
export function typeschemaResolver<Input extends FieldValues, Context, Output>(
schema: StandardSchemaV1<Input, Output>,
_schemaOptions?: never,
resolverOptions: {
raw?: boolean;
} = {},
): Resolver<Input, Context, Output | Input> {
return async (values, _, options) => {
let result = schema['~standard'].validate(values);
if (result instanceof Promise) {
result = await result;
}
if (result.issues) {
const errors = parseErrorSchema(
result.issues,
!options.shouldUseNativeValidation && options.criteriaMode === 'all',
);
return {
values: {},
errors: toNestErrors(errors, options),
};
}
options.shouldUseNativeValidation && validateFieldsNatively({}, options);
return {
values: resolverOptions.raw ? Object.assign({}, values) : result.value,
errors: {},
};
};
}