Skip to content

Commit 5f1bd8a

Browse files
Fixed rjsf-team#1596 by adapting the fix from rjsf-team#2002 into rjsf v5 (rjsf-team#3047)
* Fixed rjsf-team#1596 by adapting the fix from rjsf-team#2002 into rjsf v5 - Added a new `mergeValidationData()` method in `@rjsf/utils` to handle the appending of errors onto the end of the validationData from an additional error schema - Added this to the `schema` directory `index.ts` along with exposing it on the `SchemaUtils` type and implementation - Also fixed the type of `toErrorList()` in `ValidatorType` to change from `fieldName: string` to `fieldPath: string[]` - Added reusable `mergeValidationDataTest.ts`, calling it in the utils - Update the `@rjsf/validator-ajv6` to pick up the breaking change from rjsf-team#2002 around `AJV6Validator.toErrorList()` - Also modified the `validateFormData()` function to return the result of `mergeValidationData()` when the user has a custom validator - Updated tests for the new structure of the `toErrorList()` data - Also updated the `schema.tests` to add the new `mergeValidationDataTest()` - Updated `Form` to use the `mergeValidationData()` function in the few places where `extraErrors` was being merged into the schema validation - Updated tests for the new structor of the `toErrorList()` data - Updated the `CHANGELOG.md` to describe this fix - Updated the `5.x upgrade guide.md` to describe all the new utility functions added and describe util.js and validator.js breaking changes - Updated the `validation.md` documentation for the `ErrorListTemplate` change along with making the `RJSFValidationError` interface describe the optional properties * - Responded to reviewer feedback... also, removed the `:` after the property in the `stack` to match AJV stack, adding `message` to also match AJV - Added migration guide changes
1 parent e3edba7 commit 5f1bd8a

19 files changed

