-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
processRawValidationErrors.ts
139 lines (123 loc) · 4.87 KB
/
processRawValidationErrors.ts
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { ErrorObject } from 'ajv';
import get from 'lodash/get';
import {
createErrorHandler,
CustomValidator,
ErrorTransformer,
FormContextType,
getDefaultFormState,
getUiOptions,
PROPERTIES_KEY,
RJSFSchema,
RJSFValidationError,
StrictRJSFSchema,
toErrorSchema,
UiSchema,
unwrapErrorHandler,
validationDataMerge,
ValidatorType,
} from '@rjsf/utils';
export type RawValidationErrorsType<Result = any> = { errors?: Result[]; validationError?: Error };
/** Transforming the error output from ajv to format used by @rjsf/utils.
* At some point, components should be updated to support ajv.
*
* @param errors - The list of AJV errors to convert to `RJSFValidationErrors`
* @param [uiSchema] - An optional uiSchema that is passed to `transformErrors` and `customValidate`
*/
export function transformRJSFValidationErrors<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(errors: ErrorObject[] = [], uiSchema?: UiSchema<T, S, F>): RJSFValidationError[] {
return errors.map((e: ErrorObject) => {
const { instancePath, keyword, params, schemaPath, parentSchema, ...rest } = e;
let { message = '' } = rest;
let property = instancePath.replace(/\//g, '.');
let stack = `${property} ${message}`.trim();
if ('missingProperty' in params) {
property = property ? `${property}.${params.missingProperty}` : params.missingProperty;
const currentProperty: string = params.missingProperty;
const uiSchemaTitle = getUiOptions(get(uiSchema, `${property.replace(/^\./, '')}`)).title;
if (uiSchemaTitle) {
message = message.replace(`'${currentProperty}'`, `'${uiSchemaTitle}'`);
} else {
const parentSchemaTitle = get(parentSchema, [PROPERTIES_KEY, currentProperty, 'title']);
if (parentSchemaTitle) {
message = message.replace(`'${currentProperty}'`, `'${parentSchemaTitle}'`);
}
}
stack = message;
} else {
const uiSchemaTitle = getUiOptions<T, S, F>(get(uiSchema, `${property.replace(/^\./, '')}`)).title;
if (uiSchemaTitle) {
stack = `'${uiSchemaTitle}' ${message}`.trim();
} else {
const parentSchemaTitle = parentSchema?.title;
if (parentSchemaTitle) {
stack = `'${parentSchemaTitle}' ${message}`.trim();
}
}
}
// put data in expected format
return {
name: keyword,
property,
message,
params, // specific to ajv
stack,
schemaPath,
};
});
}
/** This function processes the `formData` with an optional user contributed `customValidate` function, which receives
* the form data and a `errorHandler` function that will be used to add custom validation errors for each field. Also
* supports a `transformErrors` function that will take the raw AJV validation errors, prior to custom validation and
* transform them in what ever way it chooses.
*
* @param validator - The `ValidatorType` implementation used for the `getDefaultFormState()` call
* @param rawErrors - The list of raw `ErrorObject`s to process
* @param formData - The form data to validate
* @param schema - The schema against which to validate the form data
* @param [customValidate] - An optional function that is used to perform custom validation
* @param [transformErrors] - An optional function that is used to transform errors after AJV validation
* @param [uiSchema] - An optional uiSchema that is passed to `transformErrors` and `customValidate`
*/
export default function processRawValidationErrors<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(
validator: ValidatorType<T, S, F>,
rawErrors: RawValidationErrorsType<ErrorObject>,
formData: T | undefined,
schema: S,
customValidate?: CustomValidator<T, S, F>,
transformErrors?: ErrorTransformer<T, S, F>,
uiSchema?: UiSchema<T, S, F>
) {
const { validationError: invalidSchemaError } = rawErrors;
let errors = transformRJSFValidationErrors<T, S, F>(rawErrors.errors, uiSchema);
if (invalidSchemaError) {
errors = [...errors, { stack: invalidSchemaError!.message }];
}
if (typeof transformErrors === 'function') {
errors = transformErrors(errors, uiSchema);
}
let errorSchema = toErrorSchema<T>(errors);
if (invalidSchemaError) {
errorSchema = {
...errorSchema,
$schema: {
__errors: [invalidSchemaError!.message],
},
};
}
if (typeof customValidate !== 'function') {
return { errors, errorSchema };
}
// Include form data with undefined values, which is required for custom validation.
const newFormData = getDefaultFormState<T, S, F>(validator, schema, formData, schema, true) as T;
const errorHandler = customValidate(newFormData, createErrorHandler<T>(newFormData), uiSchema);
const userErrorSchema = unwrapErrorHandler<T>(errorHandler);
return validationDataMerge<T>({ errors, errorSchema }, userErrorSchema);
}