import { z } from "zod" import type { DiscriminatedUnionError, Option, } from "@/types/discriminatedUnion" /** * This file is created to handle our discriminated unions * validations primarily for union returns from Contentstacks * GraphQL server. * * In the case of a new block being added to the union in Contenstack, * Zod will throw because that typename is not expected ("invalid_union_discriminator"). * Therefore we add a safety that we return everytime we stumble upon * the issue and then we filter it out in the transform. * * This replaces the `cleanEmptyObjects` function that would require * everyone to never make a mistake in adding __typename to root * anywhere (or any other potentially global fields in case the return type * is an Interface e.g). */ export function discriminatedUnion(options: Option[]) { return z .discriminatedUnion("__typename", [ z.object({ __typename: z.literal(undefined) }), ...options, ]) .catch(({ error }: DiscriminatedUnionError) => { if ( error.issues.find( (issue) => issue.code === "invalid_union_discriminator" ) ) { return { __typename: undefined } } throw new Error(error.message) }) .transform((data) => { if (data.__typename === "undefined" || data.__typename === undefined) { return null } return data as R }) } export function discriminatedUnionArray(options: T[]) { return z .array(discriminatedUnion(options)) .transform((blocks) => blocks.filter((block) => !!block) ) as unknown as z.ZodEffects> }