diff --git a/CHANGELOG.md b/CHANGELOG.md index fc45839147..96a569d315 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ should change the heading of the (upcoming) version to include a major version b - Updated `Experimental_DefaultFormStateBehavior` to add a new `constAsDefaults` option - Updated `getDefaultFormState()` to use the new `constAsDefaults` option to control how const is used for defaulting, fixing [#4344](https://github.com/rjsf-team/react-jsonschema-form/issues/4344), [#4361](https://github.com/rjsf-team/react-jsonschema-form/issues/4361) and [#4377](https://github.com/rjsf-team/react-jsonschema-form/issues/4377) +- Use `experimental_customMergeAllOf` option in functions that have previously missed it. ## Dev / docs / playground diff --git a/packages/docs/docs/api-reference/utility-functions.md b/packages/docs/docs/api-reference/utility-functions.md index a6b0455234..1bc00e0cfb 100644 --- a/packages/docs/docs/api-reference/utility-functions.md +++ b/packages/docs/docs/api-reference/utility-functions.md @@ -899,7 +899,7 @@ Returns the superset of `formData` that includes the given set updated to includ - [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s - [includeUndefinedValues=false]: boolean | "excludeObjectChildren" - Optional flag, if true, cause undefined values to be added as defaults. If "excludeObjectChildren", cause undefined values for this object and pass `includeUndefinedValues` as false when computing defaults for any nested object properties. - [experimental_defaultFormStateBehavior]: Experimental_DefaultFormStateBehavior - See `Form` documentation for the [experimental_defaultFormStateBehavior](./form-props.md#experimental_defaultFormStateBehavior) prop -- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_customMergeAllOf) prop +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -916,6 +916,7 @@ Determines whether the combination of `schema` and `uiSchema` properties indicat - [uiSchema={}]: UiSchema - The UI schema from which to derive potentially displayable information - [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s - [globalOptions={}]: GlobalUISchemaOptions - The optional Global UI Schema from which to get any fallback `xxx` options +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -936,6 +937,7 @@ The closest match is determined using the number of matching properties, and mor - options: S[] - The list of options to find a matching options from - [selectedOption=-1]: number - The index of the currently selected option, defaulted to -1 if not specified - [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -985,6 +987,7 @@ Checks to see if the `schema` and `uiSchema` combination represents an array of - schema: S - The schema for which check for array of files flag is desired - [uiSchema={}]: UiSchema - The UI schema from which to check the widget - [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -999,6 +1002,7 @@ Checks to see if the `schema` combination represents a multi-select - validator: ValidatorType - 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 | undefined - The root schema, used to primarily to look up `$ref`s +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -1013,6 +1017,7 @@ Checks to see if the `schema` combination represents a select - validator: ValidatorType - 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 | undefined - The root schema, used to primarily to look up `$ref`s +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -1048,6 +1053,7 @@ potentially recursive resolution. - 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 | undefined - The current formData, if any, to assist retrieving a schema +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -1067,6 +1073,7 @@ Also, any properties in the old schema that are non-existent in the new schema a - [newSchema]: S | undefined - The new schema for which the data is being sanitized - [oldSchema]: S | undefined - The old schema from which the data originated - [data={}]: any - The form data associated with the schema, defaulting to an empty object when undefined +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -1085,6 +1092,7 @@ Generates an `IdSchema` object for the `schema`, recursively - [formData]: T | undefined - The current formData, if any, to assist retrieving a schema - [idPrefix='root']: string - The prefix to use for the id - [idSeparator='_']: string - The separator to use for the path segments in the id +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns @@ -1101,6 +1109,7 @@ Generates an `PathSchema` object for the `schema`, recursively - [name='']: string - The base name for the schema - [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s - [formData]: T | undefined - The current formData, if any, to assist retrieving a schema +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop #### Returns diff --git a/packages/utils/src/createSchemaUtils.ts b/packages/utils/src/createSchemaUtils.ts index cfd6883e39..153dd9a000 100644 --- a/packages/utils/src/createSchemaUtils.ts +++ b/packages/utils/src/createSchemaUtils.ts @@ -133,7 +133,14 @@ class SchemaUtils, globalOptions?: GlobalUISchemaOptions) { - return getDisplayLabel(this.validator, schema, uiSchema, this.rootSchema, globalOptions); + return getDisplayLabel( + this.validator, + schema, + uiSchema, + this.rootSchema, + globalOptions, + this.experimental_customMergeAllOf + ); } /** Determines which of the given `options` provided most closely matches the `formData`. @@ -161,7 +168,8 @@ class SchemaUtils) { - return isFilesArray(this.validator, schema, uiSchema, this.rootSchema); + return isFilesArray(this.validator, schema, uiSchema, this.rootSchema, this.experimental_customMergeAllOf); } /** Checks to see if the `schema` combination represents a multi-select @@ -208,7 +216,7 @@ class SchemaUtils(this.validator, schema, this.rootSchema); + return isMultiSelect(this.validator, schema, this.rootSchema, this.experimental_customMergeAllOf); } /** Checks to see if the `schema` combination represents a select @@ -217,7 +225,7 @@ class SchemaUtils(this.validator, schema, this.rootSchema); + return isSelect(this.validator, schema, this.rootSchema, this.experimental_customMergeAllOf); } /** Merges the errors in `additionalErrorSchema` into the existing `validationData` by combining the hierarchies in @@ -265,7 +273,14 @@ class SchemaUtils { - return toPathSchema(this.validator, schema, name, this.rootSchema, formData); + return toPathSchema( + this.validator, + schema, + name, + this.rootSchema, + formData, + this.experimental_customMergeAllOf + ); } } diff --git a/packages/utils/src/schema/getClosestMatchingOption.ts b/packages/utils/src/schema/getClosestMatchingOption.ts index 400ebab75e..3360db3747 100644 --- a/packages/utils/src/schema/getClosestMatchingOption.ts +++ b/packages/utils/src/schema/getClosestMatchingOption.ts @@ -10,7 +10,7 @@ import getFirstMatchingOption from './getFirstMatchingOption'; import retrieveSchema, { resolveAllReferences } from './retrieveSchema'; import { ONE_OF_KEY, REF_KEY, JUNK_OPTION_ID, ANY_OF_KEY } from '../constants'; import guessType from '../guessType'; -import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; +import { Experimental_CustomMergeAllOf, FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema'; import getOptionMatchingSimpleDiscriminator from '../getOptionMatchingSimpleDiscriminator'; @@ -45,13 +45,15 @@ export const JUNK_OPTION: StrictRJSFSchema = { * @param rootSchema - The root JSON schema of the entire form * @param schema - The schema for which the score is being calculated * @param formData - The form data associated with the schema, used to calculate the score + * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas * @returns - The score a schema against the formData */ export function calculateIndexScore( validator: ValidatorType, rootSchema: S, schema?: S, - formData?: any + formData?: any, + experimental_customMergeAllOf?: Experimental_CustomMergeAllOf ): number { let totalScore = 0; if (schema) { @@ -64,8 +66,23 @@ export function calculateIndexScore(validator, value as S, rootSchema, formValue); - return score + calculateIndexScore(validator, rootSchema, newSchema, formValue || {}); + const newSchema = retrieveSchema( + validator, + value as S, + rootSchema, + formValue, + experimental_customMergeAllOf + ); + return ( + score + + calculateIndexScore( + validator, + rootSchema, + newSchema, + formValue || {}, + experimental_customMergeAllOf + ) + ); } if ((has(value, ONE_OF_KEY) || has(value, ANY_OF_KEY)) && formValue) { const key = has(value, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY; @@ -78,7 +95,8 @@ export function calculateIndexScore(validator, rootSchema, value as S, formValue); + return ( + score + + calculateIndexScore(validator, rootSchema, value as S, formValue, experimental_customMergeAllOf) + ); } if (value.type === guessType(formValue)) { // If the types match, then we bump the score by one @@ -135,6 +156,7 @@ export function calculateIndexScore ): number { // First resolve any refs in the options const resolvedOptions = options.map((option) => { @@ -185,7 +208,7 @@ export default function getClosestMatchingOption< (scoreData: BestType, index: number) => { const { bestScore } = scoreData; const option = resolvedOptions[index]; - const score = calculateIndexScore(validator, rootSchema, option, formData); + const score = calculateIndexScore(validator, rootSchema, option, formData, experimental_customMergeAllOf); scoreCount.add(score); if (score > bestScore) { return { bestIndex: index, bestScore: score }; diff --git a/packages/utils/src/schema/getDefaultFormState.ts b/packages/utils/src/schema/getDefaultFormState.ts index 580e9f8d98..f367b2cbf0 100644 --- a/packages/utils/src/schema/getDefaultFormState.ts +++ b/packages/utils/src/schema/getDefaultFormState.ts @@ -241,6 +241,7 @@ export function computeDefaults = {}, defaults?: T | T[] | undefined @@ -465,6 +471,7 @@ export function getArrayDefaults(validator, schema, rootSchema) || + isMultiSelect(validator, schema, rootSchema, experimental_customMergeAllOf) || computeSkipPopulate(validator, schema, rootSchema) || schema.minItems <= defaultsLength ) { @@ -531,6 +539,7 @@ export function getArrayDefaults = {}, rootSchema?: S, - globalOptions?: GlobalUISchemaOptions + globalOptions?: GlobalUISchemaOptions, + experimental_customMergeAllOf?: Experimental_CustomMergeAllOf ): boolean { const uiOptions = getUiOptions(uiSchema, globalOptions); const { label = true } = uiOptions; @@ -41,8 +44,8 @@ export default function getDisplayLabel< if (schemaType === 'array') { displayLabel = - isMultiSelect(validator, schema, rootSchema) || - isFilesArray(validator, schema, uiSchema, rootSchema) || + isMultiSelect(validator, schema, rootSchema, experimental_customMergeAllOf) || + isFilesArray(validator, schema, uiSchema, rootSchema, experimental_customMergeAllOf) || isCustomWidget(uiSchema); } diff --git a/packages/utils/src/schema/isFilesArray.ts b/packages/utils/src/schema/isFilesArray.ts index 1e7f43451b..9c69020f2e 100644 --- a/packages/utils/src/schema/isFilesArray.ts +++ b/packages/utils/src/schema/isFilesArray.ts @@ -1,5 +1,12 @@ import { UI_WIDGET_KEY } from '../constants'; -import { FormContextType, RJSFSchema, StrictRJSFSchema, UiSchema, ValidatorType } from '../types'; +import { + Experimental_CustomMergeAllOf, + FormContextType, + RJSFSchema, + StrictRJSFSchema, + UiSchema, + ValidatorType, +} from '../types'; import retrieveSchema from './retrieveSchema'; /** Checks to see if the `schema` and `uiSchema` combination represents an array of files @@ -8,19 +15,27 @@ import retrieveSchema from './retrieveSchema'; * @param schema - The schema for which check for array of files flag is desired * @param [uiSchema={}] - The UI schema from which to check the widget * @param [rootSchema] - The root schema, used to primarily to look up `$ref`s + * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas * @returns - True if schema/uiSchema contains an array of files, otherwise false */ export default function isFilesArray( validator: ValidatorType, schema: S, uiSchema: UiSchema = {}, - rootSchema?: S + rootSchema?: S, + experimental_customMergeAllOf?: Experimental_CustomMergeAllOf ) { if (uiSchema[UI_WIDGET_KEY] === 'files') { return true; } if (schema.items) { - const itemsSchema = retrieveSchema(validator, schema.items as S, rootSchema); + const itemsSchema = retrieveSchema( + validator, + schema.items as S, + rootSchema, + undefined, + experimental_customMergeAllOf + ); return itemsSchema.type === 'string' && itemsSchema.format === 'data-url'; } return false; diff --git a/packages/utils/src/schema/isMultiSelect.ts b/packages/utils/src/schema/isMultiSelect.ts index 04c8a54e68..412a5e6752 100644 --- a/packages/utils/src/schema/isMultiSelect.ts +++ b/packages/utils/src/schema/isMultiSelect.ts @@ -1,4 +1,4 @@ -import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; +import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType, Experimental_CustomMergeAllOf } from '../types'; import isSelect from './isSelect'; @@ -7,15 +7,21 @@ import isSelect from './isSelect'; * @param validator - An implementation of the `ValidatorType` interface that will be used when necessary * @param schema - The schema for which check for a multi-select flag is desired * @param [rootSchema] - The root schema, used to primarily to look up `$ref`s + * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas * @returns - True if schema contains a multi-select, otherwise false */ export default function isMultiSelect< T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any ->(validator: ValidatorType, schema: S, rootSchema?: S) { +>( + validator: ValidatorType, + schema: S, + rootSchema?: S, + experimental_customMergeAllOf?: Experimental_CustomMergeAllOf +) { if (!schema.uniqueItems || !schema.items || typeof schema.items === 'boolean') { return false; } - return isSelect(validator, schema.items as S, rootSchema); + return isSelect(validator, schema.items as S, rootSchema, experimental_customMergeAllOf); } diff --git a/packages/utils/src/schema/isSelect.ts b/packages/utils/src/schema/isSelect.ts index 1be32b670c..741912a2ab 100644 --- a/packages/utils/src/schema/isSelect.ts +++ b/packages/utils/src/schema/isSelect.ts @@ -1,5 +1,5 @@ import isConstant from '../isConstant'; -import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; +import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType, Experimental_CustomMergeAllOf } from '../types'; import retrieveSchema from './retrieveSchema'; /** Checks to see if the `schema` combination represents a select @@ -7,14 +7,16 @@ import retrieveSchema from './retrieveSchema'; * @param validator - An implementation of the `ValidatorType` interface that will be used when necessary * @param theSchema - The schema for which check for a select flag is desired * @param [rootSchema] - The root schema, used to primarily to look up `$ref`s + * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas * @returns - True if schema contains a select, otherwise false */ export default function isSelect( validator: ValidatorType, theSchema: S, - rootSchema: S = {} as S + rootSchema: S = {} as S, + experimental_customMergeAllOf?: Experimental_CustomMergeAllOf ) { - const schema = retrieveSchema(validator, theSchema, rootSchema, undefined); + const schema = retrieveSchema(validator, theSchema, rootSchema, undefined, experimental_customMergeAllOf); const altSchemas = schema.oneOf || schema.anyOf; if (Array.isArray(schema.enum)) { return true; diff --git a/packages/utils/src/schema/retrieveSchema.ts b/packages/utils/src/schema/retrieveSchema.ts index af837512ac..17439cf396 100644 --- a/packages/utils/src/schema/retrieveSchema.ts +++ b/packages/utils/src/schema/retrieveSchema.ts @@ -365,13 +365,20 @@ export function resolveAllReferences( * @param theSchema - The schema for which the existing additional properties is desired * @param [rootSchema] - The root schema, used to primarily to look up `$ref`s * @param validator * @param [aFormData] - The current formData, if any, to assist retrieving a schema + * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas * @returns - The updated schema with additional properties stubbed */ export function stubExistingAdditionalProperties< T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any ->(validator: ValidatorType, theSchema: S, rootSchema?: S, aFormData?: T): S { +>( + validator: ValidatorType, + theSchema: S, + rootSchema?: S, + aFormData?: T, + experimental_customMergeAllOf?: Experimental_CustomMergeAllOf +): S { // Clone the schema so that we don't ruin the consumer's original const schema = { ...theSchema, @@ -393,7 +400,8 @@ export function stubExistingAdditionalProperties< validator, { $ref: get(schema.additionalProperties, [REF_KEY]) } as S, rootSchema, - formData as T + formData as T, + experimental_customMergeAllOf ); } else if ('type' in schema.additionalProperties!) { additionalProperties = { ...schema.additionalProperties }; @@ -456,7 +464,8 @@ export function retrieveSchemaInternal< rootSchema, expandAllBranches, recurseList, - rawFormData + rawFormData, + experimental_customMergeAllOf ); return resolvedSchemas.flatMap((s: S) => { let resolvedSchema = s; @@ -507,7 +516,13 @@ export function retrieveSchemaInternal< const hasAdditionalProperties = ADDITIONAL_PROPERTIES_KEY in resolvedSchema && resolvedSchema.additionalProperties !== false; if (hasAdditionalProperties) { - return stubExistingAdditionalProperties(validator, resolvedSchema, rootSchema, rawFormData as T); + return stubExistingAdditionalProperties( + validator, + resolvedSchema, + rootSchema, + rawFormData as T, + experimental_customMergeAllOf + ); } return resolvedSchema; diff --git a/packages/utils/src/schema/sanitizeDataForNewSchema.ts b/packages/utils/src/schema/sanitizeDataForNewSchema.ts index cd07eea930..c1ab83c7b8 100644 --- a/packages/utils/src/schema/sanitizeDataForNewSchema.ts +++ b/packages/utils/src/schema/sanitizeDataForNewSchema.ts @@ -1,7 +1,14 @@ import get from 'lodash/get'; import has from 'lodash/has'; -import { FormContextType, GenericObjectType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; +import { + Experimental_CustomMergeAllOf, + FormContextType, + GenericObjectType, + RJSFSchema, + StrictRJSFSchema, + ValidatorType, +} from '../types'; import { PROPERTIES_KEY, REF_KEY } from '../constants'; import retrieveSchema from './retrieveSchema'; @@ -51,6 +58,7 @@ const NO_VALUE = Symbol('no Value'); * @param [newSchema] - The new schema for which the data is being sanitized * @param [oldSchema] - The old schema from which the data originated * @param [data={}] - The form data associated with the schema, defaulting to an empty object when undefined + * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas * @returns - The new form data, with all the fields uniquely associated with the old schema set * to `undefined`. Will return `undefined` if the new schema is not an object containing properties. */ @@ -58,7 +66,14 @@ export default function sanitizeDataForNewSchema< T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any ->(validator: ValidatorType, rootSchema: S, newSchema?: S, oldSchema?: S, data: any = {}): T { +>( + validator: ValidatorType, + rootSchema: S, + newSchema?: S, + oldSchema?: S, + data: any = {}, + experimental_customMergeAllOf?: Experimental_CustomMergeAllOf +): T { // By default, we will clear the form data let newFormData; // If the new schema is of type object and that object contains a list of properties @@ -82,10 +97,22 @@ export default function sanitizeDataForNewSchema< let newKeyedSchema: S = get(newSchema, [PROPERTIES_KEY, key], {}); // Resolve the refs if they exist if (has(oldKeyedSchema, REF_KEY)) { - oldKeyedSchema = retrieveSchema(validator, oldKeyedSchema, rootSchema, formValue); + oldKeyedSchema = retrieveSchema( + validator, + oldKeyedSchema, + rootSchema, + formValue, + experimental_customMergeAllOf + ); } if (has(newKeyedSchema, REF_KEY)) { - newKeyedSchema = retrieveSchema(validator, newKeyedSchema, rootSchema, formValue); + newKeyedSchema = retrieveSchema( + validator, + newKeyedSchema, + rootSchema, + formValue, + experimental_customMergeAllOf + ); } // Now get types and see if they are the same const oldSchemaTypeForKey = get(oldKeyedSchema, 'type'); @@ -104,7 +131,8 @@ export default function sanitizeDataForNewSchema< rootSchema, newKeyedSchema, oldKeyedSchema, - formValue + formValue, + experimental_customMergeAllOf ); if (itemData !== undefined || newSchemaTypeForKey === 'array') { // only put undefined values for the array type and not the object type @@ -154,10 +182,22 @@ export default function sanitizeDataForNewSchema< !Array.isArray(newSchemaItems) ) { if (has(oldSchemaItems, REF_KEY)) { - oldSchemaItems = retrieveSchema(validator, oldSchemaItems as S, rootSchema, data as T); + oldSchemaItems = retrieveSchema( + validator, + oldSchemaItems as S, + rootSchema, + data as T, + experimental_customMergeAllOf + ); } if (has(newSchemaItems, REF_KEY)) { - newSchemaItems = retrieveSchema(validator, newSchemaItems as S, rootSchema, data as T); + newSchemaItems = retrieveSchema( + validator, + newSchemaItems as S, + rootSchema, + data as T, + experimental_customMergeAllOf + ); } // Now get types and see if they are the same const oldSchemaType = get(oldSchemaItems, 'type'); @@ -172,7 +212,8 @@ export default function sanitizeDataForNewSchema< rootSchema, newSchemaItems as S, oldSchemaItems as S, - aValue + aValue, + experimental_customMergeAllOf ); if (itemValue !== undefined && (maxItems < 0 || newValue.length < maxItems)) { newValue.push(itemValue); diff --git a/packages/utils/src/schema/toIdSchema.ts b/packages/utils/src/schema/toIdSchema.ts index 1265cd8af8..21cb334517 100644 --- a/packages/utils/src/schema/toIdSchema.ts +++ b/packages/utils/src/schema/toIdSchema.ts @@ -41,7 +41,7 @@ function toIdSchemaInternal ): IdSchema { if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) { - const _schema = retrieveSchema(validator, schema, rootSchema, formData); + const _schema = retrieveSchema(validator, schema, rootSchema, formData, experimental_customMergeAllOf); const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema)); if (sameSchemaIndex === -1) { return toIdSchemaInternal( diff --git a/packages/utils/src/schema/toPathSchema.ts b/packages/utils/src/schema/toPathSchema.ts index e0b2abb368..d29f225e5a 100644 --- a/packages/utils/src/schema/toPathSchema.ts +++ b/packages/utils/src/schema/toPathSchema.ts @@ -15,7 +15,15 @@ import { RJSF_ADDITIONAL_PROPERTIES_FLAG, } from '../constants'; import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema'; -import { FormContextType, GenericObjectType, PathSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; +import { + Experimental_CustomMergeAllOf, + FormContextType, + GenericObjectType, + PathSchema, + RJSFSchema, + StrictRJSFSchema, + ValidatorType, +} from '../types'; import getClosestMatchingOption from './getClosestMatchingOption'; import retrieveSchema from './retrieveSchema'; @@ -28,6 +36,7 @@ import retrieveSchema from './retrieveSchema'; * @param [rootSchema] - The root schema, used to primarily to look up `$ref`s * @param [formData] - The current formData, if any, to assist retrieving a schema * @param [_recurseList=[]] - The list of retrieved schemas currently being recursed, used to prevent infinite recursion + * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas * @returns - The `PathSchema` object for the `schema` */ function toPathSchemaInternal( @@ -36,10 +45,11 @@ function toPathSchemaInternal ): PathSchema { if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) { - const _schema = retrieveSchema(validator, schema, rootSchema, formData); + const _schema = retrieveSchema(validator, schema, rootSchema, formData, experimental_customMergeAllOf); const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema)); if (sameSchemaIndex === -1) { return toPathSchemaInternal( @@ -48,7 +58,8 @@ function toPathSchemaInternal(schema); - const index = getClosestMatchingOption(validator, rootSchema!, formData, xxxOf, 0, discriminator); + const index = getClosestMatchingOption( + validator, + rootSchema!, + formData, + xxxOf, + 0, + discriminator, + experimental_customMergeAllOf + ); const _schema: S = xxxOf![index] as S; pathSchema = { ...pathSchema, - ...toPathSchemaInternal(validator, _schema, name, rootSchema, formData, _recurseList), + ...toPathSchemaInternal( + validator, + _schema, + name, + rootSchema, + formData, + _recurseList, + experimental_customMergeAllOf + ), }; } @@ -84,7 +111,8 @@ function toPathSchemaInternal)[i] = toPathSchemaInternal( @@ -93,7 +121,8 @@ function toPathSchemaInternal( @@ -143,7 +175,8 @@ export default function toPathSchema ): PathSchema { - return toPathSchemaInternal(validator, schema, name, rootSchema, formData); + return toPathSchemaInternal(validator, schema, name, rootSchema, formData, undefined, experimental_customMergeAllOf); }