@rjsf/utils 6.1.1 → 6.2.3
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.cjs +241 -163
- package/dist/index.cjs.map +4 -4
- package/dist/utils.esm.js +241 -163
- package/dist/utils.esm.js.map +4 -4
- package/dist/utils.umd.js +258 -184
- package/lib/createSchemaUtils.js +13 -1
- package/lib/createSchemaUtils.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/schema/getDefaultFormState.js +21 -8
- package/lib/schema/getDefaultFormState.js.map +1 -1
- package/lib/schema/index.d.ts +4 -1
- package/lib/schema/index.js +4 -1
- package/lib/schema/index.js.map +1 -1
- package/lib/schema/omitExtraData.d.ts +26 -0
- package/lib/schema/omitExtraData.js +79 -0
- package/lib/schema/omitExtraData.js.map +1 -0
- package/lib/schema/retrieveSchema.js +19 -8
- package/lib/schema/retrieveSchema.js.map +1 -1
- package/lib/schema/toPathSchema.js +2 -2
- package/lib/schema/toPathSchema.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types.d.ts +19 -2
- package/package.json +2 -3
- package/src/createSchemaUtils.ts +13 -0
- package/src/enums.ts +2 -0
- package/src/schema/getDefaultFormState.ts +26 -10
- package/src/schema/index.ts +4 -0
- package/src/schema/omitExtraData.ts +93 -0
- package/src/schema/retrieveSchema.ts +22 -8
- package/src/schema/toPathSchema.ts +2 -1
- package/src/types.ts +19 -1
package/lib/types.d.ts
CHANGED
|
@@ -316,6 +316,8 @@ export type TemplatesType<T = any, S extends StrictRJSFSchema = RJSFSchema, F ex
|
|
|
316
316
|
MoveUpButton: ComponentType<IconButtonProps<T, S, F>>;
|
|
317
317
|
/** The template to use for the Remove button used for AdditionalProperties and Array items */
|
|
318
318
|
RemoveButton: ComponentType<IconButtonProps<T, S, F>>;
|
|
319
|
+
/** The template to use for the Clear button used for input fields */
|
|
320
|
+
ClearButton: ComponentType<IconButtonProps<T, S, F>>;
|
|
319
321
|
};
|
|
320
322
|
} & {
|
|
321
323
|
/** Allow this to support any named `ComponentType` or an object of named `ComponentType`s */
|
|
@@ -338,6 +340,9 @@ export type GlobalUISchemaOptions = GenericObjectType & {
|
|
|
338
340
|
removable?: boolean;
|
|
339
341
|
/** Field labels are rendered by default. Labels may be omitted by setting the `label` option to `false` */
|
|
340
342
|
label?: boolean;
|
|
343
|
+
/** Flag, if set to `true`, will allow the text input fields to be cleared
|
|
344
|
+
*/
|
|
345
|
+
allowClearTextInputs?: boolean;
|
|
341
346
|
/** When using `additionalProperties`, key collision is prevented by appending a unique integer to the duplicate key.
|
|
342
347
|
* This option allows you to change the separator between the original key name and the integer. Default is "-"
|
|
343
348
|
*/
|
|
@@ -447,6 +452,8 @@ export type Field<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
447
452
|
};
|
|
448
453
|
/** The properties that are passed to a `FieldTemplate` implementation */
|
|
449
454
|
export type FieldTemplateProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> = RJSFBaseProps<T, S, F> & {
|
|
455
|
+
/** The FieldPathId containing the id and path for this field */
|
|
456
|
+
fieldPathId: FieldPathId;
|
|
450
457
|
/** The id of the field in the hierarchy. You can use it to render a label targeting the wrapped widget */
|
|
451
458
|
id: string;
|
|
452
459
|
/** A string containing the base CSS classes, merged with any custom ones defined in your uiSchema */
|
|
@@ -914,10 +921,10 @@ export type UiSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
914
921
|
*/
|
|
915
922
|
items?: UiSchema<ArrayElement<T>, S, F> | ((itemData: ArrayElement<T>, index: number, formContext?: F) => UiSchema<ArrayElement<T>, S, F>);
|
|
916
923
|
};
|
|
917
|
-
/** A `CustomValidator` function takes in a `formData`, `errors` and `
|
|
924
|
+
/** A `CustomValidator` function takes in a `formData`, `errors`, `uiSchema` and `errorSchema` objects and returns the given `errors`
|
|
918
925
|
* object back, while potentially adding additional messages to the `errors`
|
|
919
926
|
*/
|
|
920
|
-
export type CustomValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> = (formData: T | undefined, errors: FormValidation<T>, uiSchema?: UiSchema<T, S, F>) => FormValidation<T>;
|
|
927
|
+
export type CustomValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> = (formData: T | undefined, errors: FormValidation<T>, uiSchema?: UiSchema<T, S, F>, errorSchema?: ErrorSchema<T>) => FormValidation<T>;
|
|
921
928
|
/** An `ErrorTransformer` function will take in a list of `errors` & a `uiSchema` and potentially return a
|
|
922
929
|
* transformation of those errors in what ever way it deems necessary
|
|
923
930
|
*/
|
|
@@ -1101,6 +1108,16 @@ export interface SchemaUtilsType<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
1101
1108
|
* @returns - True if schema contains a select, otherwise false
|
|
1102
1109
|
*/
|
|
1103
1110
|
isSelect(schema: S): boolean;
|
|
1111
|
+
/**
|
|
1112
|
+
* The function takes a `schema` and `formData` and returns a copy of the formData with any fields not defined in the schema removed.
|
|
1113
|
+
* This is useful for ensuring that only data that is relevant to the schema is preserved. Objects with `additionalProperties`
|
|
1114
|
+
* keyword set to `true` will not have their extra fields removed.
|
|
1115
|
+
*
|
|
1116
|
+
* @param schema - The schema to use for filtering the `formData`
|
|
1117
|
+
* @param [formData] - The formData to filter
|
|
1118
|
+
* @returns The new form data, with any fields not defined in the schema removed
|
|
1119
|
+
*/
|
|
1120
|
+
omitExtraData(schema: S, formData?: T): T | undefined;
|
|
1104
1121
|
/** Retrieves an expanded schema that has had all of its conditions, additional properties, references and
|
|
1105
1122
|
* dependencies resolved and merged into the `schema` given a `rawFormData` that is used to do the potentially
|
|
1106
1123
|
* recursive resolution.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rjsf/utils",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.3",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"react": ">=18"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
+
"@x0k/json-schema-merge": "^1.0.2",
|
|
68
69
|
"fast-uri": "^3.1.0",
|
|
69
|
-
"json-schema-merge-allof": "^0.8.1",
|
|
70
70
|
"jsonpointer": "^5.0.1",
|
|
71
71
|
"lodash": "^4.17.21",
|
|
72
72
|
"lodash-es": "^4.17.21",
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@types/json-schema": "^7.0.15",
|
|
77
|
-
"@types/json-schema-merge-allof": "^0.6.5",
|
|
78
77
|
"@types/react-is": "^18.3.1",
|
|
79
78
|
"deep-freeze-es6": "^4.0.1",
|
|
80
79
|
"eslint": "^8.57.1"
|
package/src/createSchemaUtils.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
isFilesArray,
|
|
24
24
|
isMultiSelect,
|
|
25
25
|
isSelect,
|
|
26
|
+
omitExtraData,
|
|
26
27
|
retrieveSchema,
|
|
27
28
|
sanitizeDataForNewSchema,
|
|
28
29
|
toPathSchema,
|
|
@@ -297,6 +298,18 @@ class SchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
297
298
|
isSelect(schema: S) {
|
|
298
299
|
return isSelect<T, S, F>(this.validator, schema, this.rootSchema, this.experimental_customMergeAllOf);
|
|
299
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* The function takes a `schema` and `formData` and returns a copy of the formData with any fields not defined in the schema removed.
|
|
303
|
+
* This is useful for ensuring that only data that is relevant to the schema is preserved. Objects with `additionalProperties`
|
|
304
|
+
* keyword set to `true` will not have their extra fields removed.
|
|
305
|
+
*
|
|
306
|
+
* @param schema - The schema to use for filtering the `formData`
|
|
307
|
+
* @param [formData] - The formData to filter
|
|
308
|
+
* @returns The new form data, with any fields not defined in the schema removed
|
|
309
|
+
*/
|
|
310
|
+
omitExtraData(schema: S, formData?: T): T | undefined {
|
|
311
|
+
return omitExtraData<T, S, F>(this.validator, schema, this.rootSchema, formData);
|
|
312
|
+
}
|
|
300
313
|
|
|
301
314
|
/** Retrieves an expanded schema that has had all of its conditions, additional properties, references and
|
|
302
315
|
* dependencies resolved and merged into the `schema` given a `rawFormData` that is used to do the potentially
|
package/src/enums.ts
CHANGED
|
@@ -55,6 +55,8 @@ export enum TranslatableString {
|
|
|
55
55
|
Type = 'Type',
|
|
56
56
|
/** Label for the 'value' field, used by FallbackField */
|
|
57
57
|
Value = 'Value',
|
|
58
|
+
/** Clear button title, used by IconButton */
|
|
59
|
+
ClearButton = 'clear input',
|
|
58
60
|
// Strings with replaceable parameters
|
|
59
61
|
/** Unknown field type reason, where %1 will be replaced with the type as provided by SchemaField */
|
|
60
62
|
UnknownFieldType = 'Unknown field type %1',
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
CONST_KEY,
|
|
9
9
|
DEFAULT_KEY,
|
|
10
10
|
DEPENDENCIES_KEY,
|
|
11
|
+
IF_KEY,
|
|
11
12
|
ONE_OF_KEY,
|
|
12
13
|
PROPERTIES_KEY,
|
|
13
14
|
REF_KEY,
|
|
@@ -251,9 +252,15 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
251
252
|
!constIsAjvDataReference(schema)
|
|
252
253
|
) {
|
|
253
254
|
defaults = schema[CONST_KEY] as unknown as T;
|
|
254
|
-
} else if (
|
|
255
|
+
} else if (
|
|
256
|
+
isObject(defaults) &&
|
|
257
|
+
isObject(schema.default) &&
|
|
258
|
+
!schema[ANY_OF_KEY] &&
|
|
259
|
+
!schema[ONE_OF_KEY] &&
|
|
260
|
+
!schema[REF_KEY]
|
|
261
|
+
) {
|
|
255
262
|
// For object defaults, only override parent defaults that are defined in
|
|
256
|
-
// schema.default.
|
|
263
|
+
// schema.default. Skip this for anyOf/oneOf/$ref schemas - they need special handling.
|
|
257
264
|
defaults = mergeObjects(defaults!, schema.default as GenericObjectType) as T;
|
|
258
265
|
} else if (DEFAULT_KEY in schema && !schema[ANY_OF_KEY] && !schema[ONE_OF_KEY] && !schema[REF_KEY]) {
|
|
259
266
|
// If the schema has a default value, then we should use it as the default.
|
|
@@ -268,8 +275,11 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
|
|
|
268
275
|
}
|
|
269
276
|
|
|
270
277
|
// If the referenced schema exists and parentDefaults is not set
|
|
271
|
-
// Then set the defaults from the current schema for the referenced schema
|
|
272
|
-
if
|
|
278
|
+
// Then set the defaults from the current schema for the referenced schema.
|
|
279
|
+
// Only do this if rawFormData has no meaningful data - we don't want to override user's existing values.
|
|
280
|
+
// Check for undefined OR empty object - rawFormData may be coerced to {} when not an object.
|
|
281
|
+
const hasNoExistingData = rawFormData === undefined || (isObject(rawFormData) && isEmpty(rawFormData));
|
|
282
|
+
if (schemaToCompute && !defaults && hasNoExistingData) {
|
|
273
283
|
defaults = schema.default as T | undefined;
|
|
274
284
|
}
|
|
275
285
|
|
|
@@ -478,12 +488,16 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
|
|
|
478
488
|
{
|
|
479
489
|
const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
|
|
480
490
|
const schema: S = rawSchema;
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
491
|
+
// Retrieve the schema:
|
|
492
|
+
// - If schema contains `allOf` AND `experimental_defaultFormStateBehavior.allOf` is set to `populateDefaults`
|
|
493
|
+
// - OR if schema contains an 'if' AND `emptyObjectFields` is not set to `skipEmptyDefaults`
|
|
494
|
+
// This ensures we compute defaults correctly for schemas with these keywords.
|
|
495
|
+
const shouldRetrieveSchema =
|
|
496
|
+
(experimental_defaultFormStateBehavior?.allOf === 'populateDefaults' && ALL_OF_KEY in schema) ||
|
|
497
|
+
(experimental_defaultFormStateBehavior?.emptyObjectFields !== 'skipEmptyDefaults' && IF_KEY in schema);
|
|
498
|
+
const retrievedSchema = shouldRetrieveSchema
|
|
499
|
+
? retrieveSchema<T, S, F>(validator, schema, rootSchema, formData, experimental_customMergeAllOf)
|
|
500
|
+
: schema;
|
|
487
501
|
const parentConst = retrievedSchema[CONST_KEY];
|
|
488
502
|
const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce(
|
|
489
503
|
(acc: GenericObjectType, key: string) => {
|
|
@@ -614,12 +628,14 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
614
628
|
if (Array.isArray(defaults)) {
|
|
615
629
|
defaults = defaults.map((item, idx) => {
|
|
616
630
|
const schemaItem: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Fallback, idx);
|
|
631
|
+
const itemFormData = Array.isArray(rawFormData) ? rawFormData[idx] : undefined;
|
|
617
632
|
return computeDefaults<T, S, F>(validator, schemaItem, {
|
|
618
633
|
rootSchema,
|
|
619
634
|
_recurseList,
|
|
620
635
|
experimental_defaultFormStateBehavior,
|
|
621
636
|
experimental_customMergeAllOf,
|
|
622
637
|
parentDefaults: item,
|
|
638
|
+
rawFormData: itemFormData,
|
|
623
639
|
required,
|
|
624
640
|
shouldMergeDefaultsIntoFormData,
|
|
625
641
|
initialDefaultsGenerated,
|
package/src/schema/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import getFromSchema from './getFromSchema';
|
|
|
8
8
|
import isFilesArray from './isFilesArray';
|
|
9
9
|
import isMultiSelect from './isMultiSelect';
|
|
10
10
|
import isSelect from './isSelect';
|
|
11
|
+
import omitExtraData, { getUsedFormData, getFieldNames } from './omitExtraData';
|
|
11
12
|
import retrieveSchema from './retrieveSchema';
|
|
12
13
|
import sanitizeDataForNewSchema from './sanitizeDataForNewSchema';
|
|
13
14
|
import toPathSchema from './toPathSchema';
|
|
@@ -17,12 +18,15 @@ export {
|
|
|
17
18
|
findSelectedOptionInXxxOf,
|
|
18
19
|
getDefaultFormState,
|
|
19
20
|
getDisplayLabel,
|
|
21
|
+
getFieldNames, // Exported only to prevent breaking change in core
|
|
20
22
|
getClosestMatchingOption,
|
|
21
23
|
getFirstMatchingOption,
|
|
22
24
|
getFromSchema,
|
|
25
|
+
getUsedFormData, // Exported only to prevent breaking change in core
|
|
23
26
|
isFilesArray,
|
|
24
27
|
isMultiSelect,
|
|
25
28
|
isSelect,
|
|
29
|
+
omitExtraData,
|
|
26
30
|
retrieveSchema,
|
|
27
31
|
sanitizeDataForNewSchema,
|
|
28
32
|
toPathSchema,
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import pick from 'lodash/pick';
|
|
2
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
|
+
import get from 'lodash/get';
|
|
4
|
+
|
|
5
|
+
import { NAME_KEY, RJSF_ADDITIONAL_PROPERTIES_FLAG } from '../constants';
|
|
6
|
+
import { GenericObjectType, PathSchema, FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
|
|
7
|
+
import retrieveSchema from './retrieveSchema';
|
|
8
|
+
import toPathSchema from './toPathSchema';
|
|
9
|
+
|
|
10
|
+
/** Returns the `formData` with only the elements specified in the `fields` list
|
|
11
|
+
*
|
|
12
|
+
* @param formData - The data for the `Form`
|
|
13
|
+
* @param fields - The fields to keep while filtering
|
|
14
|
+
* @deprecated - To be removed as an exported `@rjsf/utils` function in a future release
|
|
15
|
+
*/
|
|
16
|
+
export function getUsedFormData<T = any>(formData: T | undefined, fields: string[]): T | undefined {
|
|
17
|
+
// For the case of a single input form
|
|
18
|
+
if (fields.length === 0 && typeof formData !== 'object') {
|
|
19
|
+
return formData;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const data: GenericObjectType = pick(formData, fields);
|
|
23
|
+
if (Array.isArray(formData)) {
|
|
24
|
+
return Object.keys(data).map((key: string) => data[key]) as unknown as T;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return data as T;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData`
|
|
31
|
+
*
|
|
32
|
+
* @param pathSchema - The `PathSchema` object for the form
|
|
33
|
+
* @param [formData] - The form data to use while checking for empty objects/arrays
|
|
34
|
+
* @deprecated - To be removed as an exported `@rjsf/utils` function in a future release
|
|
35
|
+
*/
|
|
36
|
+
export function getFieldNames<T = any>(pathSchema: PathSchema<T>, formData?: T): string[][] {
|
|
37
|
+
const formValueHasData = (value: T, isLeaf: boolean) =>
|
|
38
|
+
typeof value !== 'object' || isEmpty(value) || (isLeaf && !isEmpty(value));
|
|
39
|
+
const getAllPaths = (_obj: GenericObjectType, acc: string[][] = [], paths: string[][] = [[]]) => {
|
|
40
|
+
const objKeys = Object.keys(_obj);
|
|
41
|
+
objKeys.forEach((key: string) => {
|
|
42
|
+
const data = _obj[key];
|
|
43
|
+
if (typeof data === 'object') {
|
|
44
|
+
const newPaths = paths.map((path) => [...path, key]);
|
|
45
|
+
// If an object is marked with additionalProperties, all its keys are valid
|
|
46
|
+
if (data[RJSF_ADDITIONAL_PROPERTIES_FLAG] && data[NAME_KEY] !== '') {
|
|
47
|
+
acc.push(data[NAME_KEY]);
|
|
48
|
+
} else {
|
|
49
|
+
getAllPaths(data, acc, newPaths);
|
|
50
|
+
}
|
|
51
|
+
} else if (key === NAME_KEY && data !== '') {
|
|
52
|
+
paths.forEach((path) => {
|
|
53
|
+
const formValue = get(formData, path);
|
|
54
|
+
const isLeaf = objKeys.length === 1;
|
|
55
|
+
// adds path to fieldNames if it points to a value or an empty object/array which is not a leaf
|
|
56
|
+
if (
|
|
57
|
+
formValueHasData(formValue, isLeaf) ||
|
|
58
|
+
(Array.isArray(formValue) && formValue.every((val) => formValueHasData(val, isLeaf)))
|
|
59
|
+
) {
|
|
60
|
+
acc.push(path);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return acc;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return getAllPaths(pathSchema);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Takes a `schema` and `formData` and returns a copy of the formData with any fields not defined in the schema removed.
|
|
72
|
+
* This is useful for ensuring that only data that is relevant to the schema is preserved. Objects with
|
|
73
|
+
* `additionalProperties` keyword set to `true` will not have their extra fields removed.
|
|
74
|
+
*
|
|
75
|
+
* @param validator - An implementation of the `ValidatorType` interface that will be used when necessary
|
|
76
|
+
* @param schema - The schema to use for filtering the formData
|
|
77
|
+
* @param [rootSchema] - The root schema, used to primarily to look up `$ref`s
|
|
78
|
+
* @param [formData] - The data for the `Form`
|
|
79
|
+
* @returns The `formData` after omitting extra data
|
|
80
|
+
*/
|
|
81
|
+
export default function omitExtraData<
|
|
82
|
+
T = any,
|
|
83
|
+
S extends StrictRJSFSchema = RJSFSchema,
|
|
84
|
+
F extends FormContextType = any,
|
|
85
|
+
>(validator: ValidatorType<T, S, F>, schema: S, rootSchema: S = {} as S, formData?: T): T | undefined {
|
|
86
|
+
const retrievedSchema = retrieveSchema(validator, schema, rootSchema, formData);
|
|
87
|
+
const pathSchema = toPathSchema(validator, retrievedSchema, '', rootSchema, formData);
|
|
88
|
+
const fieldNames = getFieldNames(pathSchema, formData);
|
|
89
|
+
const lodashFieldNames = fieldNames.map((fieldPaths: string[]) =>
|
|
90
|
+
Array.isArray(fieldPaths) ? fieldPaths.join('.') : fieldPaths,
|
|
91
|
+
);
|
|
92
|
+
return getUsedFormData(formData, lodashFieldNames);
|
|
93
|
+
}
|
|
@@ -5,7 +5,9 @@ import transform from 'lodash/transform';
|
|
|
5
5
|
import merge from 'lodash/merge';
|
|
6
6
|
import flattenDeep from 'lodash/flattenDeep';
|
|
7
7
|
import uniq from 'lodash/uniq';
|
|
8
|
-
import
|
|
8
|
+
import isEmpty from 'lodash/isEmpty';
|
|
9
|
+
import { createComparator, createMerger, createShallowAllOfMerge } from '@x0k/json-schema-merge';
|
|
10
|
+
import { createDeduplicator, createIntersector } from '@x0k/json-schema-merge/lib/array';
|
|
9
11
|
|
|
10
12
|
import {
|
|
11
13
|
ADDITIONAL_PROPERTIES_KEY,
|
|
@@ -36,7 +38,6 @@ import {
|
|
|
36
38
|
} from '../types';
|
|
37
39
|
import getFirstMatchingOption from './getFirstMatchingOption';
|
|
38
40
|
import deepEquals from '../deepEquals';
|
|
39
|
-
import isEmpty from 'lodash/isEmpty';
|
|
40
41
|
|
|
41
42
|
/** Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies
|
|
42
43
|
* resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the
|
|
@@ -512,6 +513,24 @@ export function stubExistingAdditionalProperties<
|
|
|
512
513
|
return schema;
|
|
513
514
|
}
|
|
514
515
|
|
|
516
|
+
// Set up @x0k/json-schema-merge utilities
|
|
517
|
+
const { compareSchemaDefinitions, compareSchemaValues } = createComparator();
|
|
518
|
+
const { mergeArrayOfSchemaDefinitions } = createMerger({
|
|
519
|
+
intersectJson: createIntersector(compareSchemaValues),
|
|
520
|
+
deduplicateJsonSchemaDef: createDeduplicator(compareSchemaDefinitions),
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
const shallowAllOfMerge = createShallowAllOfMerge(mergeArrayOfSchemaDefinitions);
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Internal helper that merges allOf schemas using @x0k/json-schema-merge's shallow allOf merge
|
|
527
|
+
* @param schema - The schema containing an `allOf` keyword
|
|
528
|
+
* @returns The schema with allOf schemas merged
|
|
529
|
+
*/
|
|
530
|
+
function mergeAllOf<S extends StrictRJSFSchema = RJSFSchema>(schema: S): S {
|
|
531
|
+
return shallowAllOfMerge(schema) as S;
|
|
532
|
+
}
|
|
533
|
+
|
|
515
534
|
/** Internal handler that retrieves an expanded schema that has had all of its conditions, additional properties,
|
|
516
535
|
* references and dependencies resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData`
|
|
517
536
|
* that is used to do the potentially recursive resolution. If `expandAllBranches` is true, then all possible branches
|
|
@@ -590,12 +609,7 @@ export function retrieveSchemaInternal<
|
|
|
590
609
|
}
|
|
591
610
|
resolvedSchema = experimental_customMergeAllOf
|
|
592
611
|
? experimental_customMergeAllOf(resolvedSchema)
|
|
593
|
-
:
|
|
594
|
-
deep: false,
|
|
595
|
-
resolvers: {
|
|
596
|
-
$defs: mergeAllOf.options.resolvers.definitions,
|
|
597
|
-
},
|
|
598
|
-
} as Options) as S);
|
|
612
|
+
: mergeAllOf(resolvedSchema);
|
|
599
613
|
if (withContainsSchemas.length) {
|
|
600
614
|
resolvedSchema.allOf = withContainsSchemas;
|
|
601
615
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ALL_OF_KEY,
|
|
7
7
|
ANY_OF_KEY,
|
|
8
8
|
DEPENDENCIES_KEY,
|
|
9
|
+
IF_KEY,
|
|
9
10
|
ITEMS_KEY,
|
|
10
11
|
NAME_KEY,
|
|
11
12
|
ONE_OF_KEY,
|
|
@@ -48,7 +49,7 @@ function toPathSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema,
|
|
|
48
49
|
_recurseList: S[] = [],
|
|
49
50
|
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
|
|
50
51
|
): PathSchema<T> {
|
|
51
|
-
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
|
|
52
|
+
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema || IF_KEY in schema) {
|
|
52
53
|
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData, experimental_customMergeAllOf);
|
|
53
54
|
const sameSchemaIndex = _recurseList.findIndex((item) => deepEquals(item, _schema));
|
|
54
55
|
if (sameSchemaIndex === -1) {
|
package/src/types.ts
CHANGED
|
@@ -380,6 +380,8 @@ export type TemplatesType<T = any, S extends StrictRJSFSchema = RJSFSchema, F ex
|
|
|
380
380
|
MoveUpButton: ComponentType<IconButtonProps<T, S, F>>;
|
|
381
381
|
/** The template to use for the Remove button used for AdditionalProperties and Array items */
|
|
382
382
|
RemoveButton: ComponentType<IconButtonProps<T, S, F>>;
|
|
383
|
+
/** The template to use for the Clear button used for input fields */
|
|
384
|
+
ClearButton: ComponentType<IconButtonProps<T, S, F>>;
|
|
383
385
|
};
|
|
384
386
|
} & {
|
|
385
387
|
/** Allow this to support any named `ComponentType` or an object of named `ComponentType`s */
|
|
@@ -401,6 +403,9 @@ export type GlobalUISchemaOptions = GenericObjectType & {
|
|
|
401
403
|
removable?: boolean;
|
|
402
404
|
/** Field labels are rendered by default. Labels may be omitted by setting the `label` option to `false` */
|
|
403
405
|
label?: boolean;
|
|
406
|
+
/** Flag, if set to `true`, will allow the text input fields to be cleared
|
|
407
|
+
*/
|
|
408
|
+
allowClearTextInputs?: boolean;
|
|
404
409
|
/** When using `additionalProperties`, key collision is prevented by appending a unique integer to the duplicate key.
|
|
405
410
|
* This option allows you to change the separator between the original key name and the integer. Default is "-"
|
|
406
411
|
*/
|
|
@@ -524,6 +529,8 @@ export type FieldTemplateProps<
|
|
|
524
529
|
S extends StrictRJSFSchema = RJSFSchema,
|
|
525
530
|
F extends FormContextType = any,
|
|
526
531
|
> = RJSFBaseProps<T, S, F> & {
|
|
532
|
+
/** The FieldPathId containing the id and path for this field */
|
|
533
|
+
fieldPathId: FieldPathId;
|
|
527
534
|
/** The id of the field in the hierarchy. You can use it to render a label targeting the wrapped widget */
|
|
528
535
|
id: string;
|
|
529
536
|
/** A string containing the base CSS classes, merged with any custom ones defined in your uiSchema */
|
|
@@ -1143,13 +1150,14 @@ export type UiSchema<
|
|
|
1143
1150
|
| ((itemData: ArrayElement<T>, index: number, formContext?: F) => UiSchema<ArrayElement<T>, S, F>);
|
|
1144
1151
|
};
|
|
1145
1152
|
|
|
1146
|
-
/** A `CustomValidator` function takes in a `formData`, `errors` and `
|
|
1153
|
+
/** A `CustomValidator` function takes in a `formData`, `errors`, `uiSchema` and `errorSchema` objects and returns the given `errors`
|
|
1147
1154
|
* object back, while potentially adding additional messages to the `errors`
|
|
1148
1155
|
*/
|
|
1149
1156
|
export type CustomValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> = (
|
|
1150
1157
|
formData: T | undefined,
|
|
1151
1158
|
errors: FormValidation<T>,
|
|
1152
1159
|
uiSchema?: UiSchema<T, S, F>,
|
|
1160
|
+
errorSchema?: ErrorSchema<T>,
|
|
1153
1161
|
) => FormValidation<T>;
|
|
1154
1162
|
|
|
1155
1163
|
/** An `ErrorTransformer` function will take in a list of `errors` & a `uiSchema` and potentially return a
|
|
@@ -1360,6 +1368,16 @@ export interface SchemaUtilsType<T = any, S extends StrictRJSFSchema = RJSFSchem
|
|
|
1360
1368
|
* @returns - True if schema contains a select, otherwise false
|
|
1361
1369
|
*/
|
|
1362
1370
|
isSelect(schema: S): boolean;
|
|
1371
|
+
/**
|
|
1372
|
+
* The function takes a `schema` and `formData` and returns a copy of the formData with any fields not defined in the schema removed.
|
|
1373
|
+
* This is useful for ensuring that only data that is relevant to the schema is preserved. Objects with `additionalProperties`
|
|
1374
|
+
* keyword set to `true` will not have their extra fields removed.
|
|
1375
|
+
*
|
|
1376
|
+
* @param schema - The schema to use for filtering the `formData`
|
|
1377
|
+
* @param [formData] - The formData to filter
|
|
1378
|
+
* @returns The new form data, with any fields not defined in the schema removed
|
|
1379
|
+
*/
|
|
1380
|
+
omitExtraData(schema: S, formData?: T): T | undefined;
|
|
1363
1381
|
/** Retrieves an expanded schema that has had all of its conditions, additional properties, references and
|
|
1364
1382
|
* dependencies resolved and merged into the `schema` given a `rawFormData` that is used to do the potentially
|
|
1365
1383
|
* recursive resolution.
|