Skip to content

Commit

Permalink
fix: Fixed rjsf-team#3170 by passing uiSchema into the `validateFor…
Browse files Browse the repository at this point in the history
…mData()` call (rjsf-team#3358)

* fix: Fixed 3170 by passing `uiSchema` into the `validateFormData()` call
Fixes rjsf-team#3170 by updating types and implementations to support passing `uiSchema` to the `validateFormData()` call so that it can be forwarded to `customValidate()` and `transformErrors()`
- In `@rjsf/utils`, updated the `ValidatorType` to take the `F` generic so that `validateFormData()` can be passed `uiSchema?: UiSchema<T, S, F>`
  - This required updating all of the schema-based functions to also take the `F` generic and properly adding generics to all the function calls
  - Also, the `CustomValidator` and `ErrorTransformer` types were updated to take all the generics needed to add the `uiSchema?: UiSchema<T, S, F>` parameter to the functions
- In `@rjsf/validator-ajv6`, updated the `customizeValidator` and `AJV6Validator` implementations to add the `S` and `F` generics
  - Updated `validateFormData()` to accept a new optional `uiSchema` parameter that is passed to `transformErrors()` and `customValidate()`
- In `@rjsf/validator-ajv8`, updated the `customizeValidator` and `AJV8Validator` implementations to add the `F` generic
  - Updated `validateFormData()` to accept a new optional `uiSchema` parameter that is passed to `transformErrors()` and `customValidate()`
- In `@rjsf/core`, updated the `ValidatorType`, `CustomValidator` and `ErrorTransformer` types to add the appropriate missing generics
  - Also passed `uiSchema` to the `validateFormData()` call
- Updated the `utility-functions.md` file to add the new generics
- Updated the `typescript.md` file to switch to using `customizeValidator()` with the generics to get the `validator`
- Updated the `CHANGELOG.md` file accordingly

* - Add test cases to validate the proper passing of `uiSchema`
  • Loading branch information
heath-freenome authored and shijistar committed Jun 8, 2023
1 parent 6e88e78 commit 237853e
Show file tree
Hide file tree
Showing 22 changed files with 470 additions and 240 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Expand Up @@ -41,6 +41,7 @@ should change the heading of the (upcoming) version to include a major version b
- Updated `ArrayField` to pass the new `totalItems` and `canAdd` props to the `ArrayFieldItemTemplate` instances, fixing [#3315](https://github.com/rjsf-team/react-jsonschema-form/issues/3315)
- Also refactored the near duplicate logic for `onAddClick` and `onAddIndexClick` into a new `_handleAddClick()` function, fixing [#3316](https://github.com/rjsf-team/react-jsonschema-form/issues/3316)
- Fix passing of generic types to a few helper methods, partially fixing [#3072](https://github.com/rjsf-team/react-jsonschema-form/issues/3072)
- Updated the types for `ValidatorType`, `CustomValidator` and `ErrorTransformer` to add the new generics, as well as passing `uiSchema` to the `validateFormData()` call, partially fixing [#3170](https://github.com/rjsf-team/react-jsonschema-form/issues/3170)

## @rjsf/fluent-ui
- Updated the usage of the `ButtonTemplates` to pass the new required `registry` prop, filtering it out in the actual implementations before spreading props, fixing - [#3314](https://github.com/rjsf-team/react-jsonschema-form/issues/3314)
Expand All @@ -66,11 +67,21 @@ should change the heading of the (upcoming) version to include a major version b
## @rjsf/utils
- Updated the `SubmitButtonProps` and `IconButtonProps` to add required `registry` prop, fixing - [#3314](https://github.com/rjsf-team/react-jsonschema-form/issues/3314)
- Updated the `ArrayFieldTemplateItemType` to add the new `totalItems` and `canAdd` props, fixing [#3315](https://github.com/rjsf-team/react-jsonschema-form/issues/3315)
- Updated the `CustomValidator` and `ErrorTransformer` types to take the full set of `T`, `S`, `F` generics in order to accept a new optional `uiSchema` property, partially fixing [#3170](https://github.com/rjsf-team/react-jsonschema-form/issues/3170)
- Updated the `ValidatorType` to add the `F` generic to allow the `validateFormData()` function to take a new optional `uiSchema` parameter, partially fixing [#3170](https://github.com/rjsf-team/react-jsonschema-form/issues/3170)
- Updated many of the schema-based utility functions to take the additional generics as well to fulfill the `ValidatorType` interface change

## @rjsf/validator-ajv6
- Updated the `customizeValidator` and `AJV6Validator` implementations to add the `S` and `F` generics, so that `validateFormData()` can accept a new optional `uiSchema` parameter that is passed to `transformErrors()` and `customValidate()`, partially fixing [#3170](https://github.com/rjsf-team/react-jsonschema-form/issues/3170)

## @rjsf/validator-ajv8
- Updated the `customizeValidator` and `AJV8Validator` implementations to add the `F` generic, so that `validateFormData()` can accept a new optional `uiSchema` parameter that is passed to `transformErrors()` and `customValidate()`, partially fixing [#3170](https://github.com/rjsf-team/react-jsonschema-form/issues/3170)

## Dev / docs / playground
- Fixed the documentation for `ArrayFieldItemTemplate`, `SubmitButtonProps` and `IconButtonProps` as part of the fix for [#3314](https://github.com/rjsf-team/react-jsonschema-form/issues/3314) and [#3315](https://github.com/rjsf-team/react-jsonschema-form/issues/3315)
- Updated the documentation in `form-props.md` for `children`, fixing [#3322](https://github.com/rjsf-team/react-jsonschema-form/issues/3322)
- Added new `typescript.md` documentation to `Advanced Customization` describing how to use custom generics as part of the fix for [#3072](https://github.com/rjsf-team/react-jsonschema-form/issues/3072)
- Updated the documentation in `utilty-functions.md` to add the new `F` generic to all the places which needed them

# 5.0.0-beta-15

Expand Down
23 changes: 17 additions & 6 deletions docs/advanced-customization/typescript.md
Expand Up @@ -47,7 +47,7 @@ If you are working with a simple, unchanging JSON Schema and you have defined a

```tsx
import { RJSFSchema } from "@rjsf/utils";
import { validator } from "@rjsf/validator-ajv8";
import { customizeValidator } from "@rjsf/validator-ajv8";
import { Form } from "@rjsf/core";

