UNPKG

@abyrd9/zod-form-data

Version:

A Zod-based form data validation library

129 lines (114 loc) 3.83 kB
import type { NestedFieldErrors } from "./flatten-zod-form-errors"; import type { DeepPartial } from "./deep-partial"; import type { $ZodType } from "zod/v4/core"; export function unflattenZodFormErrors<T extends $ZodType>( errors: Record<string, string>, root?: string ): DeepPartial<NestedFieldErrors<T>> { const result: Record<string, unknown> = {}; const nest = ( errors: Record<string, unknown> | unknown[], keys: string[], level: number, value: string ) => { const key = keys[level]; const nextKey = keys[level + 1]; /* If we're on the last key, we're dealing with a primitive value. So either push it to an array if that's what's passed in, or set is as the value of the key. */ const isLastKey = nextKey === undefined; if (isLastKey) { if (Array.isArray(errors)) { errors.push(value); return errors; } errors[key] = value; return errors; } // If the next key is a number, the current levels value is an array const keyIsArray = !Number.isNaN(Number(nextKey)); if (keyIsArray) { if (Array.isArray(errors)) { // In this instance we're dealing with an array within an array console.warn("ARRAY WITHIN ARRAY"); } else { // We're dealing with a passed in object // We need to check if the current level key already exists // If it does, we want to pass the values down the chain if (errors[key]) { return nest(errors[key] as unknown[], keys, level + 1, value); } // We need to create the empty array value if it doesn't exist errors[key] = []; return nest(errors[key] as unknown[], keys, level + 1, value); } } else { // If the next key is not a number, the current level value is an object if (Array.isArray(errors)) { /* If the passed in errors is an array, check if the current level key (index) already exists in the array. */ // We know that the previous level key was a number // So we can assume that the current level key is a number const valueAtIndex = errors[Number(key)]; // If the key at the index exists, we just need to pass down values if (valueAtIndex !== undefined) { return nest( valueAtIndex as Record<string, unknown>, keys, level + 1, value ); } // If it doesn't exist, we know it's an empty object errors[Number(key)] = {}; return nest( errors[Number(key)] as Record<string, unknown>, keys, level + 1, value ); } /* And finally, we're dealing with objects. If the current level key doesn't exist on the passed in errors, we need to create an empty object and pass down the values. Otherwise, we just need to pass down the values. */ if (!errors[key]) { errors[key] = {}; return nest( errors[key] as Record<string, unknown>, keys, level + 1, value ); } if (errors[key]) { return nest( errors[key] as Record<string, unknown>, keys, level + 1, value ); } } }; for (const [key, value] of Object.entries(errors)) { const keys = key.split("."); // Check if a root is provided and if the current key starts with it if (root) { if (key.startsWith(`${root}.`)) { nest(result, keys, 0, value); } } else { // If no root is provided, process all keys as before nest(result, keys, 0, value); } } return root ? (result[root] as DeepPartial<NestedFieldErrors<T>>) : (result as DeepPartial<NestedFieldErrors<T>>); }