Skip to content

Commit

Permalink
Improved zodToTypeInfo
Browse files Browse the repository at this point in the history
If passed, `getDecorator` function will be called to get the decorator
to apply to dynamically generated class from zod instance, for object
validation schemas.
  • Loading branch information
incetarik committed Aug 22, 2022
1 parent eafea9b commit 5620ec4
Showing 1 changed file with 37 additions and 7 deletions.
44 changes: 37 additions & 7 deletions src/helpers/zod-to-type-info.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { IModelFromZodOptions } from 'src/model-from-zod'
import * as zod from 'zod'

import { Float, Int } from '@nestjs/graphql'

import { modelFromZod } from '../model-from-zod'
import { modelFromZod, modelFromZodBase } from '../model-from-zod'
import { isZodInstance } from './is-zod-instance'
import { toTitleCase } from './to-title-case'

Expand Down Expand Up @@ -75,6 +73,18 @@ export interface ZodTypeInfo {
isItemNullable?: boolean
}

type Options<T extends object> = IModelFromZodOptions<T> & {
/**
* Provides the decorator to decorate the dynamically generated class.
*
* @param {T} zodInput The zod input.
* @param {string} key The name of the currently processsed property.
* @return {ClassDecorator} The class decorator to decorate the class.
* @memberof IOptions
*/
getDecorator?(zodInput: T, key: string): ClassDecorator
}

/**
* Converts a given `zod` object input for a key, into {@link ZodTypeInfo}.
*
Expand All @@ -84,10 +94,15 @@ export interface ZodTypeInfo {
* that is being converted.
*
* @param {zod.ZodTypeAny} prop The `zod` object property.
* @param {IModelFromZodOptions<T>} options The options for conversion.
* @param {Options<T>} options The options for conversion.
* @return {ZodTypeInfo} The {@link ZodTypeInfo} of the property.
*/
export function zodToTypeInfo<T extends zod.AnyZodObject>(key: string, prop: zod.ZodTypeAny, options: IModelFromZodOptions<T>): ZodTypeInfo {
export function zodToTypeInfo<T extends zod.AnyZodObject>(
key: string,
prop: zod.ZodTypeAny,
options: Options<T>
): ZodTypeInfo {

if (isZodInstance(zod.ZodArray, prop)) {
const data = zodToTypeInfo(key, prop.element, options)

Expand Down Expand Up @@ -124,7 +139,9 @@ export function zodToTypeInfo<T extends zod.AnyZodObject>(key: string, prop: zod
}
else if (isZodInstance(zod.ZodNumber, prop)) {
return {
type: prop.isInt ? Int : Float,
// FIXME: There is a known bug in NestJS that does not support `Int` and
// `Float` separately therefore we will just be passing `Number` here.
type: Number,
isOptional: prop.isOptional(),
isNullable: prop.isNullable(),
}
Expand Down Expand Up @@ -158,7 +175,17 @@ export function zodToTypeInfo<T extends zod.AnyZodObject>(key: string, prop: zod
isAbstract: isNullable,
}

const model = modelFromZod(prop as any, nestedOptions)
let model: any
if (typeof options.getDecorator === 'function') {
model = modelFromZodBase(
prop as any,
nestedOptions,
options.getDecorator(prop as T, nestedOptions.name)
)
}
else {
model = modelFromZod(prop as any, nestedOptions)
}

return {
type: model,
Expand All @@ -175,6 +202,9 @@ export function zodToTypeInfo<T extends zod.AnyZodObject>(key: string, prop: zod
isEnum: true,
}
}
else if (isZodInstance(zod.ZodDefault, prop)) {
return zodToTypeInfo(key, prop._def.innerType, options)
}
else {
throw new Error(`Unsupported type info of Key("${key}")`)
}
Expand Down

0 comments on commit 5620ec4

Please sign in to comment.