@rjsf/utils 6.0.0-alpha.0 → 6.0.0-beta.1
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 +1281 -625
- package/dist/index.js.map +4 -4
- package/dist/utils.esm.js +1254 -598
- package/dist/utils.esm.js.map +4 -4
- package/dist/utils.umd.js +1201 -570
- package/lib/ErrorSchemaBuilder.d.ts +8 -4
- package/lib/ErrorSchemaBuilder.js +10 -8
- package/lib/ErrorSchemaBuilder.js.map +1 -1
- package/lib/allowAdditionalItems.d.ts +1 -1
- package/lib/allowAdditionalItems.js +1 -1
- package/lib/allowAdditionalItems.js.map +1 -1
- package/lib/asNumber.js.map +1 -1
- package/lib/canExpand.d.ts +1 -1
- package/lib/canExpand.js +2 -2
- package/lib/canExpand.js.map +1 -1
- package/lib/constIsAjvDataReference.d.ts +9 -0
- package/lib/constIsAjvDataReference.js +15 -0
- package/lib/constIsAjvDataReference.js.map +1 -0
- package/lib/constants.d.ts +11 -3
- package/lib/constants.js +11 -3
- package/lib/constants.js.map +1 -1
- package/lib/createErrorHandler.d.ts +1 -1
- package/lib/createErrorHandler.js +2 -2
- package/lib/createErrorHandler.js.map +1 -1
- package/lib/createSchemaUtils.d.ts +3 -2
- package/lib/createSchemaUtils.js +56 -46
- package/lib/createSchemaUtils.js.map +1 -1
- package/lib/dataURItoBlob.js.map +1 -1
- package/lib/dateRangeOptions.d.ts +1 -1
- package/lib/dateRangeOptions.js +1 -1
- package/lib/dateRangeOptions.js.map +1 -1
- package/lib/deepEquals.js +1 -1
- package/lib/deepEquals.js.map +1 -1
- package/lib/englishStringTranslator.d.ts +1 -1
- package/lib/englishStringTranslator.js +1 -1
- package/lib/enumOptionsDeselectValue.d.ts +1 -1
- package/lib/enumOptionsDeselectValue.js +4 -4
- package/lib/enumOptionsDeselectValue.js.map +1 -1
- package/lib/enumOptionsIndexForValue.d.ts +1 -1
- package/lib/enumOptionsIndexForValue.js +1 -1
- package/lib/enumOptionsIndexForValue.js.map +1 -1
- package/lib/enumOptionsIsSelected.d.ts +1 -1
- package/lib/enumOptionsIsSelected.js +3 -3
- package/lib/enumOptionsIsSelected.js.map +1 -1
- package/lib/enumOptionsSelectValue.d.ts +1 -1
- package/lib/enumOptionsSelectValue.js +2 -2
- package/lib/enumOptionsSelectValue.js.map +1 -1
- package/lib/enumOptionsValueForIndex.d.ts +1 -1
- package/lib/enumOptionsValueForIndex.js.map +1 -1
- package/lib/enums.d.ts +2 -0
- package/lib/enums.js +2 -0
- package/lib/enums.js.map +1 -1
- package/lib/findSchemaDefinition.d.ts +1 -1
- package/lib/findSchemaDefinition.js +2 -2
- package/lib/findSchemaDefinition.js.map +1 -1
- package/lib/getChangedFields.d.ts +17 -0
- package/lib/getChangedFields.js +42 -0
- package/lib/getChangedFields.js.map +1 -0
- package/lib/getDateElementProps.d.ts +1 -1
- package/lib/getDateElementProps.js.map +1 -1
- package/lib/getDiscriminatorFieldFromSchema.d.ts +1 -1
- package/lib/getDiscriminatorFieldFromSchema.js +4 -3
- package/lib/getDiscriminatorFieldFromSchema.js.map +1 -1
- package/lib/getInputProps.d.ts +1 -1
- package/lib/getInputProps.js +4 -1
- package/lib/getInputProps.js.map +1 -1
- package/lib/getOptionMatchingSimpleDiscriminator.d.ts +1 -1
- package/lib/getOptionMatchingSimpleDiscriminator.js +2 -2
- package/lib/getOptionMatchingSimpleDiscriminator.js.map +1 -1
- package/lib/getSchemaType.d.ts +2 -1
- package/lib/getSchemaType.js +3 -2
- package/lib/getSchemaType.js.map +1 -1
- package/lib/getSubmitButtonOptions.d.ts +1 -1
- package/lib/getSubmitButtonOptions.js +2 -2
- package/lib/getSubmitButtonOptions.js.map +1 -1
- package/lib/getTemplate.d.ts +1 -1
- package/lib/getTemplate.js +9 -0
- package/lib/getTemplate.js.map +1 -1
- package/lib/getTestIds.d.ts +17 -0
- package/lib/getTestIds.js +34 -0
- package/lib/getTestIds.js.map +1 -0
- package/lib/getUiOptions.d.ts +1 -1
- package/lib/getUiOptions.js +2 -2
- package/lib/getUiOptions.js.map +1 -1
- package/lib/getWidget.d.ts +1 -1
- package/lib/getWidget.js +3 -3
- package/lib/getWidget.js.map +1 -1
- package/lib/guessType.d.ts +1 -1
- package/lib/guessType.js.map +1 -1
- package/lib/hasWidget.d.ts +1 -1
- package/lib/hasWidget.js +1 -1
- package/lib/hasWidget.js.map +1 -1
- package/lib/hashForSchema.d.ts +23 -1
- package/lib/hashForSchema.js +24 -6
- package/lib/hashForSchema.js.map +1 -1
- package/lib/idGenerators.d.ts +8 -1
- package/lib/idGenerators.js +11 -2
- package/lib/idGenerators.js.map +1 -1
- package/lib/index.d.ts +63 -60
- package/lib/index.js +63 -60
- package/lib/index.js.map +1 -1
- package/lib/isConstant.d.ts +1 -1
- package/lib/isConstant.js +1 -1
- package/lib/isCustomWidget.d.ts +1 -1
- package/lib/isCustomWidget.js +1 -1
- package/lib/isFixedItems.d.ts +1 -1
- package/lib/isFixedItems.js +1 -1
- package/lib/isObject.d.ts +2 -2
- package/lib/isObject.js +11 -4
- package/lib/isObject.js.map +1 -1
- package/lib/lookupFromFormContext.d.ts +11 -0
- package/lib/lookupFromFormContext.js +20 -0
- package/lib/lookupFromFormContext.js.map +1 -0
- package/lib/mergeDefaultsWithFormData.d.ts +8 -2
- package/lib/mergeDefaultsWithFormData.js +39 -10
- package/lib/mergeDefaultsWithFormData.js.map +1 -1
- package/lib/mergeObjects.d.ts +1 -1
- package/lib/mergeObjects.js +1 -1
- package/lib/mergeObjects.js.map +1 -1
- package/lib/mergeSchemas.d.ts +1 -1
- package/lib/mergeSchemas.js +4 -4
- package/lib/mergeSchemas.js.map +1 -1
- package/lib/optionsList.d.ts +9 -7
- package/lib/optionsList.js +30 -19
- package/lib/optionsList.js.map +1 -1
- package/lib/orderProperties.js.map +1 -1
- package/lib/pad.js.map +1 -1
- package/lib/parseDateString.d.ts +1 -1
- package/lib/parseDateString.js +1 -1
- package/lib/parseDateString.js.map +1 -1
- package/lib/parser/ParserValidator.d.ts +1 -1
- package/lib/parser/ParserValidator.js +6 -6
- package/lib/parser/ParserValidator.js.map +1 -1
- package/lib/parser/index.d.ts +2 -2
- package/lib/parser/index.js +1 -1
- package/lib/parser/schemaParser.d.ts +2 -2
- package/lib/parser/schemaParser.js +6 -6
- package/lib/parser/schemaParser.js.map +1 -1
- package/lib/rangeSpec.d.ts +2 -2
- package/lib/rangeSpec.js.map +1 -1
- package/lib/replaceStringParameters.js.map +1 -1
- package/lib/schema/findFieldInSchema.d.ts +19 -0
- package/lib/schema/findFieldInSchema.js +61 -0
- package/lib/schema/findFieldInSchema.js.map +1 -0
- package/lib/schema/findSelectedOptionInXxxOf.d.ts +16 -0
- package/lib/schema/findSelectedOptionInXxxOf.js +34 -0
- package/lib/schema/findSelectedOptionInXxxOf.js.map +1 -0
- package/lib/schema/getClosestMatchingOption.d.ts +5 -3
- package/lib/schema/getClosestMatchingOption.js +28 -20
- package/lib/schema/getClosestMatchingOption.js.map +1 -1
- package/lib/schema/getDefaultFormState.d.ts +60 -13
- package/lib/schema/getDefaultFormState.js +304 -166
- package/lib/schema/getDefaultFormState.js.map +1 -1
- package/lib/schema/getDisplayLabel.d.ts +3 -2
- package/lib/schema/getDisplayLabel.js +10 -9
- package/lib/schema/getDisplayLabel.js.map +1 -1
- package/lib/schema/getFirstMatchingOption.d.ts +1 -1
- package/lib/schema/getFirstMatchingOption.js +70 -2
- package/lib/schema/getFirstMatchingOption.js.map +1 -1
- package/lib/schema/getFromSchema.d.ts +14 -0
- package/lib/schema/getFromSchema.js +39 -0
- package/lib/schema/getFromSchema.js.map +1 -0
- package/lib/schema/index.d.ts +15 -14
- package/lib/schema/index.js +15 -14
- package/lib/schema/index.js.map +1 -1
- package/lib/schema/isFilesArray.d.ts +3 -2
- package/lib/schema/isFilesArray.js +5 -4
- package/lib/schema/isFilesArray.js.map +1 -1
- package/lib/schema/isMultiSelect.d.ts +3 -2
- package/lib/schema/isMultiSelect.js +4 -3
- package/lib/schema/isMultiSelect.js.map +1 -1
- package/lib/schema/isSelect.d.ts +3 -2
- package/lib/schema/isSelect.js +5 -4
- package/lib/schema/isSelect.js.map +1 -1
- package/lib/schema/retrieveSchema.d.ts +28 -11
- package/lib/schema/retrieveSchema.js +142 -66
- package/lib/schema/retrieveSchema.js.map +1 -1
- package/lib/schema/sanitizeDataForNewSchema.d.ts +3 -2
- package/lib/schema/sanitizeDataForNewSchema.js +12 -11
- package/lib/schema/sanitizeDataForNewSchema.js.map +1 -1
- package/lib/schema/toIdSchema.d.ts +3 -2
- package/lib/schema/toIdSchema.js +30 -27
- package/lib/schema/toIdSchema.js.map +1 -1
- package/lib/schema/toPathSchema.d.ts +3 -2
- package/lib/schema/toPathSchema.js +22 -20
- package/lib/schema/toPathSchema.js.map +1 -1
- package/lib/schemaRequiresTrueValue.d.ts +1 -1
- package/lib/schemaRequiresTrueValue.js.map +1 -1
- package/lib/shouldRender.js +1 -1
- package/lib/toConstant.d.ts +1 -1
- package/lib/toConstant.js +1 -1
- package/lib/toConstant.js.map +1 -1
- package/lib/toDateString.d.ts +1 -1
- package/lib/toErrorList.d.ts +1 -1
- package/lib/toErrorList.js +2 -2
- package/lib/toErrorList.js.map +1 -1
- package/lib/toErrorSchema.d.ts +1 -1
- package/lib/toErrorSchema.js +2 -2
- package/lib/toErrorSchema.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types.d.ts +160 -131
- package/lib/unwrapErrorHandler.d.ts +1 -1
- package/lib/unwrapErrorHandler.js +1 -1
- package/lib/unwrapErrorHandler.js.map +1 -1
- package/lib/utcToLocal.js +1 -1
- package/lib/utcToLocal.js.map +1 -1
- package/lib/validationDataMerge.d.ts +1 -1
- package/lib/validationDataMerge.js +3 -3
- package/lib/validationDataMerge.js.map +1 -1
- package/lib/withIdRefPrefix.d.ts +1 -1
- package/lib/withIdRefPrefix.js +2 -2
- package/lib/withIdRefPrefix.js.map +1 -1
- package/package.json +36 -26
- package/src/ErrorSchemaBuilder.ts +15 -8
- package/src/canExpand.ts +2 -2
- package/src/constIsAjvDataReference.ts +17 -0
- package/src/constants.ts +12 -3
- package/src/createSchemaUtils.ts +140 -50
- package/src/dataURItoBlob.ts +1 -1
- package/src/dateRangeOptions.ts +1 -1
- package/src/enumOptionsDeselectValue.ts +4 -5
- package/src/enumOptionsIndexForValue.ts +1 -1
- package/src/enumOptionsIsSelected.ts +4 -5
- package/src/enumOptionsSelectValue.ts +1 -1
- package/src/enumOptionsValueForIndex.ts +1 -1
- package/src/enums.ts +2 -0
- package/src/findSchemaDefinition.ts +2 -2
- package/src/getChangedFields.ts +40 -0
- package/src/getDateElementProps.ts +2 -2
- package/src/getDiscriminatorFieldFromSchema.ts +2 -1
- package/src/getInputProps.ts +6 -2
- package/src/getOptionMatchingSimpleDiscriminator.ts +2 -2
- package/src/getSchemaType.ts +3 -2
- package/src/getSubmitButtonOptions.ts +1 -1
- package/src/getTemplate.ts +12 -1
- package/src/getTestIds.ts +40 -0
- package/src/getUiOptions.ts +2 -2
- package/src/getWidget.tsx +2 -2
- package/src/hasWidget.ts +1 -1
- package/src/hashForSchema.ts +26 -6
- package/src/idGenerators.ts +10 -0
- package/src/index.ts +21 -2
- package/src/isCustomWidget.ts +1 -1
- package/src/isObject.ts +12 -5
- package/src/labelValue.ts +2 -2
- package/src/lookupFromFormContext.ts +26 -0
- package/src/mergeDefaultsWithFormData.ts +54 -9
- package/src/mergeObjects.ts +24 -21
- package/src/optionsList.ts +31 -22
- package/src/parser/ParserValidator.ts +5 -5
- package/src/parser/schemaParser.ts +6 -6
- package/src/schema/findFieldInSchema.ts +138 -0
- package/src/schema/findSelectedOptionInXxxOf.ts +53 -0
- package/src/schema/getClosestMatchingOption.ts +38 -11
- package/src/schema/getDefaultFormState.ts +447 -191
- package/src/schema/getDisplayLabel.ts +7 -4
- package/src/schema/getFirstMatchingOption.ts +79 -4
- package/src/schema/getFromSchema.ts +100 -0
- package/src/schema/index.ts +6 -4
- package/src/schema/isFilesArray.ts +18 -3
- package/src/schema/isMultiSelect.ts +10 -4
- package/src/schema/isSelect.ts +5 -3
- package/src/schema/retrieveSchema.ts +256 -75
- package/src/schema/sanitizeDataForNewSchema.ts +52 -11
- package/src/schema/toIdSchema.ts +69 -43
- package/src/schema/toPathSchema.ts +49 -16
- package/src/toErrorList.ts +2 -2
- package/src/types.ts +266 -174
- package/src/validationDataMerge.ts +1 -1
- package/src/withIdRefPrefix.ts +1 -1
- package/LICENSE.md +0 -201
- package/lib/schema/getMatchingOption.d.ts +0 -14
- package/lib/schema/getMatchingOption.js +0 -85
- package/lib/schema/getMatchingOption.js.map +0 -1
- package/lib/schema/mergeValidationData.d.ts +0 -14
- package/lib/schema/mergeValidationData.js +0 -28
- package/lib/schema/mergeValidationData.js.map +0 -1
- package/src/schema/getMatchingOption.ts +0 -103
- package/src/schema/mergeValidationData.ts +0 -38
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
import isEmpty from 'lodash/isEmpty';
|
|
3
|
+
import { JSONSchema7Object } from 'json-schema';
|
|
3
4
|
|
|
4
5
|
import {
|
|
6
|
+
ALL_OF_KEY,
|
|
5
7
|
ANY_OF_KEY,
|
|
8
|
+
CONST_KEY,
|
|
6
9
|
DEFAULT_KEY,
|
|
7
10
|
DEPENDENCIES_KEY,
|
|
8
|
-
PROPERTIES_KEY,
|
|
9
11
|
ONE_OF_KEY,
|
|
12
|
+
PROPERTIES_KEY,
|
|
10
13
|
REF_KEY,
|
|
11
|
-
ALL_OF_KEY,
|
|
12
14
|
} from '../constants';
|
|
13
15
|
import findSchemaDefinition from '../findSchemaDefinition';
|
|
14
16
|
import getClosestMatchingOption from './getClosestMatchingOption';
|
|
@@ -20,6 +22,7 @@ import mergeDefaultsWithFormData from '../mergeDefaultsWithFormData';
|
|
|
20
22
|
import mergeObjects from '../mergeObjects';
|
|
21
23
|
import mergeSchemas from '../mergeSchemas';
|
|
22
24
|
import {
|
|
25
|
+
Experimental_CustomMergeAllOf,
|
|
23
26
|
Experimental_DefaultFormStateBehavior,
|
|
24
27
|
FormContextType,
|
|
25
28
|
GenericObjectType,
|
|
@@ -28,7 +31,14 @@ import {
|
|
|
28
31
|
ValidatorType,
|
|
29
32
|
} from '../types';
|
|
30
33
|
import isMultiSelect from './isMultiSelect';
|
|
34
|
+
import isSelect from './isSelect';
|
|
31
35
|
import retrieveSchema, { resolveDependencies } from './retrieveSchema';
|
|
36
|
+
import isConstant from '../isConstant';
|
|
37
|
+
import constIsAjvDataReference from '../constIsAjvDataReference';
|
|
38
|
+
import optionsList from '../optionsList';
|
|
39
|
+
import deepEquals from '../deepEquals';
|
|
40
|
+
|
|
41
|
+
const PRIMITIVE_TYPES = ['string', 'number', 'integer', 'boolean', 'null'];
|
|
32
42
|
|
|
33
43
|
/** Enum that indicates how `schema.additionalItems` should be handled by the `getInnerSchemaForArrayItem()` function.
|
|
34
44
|
*/
|
|
@@ -56,7 +66,7 @@ export enum AdditionalItemsHandling {
|
|
|
56
66
|
export function getInnerSchemaForArrayItem<S extends StrictRJSFSchema = RJSFSchema>(
|
|
57
67
|
schema: S,
|
|
58
68
|
additionalItems: AdditionalItemsHandling = AdditionalItemsHandling.Ignore,
|
|
59
|
-
idx = -1
|
|
69
|
+
idx = -1,
|
|
60
70
|
): S {
|
|
61
71
|
if (idx >= 0) {
|
|
62
72
|
if (Array.isArray(schema.items) && idx < schema.items.length) {
|
|
@@ -92,6 +102,7 @@ export function getInnerSchemaForArrayItem<S extends StrictRJSFSchema = RJSFSche
|
|
|
92
102
|
* @param requiredFields - The list of fields that are required
|
|
93
103
|
* @param experimental_defaultFormStateBehavior - Optional configuration object, if provided, allows users to override
|
|
94
104
|
* default form state behavior
|
|
105
|
+
* @param isConst - Optional flag, if true, indicates that the schema has a const property defined, thus we should always return the computedDefault since it's coming from the const.
|
|
95
106
|
*/
|
|
96
107
|
function maybeAddDefaultToObject<T = any>(
|
|
97
108
|
obj: GenericObjectType,
|
|
@@ -100,24 +111,26 @@ function maybeAddDefaultToObject<T = any>(
|
|
|
100
111
|
includeUndefinedValues: boolean | 'excludeObjectChildren',
|
|
101
112
|
isParentRequired?: boolean,
|
|
102
113
|
requiredFields: string[] = [],
|
|
103
|
-
experimental_defaultFormStateBehavior: Experimental_DefaultFormStateBehavior = {}
|
|
114
|
+
experimental_defaultFormStateBehavior: Experimental_DefaultFormStateBehavior = {},
|
|
115
|
+
isConst = false,
|
|
104
116
|
) {
|
|
105
117
|
const { emptyObjectFields = 'populateAllDefaults' } = experimental_defaultFormStateBehavior;
|
|
106
|
-
if (includeUndefinedValues) {
|
|
118
|
+
if (includeUndefinedValues || isConst) {
|
|
119
|
+
// If includeUndefinedValues
|
|
120
|
+
// Or if the schema has a const property defined, then we should always return the computedDefault since it's coming from the const.
|
|
107
121
|
obj[key] = computedDefault;
|
|
108
122
|
} else if (emptyObjectFields !== 'skipDefaults') {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const isSelfOrParentRequired = isParentRequired === undefined ? requiredFields.includes(key) : isParentRequired;
|
|
123
|
+
// If isParentRequired is undefined, then we are at the root level of the schema so defer to the requiredness of
|
|
124
|
+
// the field key itself in the `requiredField` list
|
|
125
|
+
const isSelfOrParentRequired = isParentRequired === undefined ? requiredFields.includes(key) : isParentRequired;
|
|
113
126
|
|
|
127
|
+
if (isObject(computedDefault)) {
|
|
114
128
|
// If emptyObjectFields 'skipEmptyDefaults' store computedDefault if it's a non-empty object(e.g. not {})
|
|
115
129
|
if (emptyObjectFields === 'skipEmptyDefaults') {
|
|
116
130
|
if (!isEmpty(computedDefault)) {
|
|
117
131
|
obj[key] = computedDefault;
|
|
118
132
|
}
|
|
119
|
-
}
|
|
120
|
-
// Else store computedDefault if it's a non-empty object(e.g. not {}) and satisfies certain conditions
|
|
133
|
+
} // Else store computedDefault if it's a non-empty object(e.g. not {}) and satisfies certain conditions
|
|
121
134
|
// Condition 1: If computedDefault is not empty or if the key is a required field
|
|
122
135
|
// Condition 2: If the parent object is required or emptyObjectFields is not 'populateRequiredDefaults'
|
|
123
136
|
else if (
|
|
@@ -129,11 +142,12 @@ function maybeAddDefaultToObject<T = any>(
|
|
|
129
142
|
} else if (
|
|
130
143
|
// Store computedDefault if it's a defined primitive (e.g., true) and satisfies certain conditions
|
|
131
144
|
// Condition 1: computedDefault is not undefined
|
|
132
|
-
// Condition 2: If emptyObjectFields is 'populateAllDefaults' or 'skipEmptyDefaults)
|
|
145
|
+
// Condition 2: If emptyObjectFields is 'populateAllDefaults' or 'skipEmptyDefaults)
|
|
146
|
+
// Or if isSelfOrParentRequired is 'true' and the key is a required field
|
|
133
147
|
computedDefault !== undefined &&
|
|
134
148
|
(emptyObjectFields === 'populateAllDefaults' ||
|
|
135
149
|
emptyObjectFields === 'skipEmptyDefaults' ||
|
|
136
|
-
requiredFields.includes(key))
|
|
150
|
+
(isSelfOrParentRequired && requiredFields.includes(key)))
|
|
137
151
|
) {
|
|
138
152
|
obj[key] = computedDefault;
|
|
139
153
|
}
|
|
@@ -141,13 +155,29 @@ function maybeAddDefaultToObject<T = any>(
|
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
interface ComputeDefaultsProps<T = any, S extends StrictRJSFSchema = RJSFSchema> {
|
|
158
|
+
/** Any defaults provided by the parent field in the schema */
|
|
144
159
|
parentDefaults?: T;
|
|
160
|
+
/** The options root schema, used to primarily to look up `$ref`s */
|
|
145
161
|
rootSchema?: S;
|
|
162
|
+
/** The current formData, if any, onto which to provide any missing defaults */
|
|
146
163
|
rawFormData?: T;
|
|
164
|
+
/** Optional flag, if true, cause undefined values to be added as defaults.
|
|
165
|
+
* If "excludeObjectChildren", cause undefined values for this object and pass `includeUndefinedValues` as
|
|
166
|
+
* false when computing defaults for any nested object properties.
|
|
167
|
+
*/
|
|
147
168
|
includeUndefinedValues?: boolean | 'excludeObjectChildren';
|
|
169
|
+
/** The list of ref names currently being recursed, used to prevent infinite recursion */
|
|
148
170
|
_recurseList?: string[];
|
|
171
|
+
/** Optional configuration object, if provided, allows users to override default form state behavior */
|
|
149
172
|
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
|
|
173
|
+
/** Optional function that allows for custom merging of `allOf` schemas */
|
|
174
|
+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
|
|
175
|
+
/** Optional flag, if true, indicates this schema was required in the parent schema. */
|
|
150
176
|
required?: boolean;
|
|
177
|
+
/** Optional flag, if true, It will merge defaults into formData.
|
|
178
|
+
* 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
|
+
*/
|
|
180
|
+
shouldMergeDefaultsIntoFormData?: boolean;
|
|
151
181
|
}
|
|
152
182
|
|
|
153
183
|
/** Computes the defaults for the current `schema` given the `rawFormData` and `parentDefaults` if any. This drills into
|
|
@@ -155,44 +185,47 @@ interface ComputeDefaultsProps<T = any, S extends StrictRJSFSchema = RJSFSchema>
|
|
|
155
185
|
*
|
|
156
186
|
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
157
187
|
* @param rawSchema - The schema for which the default state is desired
|
|
158
|
-
* @param
|
|
159
|
-
* @param [props.parentDefaults] - Any defaults provided by the parent field in the schema
|
|
160
|
-
* @param [props.rootSchema] - The options root schema, used to primarily to look up `$ref`s
|
|
161
|
-
* @param [props.rawFormData] - The current formData, if any, onto which to provide any missing defaults
|
|
162
|
-
* @param [props.includeUndefinedValues=false] - Optional flag, if true, cause undefined values to be added as defaults.
|
|
163
|
-
* If "excludeObjectChildren", cause undefined values for this object and pass `includeUndefinedValues` as
|
|
164
|
-
* false when computing defaults for any nested object properties.
|
|
165
|
-
* @param [props._recurseList=[]] - The list of ref names currently being recursed, used to prevent infinite recursion
|
|
166
|
-
* @param [props.experimental_defaultFormStateBehavior] Optional configuration object, if provided, allows users to override default form state behavior
|
|
167
|
-
* @param [props.required] - Optional flag, if true, indicates this schema was required in the parent schema.
|
|
188
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
168
189
|
* @returns - The resulting `formData` with all the defaults provided
|
|
169
190
|
*/
|
|
170
191
|
export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
171
192
|
validator: ValidatorType<T, S, F>,
|
|
172
193
|
rawSchema: S,
|
|
173
|
-
{
|
|
194
|
+
computeDefaultsProps: ComputeDefaultsProps<T, S> = {},
|
|
195
|
+
): T | T[] | undefined {
|
|
196
|
+
const {
|
|
174
197
|
parentDefaults,
|
|
175
198
|
rawFormData,
|
|
176
199
|
rootSchema = {} as S,
|
|
177
200
|
includeUndefinedValues = false,
|
|
178
201
|
_recurseList = [],
|
|
179
202
|
experimental_defaultFormStateBehavior = undefined,
|
|
203
|
+
experimental_customMergeAllOf = undefined,
|
|
180
204
|
required,
|
|
181
|
-
|
|
182
|
-
|
|
205
|
+
shouldMergeDefaultsIntoFormData = false,
|
|
206
|
+
} = computeDefaultsProps;
|
|
183
207
|
const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
|
|
184
208
|
const schema: S = isObject(rawSchema) ? rawSchema : ({} as S);
|
|
185
209
|
// Compute the defaults recursively: give highest priority to deepest nodes.
|
|
186
210
|
let defaults: T | T[] | undefined = parentDefaults;
|
|
187
211
|
// If we get a new schema, then we need to recompute defaults again for the new schema found.
|
|
188
212
|
let schemaToCompute: S | null = null;
|
|
213
|
+
let experimental_dfsb_to_compute = experimental_defaultFormStateBehavior;
|
|
189
214
|
let updatedRecurseList = _recurseList;
|
|
190
215
|
|
|
191
|
-
if (
|
|
216
|
+
if (
|
|
217
|
+
schema[CONST_KEY] &&
|
|
218
|
+
experimental_defaultFormStateBehavior?.constAsDefaults !== 'never' &&
|
|
219
|
+
!constIsAjvDataReference(schema)
|
|
220
|
+
) {
|
|
221
|
+
defaults = schema[CONST_KEY] as unknown as T;
|
|
222
|
+
} else if (isObject(defaults) && isObject(schema.default)) {
|
|
192
223
|
// For object defaults, only override parent defaults that are defined in
|
|
193
224
|
// schema.default.
|
|
194
225
|
defaults = mergeObjects(defaults!, schema.default as GenericObjectType) as T;
|
|
195
|
-
} else if (DEFAULT_KEY in schema) {
|
|
226
|
+
} else if (DEFAULT_KEY in schema && !schema[ANY_OF_KEY] && !schema[ONE_OF_KEY]) {
|
|
227
|
+
// If the schema has a default value, then we should use it as the default.
|
|
228
|
+
// And if the schema does not have anyOf or oneOf, this is done because we need to merge the defaults with the formData.
|
|
196
229
|
defaults = schema.default as unknown as T;
|
|
197
230
|
} else if (REF_KEY in schema) {
|
|
198
231
|
const refName = schema[REF_KEY];
|
|
@@ -202,7 +235,20 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
202
235
|
schemaToCompute = findSchemaDefinition<S>(refName, rootSchema);
|
|
203
236
|
}
|
|
204
237
|
} else if (DEPENDENCIES_KEY in schema) {
|
|
205
|
-
|
|
238
|
+
// Get the default if set from properties to ensure the dependencies conditions are resolved based on it
|
|
239
|
+
const defaultFormData: T = {
|
|
240
|
+
...getDefaultBasedOnSchemaType(validator, schema, computeDefaultsProps, defaults),
|
|
241
|
+
...formData,
|
|
242
|
+
};
|
|
243
|
+
const resolvedSchema = resolveDependencies<T, S, F>(
|
|
244
|
+
validator,
|
|
245
|
+
schema,
|
|
246
|
+
rootSchema,
|
|
247
|
+
false,
|
|
248
|
+
[],
|
|
249
|
+
defaultFormData,
|
|
250
|
+
experimental_customMergeAllOf,
|
|
251
|
+
);
|
|
206
252
|
schemaToCompute = resolvedSchema[0]; // pick the first element from resolve dependencies
|
|
207
253
|
} else if (isFixedItems(schema)) {
|
|
208
254
|
defaults = (schema.items! as S[]).map((itemSchema: S, idx: number) =>
|
|
@@ -211,10 +257,12 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
211
257
|
includeUndefinedValues,
|
|
212
258
|
_recurseList,
|
|
213
259
|
experimental_defaultFormStateBehavior,
|
|
260
|
+
experimental_customMergeAllOf,
|
|
214
261
|
parentDefaults: Array.isArray(parentDefaults) ? parentDefaults[idx] : undefined,
|
|
215
262
|
rawFormData: formData as T,
|
|
216
263
|
required,
|
|
217
|
-
|
|
264
|
+
shouldMergeDefaultsIntoFormData,
|
|
265
|
+
}),
|
|
218
266
|
) as T[];
|
|
219
267
|
} else if (ONE_OF_KEY in schema) {
|
|
220
268
|
const { oneOf, ...remaining } = schema;
|
|
@@ -222,14 +270,27 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
222
270
|
return undefined;
|
|
223
271
|
}
|
|
224
272
|
const discriminator = getDiscriminatorFieldFromSchema<S>(schema);
|
|
273
|
+
const { type = 'null' } = remaining;
|
|
274
|
+
if (
|
|
275
|
+
!Array.isArray(type) &&
|
|
276
|
+
PRIMITIVE_TYPES.includes(type) &&
|
|
277
|
+
experimental_dfsb_to_compute?.constAsDefaults === 'skipOneOf'
|
|
278
|
+
) {
|
|
279
|
+
// If we are in a oneOf of a primitive type, then we want to pass constAsDefaults as 'never' for the recursion
|
|
280
|
+
experimental_dfsb_to_compute = {
|
|
281
|
+
...experimental_dfsb_to_compute,
|
|
282
|
+
constAsDefaults: 'never',
|
|
283
|
+
};
|
|
284
|
+
}
|
|
225
285
|
schemaToCompute = oneOf![
|
|
226
286
|
getClosestMatchingOption<T, S, F>(
|
|
227
287
|
validator,
|
|
228
288
|
rootSchema,
|
|
229
|
-
|
|
289
|
+
rawFormData ?? (schema.default as T),
|
|
230
290
|
oneOf as S[],
|
|
231
291
|
0,
|
|
232
|
-
discriminator
|
|
292
|
+
discriminator,
|
|
293
|
+
experimental_customMergeAllOf,
|
|
233
294
|
)
|
|
234
295
|
] as S;
|
|
235
296
|
schemaToCompute = mergeSchemas(remaining, schemaToCompute) as S;
|
|
@@ -243,10 +304,11 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
243
304
|
getClosestMatchingOption<T, S, F>(
|
|
244
305
|
validator,
|
|
245
306
|
rootSchema,
|
|
246
|
-
|
|
307
|
+
rawFormData ?? (schema.default as T),
|
|
247
308
|
anyOf as S[],
|
|
248
309
|
0,
|
|
249
|
-
discriminator
|
|
310
|
+
discriminator,
|
|
311
|
+
experimental_customMergeAllOf,
|
|
250
312
|
)
|
|
251
313
|
] as S;
|
|
252
314
|
schemaToCompute = mergeSchemas(remaining, schemaToCompute) as S;
|
|
@@ -257,10 +319,12 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
257
319
|
rootSchema,
|
|
258
320
|
includeUndefinedValues,
|
|
259
321
|
_recurseList: updatedRecurseList,
|
|
260
|
-
experimental_defaultFormStateBehavior,
|
|
322
|
+
experimental_defaultFormStateBehavior: experimental_dfsb_to_compute,
|
|
323
|
+
experimental_customMergeAllOf,
|
|
261
324
|
parentDefaults: defaults as T | undefined,
|
|
262
325
|
rawFormData: formData as T,
|
|
263
326
|
required,
|
|
327
|
+
shouldMergeDefaultsIntoFormData,
|
|
264
328
|
});
|
|
265
329
|
}
|
|
266
330
|
|
|
@@ -269,164 +333,343 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
269
333
|
defaults = schema.default as unknown as T;
|
|
270
334
|
}
|
|
271
335
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
key,
|
|
297
|
-
computedDefault,
|
|
298
|
-
includeUndefinedValues,
|
|
299
|
-
required,
|
|
300
|
-
retrievedSchema.required,
|
|
301
|
-
experimental_defaultFormStateBehavior
|
|
302
|
-
);
|
|
303
|
-
return acc;
|
|
304
|
-
},
|
|
305
|
-
{}
|
|
336
|
+
const defaultBasedOnSchemaType = getDefaultBasedOnSchemaType(validator, schema, computeDefaultsProps, defaults);
|
|
337
|
+
|
|
338
|
+
let defaultsWithFormData = defaultBasedOnSchemaType ?? defaults;
|
|
339
|
+
// if shouldMergeDefaultsIntoFormData is true, then merge the defaults into the formData.
|
|
340
|
+
if (shouldMergeDefaultsIntoFormData) {
|
|
341
|
+
const { arrayMinItems = {} } = experimental_defaultFormStateBehavior || {};
|
|
342
|
+
const { mergeExtraDefaults } = arrayMinItems;
|
|
343
|
+
|
|
344
|
+
const matchingFormData = ensureFormDataMatchingSchema(
|
|
345
|
+
validator,
|
|
346
|
+
schema,
|
|
347
|
+
rootSchema,
|
|
348
|
+
rawFormData,
|
|
349
|
+
experimental_defaultFormStateBehavior,
|
|
350
|
+
experimental_customMergeAllOf,
|
|
351
|
+
);
|
|
352
|
+
if (!isObject(rawFormData) || ALL_OF_KEY in schema) {
|
|
353
|
+
// If the formData is not an object which means it's a primitive field, then we need to merge the defaults into the formData.
|
|
354
|
+
// Or if the schema has allOf, we need to merge the defaults into the formData because we don't compute the defaults for allOf.
|
|
355
|
+
defaultsWithFormData = mergeDefaultsWithFormData<T>(
|
|
356
|
+
defaultsWithFormData as T,
|
|
357
|
+
matchingFormData as T,
|
|
358
|
+
mergeExtraDefaults,
|
|
359
|
+
true,
|
|
306
360
|
) as T;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return defaultsWithFormData;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Ensure that the formData matches the given schema. If it's not matching in the case of a selectField, we change it to match the schema.
|
|
369
|
+
*
|
|
370
|
+
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
371
|
+
* @param schema - The schema for which the formData state is desired
|
|
372
|
+
* @param rootSchema - The root schema, used to primarily to look up `$ref`s
|
|
373
|
+
* @param formData - The current formData
|
|
374
|
+
* @param [experimental_defaultFormStateBehavior] - Optional configuration object, if provided, allows users to override default form state behavior
|
|
375
|
+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
|
|
376
|
+
* @returns - valid formData that matches schema
|
|
377
|
+
*/
|
|
378
|
+
export function ensureFormDataMatchingSchema<
|
|
379
|
+
T = any,
|
|
380
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
381
|
+
F extends FormContextType = any,
|
|
382
|
+
>(
|
|
383
|
+
validator: ValidatorType<T, S, F>,
|
|
384
|
+
schema: S,
|
|
385
|
+
rootSchema: S,
|
|
386
|
+
formData: T | undefined,
|
|
387
|
+
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior,
|
|
388
|
+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
389
|
+
): T | T[] | undefined {
|
|
390
|
+
const isSelectField =
|
|
391
|
+
!isConstant<S>(schema) && isSelect<T, S, F>(validator, schema, rootSchema, experimental_customMergeAllOf);
|
|
392
|
+
let validFormData: T | T[] | undefined = formData;
|
|
393
|
+
if (isSelectField) {
|
|
394
|
+
const getOptionsList = optionsList<T, S, F>(schema);
|
|
395
|
+
const isValid = getOptionsList?.some((option) => deepEquals(option.value, formData));
|
|
396
|
+
validFormData = isValid ? formData : undefined;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Override the formData with the const if the constAsDefaults is set to always
|
|
400
|
+
const constTakesPrecedence = schema[CONST_KEY] && experimental_defaultFormStateBehavior?.constAsDefaults === 'always';
|
|
401
|
+
if (constTakesPrecedence) {
|
|
402
|
+
validFormData = schema.const as T;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return validFormData;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Computes the default value for objects.
|
|
409
|
+
*
|
|
410
|
+
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
411
|
+
* @param rawSchema - The schema for which the default state is desired
|
|
412
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
413
|
+
* @param defaults - Optional props for this function
|
|
414
|
+
* @returns - The default value based on the schema type if they are defined for object or array schemas.
|
|
415
|
+
*/
|
|
416
|
+
export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
417
|
+
validator: ValidatorType<T, S, F>,
|
|
418
|
+
rawSchema: S,
|
|
419
|
+
{
|
|
420
|
+
rawFormData,
|
|
421
|
+
rootSchema = {} as S,
|
|
422
|
+
includeUndefinedValues = false,
|
|
423
|
+
_recurseList = [],
|
|
424
|
+
experimental_defaultFormStateBehavior = undefined,
|
|
425
|
+
experimental_customMergeAllOf = undefined,
|
|
426
|
+
required,
|
|
427
|
+
shouldMergeDefaultsIntoFormData,
|
|
428
|
+
}: ComputeDefaultsProps<T, S> = {},
|
|
429
|
+
defaults?: T | T[] | undefined,
|
|
430
|
+
): T {
|
|
431
|
+
{
|
|
432
|
+
const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
|
|
433
|
+
const schema: S = rawSchema;
|
|
434
|
+
// This is a custom addition that fixes this issue:
|
|
435
|
+
// https://github.com/rjsf-team/react-jsonschema-form/issues/3832
|
|
436
|
+
const retrievedSchema =
|
|
437
|
+
experimental_defaultFormStateBehavior?.allOf === 'populateDefaults' && ALL_OF_KEY in schema
|
|
438
|
+
? retrieveSchema<T, S, F>(validator, schema, rootSchema, formData, experimental_customMergeAllOf)
|
|
439
|
+
: schema;
|
|
440
|
+
const parentConst = retrievedSchema[CONST_KEY];
|
|
441
|
+
const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce(
|
|
442
|
+
(acc: GenericObjectType, key: string) => {
|
|
443
|
+
const propertySchema: S = get(retrievedSchema, [PROPERTIES_KEY, key], {}) as S;
|
|
444
|
+
// Check if the parent schema has a const property defined AND we are supporting const as defaults, then we
|
|
445
|
+
// should always return the computedDefault since it's coming from the const.
|
|
446
|
+
const hasParentConst = isObject(parentConst) && (parentConst as JSONSchema7Object)[key] !== undefined;
|
|
447
|
+
const hasConst =
|
|
448
|
+
((isObject(propertySchema) && CONST_KEY in propertySchema) || hasParentConst) &&
|
|
449
|
+
experimental_defaultFormStateBehavior?.constAsDefaults !== 'never' &&
|
|
450
|
+
!constIsAjvDataReference(propertySchema);
|
|
451
|
+
// Compute the defaults for this node, with the parent defaults we might
|
|
452
|
+
// have from a previous run: defaults[key].
|
|
453
|
+
const computedDefault = computeDefaults<T, S, F>(validator, propertySchema, {
|
|
454
|
+
rootSchema,
|
|
455
|
+
_recurseList,
|
|
456
|
+
experimental_defaultFormStateBehavior,
|
|
457
|
+
experimental_customMergeAllOf,
|
|
458
|
+
includeUndefinedValues: includeUndefinedValues === true,
|
|
459
|
+
parentDefaults: get(defaults, [key]),
|
|
460
|
+
rawFormData: get(formData, [key]),
|
|
461
|
+
required: retrievedSchema.required?.includes(key),
|
|
462
|
+
shouldMergeDefaultsIntoFormData,
|
|
345
463
|
});
|
|
464
|
+
maybeAddDefaultToObject<T>(
|
|
465
|
+
acc,
|
|
466
|
+
key,
|
|
467
|
+
computedDefault,
|
|
468
|
+
includeUndefinedValues,
|
|
469
|
+
required,
|
|
470
|
+
retrievedSchema.required,
|
|
471
|
+
experimental_defaultFormStateBehavior,
|
|
472
|
+
hasConst,
|
|
473
|
+
);
|
|
474
|
+
return acc;
|
|
475
|
+
},
|
|
476
|
+
{},
|
|
477
|
+
) as T;
|
|
478
|
+
if (retrievedSchema.additionalProperties) {
|
|
479
|
+
// as per spec additionalProperties may be either schema or boolean
|
|
480
|
+
const additionalPropertiesSchema = isObject(retrievedSchema.additionalProperties)
|
|
481
|
+
? retrievedSchema.additionalProperties
|
|
482
|
+
: {};
|
|
483
|
+
|
|
484
|
+
const keys = new Set<string>();
|
|
485
|
+
if (isObject(defaults)) {
|
|
486
|
+
Object.keys(defaults as GenericObjectType)
|
|
487
|
+
.filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
|
|
488
|
+
.forEach((key) => keys.add(key));
|
|
346
489
|
}
|
|
347
|
-
|
|
490
|
+
const formDataRequired: string[] = [];
|
|
491
|
+
Object.keys(formData as GenericObjectType)
|
|
492
|
+
.filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
|
|
493
|
+
.forEach((key) => {
|
|
494
|
+
keys.add(key);
|
|
495
|
+
formDataRequired.push(key);
|
|
496
|
+
});
|
|
497
|
+
keys.forEach((key) => {
|
|
498
|
+
const computedDefault = computeDefaults(validator, additionalPropertiesSchema as S, {
|
|
499
|
+
rootSchema,
|
|
500
|
+
_recurseList,
|
|
501
|
+
experimental_defaultFormStateBehavior,
|
|
502
|
+
experimental_customMergeAllOf,
|
|
503
|
+
includeUndefinedValues: includeUndefinedValues === true,
|
|
504
|
+
parentDefaults: get(defaults, [key]),
|
|
505
|
+
rawFormData: get(formData, [key]),
|
|
506
|
+
required: retrievedSchema.required?.includes(key),
|
|
507
|
+
shouldMergeDefaultsIntoFormData,
|
|
508
|
+
});
|
|
509
|
+
// Since these are additional properties we don't need to add the `experimental_defaultFormStateBehavior` prop
|
|
510
|
+
maybeAddDefaultToObject<T>(
|
|
511
|
+
objectDefaults as GenericObjectType,
|
|
512
|
+
key,
|
|
513
|
+
computedDefault,
|
|
514
|
+
includeUndefinedValues,
|
|
515
|
+
required,
|
|
516
|
+
formDataRequired,
|
|
517
|
+
);
|
|
518
|
+
});
|
|
348
519
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
|
|
353
|
-
const computeSkipPopulate =
|
|
354
|
-
experimental_defaultFormStateBehavior?.arrayMinItems?.computeSkipPopulate ?? (() => false);
|
|
355
|
-
|
|
356
|
-
const emptyDefault = isSkipEmptyDefaults ? undefined : [];
|
|
357
|
-
|
|
358
|
-
// Inject defaults into existing array defaults
|
|
359
|
-
if (Array.isArray(defaults)) {
|
|
360
|
-
defaults = defaults.map((item, idx) => {
|
|
361
|
-
const schemaItem: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Fallback, idx);
|
|
362
|
-
return computeDefaults<T, S, F>(validator, schemaItem, {
|
|
363
|
-
rootSchema,
|
|
364
|
-
_recurseList,
|
|
365
|
-
experimental_defaultFormStateBehavior,
|
|
366
|
-
parentDefaults: item,
|
|
367
|
-
required,
|
|
368
|
-
});
|
|
369
|
-
}) as T[];
|
|
370
|
-
}
|
|
520
|
+
return objectDefaults;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
371
523
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
524
|
+
/** Computes the default value for arrays.
|
|
525
|
+
*
|
|
526
|
+
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
527
|
+
* @param rawSchema - The schema for which the default state is desired
|
|
528
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
529
|
+
* @param defaults - Optional props for this function
|
|
530
|
+
* @returns - The default value based on the schema type if they are defined for object or array schemas.
|
|
531
|
+
*/
|
|
532
|
+
export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
533
|
+
validator: ValidatorType<T, S, F>,
|
|
534
|
+
rawSchema: S,
|
|
535
|
+
{
|
|
536
|
+
rawFormData,
|
|
537
|
+
rootSchema = {} as S,
|
|
538
|
+
_recurseList = [],
|
|
539
|
+
experimental_defaultFormStateBehavior = undefined,
|
|
540
|
+
experimental_customMergeAllOf = undefined,
|
|
541
|
+
required,
|
|
542
|
+
shouldMergeDefaultsIntoFormData,
|
|
543
|
+
}: ComputeDefaultsProps<T, S> = {},
|
|
544
|
+
defaults?: T | T[] | undefined,
|
|
545
|
+
): T | T[] | undefined {
|
|
546
|
+
const schema: S = rawSchema;
|
|
390
547
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
if (ignoreMinItemsFlagSet && !required) {
|
|
395
|
-
// If no form data exists or defaults are set leave the field empty/non-existent, otherwise
|
|
396
|
-
// return form data/defaults
|
|
397
|
-
return defaults ? defaults : undefined;
|
|
398
|
-
}
|
|
548
|
+
const arrayMinItemsStateBehavior = experimental_defaultFormStateBehavior?.arrayMinItems ?? {};
|
|
549
|
+
const { populate: arrayMinItemsPopulate, mergeExtraDefaults: arrayMergeExtraDefaults } = arrayMinItemsStateBehavior;
|
|
399
550
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
schema.minItems <= defaultsLength
|
|
406
|
-
) {
|
|
407
|
-
return defaults ? defaults : emptyDefault;
|
|
408
|
-
}
|
|
551
|
+
const neverPopulate = arrayMinItemsPopulate === 'never';
|
|
552
|
+
const ignoreMinItemsFlagSet = arrayMinItemsPopulate === 'requiredOnly';
|
|
553
|
+
const isPopulateAll = arrayMinItemsPopulate === 'all' || (!neverPopulate && !ignoreMinItemsFlagSet);
|
|
554
|
+
const computeSkipPopulate = arrayMinItemsStateBehavior?.computeSkipPopulate ?? (() => false);
|
|
555
|
+
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
|
|
409
556
|
|
|
410
|
-
|
|
411
|
-
const fillerSchema: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Invert);
|
|
412
|
-
const fillerDefault = fillerSchema.default;
|
|
557
|
+
const emptyDefault = isSkipEmptyDefaults ? undefined : [];
|
|
413
558
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
559
|
+
// Inject defaults into existing array defaults
|
|
560
|
+
if (Array.isArray(defaults)) {
|
|
561
|
+
defaults = defaults.map((item, idx) => {
|
|
562
|
+
const schemaItem: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Fallback, idx);
|
|
563
|
+
return computeDefaults<T, S, F>(validator, schemaItem, {
|
|
564
|
+
rootSchema,
|
|
565
|
+
_recurseList,
|
|
566
|
+
experimental_defaultFormStateBehavior,
|
|
567
|
+
experimental_customMergeAllOf,
|
|
568
|
+
parentDefaults: item,
|
|
569
|
+
required,
|
|
570
|
+
shouldMergeDefaultsIntoFormData,
|
|
571
|
+
});
|
|
572
|
+
}) as T[];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Deeply inject defaults into already existing form data
|
|
576
|
+
if (Array.isArray(rawFormData)) {
|
|
577
|
+
const schemaItem: S = getInnerSchemaForArrayItem<S>(schema);
|
|
578
|
+
if (neverPopulate) {
|
|
579
|
+
defaults = rawFormData;
|
|
580
|
+
} else {
|
|
581
|
+
const itemDefaults = rawFormData.map((item: T, idx: number) => {
|
|
582
|
+
return computeDefaults<T, S, F>(validator, schemaItem, {
|
|
418
583
|
rootSchema,
|
|
419
584
|
_recurseList,
|
|
420
585
|
experimental_defaultFormStateBehavior,
|
|
586
|
+
experimental_customMergeAllOf,
|
|
587
|
+
rawFormData: item,
|
|
588
|
+
parentDefaults: get(defaults, [idx]),
|
|
421
589
|
required,
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
590
|
+
shouldMergeDefaultsIntoFormData,
|
|
591
|
+
});
|
|
592
|
+
}) as T[];
|
|
593
|
+
|
|
594
|
+
// If the populate 'requiredOnly' flag is set then we only merge and include extra defaults if they are required.
|
|
595
|
+
// Or if populate 'all' is set we merge and include extra defaults.
|
|
596
|
+
const mergeExtraDefaults = ((ignoreMinItemsFlagSet && required) || isPopulateAll) && arrayMergeExtraDefaults;
|
|
597
|
+
defaults = mergeDefaultsWithFormData(defaults, itemDefaults, mergeExtraDefaults);
|
|
426
598
|
}
|
|
427
599
|
}
|
|
428
600
|
|
|
429
|
-
|
|
601
|
+
// Check if the schema has a const property defined AND we are supporting const as defaults, then we should always
|
|
602
|
+
// return the computedDefault since it's coming from the const.
|
|
603
|
+
const hasConst =
|
|
604
|
+
isObject(schema) && CONST_KEY in schema && experimental_defaultFormStateBehavior?.constAsDefaults !== 'never';
|
|
605
|
+
if (hasConst === false) {
|
|
606
|
+
if (neverPopulate) {
|
|
607
|
+
return defaults ?? emptyDefault;
|
|
608
|
+
}
|
|
609
|
+
if (ignoreMinItemsFlagSet && !required) {
|
|
610
|
+
// If no form data exists or defaults are set leave the field empty/non-existent, otherwise
|
|
611
|
+
// return form data/defaults
|
|
612
|
+
return defaults ? defaults : undefined;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const defaultsLength = Array.isArray(defaults) ? defaults.length : 0;
|
|
617
|
+
if (
|
|
618
|
+
!schema.minItems ||
|
|
619
|
+
isMultiSelect<T, S, F>(validator, schema, rootSchema, experimental_customMergeAllOf) ||
|
|
620
|
+
computeSkipPopulate<T, S, F>(validator, schema, rootSchema) ||
|
|
621
|
+
schema.minItems <= defaultsLength
|
|
622
|
+
) {
|
|
623
|
+
return defaults ? defaults : emptyDefault;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const defaultEntries: T[] = (defaults || []) as T[];
|
|
627
|
+
const fillerSchema: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Invert);
|
|
628
|
+
const fillerDefault = fillerSchema.default;
|
|
629
|
+
|
|
630
|
+
// Calculate filler entries for remaining items (minItems - existing raw data/defaults)
|
|
631
|
+
const fillerEntries: T[] = new Array(schema.minItems - defaultsLength).fill(
|
|
632
|
+
computeDefaults<any, S, F>(validator, fillerSchema, {
|
|
633
|
+
parentDefaults: fillerDefault,
|
|
634
|
+
rootSchema,
|
|
635
|
+
_recurseList,
|
|
636
|
+
experimental_defaultFormStateBehavior,
|
|
637
|
+
experimental_customMergeAllOf,
|
|
638
|
+
required,
|
|
639
|
+
shouldMergeDefaultsIntoFormData,
|
|
640
|
+
}),
|
|
641
|
+
) as T[];
|
|
642
|
+
// then fill up the rest with either the item default or empty, up to minItems
|
|
643
|
+
return defaultEntries.concat(fillerEntries);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/** Computes the default value based on the schema type.
|
|
647
|
+
*
|
|
648
|
+
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
649
|
+
* @param rawSchema - The schema for which the default state is desired
|
|
650
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
651
|
+
* @param defaults - Optional props for this function
|
|
652
|
+
* @returns - The default value based on the schema type if they are defined for object or array schemas.
|
|
653
|
+
*/
|
|
654
|
+
export function getDefaultBasedOnSchemaType<
|
|
655
|
+
T = any,
|
|
656
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
657
|
+
F extends FormContextType = any,
|
|
658
|
+
>(
|
|
659
|
+
validator: ValidatorType<T, S, F>,
|
|
660
|
+
rawSchema: S,
|
|
661
|
+
computeDefaultsProps: ComputeDefaultsProps<T, S> = {},
|
|
662
|
+
defaults?: T | T[] | undefined,
|
|
663
|
+
): T | T[] | void {
|
|
664
|
+
switch (getSchemaType<S>(rawSchema)) {
|
|
665
|
+
// We need to recurse for object schema inner default values.
|
|
666
|
+
case 'object': {
|
|
667
|
+
return getObjectDefaults(validator, rawSchema, computeDefaultsProps, defaults);
|
|
668
|
+
}
|
|
669
|
+
case 'array': {
|
|
670
|
+
return getArrayDefaults(validator, rawSchema, computeDefaultsProps, defaults);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
430
673
|
}
|
|
431
674
|
|
|
432
675
|
/** Returns the superset of `formData` that includes the given set updated to include any missing fields that have
|
|
@@ -440,40 +683,53 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
440
683
|
* If "excludeObjectChildren", cause undefined values for this object and pass `includeUndefinedValues` as
|
|
441
684
|
* false when computing defaults for any nested object properties.
|
|
442
685
|
* @param [experimental_defaultFormStateBehavior] Optional configuration object, if provided, allows users to override default form state behavior
|
|
686
|
+
* @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
|
|
443
687
|
* @returns - The resulting `formData` with all the defaults provided
|
|
444
688
|
*/
|
|
445
689
|
export default function getDefaultFormState<
|
|
446
690
|
T = any,
|
|
447
691
|
S extends StrictRJSFSchema = RJSFSchema,
|
|
448
|
-
F extends FormContextType = any
|
|
692
|
+
F extends FormContextType = any,
|
|
449
693
|
>(
|
|
450
694
|
validator: ValidatorType<T, S, F>,
|
|
451
695
|
theSchema: S,
|
|
452
696
|
formData?: T,
|
|
453
697
|
rootSchema?: S,
|
|
454
698
|
includeUndefinedValues: boolean | 'excludeObjectChildren' = false,
|
|
455
|
-
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior
|
|
699
|
+
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior,
|
|
700
|
+
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
456
701
|
) {
|
|
457
702
|
if (!isObject(theSchema)) {
|
|
458
703
|
throw new Error('Invalid schema: ' + theSchema);
|
|
459
704
|
}
|
|
460
|
-
const schema = retrieveSchema<T, S, F>(validator, theSchema, rootSchema, formData);
|
|
705
|
+
const schema = retrieveSchema<T, S, F>(validator, theSchema, rootSchema, formData, experimental_customMergeAllOf);
|
|
706
|
+
|
|
707
|
+
// Get the computed defaults with 'shouldMergeDefaultsIntoFormData' set to true to merge defaults into formData.
|
|
708
|
+
// This is done when for example the value from formData does not exist in the schema 'enum' property, in such
|
|
709
|
+
// cases we take the value from the defaults because the value from the formData is not valid.
|
|
461
710
|
const defaults = computeDefaults<T, S, F>(validator, schema, {
|
|
462
711
|
rootSchema,
|
|
463
712
|
includeUndefinedValues,
|
|
464
713
|
experimental_defaultFormStateBehavior,
|
|
714
|
+
experimental_customMergeAllOf,
|
|
465
715
|
rawFormData: formData,
|
|
716
|
+
shouldMergeDefaultsIntoFormData: true,
|
|
466
717
|
});
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
718
|
+
|
|
719
|
+
// If the formData is an object or an array, add additional properties from formData and override formData with
|
|
720
|
+
// defaults since the defaults are already merged with formData.
|
|
721
|
+
if (isObject(formData) || Array.isArray(formData)) {
|
|
722
|
+
const { mergeDefaultsIntoFormData } = experimental_defaultFormStateBehavior || {};
|
|
723
|
+
const defaultSupercedesUndefined = mergeDefaultsIntoFormData === 'useDefaultIfFormDataUndefined';
|
|
724
|
+
const result = mergeDefaultsWithFormData<T | T[]>(
|
|
725
|
+
defaults,
|
|
726
|
+
formData,
|
|
727
|
+
true, // set to true to add any additional default array entries.
|
|
728
|
+
defaultSupercedesUndefined,
|
|
729
|
+
true, // set to true to override formData with defaults if they exist.
|
|
730
|
+
);
|
|
731
|
+
return result;
|
|
477
732
|
}
|
|
478
|
-
|
|
733
|
+
|
|
734
|
+
return defaults;
|
|
479
735
|
}
|