resolvers icon indicating copy to clipboard operation
resolvers copied to clipboard

Fix nested error reporting

Open marcospassos opened this issue 3 years ago • 6 comments

Fixes #441

marcospassos avatar Aug 11 '22 00:08 marcospassos

@bluebill1049, is there anything else you'd like to address on this PR?

marcospassos avatar Aug 11 '22 13:08 marcospassos

I am quite busy at the moment, but I will find some time to review it properly in the following days. thanks for the help <3

bluebill1049 avatar Aug 11 '22 23:08 bluebill1049

The problem is that there is no easy way to fix or monkey patch this other than maintaining a fork. Also, this is a real feature bug for those who use the all criteria.

marcospassos avatar Aug 30 '22 16:08 marcospassos

I was having the same error on my application and I can confirm this PR solves the issue. Is there something missing so we can have this in a future release of resolvers?

georgekaran avatar Aug 30 '22 19:08 georgekaran

@georgekaran , this is a terrible but functional workaround for the issue:

import {ValidationError} from "yup";
import {yupResolver as baseResolver} from "@hookform/resolvers/yup";
import BaseSchema from "yup/lib/schema";

/**
 * Workaround for https://github.com/react-hook-form/resolvers/issues/441
 */

function fixErrorNesting(errors: Record<string, any>): Record<string, any> | any[] {
  const fieldErrors: Record<string, any> = {};

  for (const [key, value] of Object.entries(errors)) {
    if (typeof value !== 'object' || value === null || !('ref' in value)) {
      fieldErrors[key] = value;

      continue;
    }

    if (Array.isArray(value)) {
      fieldErrors[key] = value.map(fixErrorNesting);

      continue;
    }

    if (!('0' in value)) {
      fieldErrors[key] = fixErrorNesting(value);

      continue;
    }

    const copy = {...value}
    const list = [];

    let index = 0;

    while (index in copy) {
      list.push(fixErrorNesting(copy[index]));
      delete copy[index];
      index++;
    }

    Object.assign(list, copy);

    fieldErrors[key] = list;
  }

  return fieldErrors;
}

export const yupResolver: typeof baseResolver = (schema, schemaOptions = {}, resolverOptions = {}) => {
  const schemaClone = (schema as any).clone() as BaseSchema;

  const validate = schemaClone.validate.bind(schemaClone);
  const validateSync = schemaClone.validateSync.bind(schemaClone);

  function sortErrors<T>(error: T): T {
    if (error instanceof ValidationError) {
      error.inner.sort((left, right) => {
        if (left.path === right.path) {
          return 0;
        }

        return (left.path ?? '') > (right.path ?? '') ? 1 : -1
      });
    }

    return error;
  }

  schemaClone.validate = async (...args) => {
    try {
      return await validate(...args);
    } catch (error) {
      throw sortErrors(error);
    }
  };

  schemaClone.validateSync = (...args) => {
    try {
      return validateSync(...args);
    } catch (error) {
      throw sortErrors(error);
    }
  };

  const resolver = baseResolver(schemaClone as typeof schema, schemaOptions, resolverOptions);

  return async (values, context, options) => {
      const result = await resolver(values, context, options);

      return {
        ...result,
        errors: fixErrorNesting(result.errors) as typeof result.errors,
      }
  };
};

It should definitely be fixed.

marcospassos avatar Aug 30 '22 22:08 marcospassos

Thanks @marcospassos it worked like a charm, but it should definitely be shipped native 😕

georgekaran avatar Aug 31 '22 13:08 georgekaran

Thank you for your contributions! This Pull Request has been automatically marked as stale because it has not had any recent activity. It will be closed if no further activity occurs. Best, RHF Team ❤️

stale[bot] avatar Oct 19 '22 01:10 stale[bot]

Thank you for your contributions! This Pull Request is being closed because it has not had any recent activity. Feel free to re-open the issue and begin work again! Best, RHF Team ❤️

stale[bot] avatar Oct 29 '22 02:10 stale[bot]