interface FormData {
Expand All @@ -65,6 +65,8 @@ const schema: RJSFSchema = {

const formData: FormData = {};

const validator = customizeValidator<FormData>();

render((
<Form<FormData> schema={schema} validator={validator} formData={formData} />
), document.getElementById("app"));
Expand All @@ -78,7 +80,7 @@ If you are using something like the [Ajv utility types for schemas](https://ajv.
```tsx
import { JSONSchemaType } from "ajv";
import { RJSFSchema } from "@rjsf/utils";
import { validator } from "@rjsf/validator-ajv8";
import { customizeValidator } from "@rjsf/validator-ajv8";
import { Form } from "@rjsf/core";

interface FormData {
Expand All @@ -96,11 +98,14 @@ const schema: MySchema = {
}
};

const validator = customizeValidator<any, MySchema>();

render((
<Form<any, MySchema> schema={schema} validator={validator} />
), document.getElementById("app"));

// Alternatively since you have the type, you could also use this
// const validator = customizeValidator<FormData, MySchema>();
// render((
// <Form<FormData, MySchema> schema={schema} validator={validator} />
//), document.getElementById("app"));
Expand All @@ -115,7 +120,7 @@ If you have a type for this data, you can override this generic as follows:

```tsx
import { RJSFSchema } from "@rjsf/utils";
import { validator } from "@rjsf/validator-ajv8";
import { customizeValidator } from "@rjsf/validator-ajv8";
import { Form } from "@rjsf/core";

interface FormContext {
Expand All @@ -136,6 +141,8 @@ const formContext: FormContext = {
}
};

const validator = customizeValidator<any, RJSFSchema, FormContext>();

render((
<Form<any, RJSFSchema, FormContext> schema={schema} validator={validator} formContext={formContext} />
), document.getElementById("app"));
Expand All @@ -147,7 +154,7 @@ Using the `withTheme()` function is just as easy:

```tsx
import { RJSFSchema } from "@rjsf/utils";
import { validator } from "@rjsf/validator-ajv8";
import { customizeValidator } from "@rjsf/validator-ajv8";
import { withTheme, ThemeProps } from '@rjsf/core';

interface FormData {
Expand All @@ -173,6 +180,8 @@ const theme: ThemeProps<FormData, MySchema, FormContext> = { widgets: {test: ()

const ThemedForm = withTheme<FormData, MySchema, FormContext>(theme);

const validator = customizeValidator<FormData, MySchema, FormContext>();

const Demo = () => (
<ThemedForm schema={schema} uiSchema={uiSchema} validator={validator} />
);
Expand All @@ -190,7 +199,7 @@ If you are doing something like the following to create a new theme based on `@r
import React from "react";
import { WidgetProps } from "@rjsf/utils";
import { ThemeProps, withTheme } from "@rjsf/core";
import { validator } from "@rjsf/validator-ajv8";
import validator from "@rjsf/validator-ajv8";
import { Theme } from "@rjsf/mui";

const OldBaseInputTemplate = Theme.templates.BaseInputTemplate;
Expand Down Expand Up @@ -221,7 +230,7 @@ Then you would use the new `generateTheme()` and `generateForm()` functions as f
import React from "react";
import { WidgetProps } from "@rjsf/utils";
import { ThemeProps, withTheme } from "@rjsf/core";
import { validator } from "@rjsf/validator-ajv8";
import { customizeValidator } from "@rjsf/validator-ajv8";
import { generateTheme } from "@rjsf/mui";

interface FormData {
Expand Down Expand Up @@ -262,6 +271,8 @@ const myTheme: ThemeProps<FormData, MySchema, FormContext> = {

const ThemedForm = withTheme<FormData, MySchema, FormContext>(myTheme);

const validator = customizeValidator<FormData, MySchema, FormContext>();

// You could also do since they are effectively the same:
// const ThemedForm = generateForm<FormData, MySchema, FormContext>(myTheme);

Expand Down
40 changes: 20 additions & 20 deletions docs/api-reference/utility-functions.md
Expand Up @@ -347,7 +347,7 @@ Extracts the range spec information `{ step?: number, min?: number, max?: number
#### Returns
- RangeSpecType: A range specification from the schema

### schemaRequiresTrueValue()
### schemaRequiresTrueValue\<S extends StrictRJSFSchema = RJSFSchema>()
Check to see if a `schema` specifies that a value must be true. This happens when:
- `schema.const` is truthy
- `schema.enum` == `[true]`
Expand Down Expand Up @@ -407,11 +407,11 @@ Converts a UTC date string into a local Date format

## Validator-based utility functions

### getDefaultFormState<T = any, S extends StrictRJSFSchema = RJSFSchema,>()
### getDefaultFormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
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`.

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

#### Parameters
- validator: ValidatorType<T, S> - An implementation of the `ValidatorType` interface that will be used when necessary
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which the display label flag is desired
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to derive potentially displayable information
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s

#### Returns
- boolean: True if the label should be displayed or false if it should not

### getMatchingOption<T = any, S extends StrictRJSFSchema = RJSFSchema,>()
### getMatchingOption<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Given the `formData` and list of `options`, attempts to find the index of the option that best matches the data.

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

#### Parameters
- validator: ValidatorType<T, S> - An implementation of the `ValidatorType` interface that will be used when necessary
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which check for array of files flag is desired
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to check the widget
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s

#### Returns
- boolean: True if schema/uiSchema contains an array of files, otherwise false

### isMultiSelect<T = any, S extends StrictRJSFSchema = RJSFSchema,>()
### isMultiSelect<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Checks to see if the `schema` combination represents a multi-select

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

#### Returns
- boolean: True if schema contains a multi-select, otherwise false

### isSelect<T = any, S extends StrictRJSFSchema = RJSFSchema,>()
### isSelect<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Checks to see if the `schema` combination represents a select

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

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

### mergeValidationData<T = any, S extends StrictRJSFSchema = RJSFSchema>()
### mergeValidationData<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
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`.
If no `additionalErrorSchema` is passed, then `validationData` is returned.

#### Parameters
- validator: ValidatorType<T, S> - An implementation of the `ValidatorType` interface that will be used to convert an ErrorSchema to a list of errors
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used to convert an ErrorSchema to a list of errors
- validationData: ValidationData<T> - The current `ValidationData` into which to merge the additional errors
- [additionalErrorSchema]: ErrorSchema<T> - The additional set of errors in an `ErrorSchema`

#### Returns
- ValidationData<T>: The `validationData` with the additional errors from `additionalErrorSchema` merged into it, if provided.

### retrieveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,>()
### retrieveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies
resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the
potentially recursive resolution.

#### Parameters
- validator: ValidatorType<T, S> - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
- schema: S - The schema for which retrieving a schema is desired
- [rootSchema={}]: S - The root schema that will be forwarded to all the APIs
- [rawFormData]: T - The current formData, if any, to assist retrieving a schema

#### Returns
- RJSFSchema: The schema having its conditions, additional properties, references and dependencies resolved

### toIdSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,>()
### toIdSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Generates an `IdSchema` object for the `schema`, recursively

#### Parameters
- validator: ValidatorType<T, S> - An implementation of the `ValidatorType` interface that will be used when necessary
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which the `IdSchema` is desired
- [id]: string | null - The base id for the schema
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
Expand All @@ -519,11 +519,11 @@ Generates an `IdSchema` object for the `schema`, recursively
#### Returns
- IDSchema<T>: The `IdSchema` object for the `schema`

### toPathSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,>()
### toPathSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Generates an `PathSchema` object for the `schema`, recursively

#### Parameters
- validator: ValidatorType<T, S> - An implementation of the `ValidatorType` interface that will be used when necessary
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
- schema: S - The schema for which the `PathSchema` is desired
- [name='']: string - The base name for the schema
- [rootSchema]: S - The root schema, used to primarily to look up `$ref`s
Expand All @@ -539,7 +539,7 @@ Creates a `SchemaUtilsType` interface that is based around the given `validator`
The resulting interface implementation will forward the `validator` and `rootSchema` to all the wrapped APIs.

#### Parameters
- validator: ValidatorType<T, S> - an implementation of the `ValidatorType` interface that will be forwarded to all the APIs
- validator: ValidatorType<T, S, F> - an implementation of the `ValidatorType` interface that will be forwarded to all the APIs
- rootSchema: S - The root schema that will be forwarded to all the APIs

#### Returns
Expand Down
15 changes: 8 additions & 7 deletions packages/core/src/components/Form.tsx
Expand Up @@ -43,7 +43,7 @@ export interface FormProps<
/** The JSON schema object for the form */
schema: S;
/** An implementation of the `ValidatorType` interface that is needed for form validation to work */
validator: ValidatorType<T, S>;
validator: ValidatorType<T, S, F>;
/** The optional children for the form, if provided, it will replace the default `SubmitButton` */
children?: React.ReactNode;
/** The uiSchema for the form */
Expand Down Expand Up @@ -138,7 +138,7 @@ export interface FormProps<
target?: string;
// Errors and validation
/** Formerly the `validate` prop; Takes a function that specifies custom validation rules for the form */
customValidate?: CustomValidator<T>;
customValidate?: CustomValidator<T, S, F>;
/** This prop allows passing in custom errors that are augmented with the existing JSON Schema errors on the form; it
* can be used to implement asynchronous validation
*/
Expand Down Expand Up @@ -169,7 +169,7 @@ export interface FormProps<
/** A function can be passed to this prop in order to make modifications to the default errors resulting from JSON
* Schema validation
*/
transformErrors?: ErrorTransformer;
transformErrors?: ErrorTransformer<T, S, F>;
// Private
/**
* _internalFormWrapper is currently used by the semantic-ui theme to provide a custom wrapper around `<Form />`
Expand Down Expand Up @@ -309,7 +309,7 @@ export default class Form<
"liveValidate" in props ? props.liveValidate : this.props.liveValidate;
const mustValidate = edit && !props.noValidate && liveValidate;
const rootSchema = schema;
let schemaUtils: SchemaUtilsType<T, S> = state.schemaUtils;
let schemaUtils: SchemaUtilsType<T, S, F> = state.schemaUtils;
if (
!schemaUtils ||
schemaUtils.doesSchemaUtilsDiffer(props.validator, rootSchema)
Expand Down Expand Up @@ -407,20 +407,21 @@ export default class Form<
validate(
formData: T,
schema = this.props.schema,
altSchemaUtils?: SchemaUtilsType<T, S>
altSchemaUtils?: SchemaUtilsType<T, S, F>
): ValidationData<T> {
const schemaUtils = altSchemaUtils
? altSchemaUtils
: this.state.schemaUtils;
const { customValidate, transformErrors } = this.props;
const { customValidate, transformErrors, uiSchema } = this.props;
const resolvedSchema = schemaUtils.retrieveSchema(schema, formData);
return schemaUtils
.getValidator()
.validateFormData(
formData,
resolvedSchema,
customValidate,
transformErrors
transformErrors,
uiSchema
);
}

Expand Down

0 comments on commit 237853e

Please sign in to comment.