Skip to content

Commit

Permalink
Merge pull request #56 from volverjs/feature/optional
Browse files Browse the repository at this point in the history
Add support for `zod.optional()` to `defaultObjectBySchema()`
  • Loading branch information
alessandrobellesia authored Jun 18, 2024
2 parents d0e3b6f + c126ba6 commit cd12830
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 11 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"credits": "npx @opengovsg/credits-generator"
},
"peerDependencies": {
"@volverjs/ui-vue": "0.0.10-beta.36",
"@volverjs/ui-vue": "0.0.10-beta.41",
"@vueuse/core": "^10.11.0",
"ts-dot-prop": "^2.1.4",
"vue": "^3.4.29",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 25 additions & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import type { FormSchema } from './types'

export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema, original: Partial<z.infer<Schema>> & Record<string, unknown> = {}): Partial<z.infer<Schema>> {
const getInnerType = <Type extends ZodTypeAny>(
const getSchemaInnerType = <Type extends ZodTypeAny>(
schema:
| Type
| ZodEffects<Type>
Expand All @@ -30,7 +30,23 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
}
return toReturn
}
const innerType = getInnerType<AnyZodObject>(schema)
const isSchemaOptional = <Type extends ZodTypeAny>(
schema:
| Type
| ZodEffects<Type>
| ZodEffects<ZodEffects<Type>>
| ZodOptional<Type>,
) => {
let toReturn = schema
while (toReturn instanceof ZodEffects) {
toReturn = toReturn.innerType()
}
if (toReturn instanceof ZodOptional) {
return true
}
return false
}
const innerType = getSchemaInnerType<AnyZodObject>(schema)
const unknownKeys
= innerType instanceof ZodObject
? innerType._def.unknownKeys === 'passthrough'
Expand All @@ -41,7 +57,8 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
(Object.entries(innerType.shape) as [string, ZodTypeAny][]).map(
([key, subSchema]) => {
const originalValue = original[key]
let innerType = getInnerType(subSchema)
const isOptional = isSchemaOptional(subSchema)
let innerType = getSchemaInnerType(subSchema)
let defaultValue: Partial<z.infer<Schema>> | undefined
if (innerType instanceof ZodDefault) {
defaultValue = innerType._def.defaultValue()
Expand All @@ -53,6 +70,9 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
) {
return [key, originalValue]
}
if ((originalValue === undefined || originalValue === null) && isOptional) {
return [key, defaultValue]
}
if (innerType instanceof ZodSchema) {
const parse = subSchema.safeParse(originalValue)
if (parse.success) {
Expand All @@ -64,7 +84,7 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
&& Array.isArray(originalValue)
&& originalValue.length
) {
const arrayType = getInnerType(innerType._def.type)
const arrayType = getSchemaInnerType(innerType._def.type)
if (arrayType instanceof ZodObject) {
return [
key,
Expand All @@ -82,7 +102,7 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
}
}
if (innerType instanceof ZodRecord && originalValue) {
const valueType = getInnerType(innerType._def.valueType)
const valueType = getSchemaInnerType(innerType._def.valueType)
if (valueType instanceof ZodObject) {
return [key, Object.keys(originalValue).reduce((acc: Record<string, unknown>, recordKey: string) => {
acc[recordKey] = defaultObjectBySchema(valueType, originalValue[recordKey])
Expand Down

0 comments on commit cd12830

Please sign in to comment.