File size: 1,879 Bytes
95ca844
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import { toNestErrors, validateFieldsNatively } from '@hookform/resolvers';
import { plainToClass } from 'class-transformer';
import { ValidationError, validate, validateSync } from 'class-validator';
import { FieldErrors } from 'react-hook-form';
import type { Resolver } from './types';

const parseErrors = (
  errors: ValidationError[],
  validateAllFieldCriteria: boolean,
  parsedErrors: FieldErrors = {},
  path = '',
) => {
  return errors.reduce((acc, error) => {
    const _path = path ? `${path}.${error.property}` : error.property;

    if (error.constraints) {
      const key = Object.keys(error.constraints)[0];
      acc[_path] = {
        type: key,
        message: error.constraints[key],
      };

      const _e = acc[_path];
      if (validateAllFieldCriteria && _e) {
        Object.assign(_e, { types: error.constraints });
      }
    }

    if (error.children && error.children.length) {
      parseErrors(error.children, validateAllFieldCriteria, acc, _path);
    }

    return acc;
  }, parsedErrors);
};

export const classValidatorResolver: Resolver =
  (schema, schemaOptions = {}, resolverOptions = {}) =>
  async (values, _, options) => {
    const { transformer, validator } = schemaOptions;
    const data = plainToClass(schema, values, transformer);

    const rawErrors = await (resolverOptions.mode === 'sync'
      ? validateSync
      : validate)(data, validator);

    if (rawErrors.length) {
      return {
        values: {},
        errors: toNestErrors(
          parseErrors(
            rawErrors,
            !options.shouldUseNativeValidation &&
              options.criteriaMode === 'all',
          ),
          options,
        ),
      };
    }

    options.shouldUseNativeValidation && validateFieldsNatively({}, options);

    return {
      values: resolverOptions.rawValues ? values : data,
      errors: {},
    };
  };