Skip to content

Commit 7c3f0d8

Browse files
committed
Merge remote-tracking branch 'origin/main' into input-const
2 parents 7ffad5b + a347257 commit 7c3f0d8

File tree

10 files changed

+295
-58
lines changed

10 files changed

+295
-58
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ should change the heading of the (upcoming) version to include a major version b
2121
## @rjsf/utils
2222

2323
- Made fields with const property pre-filled and readonly, fixing [#2600](https://github.com/rjsf-team/react-jsonschema-form/issues/2600)
24+
- Added `experimental_customMergeAllOf` option to `retrieveSchema` to allow custom merging of `allOf` schemas
2425

2526
# 5.21.2
2627

@@ -2000,7 +2001,7 @@ const Component = () => {
20002001

20012002
## @rjsf/validator-ajv8
20022003

2003-
- Support for localization (L12n) on a customized validator using a `Localizer` function passed as a second parameter to `customizeValidator()`, fixing (https://github.com/rjsf-team/react-jsonschema-form/pull/846, and https://github.com/rjsf-team/react-jsonschema-form/issues/1195)
2004+
- Support for localization (L10n) on a customized validator using a `Localizer` function passed as a second parameter to `customizeValidator()`, fixing (https://github.com/rjsf-team/react-jsonschema-form/pull/846, and https://github.com/rjsf-team/react-jsonschema-form/issues/1195)
20042005
- Fixed the `README.md` to correct the package name in several places to match the actual package
20052006

20062007
## Dev / docs / playground

packages/core/src/components/Form.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
validationDataMerge,
3434
ValidatorType,
3535
Experimental_DefaultFormStateBehavior,
36+
Experimental_CustomMergeAllOf,
3637
} from '@rjsf/utils';
3738
import _forEach from 'lodash/forEach';
3839
import _get from 'lodash/get';
@@ -196,6 +197,9 @@ export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
196197
* `emptyObjectFields`
197198
*/
198199
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
200+
/** Optional function that allows for custom merging of `allOf` schemas
201+
*/
202+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
199203
// Private
200204
/**
201205
* _internalFormWrapper is currently used by the semantic-ui theme to provide a custom wrapper around `<Form />`
@@ -390,12 +394,26 @@ export default class Form<
390394
'experimental_defaultFormStateBehavior' in props
391395
? props.experimental_defaultFormStateBehavior
392396
: this.props.experimental_defaultFormStateBehavior;
397+
const experimental_customMergeAllOf =
398+
'experimental_customMergeAllOf' in props
399+
? props.experimental_customMergeAllOf
400+
: this.props.experimental_customMergeAllOf;
393401
let schemaUtils: SchemaUtilsType<T, S, F> = state.schemaUtils;
394402
if (
395403
!schemaUtils ||
396-
schemaUtils.doesSchemaUtilsDiffer(props.validator, rootSchema, experimental_defaultFormStateBehavior)
404+
schemaUtils.doesSchemaUtilsDiffer(
405+
props.validator,
406+
rootSchema,
407+
experimental_defaultFormStateBehavior,
408+
experimental_customMergeAllOf
409+
)
397410
) {
398-
schemaUtils = createSchemaUtils<T, S, F>(props.validator, rootSchema, experimental_defaultFormStateBehavior);
411+
schemaUtils = createSchemaUtils<T, S, F>(
412+
props.validator,
413+
rootSchema,
414+
experimental_defaultFormStateBehavior,
415+
experimental_customMergeAllOf
416+
);
399417
}
400418
const formData: T = schemaUtils.getDefaultFormState(schema, inputFormData) as T;
401419
const _retrievedSchema = retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData);

packages/docs/docs/api-reference/form-props.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ The signature and documentation for this property is as follow:
9191
##### computeSkipPopulate <T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
9292

9393
A function that determines whether to skip populating the array with default values based on the provided validator, schema, and root schema.
94-
If the function returns `true`, the array will not be populated with default values.
95-
If the function returns `false`, the array will be populated with default values according to the `populate` option.
94+
If the function returns `true`, the array will not be populated with default values.
95+
If the function returns `false`, the array will be populated with default values according to the `populate` option.
9696

9797
###### Parameters
9898

@@ -104,7 +104,6 @@ A function that determines whether to skip populating the array with default val
104104

105105
- boolean: A boolean indicating whether to skip populating the array with default values.
106106

107-
108107
##### Example
109108

110109
```tsx
@@ -252,6 +251,30 @@ render(
252251
);
253252
```
254253

254+
## experimental_customMergeAllOf
255+
256+
The `experimental_customMergeAllOf` function allows you to provide a custom implementation for merging `allOf` schemas. This can be particularly useful in scenarios where the default [json-schema-merge-allof](https://github.com/mokkabonna/json-schema-merge-allof) library becomes a performance bottleneck, especially with large and complex schemas or doesn't satisfy your needs.
257+
258+
By providing your own implementation, you can potentially achieve significant performance improvements. For instance, if your use case only requires a subset of JSON Schema features, you can implement a faster, more tailored merging strategy.
259+
260+
If you're looking for alternative `allOf` merging implementations, you might consider [allof-merge](https://github.com/udamir/allof-merge).
261+
262+
**Warning:** This is an experimental feature. Only use this if you fully understand the implications of custom `allOf` merging and are prepared to handle potential edge cases. Incorrect implementations may lead to unexpected behavior or validation errors.
263+
264+
```tsx
265+
import { Form } from '@rjsf/core';
266+
import validator from '@rjsf/validator-ajv8';
267+
268+
const customMergeAllOf = (schema: RJSFSchema): RJSFSchema => {
269+
// Your custom implementation here
270+
};
271+
272+
render(
273+
<Form schema={schema} validator={validator} experimental_customMergeAllOf={customMergeAllOf} />,
274+
document.getElementById('app')
275+
);
276+
```
277+
255278
## disabled
256279

257280
It's possible to disable the whole form by setting the `disabled` prop. The `disabled` prop is then forwarded down to each field of the form.

packages/docs/docs/usage/validation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ const validator = customizeValidator({ AjvClass: Ajv2019 });
703703
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));
704704
```
705705

706-
### Localization (L12n) support
706+
### Localization (L10n) support
707707

708708
The Ajv 8 validator supports the localization of error messages using [ajv-i18n](https://github.com/ajv-validator/ajv-i18n).
709709
In addition, you may provide a custom solution by implementing a function that conforms to the `Localizer` interface if your language is not supported.

packages/utils/src/createSchemaUtils.ts

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import deepEquals from './deepEquals';
22
import {
33
ErrorSchema,
4+
Experimental_CustomMergeAllOf,
45
Experimental_DefaultFormStateBehavior,
56
FormContextType,
67
GlobalUISchemaOptions,
@@ -30,31 +31,36 @@ import {
3031
} from './schema';
3132

3233
/** The `SchemaUtils` class provides a wrapper around the publicly exported APIs in the `utils/schema` directory such
33-
* that one does not have to explicitly pass the `validator`, `rootSchema`, or `experimental_defaultFormStateBehavior` to each method.
34-
* Since these generally do not change across a `Form`, this allows for providing a simplified set of APIs to the
35-
* `@rjsf/core` components and the various themes as well. This class implements the `SchemaUtilsType` interface.
34+
* that one does not have to explicitly pass the `validator`, `rootSchema`, `experimental_defaultFormStateBehavior` or
35+
* `experimental_customMergeAllOf` to each method. Since these generally do not change across a `Form`, this allows for
36+
* providing a simplified set of APIs to the `@rjsf/core` components and the various themes as well. This class
37+
* implements the `SchemaUtilsType` interface.
3638
*/
3739
class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>
3840
implements SchemaUtilsType<T, S, F>
3941
{
4042
rootSchema: S;
4143
validator: ValidatorType<T, S, F>;
4244
experimental_defaultFormStateBehavior: Experimental_DefaultFormStateBehavior;
45+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
4346

4447
/** Constructs the `SchemaUtils` instance with the given `validator` and `rootSchema` stored as instance variables
4548
*
4649
* @param validator - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
4750
* @param rootSchema - The root schema that will be forwarded to all the APIs
4851
* @param experimental_defaultFormStateBehavior - Configuration flags to allow users to override default form state behavior
52+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
4953
*/
5054
constructor(
5155
validator: ValidatorType<T, S, F>,
5256
rootSchema: S,
53-
experimental_defaultFormStateBehavior: Experimental_DefaultFormStateBehavior
57+
experimental_defaultFormStateBehavior: Experimental_DefaultFormStateBehavior,
58+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
5459
) {
5560
this.rootSchema = rootSchema;
5661
this.validator = validator;
5762
this.experimental_defaultFormStateBehavior = experimental_defaultFormStateBehavior;
63+
this.experimental_customMergeAllOf = experimental_customMergeAllOf;
5864
}
5965

6066
/** Returns the `ValidatorType` in the `SchemaUtilsType`
@@ -72,20 +78,23 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
7278
* @param validator - An implementation of the `ValidatorType` interface that will be compared against the current one
7379
* @param rootSchema - The root schema that will be compared against the current one
7480
* @param [experimental_defaultFormStateBehavior] Optional configuration object, if provided, allows users to override default form state behavior
81+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
7582
* @returns - True if the `SchemaUtilsType` differs from the given `validator` or `rootSchema`
7683
*/
7784
doesSchemaUtilsDiffer(
7885
validator: ValidatorType<T, S, F>,
7986
rootSchema: S,
80-
experimental_defaultFormStateBehavior = {}
87+
experimental_defaultFormStateBehavior = {},
88+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
8189
): boolean {
8290
if (!validator || !rootSchema) {
8391
return false;
8492
}
8593
return (
8694
this.validator !== validator ||
8795
!deepEquals(this.rootSchema, rootSchema) ||
88-
!deepEquals(this.experimental_defaultFormStateBehavior, experimental_defaultFormStateBehavior)
96+
!deepEquals(this.experimental_defaultFormStateBehavior, experimental_defaultFormStateBehavior) ||
97+
this.experimental_customMergeAllOf !== experimental_customMergeAllOf
8998
);
9099
}
91100

@@ -110,7 +119,8 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
110119
formData,
111120
this.rootSchema,
112121
includeUndefinedValues,
113-
this.experimental_defaultFormStateBehavior
122+
this.experimental_defaultFormStateBehavior,
123+
this.experimental_customMergeAllOf
114124
);
115125
}
116126

@@ -234,7 +244,13 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
234244
* @returns - The schema having its conditions, additional properties, references and dependencies resolved
235245
*/
236246
retrieveSchema(schema: S, rawFormData?: T) {
237-
return retrieveSchema<T, S, F>(this.validator, schema, this.rootSchema, rawFormData);
247+
return retrieveSchema<T, S, F>(
248+
this.validator,
249+
schema,
250+
this.rootSchema,
251+
rawFormData,
252+
this.experimental_customMergeAllOf
253+
);
238254
}
239255

240256
/** Sanitize the `data` associated with the `oldSchema` so it is considered appropriate for the `newSchema`. If the
@@ -262,7 +278,16 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
262278
* @returns - The `IdSchema` object for the `schema`
263279
*/
264280
toIdSchema(schema: S, id?: string | null, formData?: T, idPrefix = 'root', idSeparator = '_'): IdSchema<T> {
265-
return toIdSchema<T, S, F>(this.validator, schema, id, this.rootSchema, formData, idPrefix, idSeparator);
281+
return toIdSchema<T, S, F>(
282+
this.validator,
283+
schema,
284+
id,
285+
this.rootSchema,
286+
formData,
287+
idPrefix,
288+
idSeparator,
289+
this.experimental_customMergeAllOf
290+
);
266291
}
267292

268293
/** Generates an `PathSchema` object for the `schema`, recursively
@@ -283,6 +308,7 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
283308
* @param validator - an implementation of the `ValidatorType` interface that will be forwarded to all the APIs
284309
* @param rootSchema - The root schema that will be forwarded to all the APIs
285310
* @param [experimental_defaultFormStateBehavior] Optional configuration object, if provided, allows users to override default form state behavior
311+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
286312
* @returns - An implementation of a `SchemaUtilsType` interface
287313
*/
288314
export default function createSchemaUtils<
@@ -292,7 +318,13 @@ export default function createSchemaUtils<
292318
>(
293319
validator: ValidatorType<T, S, F>,
294320
rootSchema: S,
295-
experimental_defaultFormStateBehavior = {}
321+
experimental_defaultFormStateBehavior = {},
322+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
296323
): SchemaUtilsType<T, S, F> {
297-
return new SchemaUtils<T, S, F>(validator, rootSchema, experimental_defaultFormStateBehavior);
324+
return new SchemaUtils<T, S, F>(
325+
validator,
326+
rootSchema,
327+
experimental_defaultFormStateBehavior,
328+
experimental_customMergeAllOf
329+
);
298330
}

packages/utils/src/schema/getDefaultFormState.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import mergeDefaultsWithFormData from '../mergeDefaultsWithFormData';
2121
import mergeObjects from '../mergeObjects';
2222
import mergeSchemas from '../mergeSchemas';
2323
import {
24+
Experimental_CustomMergeAllOf,
2425
Experimental_DefaultFormStateBehavior,
2526
FormContextType,
2627
GenericObjectType,
@@ -163,6 +164,8 @@ interface ComputeDefaultsProps<T = any, S extends StrictRJSFSchema = RJSFSchema>
163164
_recurseList?: string[];
164165
/** Optional configuration object, if provided, allows users to override default form state behavior */
165166
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
167+
/** Optional function that allows for custom merging of `allOf` schemas */
168+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
166169
/** Optional flag, if true, indicates this schema was required in the parent schema. */
167170
required?: boolean;
168171
}
@@ -187,6 +190,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
187190
includeUndefinedValues = false,
188191
_recurseList = [],
189192
experimental_defaultFormStateBehavior = undefined,
193+
experimental_customMergeAllOf = undefined,
190194
required,
191195
} = computeDefaultsProps;
192196
const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
@@ -218,7 +222,15 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
218222
...formData,
219223
...getDefaultBasedOnSchemaType(validator, schema, computeDefaultsProps, defaults),
220224
};
221-
const resolvedSchema = resolveDependencies<T, S, F>(validator, schema, rootSchema, false, [], defaultFormData);
225+
const resolvedSchema = resolveDependencies<T, S, F>(
226+
validator,
227+
schema,
228+
rootSchema,
229+
false,
230+
[],
231+
defaultFormData,
232+
experimental_customMergeAllOf
233+
);
222234
schemaToCompute = resolvedSchema[0]; // pick the first element from resolve dependencies
223235
} else if (isFixedItems(schema)) {
224236
defaults = (schema.items! as S[]).map((itemSchema: S, idx: number) =>
@@ -307,6 +319,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
307319
includeUndefinedValues = false,
308320
_recurseList = [],
309321
experimental_defaultFormStateBehavior = undefined,
322+
experimental_customMergeAllOf = undefined,
310323
required,
311324
}: ComputeDefaultsProps<T, S> = {},
312325
defaults?: T | T[] | undefined
@@ -318,7 +331,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
318331
// https://github.com/rjsf-team/react-jsonschema-form/issues/3832
319332
const retrievedSchema =
320333
experimental_defaultFormStateBehavior?.allOf === 'populateDefaults' && ALL_OF_KEY in schema
321-
? retrieveSchema<T, S, F>(validator, schema, rootSchema, formData)
334+
? retrieveSchema<T, S, F>(validator, schema, rootSchema, formData, experimental_customMergeAllOf)
322335
: schema;
323336
const parentConst = retrievedSchema[CONST_KEY];
324337
const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce(
@@ -333,6 +346,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
333346
rootSchema,
334347
_recurseList,
335348
experimental_defaultFormStateBehavior,
349+
experimental_customMergeAllOf,
336350
includeUndefinedValues: includeUndefinedValues === true,
337351
parentDefaults: get(defaults, [key]),
338352
rawFormData: get(formData, [key]),
@@ -540,6 +554,7 @@ export function getDefaultBasedOnSchemaType<
540554
* If "excludeObjectChildren", cause undefined values for this object and pass `includeUndefinedValues` as
541555
* false when computing defaults for any nested object properties.
542556
* @param [experimental_defaultFormStateBehavior] Optional configuration object, if provided, allows users to override default form state behavior
557+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
543558
* @returns - The resulting `formData` with all the defaults provided
544559
*/
545560
export default function getDefaultFormState<
@@ -552,16 +567,18 @@ export default function getDefaultFormState<
552567
formData?: T,
553568
rootSchema?: S,
554569
includeUndefinedValues: boolean | 'excludeObjectChildren' = false,
555-
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior
570+
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior,
571+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
556572
) {
557573
if (!isObject(theSchema)) {
558574
throw new Error('Invalid schema: ' + theSchema);
559575
}
560-
const schema = retrieveSchema<T, S, F>(validator, theSchema, rootSchema, formData);
576+
const schema = retrieveSchema<T, S, F>(validator, theSchema, rootSchema, formData, experimental_customMergeAllOf);
561577
const defaults = computeDefaults<T, S, F>(validator, schema, {
562578
rootSchema,
563579
includeUndefinedValues,
564580
experimental_defaultFormStateBehavior,
581+
experimental_customMergeAllOf,
565582
rawFormData: formData,
566583
});
567584

0 commit comments

Comments
 (0)