@ordao/zod-utils
Version:
Helper utilities for working with zod
178 lines (177 loc) • 5.61 kB
JavaScript
export const primitiveTypeNames = ['number', 'bigint', 'boolean'];
export function strTypeLength(strt) {
const length = strt.checks.find(c => c.kind === 'length');
return length?.value;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function strTypeMinLength(strt) {
const length = strTypeLength(strt);
if (length) {
return length;
}
else {
const min = strt.checks.find(c => c.kind === 'min');
return min?.value;
}
}
export function strTypeMaxLength(strt) {
const length = strTypeLength(strt);
if (length) {
return length;
}
else {
const max = strt.checks.find(c => c.kind === 'max');
return max?.value;
}
}
export function isPrimitive(typeInfo) {
return primitiveTypeNames.find(tn => tn === typeInfo.typeName) !== undefined;
}
const descriptionRe = /^(?:\s)?([^\n]+)\n{2}((?:\s|\S)*)$/g;
export function extractZodDescription(schema) {
const description = schema.description;
const r = {};
if (description !== undefined) {
const titleDescMatch = new RegExp(descriptionRe).exec(description);
if (titleDescMatch) {
r.title = titleDescMatch[1];
const d = titleDescMatch[2].trimStart();
r.description = d.length === 0 ? undefined : d;
}
else {
const d = description.trimStart();
r.description = d.length === 0 ? undefined : d;
}
}
return r;
}
export function zodEffectInnerType(effect) {
return effect.innerType();
}
export function zodOptionalInnerType(optional) {
return optional.unwrap();
}
export function zodNullableInnerType(nullable) {
return nullable.unwrap();
}
export function zodPipelineInnerType(pipeline) {
return pipeline._def.out;
}
export function zodDefaultValue(schema) {
return schema._def.defaultValue;
}
export function zodDefaultInnerType(schema) {
return schema._def.innerType;
}
export function zodLiteralInnerType(literal) {
return literal._def.value;
}
export function zodObjectFields(schema) {
const r = {};
for (const field in schema.shape) {
const fieldType = schema.shape[field];
r[field] = getTypeInfo(fieldType);
}
return r;
}
export function zodTypeStr(type) {
return type._def.typeName;
}
export function zodArrayElementType(array) {
return getTypeInfo(array.element);
}
export function zodArrayMinLength(array) {
return array._def.minLength === null ? undefined : array._def.minLength.value;
}
export function zodArrayMaxLength(array) {
return array._def.maxLength === null ? undefined : array._def.maxLength.value;
}
export function zodStringChecks(zstr) {
return zstr._def.checks;
}
export function overwriteDescription(typeInfo, schema) {
const { title, description } = extractZodDescription(schema);
if (title !== undefined || description !== undefined) {
return {
...typeInfo,
title,
description
};
}
else {
return typeInfo;
}
}
export function getTypeInfo(schema) {
const typeStr = zodTypeStr(schema);
switch (typeStr) {
case 'ZodDefault': {
const ti = getTypeInfo(zodDefaultInnerType(schema));
ti.defaultValue = zodDefaultValue(schema);
return overwriteDescription(ti, schema);
}
case 'ZodEffects': {
const ti = getTypeInfo(zodEffectInnerType(schema));
return overwriteDescription(ti, schema);
}
case 'ZodOptional': {
const ti = getTypeInfo(zodOptionalInnerType(schema));
ti.optional = true;
return overwriteDescription(ti, schema);
}
case 'ZodNullable': {
const ti = getTypeInfo(zodNullableInnerType(schema));
ti.optional = true;
return overwriteDescription(ti, schema);
}
case 'ZodPipeline': {
const ti = getTypeInfo(zodPipelineInnerType(schema));
return overwriteDescription(ti, schema);
}
case 'ZodLiteral': {
const r = {
typeName: 'literal',
schema,
value: zodLiteralInnerType(schema),
...extractZodDescription(schema)
};
}
case 'ZodObject': {
const r = {
typeName: 'object',
schema,
fields: zodObjectFields(schema),
...extractZodDescription(schema)
};
return r;
}
case 'ZodArray': {
const r = {
typeName: 'array',
schema,
elementType: zodArrayElementType(schema),
min: zodArrayMinLength(schema),
max: zodArrayMaxLength(schema),
...extractZodDescription(schema)
};
return r;
}
case 'ZodNumber':
return { typeName: 'number', schema, ...extractZodDescription(schema) };
case 'ZodBigInt':
return { typeName: 'bigint', schema, ...extractZodDescription(schema) };
case 'ZodString': {
const r = {
typeName: 'string',
schema,
checks: zodStringChecks(schema),
...extractZodDescription(schema)
};
return r;
}
case 'ZodBoolean':
return { typeName: 'boolean', schema, ...extractZodDescription(schema) };
default:
throw new Error(`Unknown type: ${typeStr}`);
}
}