UNPKG

@ordao/zod-utils

Version:

Helper utilities for working with zod

178 lines (177 loc) 5.61 kB
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}`); } }