@vee-validate/zod
Version:
vee-validate integration with zod schema validation
209 lines (204 loc) • 6.36 kB
JavaScript
/**
* vee-validate v4.15.1
* (c) 2025 Abdelrahman Awad
* @license MIT
*/
;
var zod = require('zod');
var veeValidate = require('vee-validate');
const isObject = (obj) => obj !== null && !!obj && typeof obj === 'object' && !Array.isArray(obj);
function isIndex(value) {
return Number(value) >= 0;
}
function isObjectLike(value) {
return typeof value === 'object' && value !== null;
}
function getTag(value) {
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]';
}
return Object.prototype.toString.call(value);
}
// Reference: https://github.com/lodash/lodash/blob/master/isPlainObject.js
function isPlainObject(value) {
if (!isObjectLike(value) || getTag(value) !== '[object Object]') {
return false;
}
if (Object.getPrototypeOf(value) === null) {
return true;
}
let proto = value;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(value) === proto;
}
function merge(target, source) {
Object.keys(source).forEach(key => {
if (isPlainObject(source[key]) && isPlainObject(target[key])) {
if (!target[key]) {
target[key] = {};
}
merge(target[key], source[key]);
return;
}
target[key] = source[key];
});
return target;
}
/**
* Constructs a path with dot paths for arrays to use brackets to be compatible with vee-validate path syntax
*/
function normalizeFormPath(path) {
const pathArr = path.split('.');
if (!pathArr.length) {
return '';
}
let fullPath = String(pathArr[0]);
for (let i = 1; i < pathArr.length; i++) {
if (isIndex(pathArr[i])) {
fullPath += `[${pathArr[i]}]`;
continue;
}
fullPath += `.${pathArr[i]}`;
}
return fullPath;
}
/**
* Transforms a Zod object schema to Yup's schema
*/
function toTypedSchema(zodSchema, opts) {
const schema = {
__type: 'VVTypedSchema',
async parse(value) {
const result = await zodSchema.safeParseAsync(value, opts);
if (result.success) {
return {
value: result.data,
errors: [],
};
}
const errors = {};
processIssues(result.error.issues, errors);
return {
errors: Object.values(errors),
};
},
cast(values) {
try {
return zodSchema.parse(values);
}
catch (_a) {
// Zod does not support "casting" or not validating a value, so next best thing is getting the defaults and merging them with the provided values.
const defaults = getDefaults(zodSchema);
if (isObject(defaults) && isObject(values)) {
return merge(defaults, values);
}
return values;
}
},
describe(path) {
try {
if (!path) {
return {
required: !zodSchema.isOptional(),
exists: true,
};
}
const description = getSchemaForPath(path, zodSchema);
if (!description) {
return {
required: false,
exists: false,
};
}
return {
required: !description.isOptional(),
exists: true,
};
}
catch (_a) {
return {
required: false,
exists: false,
};
}
},
};
return schema;
}
function processIssues(issues, errors) {
issues.forEach(issue => {
const path = normalizeFormPath(issue.path.join('.'));
if (issue.code === 'invalid_union') {
processIssues(issue.unionErrors.flatMap(ue => ue.issues), errors);
if (!path) {
return;
}
}
if (!errors[path]) {
errors[path] = { errors: [], path };
}
errors[path].errors.push(issue.message);
});
}
// Zod does not support extracting default values so the next best thing is manually extracting them.
// https://github.com/colinhacks/zod/issues/1944#issuecomment-1406566175
function getDefaults(schema) {
if (!(schema instanceof zod.ZodObject)) {
return undefined;
}
return Object.fromEntries(Object.entries(schema.shape).map(([key, value]) => {
if (value instanceof zod.ZodDefault) {
return [key, value._def.defaultValue()];
}
if (value instanceof zod.ZodObject) {
return [key, getDefaults(value)];
}
return [key, undefined];
}));
}
/**
* @deprecated use toTypedSchema instead.
*/
const toFieldValidator = toTypedSchema;
/**
* @deprecated use toTypedSchema instead.
*/
const toFormValidator = toTypedSchema;
function getSchemaForPath(path, schema) {
if (!isObjectSchema(schema)) {
return null;
}
if (veeValidate.isNotNestedPath(path)) {
return schema.shape[veeValidate.cleanupNonNestedPath(path)];
}
const paths = (path || '').split(/\.|\[(\d+)\]/).filter(Boolean);
let currentSchema = schema;
for (let i = 0; i <= paths.length; i++) {
const p = paths[i];
if (!p || !currentSchema) {
return currentSchema;
}
if (isObjectSchema(currentSchema)) {
currentSchema = currentSchema.shape[p] || null;
continue;
}
if (isIndex(p) && isArraySchema(currentSchema)) {
currentSchema = currentSchema._def.type;
}
}
return null;
}
function getDefType(schema) {
return schema._def.typeName;
}
function isArraySchema(schema) {
return getDefType(schema) === zod.ZodFirstPartyTypeKind.ZodArray;
}
function isObjectSchema(schema) {
return getDefType(schema) === zod.ZodFirstPartyTypeKind.ZodObject;
}
exports.toFieldValidator = toFieldValidator;
exports.toFormValidator = toFormValidator;
exports.toTypedSchema = toTypedSchema;