@rjsf/utils 6.0.0-beta.2 → 6.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index.js → index.cjs} +396 -264
- package/dist/index.cjs.map +7 -0
- package/dist/utils.esm.js +395 -263
- package/dist/utils.esm.js.map +4 -4
- package/dist/utils.umd.js +368 -249
- package/lib/ErrorSchemaBuilder.d.ts +2 -2
- package/lib/canExpand.d.ts +1 -1
- package/lib/constants.d.ts +3 -0
- package/lib/constants.js +3 -0
- package/lib/constants.js.map +1 -1
- package/lib/createSchemaUtils.js +25 -18
- package/lib/createSchemaUtils.js.map +1 -1
- package/lib/enums.d.ts +9 -3
- package/lib/enums.js +9 -3
- package/lib/enums.js.map +1 -1
- package/lib/findSchemaDefinition.d.ts +7 -1
- package/lib/findSchemaDefinition.js +48 -6
- package/lib/findSchemaDefinition.js.map +1 -1
- package/lib/getTestIds.js +2 -2
- package/lib/getTestIds.js.map +1 -1
- package/lib/getUiOptions.js +4 -0
- package/lib/getUiOptions.js.map +1 -1
- package/lib/getWidget.js +3 -3
- package/lib/getWidget.js.map +1 -1
- package/lib/guessType.d.ts +1 -1
- package/lib/idGenerators.d.ts +22 -15
- package/lib/idGenerators.js +17 -8
- package/lib/idGenerators.js.map +1 -1
- package/lib/index.d.ts +10 -4
- package/lib/index.js +9 -4
- package/lib/index.js.map +1 -1
- package/lib/isFormDataAvailable.d.ts +7 -0
- package/lib/isFormDataAvailable.js +13 -0
- package/lib/isFormDataAvailable.js.map +1 -0
- package/lib/isRootSchema.d.ts +13 -0
- package/lib/isRootSchema.js +25 -0
- package/lib/isRootSchema.js.map +1 -0
- package/lib/mergeDefaultsWithFormData.js +14 -2
- package/lib/mergeDefaultsWithFormData.js.map +1 -1
- package/lib/schema/findFieldInSchema.d.ts +1 -1
- package/lib/schema/findFieldInSchema.js +1 -1
- package/lib/schema/getDefaultFormState.d.ts +17 -3
- package/lib/schema/getDefaultFormState.js +73 -27
- package/lib/schema/getDefaultFormState.js.map +1 -1
- package/lib/schema/getDisplayLabel.js +2 -2
- package/lib/schema/getDisplayLabel.js.map +1 -1
- package/lib/schema/index.d.ts +1 -2
- package/lib/schema/index.js +1 -2
- package/lib/schema/index.js.map +1 -1
- package/lib/schema/retrieveSchema.d.ts +11 -6
- package/lib/schema/retrieveSchema.js +42 -19
- package/lib/schema/retrieveSchema.js.map +1 -1
- package/lib/shallowEquals.d.ts +8 -0
- package/lib/shallowEquals.js +36 -0
- package/lib/shallowEquals.js.map +1 -0
- package/lib/shouldRender.d.ts +8 -2
- package/lib/shouldRender.js +17 -2
- package/lib/shouldRender.js.map +1 -1
- package/lib/shouldRenderOptionalField.d.ts +18 -0
- package/lib/shouldRenderOptionalField.js +47 -0
- package/lib/shouldRenderOptionalField.js.map +1 -0
- package/lib/toFieldPathId.d.ts +12 -0
- package/lib/toFieldPathId.js +19 -0
- package/lib/toFieldPathId.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types.d.ts +136 -81
- package/lib/validationDataMerge.d.ts +2 -1
- package/lib/validationDataMerge.js +3 -2
- package/lib/validationDataMerge.js.map +1 -1
- package/package.json +13 -14
- package/src/ErrorSchemaBuilder.ts +2 -2
- package/src/constants.ts +3 -0
- package/src/createSchemaUtils.ts +25 -26
- package/src/enums.ts +9 -3
- package/src/findSchemaDefinition.ts +55 -6
- package/src/getTestIds.ts +2 -2
- package/src/getUiOptions.ts +4 -0
- package/src/getWidget.tsx +3 -3
- package/src/idGenerators.ts +35 -25
- package/src/index.ts +16 -2
- package/src/isFormDataAvailable.ts +13 -0
- package/src/isRootSchema.ts +30 -0
- package/src/mergeDefaultsWithFormData.ts +16 -2
- package/src/schema/findFieldInSchema.ts +1 -1
- package/src/schema/getDefaultFormState.ts +95 -33
- package/src/schema/getDisplayLabel.ts +2 -2
- package/src/schema/index.ts +0 -2
- package/src/schema/retrieveSchema.ts +46 -10
- package/src/shallowEquals.ts +41 -0
- package/src/shouldRender.ts +27 -2
- package/src/shouldRenderOptionalField.ts +56 -0
- package/src/toFieldPathId.ts +24 -0
- package/src/types.ts +156 -84
- package/src/validationDataMerge.ts +7 -1
- package/dist/index.js.map +0 -7
- package/lib/schema/toIdSchema.d.ts +0 -14
- package/lib/schema/toIdSchema.js +0 -62
- package/lib/schema/toIdSchema.js.map +0 -1
- package/src/schema/toIdSchema.ts +0 -131
|
@@ -84,6 +84,24 @@ export function getInnerSchemaForArrayItem<S extends StrictRJSFSchema = RJSFSche
|
|
|
84
84
|
return {} as S;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/** Checks if the given `schema` contains the `null` type along with another type AND if the `default` contained within
|
|
88
|
+
* the schema is `null` AND the `computedDefault` is empty. If all of those conditions are true, then the `schema`'s
|
|
89
|
+
* default should be `null` rather than `computedDefault`.
|
|
90
|
+
*
|
|
91
|
+
* @param schema - The schema to inspect
|
|
92
|
+
* @param computedDefault - The computed default for the schema
|
|
93
|
+
* @returns - Flag indicating whether a null should be returned instead of the computedDefault
|
|
94
|
+
*/
|
|
95
|
+
export function computeDefaultBasedOnSchemaTypeAndDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema>(
|
|
96
|
+
schema: S,
|
|
97
|
+
computedDefault: T,
|
|
98
|
+
) {
|
|
99
|
+
const { default: schemaDefault, type } = schema;
|
|
100
|
+
const shouldReturnNullAsDefault =
|
|
101
|
+
Array.isArray(type) && type.includes('null') && isEmpty(computedDefault) && schemaDefault === null;
|
|
102
|
+
return shouldReturnNullAsDefault ? (null as T) : computedDefault;
|
|
103
|
+
}
|
|
104
|
+
|
|
87
105
|
/** Either add `computedDefault` at `key` into `obj` or not add it based on its value, the value of
|
|
88
106
|
* `includeUndefinedValues`, the value of `emptyObjectFields` and if its parent field is required. Generally undefined
|
|
89
107
|
* `computedDefault` values are added only when `includeUndefinedValues` is either true/"excludeObjectChildren". If `
|
|
@@ -115,10 +133,18 @@ function maybeAddDefaultToObject<T = any>(
|
|
|
115
133
|
isConst = false,
|
|
116
134
|
) {
|
|
117
135
|
const { emptyObjectFields = 'populateAllDefaults' } = experimental_defaultFormStateBehavior;
|
|
118
|
-
|
|
119
|
-
|
|
136
|
+
|
|
137
|
+
if (includeUndefinedValues === true || isConst) {
|
|
138
|
+
// If includeUndefinedValues is explicitly true
|
|
120
139
|
// Or if the schema has a const property defined, then we should always return the computedDefault since it's coming from the const.
|
|
121
140
|
obj[key] = computedDefault;
|
|
141
|
+
} else if (includeUndefinedValues === 'excludeObjectChildren') {
|
|
142
|
+
// Fix for Issue #4709: When in 'excludeObjectChildren' mode, don't set primitive fields to empty objects
|
|
143
|
+
// Only add the computed default if it's not an empty object placeholder for a primitive field
|
|
144
|
+
if (!isObject(computedDefault) || !isEmpty(computedDefault)) {
|
|
145
|
+
obj[key] = computedDefault;
|
|
146
|
+
}
|
|
147
|
+
// If computedDefault is an empty object {}, don't add it - let the field stay undefined
|
|
122
148
|
} else if (emptyObjectFields !== 'skipDefaults') {
|
|
123
149
|
// If isParentRequired is undefined, then we are at the root level of the schema so defer to the requiredness of
|
|
124
150
|
// the field key itself in the `requiredField` list
|
|
@@ -174,10 +200,14 @@ interface ComputeDefaultsProps<T = any, S extends StrictRJSFSchema = RJSFSchema>
|
|
|
174
200
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
|
|
175
201
|
/** Optional flag, if true, indicates this schema was required in the parent schema. */
|
|
176
202
|
required?: boolean;
|
|
203
|
+
/** Optional flag, if true, indicates this schema was required because it is the root. */
|
|
204
|
+
requiredAsRoot?: boolean;
|
|
177
205
|
/** Optional flag, if true, It will merge defaults into formData.
|
|
178
206
|
* The formData should take precedence unless it's not valid. This is useful when for example the value from formData does not exist in the schema 'enum' property, in such cases we take the value from the defaults because the value from the formData is not valid.
|
|
179
207
|
*/
|
|
180
208
|
shouldMergeDefaultsIntoFormData?: boolean;
|
|
209
|
+
/** Indicates whether initial defaults have been generated */
|
|
210
|
+
initialDefaultsGenerated?: boolean;
|
|
181
211
|
}
|
|
182
212
|
|
|
183
213
|
/** Computes the defaults for the current `schema` given the `rawFormData` and `parentDefaults` if any. This drills into
|
|
@@ -203,8 +233,9 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
203
233
|
experimental_customMergeAllOf = undefined,
|
|
204
234
|
required,
|
|
205
235
|
shouldMergeDefaultsIntoFormData = false,
|
|
236
|
+
initialDefaultsGenerated,
|
|
206
237
|
} = computeDefaultsProps;
|
|
207
|
-
|
|
238
|
+
let formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
|
|
208
239
|
const schema: S = isObject(rawSchema) ? rawSchema : ({} as S);
|
|
209
240
|
// Compute the defaults recursively: give highest priority to deepest nodes.
|
|
210
241
|
let defaults: T | T[] | undefined = parentDefaults;
|
|
@@ -212,9 +243,8 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
212
243
|
let schemaToCompute: S | null = null;
|
|
213
244
|
let experimental_dfsb_to_compute = experimental_defaultFormStateBehavior;
|
|
214
245
|
let updatedRecurseList = _recurseList;
|
|
215
|
-
|
|
216
246
|
if (
|
|
217
|
-
schema[CONST_KEY] &&
|
|
247
|
+
schema[CONST_KEY] !== undefined &&
|
|
218
248
|
experimental_defaultFormStateBehavior?.constAsDefaults !== 'never' &&
|
|
219
249
|
!constIsAjvDataReference(schema)
|
|
220
250
|
) {
|
|
@@ -240,6 +270,13 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
240
270
|
if (schemaToCompute && !defaults) {
|
|
241
271
|
defaults = schema.default as T | undefined;
|
|
242
272
|
}
|
|
273
|
+
|
|
274
|
+
// If shouldMergeDefaultsIntoFormData is true
|
|
275
|
+
// And the schemaToCompute is set and the rawFormData is not an object
|
|
276
|
+
// Then set the formData to the rawFormData
|
|
277
|
+
if (shouldMergeDefaultsIntoFormData && schemaToCompute && !isObject(rawFormData)) {
|
|
278
|
+
formData = rawFormData as T;
|
|
279
|
+
}
|
|
243
280
|
} else if (DEPENDENCIES_KEY in schema) {
|
|
244
281
|
// Get the default if set from properties to ensure the dependencies conditions are resolved based on it
|
|
245
282
|
const defaultFormData: T = {
|
|
@@ -328,9 +365,10 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
328
365
|
experimental_defaultFormStateBehavior: experimental_dfsb_to_compute,
|
|
329
366
|
experimental_customMergeAllOf,
|
|
330
367
|
parentDefaults: defaults as T | undefined,
|
|
331
|
-
rawFormData: formData as T,
|
|
368
|
+
rawFormData: (rawFormData ?? formData) as T,
|
|
332
369
|
required,
|
|
333
370
|
shouldMergeDefaultsIntoFormData,
|
|
371
|
+
initialDefaultsGenerated,
|
|
334
372
|
});
|
|
335
373
|
}
|
|
336
374
|
|
|
@@ -431,8 +469,9 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
|
|
|
431
469
|
experimental_customMergeAllOf = undefined,
|
|
432
470
|
required,
|
|
433
471
|
shouldMergeDefaultsIntoFormData,
|
|
472
|
+
initialDefaultsGenerated,
|
|
434
473
|
}: ComputeDefaultsProps<T, S> = {},
|
|
435
|
-
defaults?: T | T[]
|
|
474
|
+
defaults?: T | T[],
|
|
436
475
|
): T {
|
|
437
476
|
{
|
|
438
477
|
const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
|
|
@@ -466,7 +505,9 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
|
|
|
466
505
|
rawFormData: get(formData, [key]),
|
|
467
506
|
required: retrievedSchema.required?.includes(key),
|
|
468
507
|
shouldMergeDefaultsIntoFormData,
|
|
508
|
+
initialDefaultsGenerated,
|
|
469
509
|
});
|
|
510
|
+
|
|
470
511
|
maybeAddDefaultToObject<T>(
|
|
471
512
|
acc,
|
|
472
513
|
key,
|
|
@@ -477,11 +518,12 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
|
|
|
477
518
|
experimental_defaultFormStateBehavior,
|
|
478
519
|
hasConst,
|
|
479
520
|
);
|
|
521
|
+
|
|
480
522
|
return acc;
|
|
481
523
|
},
|
|
482
524
|
{},
|
|
483
525
|
) as T;
|
|
484
|
-
if (retrievedSchema.additionalProperties) {
|
|
526
|
+
if (retrievedSchema.additionalProperties && !initialDefaultsGenerated) {
|
|
485
527
|
// as per spec additionalProperties may be either schema or boolean
|
|
486
528
|
const additionalPropertiesSchema = isObject(retrievedSchema.additionalProperties)
|
|
487
529
|
? retrievedSchema.additionalProperties
|
|
@@ -511,6 +553,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
|
|
|
511
553
|
rawFormData: get(formData, [key]),
|
|
512
554
|
required: retrievedSchema.required?.includes(key),
|
|
513
555
|
shouldMergeDefaultsIntoFormData,
|
|
556
|
+
initialDefaultsGenerated,
|
|
514
557
|
});
|
|
515
558
|
// Since these are additional properties we don't need to add the `experimental_defaultFormStateBehavior` prop
|
|
516
559
|
maybeAddDefaultToObject<T>(
|
|
@@ -523,7 +566,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
|
|
|
523
566
|
);
|
|
524
567
|
});
|
|
525
568
|
}
|
|
526
|
-
return objectDefaults;
|
|
569
|
+
return computeDefaultBasedOnSchemaTypeAndDefaults<T, S>(rawSchema, objectDefaults);
|
|
527
570
|
}
|
|
528
571
|
}
|
|
529
572
|
|
|
@@ -545,10 +588,12 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
545
588
|
experimental_defaultFormStateBehavior = undefined,
|
|
546
589
|
experimental_customMergeAllOf = undefined,
|
|
547
590
|
required,
|
|
591
|
+
requiredAsRoot = false,
|
|
548
592
|
shouldMergeDefaultsIntoFormData,
|
|
593
|
+
initialDefaultsGenerated,
|
|
549
594
|
}: ComputeDefaultsProps<T, S> = {},
|
|
550
|
-
defaults?: T
|
|
551
|
-
): T
|
|
595
|
+
defaults?: T[],
|
|
596
|
+
): T[] | undefined {
|
|
552
597
|
const schema: S = rawSchema;
|
|
553
598
|
|
|
554
599
|
const arrayMinItemsStateBehavior = experimental_defaultFormStateBehavior?.arrayMinItems ?? {};
|
|
@@ -560,7 +605,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
560
605
|
const computeSkipPopulate = arrayMinItemsStateBehavior?.computeSkipPopulate ?? (() => false);
|
|
561
606
|
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
|
|
562
607
|
|
|
563
|
-
const emptyDefault = isSkipEmptyDefaults ? undefined : [];
|
|
608
|
+
const emptyDefault: T[] | undefined = isSkipEmptyDefaults ? undefined : [];
|
|
564
609
|
|
|
565
610
|
// Inject defaults into existing array defaults
|
|
566
611
|
if (Array.isArray(defaults)) {
|
|
@@ -574,6 +619,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
574
619
|
parentDefaults: item,
|
|
575
620
|
required,
|
|
576
621
|
shouldMergeDefaultsIntoFormData,
|
|
622
|
+
initialDefaultsGenerated,
|
|
577
623
|
});
|
|
578
624
|
}) as T[];
|
|
579
625
|
}
|
|
@@ -582,7 +628,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
582
628
|
if (Array.isArray(rawFormData)) {
|
|
583
629
|
const schemaItem: S = getInnerSchemaForArrayItem<S>(schema);
|
|
584
630
|
if (neverPopulate) {
|
|
585
|
-
defaults = rawFormData;
|
|
631
|
+
defaults = rawFormData as typeof defaults;
|
|
586
632
|
} else {
|
|
587
633
|
const itemDefaults = rawFormData.map((item: T, idx: number) => {
|
|
588
634
|
return computeDefaults<T, S, F>(validator, schemaItem, {
|
|
@@ -594,6 +640,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
594
640
|
parentDefaults: get(defaults, [idx]),
|
|
595
641
|
required,
|
|
596
642
|
shouldMergeDefaultsIntoFormData,
|
|
643
|
+
initialDefaultsGenerated,
|
|
597
644
|
});
|
|
598
645
|
}) as T[];
|
|
599
646
|
|
|
@@ -619,6 +666,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
619
666
|
}
|
|
620
667
|
}
|
|
621
668
|
|
|
669
|
+
let arrayDefault: T[] | undefined;
|
|
622
670
|
const defaultsLength = Array.isArray(defaults) ? defaults.length : 0;
|
|
623
671
|
if (
|
|
624
672
|
!schema.minItems ||
|
|
@@ -626,27 +674,30 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
626
674
|
computeSkipPopulate<T, S, F>(validator, schema, rootSchema) ||
|
|
627
675
|
schema.minItems <= defaultsLength
|
|
628
676
|
) {
|
|
629
|
-
|
|
677
|
+
// we don't want undefined defaults unless it is both not required or not required as root
|
|
678
|
+
arrayDefault = defaults || (!required && !requiredAsRoot) ? defaults : emptyDefault;
|
|
679
|
+
} else {
|
|
680
|
+
const defaultEntries: T[] = (defaults || []) as T[];
|
|
681
|
+
const fillerSchema: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Invert);
|
|
682
|
+
const fillerDefault = fillerSchema.default;
|
|
683
|
+
|
|
684
|
+
// Calculate filler entries for remaining items (minItems - existing raw data/defaults)
|
|
685
|
+
const fillerEntries: T[] = Array.from({ length: schema.minItems - defaultsLength }, () =>
|
|
686
|
+
computeDefaults<any, S, F>(validator, fillerSchema, {
|
|
687
|
+
parentDefaults: fillerDefault,
|
|
688
|
+
rootSchema,
|
|
689
|
+
_recurseList,
|
|
690
|
+
experimental_defaultFormStateBehavior,
|
|
691
|
+
experimental_customMergeAllOf,
|
|
692
|
+
required,
|
|
693
|
+
shouldMergeDefaultsIntoFormData,
|
|
694
|
+
}),
|
|
695
|
+
) as T[];
|
|
696
|
+
// then fill up the rest with either the item default or empty, up to minItems
|
|
697
|
+
arrayDefault = defaultEntries.concat(fillerEntries);
|
|
630
698
|
}
|
|
631
699
|
|
|
632
|
-
|
|
633
|
-
const fillerSchema: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Invert);
|
|
634
|
-
const fillerDefault = fillerSchema.default;
|
|
635
|
-
|
|
636
|
-
// Calculate filler entries for remaining items (minItems - existing raw data/defaults)
|
|
637
|
-
const fillerEntries: T[] = new Array(schema.minItems - defaultsLength).fill(
|
|
638
|
-
computeDefaults<any, S, F>(validator, fillerSchema, {
|
|
639
|
-
parentDefaults: fillerDefault,
|
|
640
|
-
rootSchema,
|
|
641
|
-
_recurseList,
|
|
642
|
-
experimental_defaultFormStateBehavior,
|
|
643
|
-
experimental_customMergeAllOf,
|
|
644
|
-
required,
|
|
645
|
-
shouldMergeDefaultsIntoFormData,
|
|
646
|
-
}),
|
|
647
|
-
) as T[];
|
|
648
|
-
// then fill up the rest with either the item default or empty, up to minItems
|
|
649
|
-
return defaultEntries.concat(fillerEntries);
|
|
700
|
+
return computeDefaultBasedOnSchemaTypeAndDefaults<T[] | undefined, S>(rawSchema, arrayDefault);
|
|
650
701
|
}
|
|
651
702
|
|
|
652
703
|
/** Computes the default value based on the schema type.
|
|
@@ -673,7 +724,7 @@ export function getDefaultBasedOnSchemaType<
|
|
|
673
724
|
return getObjectDefaults(validator, rawSchema, computeDefaultsProps, defaults);
|
|
674
725
|
}
|
|
675
726
|
case 'array': {
|
|
676
|
-
return getArrayDefaults(validator, rawSchema, computeDefaultsProps, defaults);
|
|
727
|
+
return getArrayDefaults(validator, rawSchema, computeDefaultsProps, defaults as T[]);
|
|
677
728
|
}
|
|
678
729
|
}
|
|
679
730
|
}
|
|
@@ -690,6 +741,7 @@ export function getDefaultBasedOnSchemaType<
|
|
|
690
741
|
* false when computing defaults for any nested object properties.
|
|
691
742
|
* @param [experimental_defaultFormStateBehavior] Optional configuration object, if provided, allows users to override default form state behavior
|
|
692
743
|
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
|
|
744
|
+
* @param initialDefaultsGenerated - Optional flag, indicates whether or not initial defaults have been generated
|
|
693
745
|
* @returns - The resulting `formData` with all the defaults provided
|
|
694
746
|
*/
|
|
695
747
|
export default function getDefaultFormState<
|
|
@@ -704,6 +756,7 @@ export default function getDefaultFormState<
|
|
|
704
756
|
includeUndefinedValues: boolean | 'excludeObjectChildren' = false,
|
|
705
757
|
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior,
|
|
706
758
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
759
|
+
initialDefaultsGenerated?: boolean,
|
|
707
760
|
) {
|
|
708
761
|
if (!isObject(theSchema)) {
|
|
709
762
|
throw new Error('Invalid schema: ' + theSchema);
|
|
@@ -720,8 +773,17 @@ export default function getDefaultFormState<
|
|
|
720
773
|
experimental_customMergeAllOf,
|
|
721
774
|
rawFormData: formData,
|
|
722
775
|
shouldMergeDefaultsIntoFormData: true,
|
|
776
|
+
initialDefaultsGenerated,
|
|
777
|
+
requiredAsRoot: true,
|
|
723
778
|
});
|
|
724
779
|
|
|
780
|
+
if (schema.type !== 'object' && isObject(schema.default)) {
|
|
781
|
+
return {
|
|
782
|
+
...defaults,
|
|
783
|
+
...formData,
|
|
784
|
+
} as T;
|
|
785
|
+
}
|
|
786
|
+
|
|
725
787
|
// If the formData is an object or an array, add additional properties from formData and override formData with
|
|
726
788
|
// defaults since the defaults are already merged with formData.
|
|
727
789
|
if (isObject(formData) || Array.isArray(formData)) {
|
|
@@ -52,10 +52,10 @@ export default function getDisplayLabel<
|
|
|
52
52
|
if (schemaType === 'object') {
|
|
53
53
|
displayLabel = false;
|
|
54
54
|
}
|
|
55
|
-
if (schemaType === 'boolean' && !uiSchema[UI_WIDGET_KEY]) {
|
|
55
|
+
if (schemaType === 'boolean' && uiSchema && !uiSchema[UI_WIDGET_KEY]) {
|
|
56
56
|
displayLabel = false;
|
|
57
57
|
}
|
|
58
|
-
if (uiSchema[UI_FIELD_KEY]) {
|
|
58
|
+
if (uiSchema && uiSchema[UI_FIELD_KEY]) {
|
|
59
59
|
displayLabel = false;
|
|
60
60
|
}
|
|
61
61
|
return displayLabel;
|
package/src/schema/index.ts
CHANGED
|
@@ -10,7 +10,6 @@ import isMultiSelect from './isMultiSelect';
|
|
|
10
10
|
import isSelect from './isSelect';
|
|
11
11
|
import retrieveSchema from './retrieveSchema';
|
|
12
12
|
import sanitizeDataForNewSchema from './sanitizeDataForNewSchema';
|
|
13
|
-
import toIdSchema from './toIdSchema';
|
|
14
13
|
import toPathSchema from './toPathSchema';
|
|
15
14
|
|
|
16
15
|
export {
|
|
@@ -26,6 +25,5 @@ export {
|
|
|
26
25
|
isSelect,
|
|
27
26
|
retrieveSchema,
|
|
28
27
|
sanitizeDataForNewSchema,
|
|
29
|
-
toIdSchema,
|
|
30
28
|
toPathSchema,
|
|
31
29
|
};
|
|
@@ -47,6 +47,7 @@ import isEmpty from 'lodash/isEmpty';
|
|
|
47
47
|
* @param [rootSchema={}] - The root schema that will be forwarded to all the APIs
|
|
48
48
|
* @param [rawFormData] - The current formData, if any, to assist retrieving a schema
|
|
49
49
|
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
|
|
50
|
+
* @param [resolveAnyOfOrOneOfRefs = false] - Optional flag indicating whether to resolved refs in anyOf/oneOf lists
|
|
50
51
|
* @returns - The schema having its conditions, additional properties, references and dependencies resolved
|
|
51
52
|
*/
|
|
52
53
|
export default function retrieveSchema<
|
|
@@ -59,6 +60,7 @@ export default function retrieveSchema<
|
|
|
59
60
|
rootSchema: S = {} as S,
|
|
60
61
|
rawFormData?: T,
|
|
61
62
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
63
|
+
resolveAnyOfOrOneOfRefs = false,
|
|
62
64
|
): S {
|
|
63
65
|
return retrieveSchemaInternal<T, S, F>(
|
|
64
66
|
validator,
|
|
@@ -68,6 +70,7 @@ export default function retrieveSchema<
|
|
|
68
70
|
undefined,
|
|
69
71
|
undefined,
|
|
70
72
|
experimental_customMergeAllOf,
|
|
73
|
+
resolveAnyOfOrOneOfRefs,
|
|
71
74
|
)[0];
|
|
72
75
|
}
|
|
73
76
|
|
|
@@ -223,6 +226,7 @@ export function getMatchingPatternProperties<S extends StrictRJSFSchema = RJSFSc
|
|
|
223
226
|
* @param recurseList - The list of recursive references already processed
|
|
224
227
|
* @param [formData] - The current formData, if any, to assist retrieving a schema
|
|
225
228
|
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
|
|
229
|
+
* @param [resolveAnyOfOrOneOfRefs] - Optional flag indicating whether to resolved refs in anyOf/oneOf lists
|
|
226
230
|
* @returns - The list of schemas having its references, dependencies and allOf schemas resolved
|
|
227
231
|
*/
|
|
228
232
|
export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
@@ -233,6 +237,7 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
233
237
|
recurseList: string[],
|
|
234
238
|
formData?: T,
|
|
235
239
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
240
|
+
resolveAnyOfOrOneOfRefs?: boolean,
|
|
236
241
|
): S[] {
|
|
237
242
|
const updatedSchemas = resolveReference<T, S, F>(
|
|
238
243
|
validator,
|
|
@@ -241,6 +246,8 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
241
246
|
expandAllBranches,
|
|
242
247
|
recurseList,
|
|
243
248
|
formData,
|
|
249
|
+
experimental_customMergeAllOf,
|
|
250
|
+
resolveAnyOfOrOneOfRefs,
|
|
244
251
|
);
|
|
245
252
|
if (updatedSchemas.length > 1 || updatedSchemas[0] !== schema) {
|
|
246
253
|
// return the updatedSchemas array if it has either multiple schemas within it
|
|
@@ -255,6 +262,7 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
255
262
|
expandAllBranches,
|
|
256
263
|
recurseList,
|
|
257
264
|
formData,
|
|
265
|
+
experimental_customMergeAllOf,
|
|
258
266
|
);
|
|
259
267
|
return resolvedSchemas.flatMap((s) => {
|
|
260
268
|
return retrieveSchemaInternal<T, S, F>(
|
|
@@ -268,7 +276,7 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
268
276
|
);
|
|
269
277
|
});
|
|
270
278
|
}
|
|
271
|
-
if (ALL_OF_KEY in schema && Array.isArray(schema
|
|
279
|
+
if (ALL_OF_KEY in schema && Array.isArray(schema[ALL_OF_KEY])) {
|
|
272
280
|
const allOfSchemaElements: S[][] = schema.allOf.map((allOfSubschema) =>
|
|
273
281
|
retrieveSchemaInternal<T, S, F>(
|
|
274
282
|
validator,
|
|
@@ -302,6 +310,7 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
302
310
|
* @param recurseList - The list of recursive references already processed
|
|
303
311
|
* @param [formData] - The current formData, if any, to assist retrieving a schema
|
|
304
312
|
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
|
|
313
|
+
* @param [resolveAnyOfOrOneOfRefs] - Optional flag indicating whether to resolved refs in anyOf/oneOf lists
|
|
305
314
|
* @returns - The list schemas retrieved after having all references resolved
|
|
306
315
|
*/
|
|
307
316
|
export function resolveReference<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
@@ -312,8 +321,9 @@ export function resolveReference<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
312
321
|
recurseList: string[],
|
|
313
322
|
formData?: T,
|
|
314
323
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
324
|
+
resolveAnyOfOrOneOfRefs?: boolean,
|
|
315
325
|
): S[] {
|
|
316
|
-
const updatedSchema = resolveAllReferences<S>(schema, rootSchema, recurseList);
|
|
326
|
+
const updatedSchema = resolveAllReferences<S>(schema, rootSchema, recurseList, undefined, resolveAnyOfOrOneOfRefs);
|
|
317
327
|
if (updatedSchema !== schema) {
|
|
318
328
|
// Only call this if the schema was actually changed by the `resolveAllReferences()` function
|
|
319
329
|
return retrieveSchemaInternal<T, S, F>(
|
|
@@ -324,6 +334,7 @@ export function resolveReference<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
324
334
|
expandAllBranches,
|
|
325
335
|
recurseList,
|
|
326
336
|
experimental_customMergeAllOf,
|
|
337
|
+
resolveAnyOfOrOneOfRefs,
|
|
327
338
|
);
|
|
328
339
|
}
|
|
329
340
|
return [schema];
|
|
@@ -334,7 +345,8 @@ export function resolveReference<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
334
345
|
* @param schema - The schema for which resolving all references is desired
|
|
335
346
|
* @param rootSchema - The root schema that will be forwarded to all the APIs
|
|
336
347
|
* @param recurseList - List of $refs already resolved to prevent recursion
|
|
337
|
-
* @param baseURI - The base URI to be used for resolving relative references
|
|
348
|
+
* @param [baseURI] - The base URI to be used for resolving relative references
|
|
349
|
+
* @param [resolveAnyOfOrOneOfRefs] - Optional flag indicating whether to resolved refs in anyOf/oneOf lists
|
|
338
350
|
* @returns - given schema will all references resolved or the original schema if no internal `$refs` were resolved
|
|
339
351
|
*/
|
|
340
352
|
export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
|
|
@@ -342,6 +354,7 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
|
|
|
342
354
|
rootSchema: S,
|
|
343
355
|
recurseList: string[],
|
|
344
356
|
baseURI?: string,
|
|
357
|
+
resolveAnyOfOrOneOfRefs?: boolean,
|
|
345
358
|
): S {
|
|
346
359
|
if (!isObject(schema)) {
|
|
347
360
|
return schema;
|
|
@@ -369,7 +382,7 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
|
|
|
369
382
|
resolvedSchema[PROPERTIES_KEY]!,
|
|
370
383
|
(result, value, key: string) => {
|
|
371
384
|
const childList: string[] = [...recurseList];
|
|
372
|
-
result[key] = resolveAllReferences(value as S, rootSchema, childList, baseURI);
|
|
385
|
+
result[key] = resolveAllReferences(value as S, rootSchema, childList, baseURI, resolveAnyOfOrOneOfRefs);
|
|
373
386
|
childrenLists.push(childList);
|
|
374
387
|
},
|
|
375
388
|
{} as RJSFSchema,
|
|
@@ -385,10 +398,30 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
|
|
|
385
398
|
) {
|
|
386
399
|
resolvedSchema = {
|
|
387
400
|
...resolvedSchema,
|
|
388
|
-
items: resolveAllReferences(resolvedSchema.items as S, rootSchema, recurseList, baseURI),
|
|
401
|
+
items: resolveAllReferences(resolvedSchema.items as S, rootSchema, recurseList, baseURI, resolveAnyOfOrOneOfRefs),
|
|
389
402
|
};
|
|
390
403
|
}
|
|
391
404
|
|
|
405
|
+
if (resolveAnyOfOrOneOfRefs) {
|
|
406
|
+
let key: 'anyOf' | 'oneOf' | undefined;
|
|
407
|
+
let schemas: S[] | undefined;
|
|
408
|
+
if (ANY_OF_KEY in schema && Array.isArray(schema[ANY_OF_KEY])) {
|
|
409
|
+
key = ANY_OF_KEY;
|
|
410
|
+
schemas = resolvedSchema[ANY_OF_KEY] as S[];
|
|
411
|
+
} else if (ONE_OF_KEY in schema && Array.isArray(schema[ONE_OF_KEY])) {
|
|
412
|
+
key = ONE_OF_KEY;
|
|
413
|
+
schemas = resolvedSchema[ONE_OF_KEY] as S[];
|
|
414
|
+
}
|
|
415
|
+
if (key && schemas) {
|
|
416
|
+
resolvedSchema = {
|
|
417
|
+
...resolvedSchema,
|
|
418
|
+
[key]: schemas.map((s: S) =>
|
|
419
|
+
resolveAllReferences(s, rootSchema, recurseList, baseURI, resolveAnyOfOrOneOfRefs),
|
|
420
|
+
),
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
392
425
|
return deepEquals(schema, resolvedSchema) ? schema : resolvedSchema;
|
|
393
426
|
}
|
|
394
427
|
|
|
@@ -430,9 +463,9 @@ export function stubExistingAdditionalProperties<
|
|
|
430
463
|
if (!isEmpty(matchingProperties)) {
|
|
431
464
|
schema.properties[key] = retrieveSchema<T, S, F>(
|
|
432
465
|
validator,
|
|
433
|
-
{
|
|
466
|
+
{ [ALL_OF_KEY]: Object.values(matchingProperties) } as S,
|
|
434
467
|
rootSchema,
|
|
435
|
-
formData as T,
|
|
468
|
+
get(formData, [key]) as T,
|
|
436
469
|
experimental_customMergeAllOf,
|
|
437
470
|
);
|
|
438
471
|
set(schema.properties, [key, ADDITIONAL_PROPERTY_FLAG], true);
|
|
@@ -440,12 +473,12 @@ export function stubExistingAdditionalProperties<
|
|
|
440
473
|
}
|
|
441
474
|
}
|
|
442
475
|
if (ADDITIONAL_PROPERTIES_KEY in schema && schema.additionalProperties !== false) {
|
|
443
|
-
let additionalProperties: S['additionalProperties']
|
|
476
|
+
let additionalProperties: S['additionalProperties'];
|
|
444
477
|
if (typeof schema.additionalProperties !== 'boolean') {
|
|
445
478
|
if (REF_KEY in schema.additionalProperties!) {
|
|
446
479
|
additionalProperties = retrieveSchema<T, S, F>(
|
|
447
480
|
validator,
|
|
448
|
-
{
|
|
481
|
+
{ [REF_KEY]: get(schema.additionalProperties, [REF_KEY]) } as S,
|
|
449
482
|
rootSchema,
|
|
450
483
|
formData as T,
|
|
451
484
|
experimental_customMergeAllOf,
|
|
@@ -492,6 +525,7 @@ export function stubExistingAdditionalProperties<
|
|
|
492
525
|
* dependencies as a list of schemas
|
|
493
526
|
* @param [recurseList=[]] - The optional, list of recursive references already processed
|
|
494
527
|
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
|
|
528
|
+
* @param [resolveAnyOfOrOneOfRefs] - Optional flag indicating whether to resolved refs in anyOf/oneOf lists
|
|
495
529
|
* @returns - The schema(s) resulting from having its conditions, additional properties, references and dependencies
|
|
496
530
|
* resolved. Multiple schemas may be returned if `expandAllBranches` is true.
|
|
497
531
|
*/
|
|
@@ -507,6 +541,7 @@ export function retrieveSchemaInternal<
|
|
|
507
541
|
expandAllBranches = false,
|
|
508
542
|
recurseList: string[] = [],
|
|
509
543
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
544
|
+
resolveAnyOfOrOneOfRefs?: boolean,
|
|
510
545
|
): S[] {
|
|
511
546
|
if (!isObject(schema)) {
|
|
512
547
|
return [{} as S];
|
|
@@ -519,6 +554,7 @@ export function retrieveSchemaInternal<
|
|
|
519
554
|
recurseList,
|
|
520
555
|
rawFormData,
|
|
521
556
|
experimental_customMergeAllOf,
|
|
557
|
+
resolveAnyOfOrOneOfRefs,
|
|
522
558
|
);
|
|
523
559
|
return resolvedSchemas.flatMap((s: S) => {
|
|
524
560
|
let resolvedSchema = s;
|
|
@@ -578,7 +614,7 @@ export function retrieveSchemaInternal<
|
|
|
578
614
|
validator,
|
|
579
615
|
{ allOf: [schema.properties[key], ...Object.values(matchingProperties)] } as S,
|
|
580
616
|
rootSchema,
|
|
581
|
-
rawFormData as T,
|
|
617
|
+
get(rawFormData, [key]) as T,
|
|
582
618
|
experimental_customMergeAllOf,
|
|
583
619
|
);
|
|
584
620
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Implements a shallow equals comparison that uses Object.is() for comparing values.
|
|
2
|
+
* This function compares objects by checking if all keys and their values are equal using Object.is().
|
|
3
|
+
*
|
|
4
|
+
* @param a - The first element to compare
|
|
5
|
+
* @param b - The second element to compare
|
|
6
|
+
* @returns - True if the `a` and `b` are shallow equal, false otherwise
|
|
7
|
+
*/
|
|
8
|
+
export default function shallowEquals(a: any, b: any): boolean {
|
|
9
|
+
// If they're the same reference, they're equal
|
|
10
|
+
if (Object.is(a, b)) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// If either is null or undefined, they're not equal (since we know they're not the same reference)
|
|
15
|
+
if (a == null || b == null) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// If they're not objects, they're not equal (since Object.is already checked)
|
|
20
|
+
if (typeof a !== 'object' || typeof b !== 'object') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const keysA = Object.keys(a);
|
|
25
|
+
const keysB = Object.keys(b);
|
|
26
|
+
|
|
27
|
+
// Different number of keys means not equal
|
|
28
|
+
if (keysA.length !== keysB.length) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check if all keys and values are equal
|
|
33
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
34
|
+
const key = keysA[i];
|
|
35
|
+
if (!Object.prototype.hasOwnProperty.call(b, key) || !Object.is(a[key], b[key])) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return true;
|
|
41
|
+
}
|
package/src/shouldRender.ts
CHANGED
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
3
|
import deepEquals from './deepEquals';
|
|
4
|
+
import shallowEquals from './shallowEquals';
|
|
5
|
+
|
|
6
|
+
/** The supported component update strategies */
|
|
7
|
+
export type ComponentUpdateStrategy = 'customDeep' | 'shallow' | 'always';
|
|
4
8
|
|
|
5
9
|
/** Determines whether the given `component` should be rerendered by comparing its current set of props and state
|
|
6
|
-
* against the next set.
|
|
10
|
+
* against the next set. The comparison strategy can be controlled via the `updateStrategy` parameter.
|
|
7
11
|
*
|
|
8
12
|
* @param component - A React component being checked
|
|
9
13
|
* @param nextProps - The next set of props against which to check
|
|
10
14
|
* @param nextState - The next set of state against which to check
|
|
15
|
+
* @param updateStrategy - The strategy to use for comparison:
|
|
16
|
+
* - 'customDeep': Uses RJSF's custom deep equality checks (default)
|
|
17
|
+
* - 'shallow': Uses shallow comparison of props and state
|
|
18
|
+
* - 'always': Always returns true (React's default behavior)
|
|
11
19
|
* @returns - True if the component should be re-rendered, false otherwise
|
|
12
20
|
*/
|
|
13
|
-
export default function shouldRender(
|
|
21
|
+
export default function shouldRender(
|
|
22
|
+
component: React.Component,
|
|
23
|
+
nextProps: any,
|
|
24
|
+
nextState: any,
|
|
25
|
+
updateStrategy: ComponentUpdateStrategy = 'customDeep',
|
|
26
|
+
) {
|
|
27
|
+
if (updateStrategy === 'always') {
|
|
28
|
+
// Use React's default behavior: always update if state or props change (no shouldComponentUpdate optimization)
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (updateStrategy === 'shallow') {
|
|
33
|
+
// Use shallow comparison for props and state
|
|
34
|
+
const { props, state } = component;
|
|
35
|
+
return !shallowEquals(props, nextProps) || !shallowEquals(state, nextState);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Use custom deep equality checks (default 'customDeep' strategy)
|
|
14
39
|
const { props, state } = component;
|
|
15
40
|
return !deepEquals(props, nextProps) || !deepEquals(state, nextState);
|
|
16
41
|
}
|