From 69e39064222d0808948899fd110b85f0e3ee06ed Mon Sep 17 00:00:00 2001 From: Edoardo Ranghieri Date: Tue, 9 Apr 2024 02:58:18 +0200 Subject: [PATCH] feat(validation-errors): add `flattenValidationErrors` function --- packages/next-safe-action/src/index.ts | 10 ++--- .../next-safe-action/src/validation-errors.ts | 39 ++++++++++++++++++- .../src/validation-errors.types.ts | 11 ++++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/packages/next-safe-action/src/index.ts b/packages/next-safe-action/src/index.ts index 292ec353..c0078731 100644 --- a/packages/next-safe-action/src/index.ts +++ b/packages/next-safe-action/src/index.ts @@ -16,6 +16,7 @@ import { DEFAULT_SERVER_ERROR_MESSAGE, isError } from "./utils"; import { ServerValidationError, buildValidationErrors, + flattenValidationErrors, returnValidationErrors, } from "./validation-errors"; import type { BindArgsValidationErrors, ValidationErrors } from "./validation-errors.types"; @@ -291,19 +292,16 @@ export const createSafeActionClient = ( }); }; -export { - DEFAULT_SERVER_ERROR_MESSAGE, - returnValidationErrors, - type BindArgsValidationErrors, - type ValidationErrors, -}; +export { DEFAULT_SERVER_ERROR_MESSAGE, flattenValidationErrors, returnValidationErrors }; export type { ActionMetadata, + BindArgsValidationErrors, MiddlewareFn, MiddlewareResult, SafeActionClientOpts, SafeActionFn, SafeActionResult, ServerCodeFn, + ValidationErrors, }; diff --git a/packages/next-safe-action/src/validation-errors.ts b/packages/next-safe-action/src/validation-errors.ts index 788ede02..709b28a1 100644 --- a/packages/next-safe-action/src/validation-errors.ts +++ b/packages/next-safe-action/src/validation-errors.ts @@ -1,6 +1,10 @@ import type { ValidationIssue } from "@typeschema/core"; import type { Schema } from "@typeschema/main"; -import type { ErrorList, ValidationErrors } from "./validation-errors.types"; +import type { + ErrorList, + FlattenedValidationErrors, + ValidationErrors, +} from "./validation-errors.types"; // This function is used internally to build the validation errors object from a list of validation issues. export const buildValidationErrors = (issues: ValidationIssue[]) => { @@ -69,3 +73,36 @@ export function returnValidationErrors( ): never { throw new ServerValidationError(validationErrors); } + +/** + * Transform default formatted validation errors into flattened structure. + * `rootErrors` contains global errors, and `fieldErrors` contains errors for each field, + * one level deep. It skips errors for nested fields. + * @param {ValidationErrors} [validationErrors] Validation errors object + * @returns {FlattenedValidationErrors} Flattened validation errors + */ +export function flattenValidationErrors< + const S extends Schema, + const VE extends ValidationErrors, +>(validationErrors?: VE) { + const flattened: FlattenedValidationErrors = { + rootErrors: [], + fieldErrors: {}, + }; + + if (!validationErrors) { + return flattened; + } + + for (const [key, value] of Object.entries(validationErrors)) { + if (key === "_errors" && Array.isArray(value)) { + flattened.rootErrors = [...value]; + } else { + if ("_errors" in value) { + flattened.fieldErrors[key as keyof Omit] = [...value._errors]; + } + } + } + + return flattened; +} diff --git a/packages/next-safe-action/src/validation-errors.types.ts b/packages/next-safe-action/src/validation-errors.types.ts index a194c998..18ab07a9 100644 --- a/packages/next-safe-action/src/validation-errors.types.ts +++ b/packages/next-safe-action/src/validation-errors.types.ts @@ -24,3 +24,14 @@ export type ValidationErrors = Extend = (ValidationErrors< BAS[number] > | null)[]; + +/** + * Type of flattened validation errors. `rootErrors` contains global errors, and `fieldErrors` + * contains errors for each field, one level deep. + */ +export type FlattenedValidationErrors> = { + rootErrors: string[]; + fieldErrors: { + [K in keyof Omit]?: string[]; + }; +};