Skip to content

Commit 011659d

Browse files
experimental_customMergeAllOf v2 (#4383)
* Pass experimental_customMergeAllOf to missing code branches * Add experimental_customMergeAllOf parameter to documentation, fix link with anchor * Changelog --------- Co-authored-by: Marek Bodinger <[email protected]>
1 parent e71cb8d commit 011659d

13 files changed

+235
-56
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ should change the heading of the (upcoming) version to include a major version b
2626

2727
- Updated `Experimental_DefaultFormStateBehavior` to add a new `constAsDefaults` option
2828
- 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)
29+
- Use `experimental_customMergeAllOf` option in functions that have previously missed it.
2930

3031
## Dev / docs / playground
3132

packages/docs/docs/api-reference/utility-functions.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ Returns the superset of `formData` that includes the given set updated to includ
899899
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
900900
- [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.
901901
- [experimental_defaultFormStateBehavior]: Experimental_DefaultFormStateBehavior - See `Form` documentation for the [experimental_defaultFormStateBehavior](./form-props.md#experimental_defaultFormStateBehavior) prop
902-
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_customMergeAllOf) prop
902+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
903903

904904
#### Returns
905905

@@ -916,6 +916,7 @@ Determines whether the combination of `schema` and `uiSchema` properties indicat
916916
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to derive potentially displayable information
917917
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
918918
- [globalOptions={}]: GlobalUISchemaOptions - The optional Global UI Schema from which to get any fallback `xxx` options
919+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
919920

920921
#### Returns
921922

@@ -936,6 +937,7 @@ The closest match is determined using the number of matching properties, and mor
936937
- options: S[] - The list of options to find a matching options from
937938
- [selectedOption=-1]: number - The index of the currently selected option, defaulted to -1 if not specified
938939
- [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected
940+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
939941

940942
#### Returns
941943

@@ -985,6 +987,7 @@ Checks to see if the `schema` and `uiSchema` combination represents an array of
985987
- schema: S - The schema for which check for array of files flag is desired
986988
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to check the widget
987989
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
990+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
988991

989992
#### Returns
990993

@@ -999,6 +1002,7 @@ Checks to see if the `schema` combination represents a multi-select
9991002
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
10001003
- schema: S - The schema for which check for a multi-select flag is desired
10011004
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
1005+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
10021006

10031007
#### Returns
10041008

@@ -1013,6 +1017,7 @@ Checks to see if the `schema` combination represents a select
10131017
- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used when necessary
10141018
- theSchema: S - The schema for which check for a select flag is desired
10151019
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
1020+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
10161021

10171022
#### Returns
10181023

@@ -1048,6 +1053,7 @@ potentially recursive resolution.
10481053
- schema: S - The schema for which retrieving a schema is desired
10491054
- [rootSchema={}]: S - The root schema that will be forwarded to all the APIs
10501055
- [rawFormData]: T | undefined - The current formData, if any, to assist retrieving a schema
1056+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
10511057

10521058
#### Returns
10531059

@@ -1067,6 +1073,7 @@ Also, any properties in the old schema that are non-existent in the new schema a
10671073
- [newSchema]: S | undefined - The new schema for which the data is being sanitized
10681074
- [oldSchema]: S | undefined - The old schema from which the data originated
10691075
- [data={}]: any - The form data associated with the schema, defaulting to an empty object when undefined
1076+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
10701077

10711078
#### Returns
10721079

@@ -1085,6 +1092,7 @@ Generates an `IdSchema` object for the `schema`, recursively
10851092
- [formData]: T | undefined - The current formData, if any, to assist retrieving a schema
10861093
- [idPrefix='root']: string - The prefix to use for the id
10871094
- [idSeparator='_']: string - The separator to use for the path segments in the id
1095+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
10881096

10891097
#### Returns
10901098

@@ -1101,6 +1109,7 @@ Generates an `PathSchema` object for the `schema`, recursively
11011109
- [name='']: string - The base name for the schema
11021110
- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s
11031111
- [formData]: T | undefined - The current formData, if any, to assist retrieving a schema
1112+
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf&lt;S&gt; - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop
11041113

11051114
#### Returns
11061115

packages/utils/src/createSchemaUtils.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,14 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
133133
* @returns - True if the label should be displayed or false if it should not
134134
*/
135135
getDisplayLabel(schema: S, uiSchema?: UiSchema<T, S, F>, globalOptions?: GlobalUISchemaOptions) {
136-
return getDisplayLabel<T, S, F>(this.validator, schema, uiSchema, this.rootSchema, globalOptions);
136+
return getDisplayLabel<T, S, F>(
137+
this.validator,
138+
schema,
139+
uiSchema,
140+
this.rootSchema,
141+
globalOptions,
142+
this.experimental_customMergeAllOf
143+
);
137144
}
138145

139146
/** Determines which of the given `options` provided most closely matches the `formData`.
@@ -161,7 +168,8 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
161168
formData,
162169
options,
163170
selectedOption,
164-
discriminatorField
171+
discriminatorField,
172+
this.experimental_customMergeAllOf
165173
);
166174
}
167175

@@ -199,7 +207,7 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
199207
* @returns - True if schema/uiSchema contains an array of files, otherwise false
200208
*/
201209
isFilesArray(schema: S, uiSchema?: UiSchema<T, S, F>) {
202-
return isFilesArray<T, S, F>(this.validator, schema, uiSchema, this.rootSchema);
210+
return isFilesArray<T, S, F>(this.validator, schema, uiSchema, this.rootSchema, this.experimental_customMergeAllOf);
203211
}
204212

205213
/** Checks to see if the `schema` combination represents a multi-select
@@ -208,7 +216,7 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
208216
* @returns - True if schema contains a multi-select, otherwise false
209217
*/
210218
isMultiSelect(schema: S) {
211-
return isMultiSelect<T, S, F>(this.validator, schema, this.rootSchema);
219+
return isMultiSelect<T, S, F>(this.validator, schema, this.rootSchema, this.experimental_customMergeAllOf);
212220
}
213221

214222
/** Checks to see if the `schema` combination represents a select
@@ -217,7 +225,7 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
217225
* @returns - True if schema contains a select, otherwise false
218226
*/
219227
isSelect(schema: S) {
220-
return isSelect<T, S, F>(this.validator, schema, this.rootSchema);
228+
return isSelect<T, S, F>(this.validator, schema, this.rootSchema, this.experimental_customMergeAllOf);
221229
}
222230

223231
/** Merges the errors in `additionalErrorSchema` into the existing `validationData` by combining the hierarchies in
@@ -265,7 +273,14 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
265273
* to `undefined`. Will return `undefined` if the new schema is not an object containing properties.
266274
*/
267275
sanitizeDataForNewSchema(newSchema?: S, oldSchema?: S, data?: any): T {
268-
return sanitizeDataForNewSchema(this.validator, this.rootSchema, newSchema, oldSchema, data);
276+
return sanitizeDataForNewSchema(
277+
this.validator,
278+
this.rootSchema,
279+
newSchema,
280+
oldSchema,
281+
data,
282+
this.experimental_customMergeAllOf
283+
);
269284
}
270285

271286
/** Generates an `IdSchema` object for the `schema`, recursively
@@ -298,7 +313,14 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
298313
* @returns - The `PathSchema` object for the `schema`
299314
*/
300315
toPathSchema(schema: S, name?: string, formData?: T): PathSchema<T> {
301-
return toPathSchema<T, S, F>(this.validator, schema, name, this.rootSchema, formData);
316+
return toPathSchema<T, S, F>(
317+
this.validator,
318+
schema,
319+
name,
320+
this.rootSchema,
321+
formData,
322+
this.experimental_customMergeAllOf
323+
);
302324
}
303325
}
304326

packages/utils/src/schema/getClosestMatchingOption.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import getFirstMatchingOption from './getFirstMatchingOption';
1010
import retrieveSchema, { resolveAllReferences } from './retrieveSchema';
1111
import { ONE_OF_KEY, REF_KEY, JUNK_OPTION_ID, ANY_OF_KEY } from '../constants';
1212
import guessType from '../guessType';
13-
import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
13+
import { Experimental_CustomMergeAllOf, FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
1414
import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema';
1515
import getOptionMatchingSimpleDiscriminator from '../getOptionMatchingSimpleDiscriminator';
1616

@@ -45,13 +45,15 @@ export const JUNK_OPTION: StrictRJSFSchema = {
4545
* @param rootSchema - The root JSON schema of the entire form
4646
* @param schema - The schema for which the score is being calculated
4747
* @param formData - The form data associated with the schema, used to calculate the score
48+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
4849
* @returns - The score a schema against the formData
4950
*/
5051
export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
5152
validator: ValidatorType<T, S, F>,
5253
rootSchema: S,
5354
schema?: S,
54-
formData?: any
55+
formData?: any,
56+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
5557
): number {
5658
let totalScore = 0;
5759
if (schema) {
@@ -64,8 +66,23 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
6466
return score;
6567
}
6668
if (has(value, REF_KEY)) {
67-
const newSchema = retrieveSchema<T, S, F>(validator, value as S, rootSchema, formValue);
68-
return score + calculateIndexScore<T, S, F>(validator, rootSchema, newSchema, formValue || {});
69+
const newSchema = retrieveSchema<T, S, F>(
70+
validator,
71+
value as S,
72+
rootSchema,
73+
formValue,
74+
experimental_customMergeAllOf
75+
);
76+
return (
77+
score +
78+
calculateIndexScore<T, S, F>(
79+
validator,
80+
rootSchema,
81+
newSchema,
82+
formValue || {},
83+
experimental_customMergeAllOf
84+
)
85+
);
6986
}
7087
if ((has(value, ONE_OF_KEY) || has(value, ANY_OF_KEY)) && formValue) {
7188
const key = has(value, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
@@ -78,7 +95,8 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
7895
formValue,
7996
get(value, key) as S[],
8097
-1,
81-
discriminator
98+
discriminator,
99+
experimental_customMergeAllOf
82100
)
83101
);
84102
}
@@ -87,7 +105,10 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
87105
// If the structure is matching then give it a little boost in score
88106
score += 1;
89107
}
90-
return score + calculateIndexScore<T, S, F>(validator, rootSchema, value as S, formValue);
108+
return (
109+
score +
110+
calculateIndexScore<T, S, F>(validator, rootSchema, value as S, formValue, experimental_customMergeAllOf)
111+
);
91112
}
92113
if (value.type === guessType(formValue)) {
93114
// If the types match, then we bump the score by one
@@ -135,6 +156,7 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
135156
* @param [selectedOption=-1] - The index of the currently selected option, defaulted to -1 if not specified
136157
* @param [discriminatorField] - The optional name of the field within the options object whose value is used to
137158
* determine which option is selected
159+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
138160
* @returns - The index of the option that is the closest match to the `formData` or the `selectedOption` if no match
139161
*/
140162
export default function getClosestMatchingOption<
@@ -147,7 +169,8 @@ export default function getClosestMatchingOption<
147169
formData: T | undefined,
148170
options: S[],
149171
selectedOption = -1,
150-
discriminatorField?: string
172+
discriminatorField?: string,
173+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
151174
): number {
152175
// First resolve any refs in the options
153176
const resolvedOptions = options.map((option) => {
@@ -185,7 +208,7 @@ export default function getClosestMatchingOption<
185208
(scoreData: BestType, index: number) => {
186209
const { bestScore } = scoreData;
187210
const option = resolvedOptions[index];
188-
const score = calculateIndexScore(validator, rootSchema, option, formData);
211+
const score = calculateIndexScore(validator, rootSchema, option, formData, experimental_customMergeAllOf);
189212
scoreCount.add(score);
190213
if (score > bestScore) {
191214
return { bestIndex: index, bestScore: score };

packages/utils/src/schema/getDefaultFormState.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
241241
includeUndefinedValues,
242242
_recurseList,
243243
experimental_defaultFormStateBehavior,
244+
experimental_customMergeAllOf,
244245
parentDefaults: Array.isArray(parentDefaults) ? parentDefaults[idx] : undefined,
245246
rawFormData: formData as T,
246247
required,
@@ -268,7 +269,8 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
268269
isEmpty(formData) ? undefined : formData,
269270
oneOf as S[],
270271
0,
271-
discriminator
272+
discriminator,
273+
experimental_customMergeAllOf
272274
)
273275
] as S;
274276
schemaToCompute = mergeSchemas(remaining, schemaToCompute) as S;
@@ -285,7 +287,8 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
285287
isEmpty(formData) ? undefined : formData,
286288
anyOf as S[],
287289
0,
288-
discriminator
290+
discriminator,
291+
experimental_customMergeAllOf
289292
)
290293
] as S;
291294
schemaToCompute = mergeSchemas(remaining, schemaToCompute) as S;
@@ -297,6 +300,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
297300
includeUndefinedValues,
298301
_recurseList: updatedRecurseList,
299302
experimental_defaultFormStateBehavior: experimental_dfsb_to_compute,
303+
experimental_customMergeAllOf,
300304
parentDefaults: defaults as T | undefined,
301305
rawFormData: formData as T,
302306
required,
@@ -404,6 +408,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
404408
rootSchema,
405409
_recurseList,
406410
experimental_defaultFormStateBehavior,
411+
experimental_customMergeAllOf,
407412
includeUndefinedValues: includeUndefinedValues === true,
408413
parentDefaults: get(defaults, [key]),
409414
rawFormData: get(formData, [key]),
@@ -440,6 +445,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
440445
rootSchema = {} as S,
441446
_recurseList = [],
442447
experimental_defaultFormStateBehavior = undefined,
448+
experimental_customMergeAllOf = undefined,
443449
required,
444450
}: ComputeDefaultsProps<T, S> = {},
445451
defaults?: T | T[] | undefined
@@ -465,6 +471,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
465471
rootSchema,
466472
_recurseList,
467473
experimental_defaultFormStateBehavior,
474+
experimental_customMergeAllOf,
468475
parentDefaults: item,
469476
required,
470477
});
@@ -482,6 +489,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
482489
rootSchema,
483490
_recurseList,
484491
experimental_defaultFormStateBehavior,
492+
experimental_customMergeAllOf,
485493
rawFormData: item,
486494
parentDefaults: get(defaults, [idx]),
487495
required,
@@ -513,7 +521,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
513521
const defaultsLength = Array.isArray(defaults) ? defaults.length : 0;
514522
if (
515523
!schema.minItems ||
516-
isMultiSelect<T, S, F>(validator, schema, rootSchema) ||
524+
isMultiSelect<T, S, F>(validator, schema, rootSchema, experimental_customMergeAllOf) ||
517525
computeSkipPopulate<T, S, F>(validator, schema, rootSchema) ||
518526
schema.minItems <= defaultsLength
519527
) {
@@ -531,6 +539,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
531539
rootSchema,
532540
_recurseList,
533541
experimental_defaultFormStateBehavior,
542+
experimental_customMergeAllOf,
534543
required,
535544
})
536545
) as T[];

0 commit comments

Comments
 (0)