@rjsf/utils 5.20.1 → 5.21.0
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 +186 -149
- package/dist/index.js.map +4 -4
- package/dist/utils.esm.js +186 -149
- package/dist/utils.esm.js.map +4 -4
- package/dist/utils.umd.js +191 -143
- package/lib/createSchemaUtils.js +1 -1
- package/lib/createSchemaUtils.js.map +1 -1
- package/lib/deepEquals.d.ts +1 -1
- package/lib/deepEquals.js +34 -10
- package/lib/deepEquals.js.map +1 -1
- package/lib/enumOptionsDeselectValue.js +3 -3
- package/lib/enumOptionsDeselectValue.js.map +1 -1
- package/lib/enumOptionsIsSelected.js +3 -3
- package/lib/enumOptionsIsSelected.js.map +1 -1
- package/lib/parser/ParserValidator.js +3 -3
- package/lib/parser/ParserValidator.js.map +1 -1
- package/lib/parser/schemaParser.js +4 -4
- package/lib/parser/schemaParser.js.map +1 -1
- package/lib/schema/getDefaultFormState.d.ts +39 -11
- package/lib/schema/getDefaultFormState.js +160 -125
- package/lib/schema/getDefaultFormState.js.map +1 -1
- package/lib/schema/retrieveSchema.js +7 -4
- package/lib/schema/retrieveSchema.js.map +1 -1
- package/lib/schema/toIdSchema.js +2 -2
- package/lib/schema/toIdSchema.js.map +1 -1
- package/lib/schema/toPathSchema.js +3 -3
- package/lib/schema/toPathSchema.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/createSchemaUtils.ts +1 -1
- package/src/deepEquals.ts +37 -10
- package/src/enumOptionsDeselectValue.ts +3 -4
- package/src/enumOptionsIsSelected.ts +3 -4
- package/src/parser/ParserValidator.ts +3 -3
- package/src/parser/schemaParser.ts +4 -4
- package/src/schema/getDefaultFormState.ts +237 -156
- package/src/schema/retrieveSchema.ts +8 -5
- package/src/schema/toIdSchema.ts +2 -2
- package/src/schema/toPathSchema.ts +3 -3
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import isEqual from 'lodash/isEqual';
|
|
3
2
|
|
|
4
3
|
import { ID_KEY } from '../constants';
|
|
5
4
|
import hashForSchema from '../hashForSchema';
|
|
@@ -15,6 +14,7 @@ import {
|
|
|
15
14
|
ValidationData,
|
|
16
15
|
ValidatorType,
|
|
17
16
|
} from '../types';
|
|
17
|
+
import deepEquals from '../deepEquals';
|
|
18
18
|
|
|
19
19
|
/** The type of the map of schema hash to schema
|
|
20
20
|
*/
|
|
@@ -67,7 +67,7 @@ export default class ParserValidator<T = any, S extends StrictRJSFSchema = RJSFS
|
|
|
67
67
|
const existing = this.schemaMap[key];
|
|
68
68
|
if (!existing) {
|
|
69
69
|
this.schemaMap[key] = identifiedSchema;
|
|
70
|
-
} else if (!
|
|
70
|
+
} else if (!deepEquals(existing, identifiedSchema)) {
|
|
71
71
|
console.error('existing schema:', JSON.stringify(existing, null, 2));
|
|
72
72
|
console.error('new schema:', JSON.stringify(identifiedSchema, null, 2));
|
|
73
73
|
throw new Error(
|
|
@@ -91,7 +91,7 @@ export default class ParserValidator<T = any, S extends StrictRJSFSchema = RJSFS
|
|
|
91
91
|
* @throws - Error when the given `rootSchema` differs from the root schema provided during construction
|
|
92
92
|
*/
|
|
93
93
|
isValid(schema: S, _formData: T, rootSchema: S): boolean {
|
|
94
|
-
if (!
|
|
94
|
+
if (!deepEquals(rootSchema, this.rootSchema)) {
|
|
95
95
|
throw new Error('Unexpectedly calling isValid() with a rootSchema that differs from the construction rootSchema');
|
|
96
96
|
}
|
|
97
97
|
this.addSchema(schema, hashForSchema<S>(schema));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import forEach from 'lodash/forEach';
|
|
2
|
-
import isEqual from 'lodash/isEqual';
|
|
3
2
|
|
|
4
3
|
import { FormContextType, RJSFSchema, StrictRJSFSchema } from '../types';
|
|
5
|
-
import {
|
|
4
|
+
import { ITEMS_KEY, PROPERTIES_KEY } from '../constants';
|
|
6
5
|
import ParserValidator, { SchemaMap } from './ParserValidator';
|
|
7
|
-
import {
|
|
6
|
+
import { resolveAnyOrOneOfSchemas, retrieveSchemaInternal } from '../schema/retrieveSchema';
|
|
7
|
+
import deepEquals from '../deepEquals';
|
|
8
8
|
|
|
9
9
|
/** Recursive function used to parse the given `schema` belonging to the `rootSchema`. The `validator` is used to
|
|
10
10
|
* capture the sub-schemas that the `isValid()` function is called with. For each schema returned by the
|
|
@@ -24,7 +24,7 @@ function parseSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
24
24
|
) {
|
|
25
25
|
const schemas = retrieveSchemaInternal<T, S, F>(validator, schema, rootSchema, undefined, true);
|
|
26
26
|
schemas.forEach((schema) => {
|
|
27
|
-
const sameSchemaIndex = recurseList.findIndex((item) =>
|
|
27
|
+
const sameSchemaIndex = recurseList.findIndex((item) => deepEquals(item, schema));
|
|
28
28
|
if (sameSchemaIndex === -1) {
|
|
29
29
|
recurseList.push(schema);
|
|
30
30
|
const allOptions = resolveAnyOrOneOfSchemas<T, S, F>(validator, schema, rootSchema, true);
|
|
@@ -141,12 +141,22 @@ function maybeAddDefaultToObject<T = any>(
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
interface ComputeDefaultsProps<T = any, S extends StrictRJSFSchema = RJSFSchema> {
|
|
144
|
+
/** Any defaults provided by the parent field in the schema */
|
|
144
145
|
parentDefaults?: T;
|
|
146
|
+
/** The options root schema, used to primarily to look up `$ref`s */
|
|
145
147
|
rootSchema?: S;
|
|
148
|
+
/** The current formData, if any, onto which to provide any missing defaults */
|
|
146
149
|
rawFormData?: T;
|
|
150
|
+
/** Optional flag, if true, cause undefined values to be added as defaults.
|
|
151
|
+
* If "excludeObjectChildren", cause undefined values for this object and pass `includeUndefinedValues` as
|
|
152
|
+
* false when computing defaults for any nested object properties.
|
|
153
|
+
*/
|
|
147
154
|
includeUndefinedValues?: boolean | 'excludeObjectChildren';
|
|
155
|
+
/** The list of ref names currently being recursed, used to prevent infinite recursion */
|
|
148
156
|
_recurseList?: string[];
|
|
157
|
+
/** Optional configuration object, if provided, allows users to override default form state behavior */
|
|
149
158
|
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
|
|
159
|
+
/** Optional flag, if true, indicates this schema was required in the parent schema. */
|
|
150
160
|
required?: boolean;
|
|
151
161
|
}
|
|
152
162
|
|
|
@@ -155,22 +165,15 @@ interface ComputeDefaultsProps<T = any, S extends StrictRJSFSchema = RJSFSchema>
|
|
|
155
165
|
*
|
|
156
166
|
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
157
167
|
* @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.
|
|
168
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
168
169
|
* @returns - The resulting `formData` with all the defaults provided
|
|
169
170
|
*/
|
|
170
171
|
export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
171
172
|
validator: ValidatorType<T, S, F>,
|
|
172
173
|
rawSchema: S,
|
|
173
|
-
{
|
|
174
|
+
computeDefaultsProps: ComputeDefaultsProps<T, S> = {}
|
|
175
|
+
): T | T[] | undefined {
|
|
176
|
+
const {
|
|
174
177
|
parentDefaults,
|
|
175
178
|
rawFormData,
|
|
176
179
|
rootSchema = {} as S,
|
|
@@ -178,8 +181,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
178
181
|
_recurseList = [],
|
|
179
182
|
experimental_defaultFormStateBehavior = undefined,
|
|
180
183
|
required,
|
|
181
|
-
}
|
|
182
|
-
): T | T[] | undefined {
|
|
184
|
+
} = computeDefaultsProps;
|
|
183
185
|
const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
|
|
184
186
|
const schema: S = isObject(rawSchema) ? rawSchema : ({} as S);
|
|
185
187
|
// Compute the defaults recursively: give highest priority to deepest nodes.
|
|
@@ -202,7 +204,12 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
202
204
|
schemaToCompute = findSchemaDefinition<S>(refName, rootSchema);
|
|
203
205
|
}
|
|
204
206
|
} else if (DEPENDENCIES_KEY in schema) {
|
|
205
|
-
|
|
207
|
+
// Get the default if set from properties to ensure the dependencies conditions are resolved based on it
|
|
208
|
+
const defaultFormData: T = {
|
|
209
|
+
...formData,
|
|
210
|
+
...getDefaultBasedOnSchemaType(validator, schema, computeDefaultsProps, defaults),
|
|
211
|
+
};
|
|
212
|
+
const resolvedSchema = resolveDependencies<T, S, F>(validator, schema, rootSchema, false, [], defaultFormData);
|
|
206
213
|
schemaToCompute = resolvedSchema[0]; // pick the first element from resolve dependencies
|
|
207
214
|
} else if (isFixedItems(schema)) {
|
|
208
215
|
defaults = (schema.items! as S[]).map((itemSchema: S, idx: number) =>
|
|
@@ -269,164 +276,238 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
269
276
|
defaults = schema.default as unknown as T;
|
|
270
277
|
}
|
|
271
278
|
|
|
272
|
-
|
|
273
|
-
// We need to recurse for object schema inner default values.
|
|
274
|
-
case 'object': {
|
|
275
|
-
// This is a custom addition that fixes this issue:
|
|
276
|
-
// https://github.com/rjsf-team/react-jsonschema-form/issues/3832
|
|
277
|
-
const retrievedSchema =
|
|
278
|
-
experimental_defaultFormStateBehavior?.allOf === 'populateDefaults' && ALL_OF_KEY in schema
|
|
279
|
-
? retrieveSchema<T, S, F>(validator, schema, rootSchema, formData)
|
|
280
|
-
: schema;
|
|
281
|
-
const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce(
|
|
282
|
-
(acc: GenericObjectType, key: string) => {
|
|
283
|
-
// Compute the defaults for this node, with the parent defaults we might
|
|
284
|
-
// have from a previous run: defaults[key].
|
|
285
|
-
const computedDefault = computeDefaults<T, S, F>(validator, get(retrievedSchema, [PROPERTIES_KEY, key]), {
|
|
286
|
-
rootSchema,
|
|
287
|
-
_recurseList,
|
|
288
|
-
experimental_defaultFormStateBehavior,
|
|
289
|
-
includeUndefinedValues: includeUndefinedValues === true,
|
|
290
|
-
parentDefaults: get(defaults, [key]),
|
|
291
|
-
rawFormData: get(formData, [key]),
|
|
292
|
-
required: retrievedSchema.required?.includes(key),
|
|
293
|
-
});
|
|
294
|
-
maybeAddDefaultToObject<T>(
|
|
295
|
-
acc,
|
|
296
|
-
key,
|
|
297
|
-
computedDefault,
|
|
298
|
-
includeUndefinedValues,
|
|
299
|
-
required,
|
|
300
|
-
retrievedSchema.required,
|
|
301
|
-
experimental_defaultFormStateBehavior
|
|
302
|
-
);
|
|
303
|
-
return acc;
|
|
304
|
-
},
|
|
305
|
-
{}
|
|
306
|
-
) as T;
|
|
307
|
-
if (retrievedSchema.additionalProperties) {
|
|
308
|
-
// as per spec additionalProperties may be either schema or boolean
|
|
309
|
-
const additionalPropertiesSchema = isObject(retrievedSchema.additionalProperties)
|
|
310
|
-
? retrievedSchema.additionalProperties
|
|
311
|
-
: {};
|
|
279
|
+
const defaultBasedOnSchemaType = getDefaultBasedOnSchemaType(validator, schema, computeDefaultsProps, defaults);
|
|
312
280
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
Object.keys(defaults as GenericObjectType)
|
|
316
|
-
.filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
|
|
317
|
-
.forEach((key) => keys.add(key));
|
|
318
|
-
}
|
|
319
|
-
const formDataRequired: string[] = [];
|
|
320
|
-
Object.keys(formData as GenericObjectType)
|
|
321
|
-
.filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
|
|
322
|
-
.forEach((key) => {
|
|
323
|
-
keys.add(key);
|
|
324
|
-
formDataRequired.push(key);
|
|
325
|
-
});
|
|
326
|
-
keys.forEach((key) => {
|
|
327
|
-
const computedDefault = computeDefaults(validator, additionalPropertiesSchema as S, {
|
|
328
|
-
rootSchema,
|
|
329
|
-
_recurseList,
|
|
330
|
-
experimental_defaultFormStateBehavior,
|
|
331
|
-
includeUndefinedValues: includeUndefinedValues === true,
|
|
332
|
-
parentDefaults: get(defaults, [key]),
|
|
333
|
-
rawFormData: get(formData, [key]),
|
|
334
|
-
required: retrievedSchema.required?.includes(key),
|
|
335
|
-
});
|
|
336
|
-
// Since these are additional properties we don't need to add the `experimental_defaultFormStateBehavior` prop
|
|
337
|
-
maybeAddDefaultToObject<T>(
|
|
338
|
-
objectDefaults as GenericObjectType,
|
|
339
|
-
key,
|
|
340
|
-
computedDefault,
|
|
341
|
-
includeUndefinedValues,
|
|
342
|
-
required,
|
|
343
|
-
formDataRequired
|
|
344
|
-
);
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
return objectDefaults;
|
|
348
|
-
}
|
|
349
|
-
case 'array': {
|
|
350
|
-
const neverPopulate = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'never';
|
|
351
|
-
const ignoreMinItemsFlagSet = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'requiredOnly';
|
|
352
|
-
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
|
|
353
|
-
const computeSkipPopulate =
|
|
354
|
-
experimental_defaultFormStateBehavior?.arrayMinItems?.computeSkipPopulate ?? (() => false);
|
|
281
|
+
return defaultBasedOnSchemaType ?? defaults;
|
|
282
|
+
}
|
|
355
283
|
|
|
356
|
-
|
|
284
|
+
/** Computes the default value for objects.
|
|
285
|
+
*
|
|
286
|
+
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
287
|
+
* @param rawSchema - The schema for which the default state is desired
|
|
288
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
289
|
+
* @param defaults - Optional props for this function
|
|
290
|
+
* @returns - The default value based on the schema type if they are defined for object or array schemas.
|
|
291
|
+
*/
|
|
292
|
+
export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
293
|
+
validator: ValidatorType<T, S, F>,
|
|
294
|
+
rawSchema: S,
|
|
295
|
+
{
|
|
296
|
+
rawFormData,
|
|
297
|
+
rootSchema = {} as S,
|
|
298
|
+
includeUndefinedValues = false,
|
|
299
|
+
_recurseList = [],
|
|
300
|
+
experimental_defaultFormStateBehavior = undefined,
|
|
301
|
+
required,
|
|
302
|
+
}: ComputeDefaultsProps<T, S> = {},
|
|
303
|
+
defaults?: T | T[] | undefined
|
|
304
|
+
): T {
|
|
305
|
+
{
|
|
306
|
+
const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
|
|
307
|
+
const schema: S = rawSchema;
|
|
308
|
+
// This is a custom addition that fixes this issue:
|
|
309
|
+
// https://github.com/rjsf-team/react-jsonschema-form/issues/3832
|
|
310
|
+
const retrievedSchema =
|
|
311
|
+
experimental_defaultFormStateBehavior?.allOf === 'populateDefaults' && ALL_OF_KEY in schema
|
|
312
|
+
? retrieveSchema<T, S, F>(validator, schema, rootSchema, formData)
|
|
313
|
+
: schema;
|
|
314
|
+
const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce(
|
|
315
|
+
(acc: GenericObjectType, key: string) => {
|
|
316
|
+
// Compute the defaults for this node, with the parent defaults we might
|
|
317
|
+
// have from a previous run: defaults[key].
|
|
318
|
+
const computedDefault = computeDefaults<T, S, F>(validator, get(retrievedSchema, [PROPERTIES_KEY, key]), {
|
|
319
|
+
rootSchema,
|
|
320
|
+
_recurseList,
|
|
321
|
+
experimental_defaultFormStateBehavior,
|
|
322
|
+
includeUndefinedValues: includeUndefinedValues === true,
|
|
323
|
+
parentDefaults: get(defaults, [key]),
|
|
324
|
+
rawFormData: get(formData, [key]),
|
|
325
|
+
required: retrievedSchema.required?.includes(key),
|
|
326
|
+
});
|
|
327
|
+
maybeAddDefaultToObject<T>(
|
|
328
|
+
acc,
|
|
329
|
+
key,
|
|
330
|
+
computedDefault,
|
|
331
|
+
includeUndefinedValues,
|
|
332
|
+
required,
|
|
333
|
+
retrievedSchema.required,
|
|
334
|
+
experimental_defaultFormStateBehavior
|
|
335
|
+
);
|
|
336
|
+
return acc;
|
|
337
|
+
},
|
|
338
|
+
{}
|
|
339
|
+
) as T;
|
|
340
|
+
if (retrievedSchema.additionalProperties) {
|
|
341
|
+
// as per spec additionalProperties may be either schema or boolean
|
|
342
|
+
const additionalPropertiesSchema = isObject(retrievedSchema.additionalProperties)
|
|
343
|
+
? retrievedSchema.additionalProperties
|
|
344
|
+
: {};
|
|
357
345
|
|
|
358
|
-
|
|
359
|
-
if (
|
|
360
|
-
defaults
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
rootSchema,
|
|
364
|
-
_recurseList,
|
|
365
|
-
experimental_defaultFormStateBehavior,
|
|
366
|
-
parentDefaults: item,
|
|
367
|
-
required,
|
|
368
|
-
});
|
|
369
|
-
}) as T[];
|
|
346
|
+
const keys = new Set<string>();
|
|
347
|
+
if (isObject(defaults)) {
|
|
348
|
+
Object.keys(defaults as GenericObjectType)
|
|
349
|
+
.filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
|
|
350
|
+
.forEach((key) => keys.add(key));
|
|
370
351
|
}
|
|
352
|
+
const formDataRequired: string[] = [];
|
|
353
|
+
Object.keys(formData as GenericObjectType)
|
|
354
|
+
.filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
|
|
355
|
+
.forEach((key) => {
|
|
356
|
+
keys.add(key);
|
|
357
|
+
formDataRequired.push(key);
|
|
358
|
+
});
|
|
359
|
+
keys.forEach((key) => {
|
|
360
|
+
const computedDefault = computeDefaults(validator, additionalPropertiesSchema as S, {
|
|
361
|
+
rootSchema,
|
|
362
|
+
_recurseList,
|
|
363
|
+
experimental_defaultFormStateBehavior,
|
|
364
|
+
includeUndefinedValues: includeUndefinedValues === true,
|
|
365
|
+
parentDefaults: get(defaults, [key]),
|
|
366
|
+
rawFormData: get(formData, [key]),
|
|
367
|
+
required: retrievedSchema.required?.includes(key),
|
|
368
|
+
});
|
|
369
|
+
// Since these are additional properties we don't need to add the `experimental_defaultFormStateBehavior` prop
|
|
370
|
+
maybeAddDefaultToObject<T>(
|
|
371
|
+
objectDefaults as GenericObjectType,
|
|
372
|
+
key,
|
|
373
|
+
computedDefault,
|
|
374
|
+
includeUndefinedValues,
|
|
375
|
+
required,
|
|
376
|
+
formDataRequired
|
|
377
|
+
);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
return objectDefaults;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
371
383
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
384
|
+
/** Computes the default value for arrays.
|
|
385
|
+
*
|
|
386
|
+
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
387
|
+
* @param rawSchema - The schema for which the default state is desired
|
|
388
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
389
|
+
* @param defaults - Optional props for this function
|
|
390
|
+
* @returns - The default value based on the schema type if they are defined for object or array schemas.
|
|
391
|
+
*/
|
|
392
|
+
export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
393
|
+
validator: ValidatorType<T, S, F>,
|
|
394
|
+
rawSchema: S,
|
|
395
|
+
{
|
|
396
|
+
rawFormData,
|
|
397
|
+
rootSchema = {} as S,
|
|
398
|
+
_recurseList = [],
|
|
399
|
+
experimental_defaultFormStateBehavior = undefined,
|
|
400
|
+
required,
|
|
401
|
+
}: ComputeDefaultsProps<T, S> = {},
|
|
402
|
+
defaults?: T | T[] | undefined
|
|
403
|
+
): T | T[] | undefined {
|
|
404
|
+
const schema: S = rawSchema;
|
|
390
405
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
// return form data/defaults
|
|
397
|
-
return defaults ? defaults : undefined;
|
|
398
|
-
}
|
|
406
|
+
const neverPopulate = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'never';
|
|
407
|
+
const ignoreMinItemsFlagSet = experimental_defaultFormStateBehavior?.arrayMinItems?.populate === 'requiredOnly';
|
|
408
|
+
const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
|
|
409
|
+
const computeSkipPopulate =
|
|
410
|
+
experimental_defaultFormStateBehavior?.arrayMinItems?.computeSkipPopulate ?? (() => false);
|
|
399
411
|
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
!schema.minItems ||
|
|
403
|
-
isMultiSelect<T, S, F>(validator, schema, rootSchema) ||
|
|
404
|
-
computeSkipPopulate<T, S, F>(validator, schema, rootSchema) ||
|
|
405
|
-
schema.minItems <= defaultsLength
|
|
406
|
-
) {
|
|
407
|
-
return defaults ? defaults : emptyDefault;
|
|
408
|
-
}
|
|
412
|
+
const emptyDefault = isSkipEmptyDefaults ? undefined : [];
|
|
409
413
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
414
|
+
// Inject defaults into existing array defaults
|
|
415
|
+
if (Array.isArray(defaults)) {
|
|
416
|
+
defaults = defaults.map((item, idx) => {
|
|
417
|
+
const schemaItem: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Fallback, idx);
|
|
418
|
+
return computeDefaults<T, S, F>(validator, schemaItem, {
|
|
419
|
+
rootSchema,
|
|
420
|
+
_recurseList,
|
|
421
|
+
experimental_defaultFormStateBehavior,
|
|
422
|
+
parentDefaults: item,
|
|
423
|
+
required,
|
|
424
|
+
});
|
|
425
|
+
}) as T[];
|
|
426
|
+
}
|
|
413
427
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
428
|
+
// Deeply inject defaults into already existing form data
|
|
429
|
+
if (Array.isArray(rawFormData)) {
|
|
430
|
+
const schemaItem: S = getInnerSchemaForArrayItem<S>(schema);
|
|
431
|
+
if (neverPopulate) {
|
|
432
|
+
defaults = rawFormData;
|
|
433
|
+
} else {
|
|
434
|
+
defaults = rawFormData.map((item: T, idx: number) => {
|
|
435
|
+
return computeDefaults<T, S, F>(validator, schemaItem, {
|
|
418
436
|
rootSchema,
|
|
419
437
|
_recurseList,
|
|
420
438
|
experimental_defaultFormStateBehavior,
|
|
439
|
+
rawFormData: item,
|
|
440
|
+
parentDefaults: get(defaults, [idx]),
|
|
421
441
|
required,
|
|
422
|
-
})
|
|
423
|
-
) as T[];
|
|
424
|
-
// then fill up the rest with either the item default or empty, up to minItems
|
|
425
|
-
return defaultEntries.concat(fillerEntries);
|
|
442
|
+
});
|
|
443
|
+
}) as T[];
|
|
426
444
|
}
|
|
427
445
|
}
|
|
428
446
|
|
|
429
|
-
|
|
447
|
+
if (neverPopulate) {
|
|
448
|
+
return defaults ?? emptyDefault;
|
|
449
|
+
}
|
|
450
|
+
if (ignoreMinItemsFlagSet && !required) {
|
|
451
|
+
// If no form data exists or defaults are set leave the field empty/non-existent, otherwise
|
|
452
|
+
// return form data/defaults
|
|
453
|
+
return defaults ? defaults : undefined;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const defaultsLength = Array.isArray(defaults) ? defaults.length : 0;
|
|
457
|
+
if (
|
|
458
|
+
!schema.minItems ||
|
|
459
|
+
isMultiSelect<T, S, F>(validator, schema, rootSchema) ||
|
|
460
|
+
computeSkipPopulate<T, S, F>(validator, schema, rootSchema) ||
|
|
461
|
+
schema.minItems <= defaultsLength
|
|
462
|
+
) {
|
|
463
|
+
return defaults ? defaults : emptyDefault;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const defaultEntries: T[] = (defaults || []) as T[];
|
|
467
|
+
const fillerSchema: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Invert);
|
|
468
|
+
const fillerDefault = fillerSchema.default;
|
|
469
|
+
|
|
470
|
+
// Calculate filler entries for remaining items (minItems - existing raw data/defaults)
|
|
471
|
+
const fillerEntries: T[] = new Array(schema.minItems - defaultsLength).fill(
|
|
472
|
+
computeDefaults<any, S, F>(validator, fillerSchema, {
|
|
473
|
+
parentDefaults: fillerDefault,
|
|
474
|
+
rootSchema,
|
|
475
|
+
_recurseList,
|
|
476
|
+
experimental_defaultFormStateBehavior,
|
|
477
|
+
required,
|
|
478
|
+
})
|
|
479
|
+
) as T[];
|
|
480
|
+
// then fill up the rest with either the item default or empty, up to minItems
|
|
481
|
+
return defaultEntries.concat(fillerEntries);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/** Computes the default value based on the schema type.
|
|
485
|
+
*
|
|
486
|
+
* @param validator - an implementation of the `ValidatorType` interface that will be used when necessary
|
|
487
|
+
* @param rawSchema - The schema for which the default state is desired
|
|
488
|
+
* @param {ComputeDefaultsProps} computeDefaultsProps - Optional props for this function
|
|
489
|
+
* @param defaults - Optional props for this function
|
|
490
|
+
* @returns - The default value based on the schema type if they are defined for object or array schemas.
|
|
491
|
+
*/
|
|
492
|
+
export function getDefaultBasedOnSchemaType<
|
|
493
|
+
T = any,
|
|
494
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
495
|
+
F extends FormContextType = any
|
|
496
|
+
>(
|
|
497
|
+
validator: ValidatorType<T, S, F>,
|
|
498
|
+
rawSchema: S,
|
|
499
|
+
computeDefaultsProps: ComputeDefaultsProps<T, S> = {},
|
|
500
|
+
defaults?: T | T[] | undefined
|
|
501
|
+
): T | T[] | void {
|
|
502
|
+
switch (getSchemaType<S>(rawSchema)) {
|
|
503
|
+
// We need to recurse for object schema inner default values.
|
|
504
|
+
case 'object': {
|
|
505
|
+
return getObjectDefaults(validator, rawSchema, computeDefaultsProps, defaults);
|
|
506
|
+
}
|
|
507
|
+
case 'array': {
|
|
508
|
+
return getArrayDefaults(validator, rawSchema, computeDefaultsProps, defaults);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
430
511
|
}
|
|
431
512
|
|
|
432
513
|
/** Returns the superset of `formData` that includes the given set updated to include any missing fields that have
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import isEqual from 'lodash/isEqual';
|
|
3
2
|
import set from 'lodash/set';
|
|
4
3
|
import times from 'lodash/times';
|
|
5
4
|
import transform from 'lodash/transform';
|
|
@@ -15,10 +14,10 @@ import {
|
|
|
15
14
|
ANY_OF_KEY,
|
|
16
15
|
DEPENDENCIES_KEY,
|
|
17
16
|
IF_KEY,
|
|
17
|
+
ITEMS_KEY,
|
|
18
18
|
ONE_OF_KEY,
|
|
19
|
-
REF_KEY,
|
|
20
19
|
PROPERTIES_KEY,
|
|
21
|
-
|
|
20
|
+
REF_KEY,
|
|
22
21
|
} from '../constants';
|
|
23
22
|
import findSchemaDefinition, { splitKeyElementFromObject } from '../findSchemaDefinition';
|
|
24
23
|
import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema';
|
|
@@ -27,6 +26,7 @@ import isObject from '../isObject';
|
|
|
27
26
|
import mergeSchemas from '../mergeSchemas';
|
|
28
27
|
import { FormContextType, GenericObjectType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
|
|
29
28
|
import getFirstMatchingOption from './getFirstMatchingOption';
|
|
29
|
+
import deepEquals from '../deepEquals';
|
|
30
30
|
|
|
31
31
|
/** Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies
|
|
32
32
|
* resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the
|
|
@@ -196,7 +196,10 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
196
196
|
)
|
|
197
197
|
);
|
|
198
198
|
const allPermutations = getAllPermutationsOfXxxOf<S>(allOfSchemaElements);
|
|
199
|
-
return allPermutations.map((permutation) => ({
|
|
199
|
+
return allPermutations.map((permutation) => ({
|
|
200
|
+
...schema,
|
|
201
|
+
allOf: permutation,
|
|
202
|
+
}));
|
|
200
203
|
}
|
|
201
204
|
// No $ref or dependencies or allOf attribute was found, returning the original schema.
|
|
202
205
|
return [schema];
|
|
@@ -293,7 +296,7 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
|
|
|
293
296
|
};
|
|
294
297
|
}
|
|
295
298
|
|
|
296
|
-
return
|
|
299
|
+
return deepEquals(schema, resolvedSchema) ? schema : resolvedSchema;
|
|
297
300
|
}
|
|
298
301
|
|
|
299
302
|
/** Creates new 'properties' items for each key in the `formData`
|
package/src/schema/toIdSchema.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import isEqual from 'lodash/isEqual';
|
|
3
2
|
|
|
4
3
|
import { ALL_OF_KEY, DEPENDENCIES_KEY, ID_KEY, ITEMS_KEY, PROPERTIES_KEY, REF_KEY } from '../constants';
|
|
5
4
|
import isObject from '../isObject';
|
|
6
5
|
import { FormContextType, GenericObjectType, IdSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
|
|
7
6
|
import retrieveSchema from './retrieveSchema';
|
|
8
7
|
import getSchemaType from '../getSchemaType';
|
|
8
|
+
import deepEquals from '../deepEquals';
|
|
9
9
|
|
|
10
10
|
/** An internal helper that generates an `IdSchema` object for the `schema`, recursively with protection against
|
|
11
11
|
* infinite recursion
|
|
@@ -32,7 +32,7 @@ function toIdSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F
|
|
|
32
32
|
): IdSchema<T> {
|
|
33
33
|
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
|
|
34
34
|
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData);
|
|
35
|
-
const sameSchemaIndex = _recurseList.findIndex((item) =>
|
|
35
|
+
const sameSchemaIndex = _recurseList.findIndex((item) => deepEquals(item, _schema));
|
|
36
36
|
if (sameSchemaIndex === -1) {
|
|
37
37
|
return toIdSchemaInternal<T, S, F>(
|
|
38
38
|
validator,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
|
-
import isEqual from 'lodash/isEqual';
|
|
3
2
|
import set from 'lodash/set';
|
|
4
3
|
|
|
5
4
|
import {
|
|
5
|
+
ADDITIONAL_PROPERTIES_KEY,
|
|
6
6
|
ALL_OF_KEY,
|
|
7
7
|
ANY_OF_KEY,
|
|
8
|
-
ADDITIONAL_PROPERTIES_KEY,
|
|
9
8
|
DEPENDENCIES_KEY,
|
|
10
9
|
ITEMS_KEY,
|
|
11
10
|
NAME_KEY,
|
|
@@ -18,6 +17,7 @@ import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema'
|
|
|
18
17
|
import { FormContextType, GenericObjectType, PathSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
|
|
19
18
|
import getClosestMatchingOption from './getClosestMatchingOption';
|
|
20
19
|
import retrieveSchema from './retrieveSchema';
|
|
20
|
+
import deepEquals from '../deepEquals';
|
|
21
21
|
|
|
22
22
|
/** An internal helper that generates an `PathSchema` object for the `schema`, recursively with protection against
|
|
23
23
|
* infinite recursion
|
|
@@ -40,7 +40,7 @@ function toPathSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
40
40
|
): PathSchema<T> {
|
|
41
41
|
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
|
|
42
42
|
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData);
|
|
43
|
-
const sameSchemaIndex = _recurseList.findIndex((item) =>
|
|
43
|
+
const sameSchemaIndex = _recurseList.findIndex((item) => deepEquals(item, _schema));
|
|
44
44
|
if (sameSchemaIndex === -1) {
|
|
45
45
|
return toPathSchemaInternal<T, S, F>(
|
|
46
46
|
validator,
|