+367
-82
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@ should change the heading of the (upcoming) version to include a major version b
1919
## @rjsf/utils
2020
- clear errors on formData change when liveOmit=true when "additionalProperties: false" [issue 1507](https://github.com/rjsf-team/react-jsonschema-form/issues/1507) (https://github.com/rjsf-team/react-jsonschema-form/pull/2631)
2121

22+
## @rjsf/validator-ajv6
23+
- A **BREAKING CHANGE** to `toErrorList()` was made so that it takes `fieldPath: string[]` rather than `fieldName='root'` as part of the fix to (https://github.com/rjsf-team/react-jsonschema-form/issues/1596)
24+
- The returned `errors` also now adds `property` from the `fieldPath` along with the proper path from the `property` to the `stack` message, making it consistent with the AJV errors.
25+
- Previously the `stack` attribute would say `root: error message`; now it says `. error message`
26+
- In addition, the extra information provided by AJV is no longer lost from the `errors` when merged with custom validation, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1596).
27+
2228
## @rjsf/core
2329
- **BREAKING CHANGE** Fix overriding core submit button className (https://github.com/rjsf-team/react-jsonschema-form/issues/2979)
2430
- Fix `ui:field` with anyOf or oneOf no longer rendered twice (#2890)
2531
- **BREAKING CHANGE** Fixed `anyOf` and `oneOf` getting incorrect, potentially duplicate ids when combined with array (https://github.com/rjsf-team/react-jsonschema-form/issues/2197)
2632
- `formContext` is now passed properly to `SchemaField`, fixes (https://github.com/rjsf-team/react-jsonschema-form/issues/2394, https://github.com/rjsf-team/react-jsonschema-form/issues/2274)
2733
- Added `ui:duplicateKeySuffixSeparator` to customize how duplicate object keys are renamed when using `additionalProperties`.
34+
- The `extraErrors` are now consistently appended onto the end of the schema validation-based `errors` information that is returned via the `onErrors()` callback when submit fails.
35+
- In addition, the extra information provided by AJV is no longer stripped from the `errors` during the merge process, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1596).
2836

2937
## @rjsf/antd
3038
- Fix esm build to use `@rollup/plugin-replace` to replace `antd/lib` and `rc-picker/lib` with `antd/es` and `rc-picker/es` respectively, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2962)

docs/5.x upgrade guide.md

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ Unfortunately, there is required work pending to properly support React 18, so u
2323
### New packages
2424

2525
There are three new packages added in RJSF version 5:
26-
- `@rjsf/utils`: All of the [utility functions](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/utiltity-functions) previously imported from `@rjsf/core/utils` as well as the Typescript types for RJSV version 5.
26+
- `@rjsf/utils`: All of the [utility functions](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/utiltity-functions) previously imported from `@rjsf/core/utils` as well as the Typescript types for RJSF version 5.
27+
- The following new utility functions were added: `createSchemaUtils()`, `getInputProps()`, `mergeValidationData()` and `processSelectValue()`
2728
- `@rjsf/validator-ajv6`: The [ajv](https://github.com/ajv-validator/ajv)-v6-based validator refactored out of `@rjsf/[email protected]`, that implements the `ValidatorType` interface defined in `@rjsf/utils`.
2829
- `@rjsf/mui`: Previously `@rjsf/material-ui/v5`, now provided as its own theme.
2930

@@ -86,10 +87,10 @@ render((
8687
), document.getElementById("app"));
8788
```
8889

89-
#### validate renamed
90+
##### validate renamed
9091
In version 5, the `validate` prop on `Form` was renamed to `customValidate` to avoid confusion with the new `validator` prop.
9192

92-
#### utils
93+
#### utils.js
9394
In version 5, all the utility functions that were previously accessed via `import { utils } from '@rjsf/core';` are now available via `import utils from '@rjsf/utils';`.
9495
Because of the decoupling of validation from `@rjsf/core` there is a breaking change for all the [validator-based utility functions](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/utiltity-functions#validator-based-utility-functions), since they now require an additional `ValidatorType` parameter.
9596

@@ -130,6 +131,93 @@ function YourWidget(props: WidgetProps) {
130131
}
131132
```
132133

134+
#### validator.js
135+
Because of the decoupling of validation from `@rjsf/core` this file was refactored into its own `@rjsf/validator-ajv` package.
136+
During that refactor a few **breaking changes** were made to how it works related to custom validation and `ErrorSchema` conversion.
137+
138+
##### toErrorList param changed
139+
In previous versions, the `toErrorList()` function used to take a `fieldName` string defaulted to `root`, and use it to format the `stack` message.
140+
In version 5, `fieldName` was changed to `fieldPath` string array defaulted to an empty array, and is used to recursively add the field name to the errors as the `property` object along with the raw `message`.
141+
The result is that if you had an `ErrorSchema` that looks like:
142+
143+
```tsx
144+
const errorSchema: ErrorSchema = {
145+
__error: [ "error message 1"],
146+
password: { __error: "passwords do not match" }
147+
}
148+
```
149+
150+
The returned result from calling `toErrorList(errorSchema)` has changed as follows:
151+
152+
```tsx
153+
// version 4 result
154+
[
155+
{ stack: "root: error message 1" },
156+
{ stack: "password: passwords do not match" }
157+
]
158+
159+
// version 5 result
160+
[
161+
{ property: ".", message: "error message 1", stack: ". error message 1" },
162+
{ property: ".password", message: "passwords do not match", stack: ".password passwords do not match" }
163+
]
164+
```
165+
166+
##### Custom validation and extraErrors
167+
In previous versions, when using a custom validator on the `Form`, any errors that were generated were inconsistently inserted into the validations `errors` list.
168+
In addition, there was an [issue](https://github.com/rjsf-team/react-jsonschema-form/issues/1596) with the additional AJV error information besides the `stack` being lost when custom validation generated errors, which has been fixed.
169+
Also, when `extraErrors` were provided, they were being inconsistently inserted into the `errors` list and the additional AJV error information besides the `stack` was also lost.
170+
In version 5, all of these errors will be consistently appended onto the end of the validation `errors` list, and the additional AJV error information is maintained.
171+
172+
In other words, if custom validation or `extraErrors` produced the following `ErrorSchema`:
173+
174+
```tsx
175+
{
176+
__error: [ "Please correct your password"],
177+
password2: { __error: "passwords do not match" }
178+
}
179+
```
180+
181+
And the AJV validation produced the following `ErrorSchema`:
182+
183+
```tsx
184+
{
185+
__error: [{
186+
message: "should NOT be shorter than 3 characters",
187+
name: "minLength",
188+
params: { limit: 3 },
189+
property: ".password2",
190+
schemaPath: "#/properties/password2/minLength",
191+
stack: ".password2 should NOT be shorter than 3 characters",
192+
}]
193+
}
194+
```
195+
196+
The resulting `errors` list has changed as follows:
197+
198+
```tsx
199+
// version 4
200+
[
201+
{ stack: "root: Please correct your password" },
202+
{ stack: "password2: passwords do not match" },
203+
{ stack: "password2: should NOT be shorter than 3 characters" }
204+
]
205+
206+
// version 5
207+
[
208+
{
209+
message: "should NOT be shorter than 3 characters",
210+
name: "minLength",
211+
params: { limit: 3 },
212+
property: ".password2",
213+
schemaPath: "#/properties/password2/minLength",
214+
stack: ".password2 should NOT be shorter than 3 characters",
215+
},
216+
{ property: ".", message: "Please correct your password", stack: ". Please correct your password" },
217+
{ property: ".", message: "passwords do not match", stack: ".password2 passwords do not match" }
218+
]
219+
```
220+
133221
#### Generate correct ids when arrays are combined with `anyOf`/`oneOf`
134222

135223
In v4, with arrays inside `anyOf` or `oneOf`, the parent name was not used to generate ids.

docs/api-reference/utility-functions.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ Converts a UTC date string into a local Date format
385385
Returns the superset of `formData` that includes the given set updated to include any missing fields that have computed to have defaults provided in the `schema`.
386386

387387
#### Parameters
388-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
388+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
389389
- theSchema: RJSFSchema - The schema for which the default state is desired
390390
- [formData]: T - The current formData, if any, onto which to provide any missing defaults
391391
- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s
@@ -398,7 +398,7 @@ Returns the superset of `formData` that includes the given set updated to includ
398398
Determines whether the combination of `schema` and `uiSchema` properties indicates that the label for the `schema` should be displayed in a UI.
399399

400400
#### Parameters
401-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
401+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
402402
- schema: RJSFSchema - The schema for which the display label flag is desired
403403
- [uiSchema={}]: UiSchema<T, F> - The UI schema from which to derive potentially displayable information
404404
- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s
@@ -410,7 +410,7 @@ Determines whether the combination of `schema` and `uiSchema` properties indicat
410410
Given the `formData` and list of `options`, attempts to find the index of the option that best matches the data.
411411

412412
#### Parameters
413-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
413+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
414414
- formData: T | undefined - The current formData, if any, used to figure out a match
415415
- options: RJSFSchema[] - The list of options to find a matching options from
416416
- rootSchema: RJSFSchema - The root schema, used to primarily to look up `$ref`s
@@ -422,7 +422,7 @@ Given the `formData` and list of `options`, attempts to find the index of the op
422422
Checks to see if the `schema` and `uiSchema` combination represents an array of files
423423

424424
#### Parameters
425-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
425+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
426426
- schema: RJSFSchema - The schema for which check for array of files flag is desired
427427
- [uiSchema={}]: UiSchema<T, F> - The UI schema from which to check the widget
428428
- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s
@@ -434,7 +434,7 @@ Checks to see if the `schema` and `uiSchema` combination represents an array of
434434
Checks to see if the `schema` combination represents a multi-select
435435

436436
#### Parameters
437-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
437+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
438438
- schema: RJSFSchema - The schema for which check for a multi-select flag is desired
439439
- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s
440440

@@ -445,20 +445,32 @@ Checks to see if the `schema` combination represents a multi-select
445445
Checks to see if the `schema` combination represents a select
446446

447447
#### Parameters
448-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
448+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
449449
- theSchema: RJSFSchema - The schema for which check for a select flag is desired
450450
- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s
451451

452452
#### Returns
453453
- boolean: True if schema contains a select, otherwise false
454454

455+
### mergeValidationData<T=any>()
456+
Merges the errors in `additionalErrorSchema` into the existing `validationData` by combining the hierarchies in the two `ErrorSchema`s and then appending the error list from the `additionalErrorSchema` obtained by calling `validator.toErrorList()` onto the `errors` in the `validationData`.
457+
If no `additionalErrorSchema` is passed, then `validationData` is returned.
458+
459+
#### Parameters
460+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used to convert an ErrorSchema to a list of errors
461+
- validationData: ValidationData<T> - The current `ValidationData` into which to merge the additional errors
462+
- [additionalErrorSchema]: ErrorSchema<T> - The additional set of errors in an `ErrorSchema`
463+
464+
#### Returns
465+
- ValidationData<T>: The `validationData` with the additional errors from `additionalErrorSchema` merged into it, if provided.
466+
455467
### retrieveSchema<T = any>()
456468
Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies
457469
resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the
458470
potentially recursive resolution.
459471

460472
#### Parameters
461-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
473+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
462474
- schema: RJSFSchema - The schema for which retrieving a schema is desired
463475
- [rootSchema={}]: RJSFSchema - The root schema that will be forwarded to all the APIs
464476
- [rawFormData]: T - The current formData, if any, to assist retrieving a schema
@@ -470,7 +482,7 @@ potentially recursive resolution.
470482
Generates an `IdSchema` object for the `schema`, recursively
471483

472484
#### Parameters
473-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
485+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
474486
- schema: RJSFSchema - The schema for which the `IdSchema` is desired
475487
- [id]: string | null - The base id for the schema
476488
- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s
@@ -485,7 +497,7 @@ Generates an `IdSchema` object for the `schema`, recursively
485497
Generates an `PathSchema` object for the `schema`, recursively
486498

487499
#### Parameters
488-
- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary
500+
- validator: ValidatorType<T> - An implementation of the `ValidatorType` interface that will be used when necessary
489501
- schema: RJSFSchema - The schema for which the `PathSchema` is desired
490502
- [name='']: string - The base name for the schema
491503
- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s
@@ -501,7 +513,7 @@ Creates a `SchemaUtilsType` interface that is based around the given `validator`
501513
The resulting interface implementation will forward the `validator` and `rootSchema` to all the wrapped APIs.
502514

503515
#### Parameters
504-
- validator: ValidatorType - an implementation of the `ValidatorType` interface that will be forwarded to all the APIs
516+
- validator: ValidatorType<T> - an implementation of the `ValidatorType` interface that will be forwarded to all the APIs
505517
- rootSchema: RJSFSchema - The root schema that will be forwarded to all the APIs
506518

507519
#### Returns

docs/usage/validation.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,19 @@ render((
123123
124124
Each element in the `errors` list passed to `transformErrors` is a `RJSFValidationError` interface (in `@rjsf/utils`) and has the following properties:
125125

126-
- `name`: name of the error, for example, "required" or "minLength"
127-
- `message`: message, for example, "is a required property" or "should NOT be shorter than 3 characters"
128-
- `params`: an object with the error params returned by ajv ([see doc](https://github.com/ajv-validator/ajv/tree/6a671057ea6aae690b5967ee26a0ddf8452c6297#error-parameters) for more info).
129-
- `property`: a string in Javascript property accessor notation to the data path of the field with the error. For example, `.name` or `['first-name']`.
130-
- `schemaPath`: JSON pointer to the schema of the keyword that failed validation. For example, `#/fields/firstName/required`. (Note: this may sometimes be wrong due to a [bug in ajv](https://github.com/ajv-validator/ajv/issues/512)).
126+
- `name`: optional name of the error, for example, "required" or "minLength"
127+
- `message`: optional message, for example, "is a required property" or "should NOT be shorter than 3 characters"
128+
- `params`: optional object with the error params returned by ajv ([see doc](https://github.com/ajv-validator/ajv/tree/6a671057ea6aae690b5967ee26a0ddf8452c6297#error-parameters) for more info).
129+
- `property`: optional string in Javascript property accessor notation to the data path of the field with the error. For example, `.name` or `.first-name`.
130+
- `schemaPath`: optional JSON pointer to the schema of the keyword that failed validation. For example, `#/fields/firstName/required`. (Note: this may sometimes be wrong due to a [bug in ajv](https://github.com/ajv-validator/ajv/issues/512)).
131131
- `stack`: full error name, for example ".name is a required property".
132132

133133
## Error List Display
134134

135135
To take control over how the form errors are displayed, you can define an *error list template* for your form.
136136
This list is the form global error list that appears at the top of your forms.
137137

138-
An error list template is basically a React stateless component being passed errors as props so you can render them as you like:
138+
An error list template is basically a React stateless component being passed errors as props, so you can render them as you like:
139139

140140
```tsx
141141
import validator from "@rjsf/validator-ajv6";
@@ -167,7 +167,7 @@ render((
167167
showErrorList={true}
168168
formData={""}
169169
liveValidate
170-
ErrorList={ErrorListTemplate} />
170+
templates: {{ ErrorListTemplate }} />
171171
), document.getElementById("app"));
172172
```
173173

@@ -181,7 +181,6 @@ The following props are passed to `ErrorList` as defined by the `ErrorListProps`
181181
- `uiSchema`: The uiSchema that was passed to `Form`.
182182
- `formContext`: The `formContext` object that you passed to `Form`.
183183

184-
185184
## The case of empty strings
186185

187186
When a text input is empty, the field in form data is set to `undefined`. String fields that use `enum` and a `select` widget will have an empty option at the top of the options list that when selected will result in the field being `undefined`.

0 commit comments

Comments
 (0)