@rjsf/utils 6.0.0-beta.2 → 6.0.0-beta.20

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.
Files changed (79) hide show
  1. package/dist/{index.js → index.cjs} +241 -205
  2. package/dist/index.cjs.map +7 -0
  3. package/dist/utils.esm.js +240 -204
  4. package/dist/utils.esm.js.map +4 -4
  5. package/dist/utils.umd.js +235 -200
  6. package/lib/canExpand.d.ts +1 -1
  7. package/lib/constants.d.ts +3 -0
  8. package/lib/constants.js +3 -0
  9. package/lib/constants.js.map +1 -1
  10. package/lib/createSchemaUtils.js +19 -14
  11. package/lib/createSchemaUtils.js.map +1 -1
  12. package/lib/enums.d.ts +3 -3
  13. package/lib/enums.js +3 -3
  14. package/lib/findSchemaDefinition.d.ts +7 -1
  15. package/lib/findSchemaDefinition.js +48 -6
  16. package/lib/findSchemaDefinition.js.map +1 -1
  17. package/lib/getTestIds.js +2 -2
  18. package/lib/getTestIds.js.map +1 -1
  19. package/lib/getUiOptions.js +4 -0
  20. package/lib/getUiOptions.js.map +1 -1
  21. package/lib/getWidget.js +3 -3
  22. package/lib/getWidget.js.map +1 -1
  23. package/lib/idGenerators.d.ts +15 -15
  24. package/lib/idGenerators.js +8 -8
  25. package/lib/idGenerators.js.map +1 -1
  26. package/lib/index.d.ts +4 -1
  27. package/lib/index.js +3 -1
  28. package/lib/index.js.map +1 -1
  29. package/lib/mergeDefaultsWithFormData.js +14 -2
  30. package/lib/mergeDefaultsWithFormData.js.map +1 -1
  31. package/lib/schema/findFieldInSchema.d.ts +1 -1
  32. package/lib/schema/findFieldInSchema.js +1 -1
  33. package/lib/schema/getDefaultFormState.d.ts +11 -2
  34. package/lib/schema/getDefaultFormState.js +59 -22
  35. package/lib/schema/getDefaultFormState.js.map +1 -1
  36. package/lib/schema/getDisplayLabel.js +2 -2
  37. package/lib/schema/getDisplayLabel.js.map +1 -1
  38. package/lib/schema/index.d.ts +1 -2
  39. package/lib/schema/index.js +1 -2
  40. package/lib/schema/index.js.map +1 -1
  41. package/lib/schema/retrieveSchema.d.ts +1 -1
  42. package/lib/schema/retrieveSchema.js +6 -6
  43. package/lib/schema/retrieveSchema.js.map +1 -1
  44. package/lib/shallowEquals.d.ts +8 -0
  45. package/lib/shallowEquals.js +36 -0
  46. package/lib/shallowEquals.js.map +1 -0
  47. package/lib/shouldRender.d.ts +8 -2
  48. package/lib/shouldRender.js +17 -2
  49. package/lib/shouldRender.js.map +1 -1
  50. package/lib/toFieldPathId.d.ts +12 -0
  51. package/lib/toFieldPathId.js +19 -0
  52. package/lib/toFieldPathId.js.map +1 -0
  53. package/lib/tsconfig.tsbuildinfo +1 -1
  54. package/lib/types.d.ts +97 -66
  55. package/package.json +13 -14
  56. package/src/constants.ts +3 -0
  57. package/src/createSchemaUtils.ts +19 -25
  58. package/src/enums.ts +3 -3
  59. package/src/findSchemaDefinition.ts +55 -6
  60. package/src/getTestIds.ts +2 -2
  61. package/src/getUiOptions.ts +4 -0
  62. package/src/getWidget.tsx +3 -3
  63. package/src/idGenerators.ts +25 -25
  64. package/src/index.ts +6 -0
  65. package/src/mergeDefaultsWithFormData.ts +16 -2
  66. package/src/schema/findFieldInSchema.ts +1 -1
  67. package/src/schema/getDefaultFormState.ts +76 -32
  68. package/src/schema/getDisplayLabel.ts +2 -2
  69. package/src/schema/index.ts +0 -2
  70. package/src/schema/retrieveSchema.ts +7 -5
  71. package/src/shallowEquals.ts +41 -0
  72. package/src/shouldRender.ts +27 -2
  73. package/src/toFieldPathId.ts +24 -0
  74. package/src/types.ts +107 -70
  75. package/dist/index.js.map +0 -7
  76. package/lib/schema/toIdSchema.d.ts +0 -14
  77. package/lib/schema/toIdSchema.js +0 -62
  78. package/lib/schema/toIdSchema.js.map +0 -1
  79. package/src/schema/toIdSchema.ts +0 -131
@@ -1,11 +1,19 @@
1
1
  import jsonpointer from 'jsonpointer';
2
2
  import omit from 'lodash/omit';
3
3
 
4
- import { ID_KEY, JSON_SCHEMA_DRAFT_2020_12, REF_KEY, SCHEMA_KEY } from './constants';
4
+ import {
5
+ ALL_OF_KEY,
6
+ ID_KEY,
7
+ JSON_SCHEMA_DRAFT_2019_09,
8
+ JSON_SCHEMA_DRAFT_2020_12,
9
+ REF_KEY,
10
+ SCHEMA_KEY,
11
+ } from './constants';
5
12
  import { GenericObjectType, RJSFSchema, StrictRJSFSchema } from './types';
6
13
  import isObject from 'lodash/isObject';
7
14
  import isEmpty from 'lodash/isEmpty';
8
15
  import UriResolver from 'fast-uri';
16
+ import get from 'lodash/get';
9
17
 
10
18
  /** Looks for the `$id` pointed by `ref` in the schema definitions embedded in
11
19
  * a JSON Schema bundle
@@ -19,7 +27,16 @@ function findEmbeddedSchemaRecursive<S extends StrictRJSFSchema = RJSFSchema>(sc
19
27
  return schema;
20
28
  }
21
29
  for (const subSchema of Object.values(schema)) {
22
- if (isObject(subSchema)) {
30
+ if (Array.isArray(subSchema)) {
31
+ for (const item of subSchema) {
32
+ if (isObject(item)) {
33
+ const result = findEmbeddedSchemaRecursive<S>(item as S, ref);
34
+ if (result !== undefined) {
35
+ return result as S;
36
+ }
37
+ }
38
+ }
39
+ } else if (isObject(subSchema)) {
23
40
  const result = findEmbeddedSchemaRecursive<S>(subSchema as S, ref);
24
41
  if (result !== undefined) {
25
42
  return result as S;
@@ -29,6 +46,31 @@ function findEmbeddedSchemaRecursive<S extends StrictRJSFSchema = RJSFSchema>(sc
29
46
  return undefined;
30
47
  }
31
48
 
49
+ /** Parses a JSONSchema and makes all references absolute with respect to
50
+ * the `baseURI` argument
51
+ * @param schema - The schema to be processed
52
+ * @param baseURI - The base URI to be used for resolving relative references
53
+ */
54
+ export function makeAllReferencesAbsolute<S extends StrictRJSFSchema = RJSFSchema>(schema: S, baseURI: string): S {
55
+ const currentURI = get(schema, ID_KEY, baseURI);
56
+ // Make all other references absolute
57
+ if (REF_KEY in schema) {
58
+ schema = { ...schema, [REF_KEY]: UriResolver.resolve(currentURI, schema[REF_KEY]!) };
59
+ }
60
+ // Look for references in nested subschemas
61
+ for (const [key, subSchema] of Object.entries(schema)) {
62
+ if (Array.isArray(subSchema)) {
63
+ schema = {
64
+ ...schema,
65
+ [key]: subSchema.map((item) => (isObject(item) ? makeAllReferencesAbsolute(item as S, currentURI) : item)),
66
+ };
67
+ } else if (isObject(subSchema)) {
68
+ schema = { ...schema, [key]: makeAllReferencesAbsolute(subSchema as S, currentURI) };
69
+ }
70
+ }
71
+ return schema;
72
+ }
73
+
32
74
  /** Splits out the value at the `key` in `object` from the `object`, returning an array that contains in the first
33
75
  * location, the `object` minus the `key: value` and in the second location the `value`.
34
76
  *
@@ -51,7 +93,7 @@ export function splitKeyElementFromObject(key: string, object: GenericObjectType
51
93
  * @param $ref - The ref string for which the schema definition is desired
52
94
  * @param [rootSchema={}] - The root schema in which to search for the definition
53
95
  * @param recurseList - List of $refs already resolved to prevent recursion
54
- * @param baseURI - The base URI to be used for resolving relative references
96
+ * @param [baseURI=rootSchema['$id']] - The base URI to be used for resolving relative references
55
97
  * @returns - The sub-schema within the `rootSchema` which matches the `$ref` if it exists
56
98
  * @throws - Error indicating that no schema for that reference could be resolved
57
99
  */
@@ -59,7 +101,7 @@ export function findSchemaDefinitionRecursive<S extends StrictRJSFSchema = RJSFS
59
101
  $ref?: string,
60
102
  rootSchema: S = {} as S,
61
103
  recurseList: string[] = [],
62
- baseURI: string | undefined = ID_KEY in rootSchema ? rootSchema[ID_KEY] : undefined,
104
+ baseURI: string | undefined = get(rootSchema, [ID_KEY]),
63
105
  ): S {
64
106
  const ref = $ref || '';
65
107
  let current: S | undefined = undefined;
@@ -102,7 +144,14 @@ export function findSchemaDefinitionRecursive<S extends StrictRJSFSchema = RJSFS
102
144
  const [remaining, theRef] = splitKeyElementFromObject(REF_KEY, current);
103
145
  const subSchema = findSchemaDefinitionRecursive<S>(theRef, rootSchema, [...recurseList, ref], baseURI);
104
146
  if (Object.keys(remaining).length > 0) {
105
- return { ...remaining, ...subSchema };
147
+ if (
148
+ rootSchema[SCHEMA_KEY] === JSON_SCHEMA_DRAFT_2019_09 ||
149
+ rootSchema[SCHEMA_KEY] === JSON_SCHEMA_DRAFT_2020_12
150
+ ) {
151
+ return { [ALL_OF_KEY]: [remaining, subSchema] } as S;
152
+ } else {
153
+ return { ...remaining, ...subSchema };
154
+ }
106
155
  }
107
156
  return subSchema;
108
157
  }
@@ -123,7 +172,7 @@ export function findSchemaDefinitionRecursive<S extends StrictRJSFSchema = RJSFS
123
172
  export default function findSchemaDefinition<S extends StrictRJSFSchema = RJSFSchema>(
124
173
  $ref?: string,
125
174
  rootSchema: S = {} as S,
126
- baseURI: string | undefined = ID_KEY in rootSchema ? rootSchema[ID_KEY] : undefined,
175
+ baseURI: string | undefined = get(rootSchema, [ID_KEY]),
127
176
  ): S {
128
177
  const recurseList: string[] = [];
129
178
  return findSchemaDefinitionRecursive($ref, rootSchema, recurseList, baseURI);
package/src/getTestIds.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { nanoid } from 'nanoid';
2
1
  import get from 'lodash/get';
2
+ import uniqueId from 'lodash/uniqueId';
3
3
 
4
4
  import { TestIdShape } from './types';
5
5
 
@@ -31,7 +31,7 @@ export default function getTestIds(): TestIdShape {
31
31
  {
32
32
  get(_obj, prop) {
33
33
  if (!ids.has(prop)) {
34
- ids.set(prop, nanoid());
34
+ ids.set(prop, uniqueId('test-id-'));
35
35
  }
36
36
  return ids.get(prop);
37
37
  },
@@ -13,6 +13,10 @@ export default function getUiOptions<T = any, S extends StrictRJSFSchema = RJSFS
13
13
  uiSchema: UiSchema<T, S, F> = {},
14
14
  globalOptions: GlobalUISchemaOptions = {},
15
15
  ): UIOptionsType<T, S, F> {
16
+ // Handle null or undefined uiSchema
17
+ if (!uiSchema) {
18
+ return { ...globalOptions };
19
+ }
16
20
  return Object.keys(uiSchema)
17
21
  .filter((key) => key.indexOf('ui:') === 0)
18
22
  .reduce(
package/src/getWidget.tsx CHANGED
@@ -110,7 +110,7 @@ export default function getWidget<T = any, S extends StrictRJSFSchema = RJSFSche
110
110
  }
111
111
 
112
112
  if (typeof widget !== 'string') {
113
- throw new Error(`Unsupported widget definition: ${typeof widget}`);
113
+ throw new Error(`Unsupported widget definition: ${typeof widget} in schema: ${JSON.stringify(schema)}`);
114
114
  }
115
115
 
116
116
  if (widget in registeredWidgets) {
@@ -120,7 +120,7 @@ export default function getWidget<T = any, S extends StrictRJSFSchema = RJSFSche
120
120
 
121
121
  if (typeof type === 'string') {
122
122
  if (!(type in widgetMap)) {
123
- throw new Error(`No widget for type '${type}'`);
123
+ throw new Error(`No widget for type '${type}' in schema: ${JSON.stringify(schema)}`);
124
124
  }
125
125
 
126
126
  if (widget in widgetMap[type]) {
@@ -129,5 +129,5 @@ export default function getWidget<T = any, S extends StrictRJSFSchema = RJSFSche
129
129
  }
130
130
  }
131
131
 
132
- throw new Error(`No widget '${widget}' for type '${type}'`);
132
+ throw new Error(`No widget '${widget}' for type '${type}' in schema: ${JSON.stringify(schema)}`);
133
133
  }
@@ -1,73 +1,73 @@
1
1
  import isString from 'lodash/isString';
2
2
 
3
- import { IdSchema } from './types';
3
+ import { FieldPathId } from './types';
4
4
  import { ID_KEY } from './constants';
5
5
 
6
6
  /** Generates a consistent `id` pattern for a given `id` and a `suffix`
7
7
  *
8
- * @param id - Either simple string id or an IdSchema from which to extract it
8
+ * @param id - Either simple string id or an FieldPathId from which to extract it
9
9
  * @param suffix - The suffix to append to the id
10
10
  */
11
- function idGenerator<T = any>(id: IdSchema<T> | string, suffix: string) {
11
+ function idGenerator(id: FieldPathId | string, suffix: string) {
12
12
  const theId = isString(id) ? id : id[ID_KEY];
13
13
  return `${theId}__${suffix}`;
14
14
  }
15
15
  /** Return a consistent `id` for the field description element
16
16
  *
17
- * @param id - Either simple string id or an IdSchema from which to extract it
17
+ * @param id - Either simple string id or an FieldPathId from which to extract it
18
18
  * @returns - The consistent id for the field description element from the given `id`
19
19
  */
20
- export function descriptionId<T = any>(id: IdSchema<T> | string) {
21
- return idGenerator<T>(id, 'description');
20
+ export function descriptionId(id: FieldPathId | string) {
21
+ return idGenerator(id, 'description');
22
22
  }
23
23
 
24
24
  /** Return a consistent `id` for the field error element
25
25
  *
26
- * @param id - Either simple string id or an IdSchema from which to extract it
26
+ * @param id - Either simple string id or an FieldPathId from which to extract it
27
27
  * @returns - The consistent id for the field error element from the given `id`
28
28
  */
29
- export function errorId<T = any>(id: IdSchema<T> | string) {
30
- return idGenerator<T>(id, 'error');
29
+ export function errorId(id: FieldPathId | string) {
30
+ return idGenerator(id, 'error');
31
31
  }
32
32
 
33
33
  /** Return a consistent `id` for the field examples element
34
34
  *
35
- * @param id - Either simple string id or an IdSchema from which to extract it
35
+ * @param id - Either simple string id or an FieldPathId from which to extract it
36
36
  * @returns - The consistent id for the field examples element from the given `id`
37
37
  */
38
- export function examplesId<T = any>(id: IdSchema<T> | string) {
39
- return idGenerator<T>(id, 'examples');
38
+ export function examplesId(id: FieldPathId | string) {
39
+ return idGenerator(id, 'examples');
40
40
  }
41
41
 
42
42
  /** Return a consistent `id` for the field help element
43
43
  *
44
- * @param id - Either simple string id or an IdSchema from which to extract it
44
+ * @param id - Either simple string id or an FieldPathId from which to extract it
45
45
  * @returns - The consistent id for the field help element from the given `id`
46
46
  */
47
- export function helpId<T = any>(id: IdSchema<T> | string) {
48
- return idGenerator<T>(id, 'help');
47
+ export function helpId(id: FieldPathId | string) {
48
+ return idGenerator(id, 'help');
49
49
  }
50
50
 
51
51
  /** Return a consistent `id` for the field title element
52
52
  *
53
- * @param id - Either simple string id or an IdSchema from which to extract it
53
+ * @param id - Either simple string id or an FieldPathId from which to extract it
54
54
  * @returns - The consistent id for the field title element from the given `id`
55
55
  */
56
- export function titleId<T = any>(id: IdSchema<T> | string) {
57
- return idGenerator<T>(id, 'title');
56
+ export function titleId(id: FieldPathId | string) {
57
+ return idGenerator(id, 'title');
58
58
  }
59
59
 
60
60
  /** Return a list of element ids that contain additional information about the field that can be used to as the aria
61
61
  * description of the field. This is correctly omitting `titleId` which would be "labeling" rather than "describing" the
62
62
  * element.
63
63
  *
64
- * @param id - Either simple string id or an IdSchema from which to extract it
64
+ * @param id - Either simple string id or an FieldPathId from which to extract it
65
65
  * @param [includeExamples=false] - Optional flag, if true, will add the `examplesId` into the list
66
66
  * @returns - The string containing the list of ids for use in an `aria-describedBy` attribute
67
67
  */
68
- export function ariaDescribedByIds<T = any>(id: IdSchema<T> | string, includeExamples = false) {
69
- const examples = includeExamples ? ` ${examplesId<T>(id)}` : '';
70
- return `${errorId<T>(id)} ${descriptionId<T>(id)} ${helpId<T>(id)}${examples}`;
68
+ export function ariaDescribedByIds(id: FieldPathId | string, includeExamples = false) {
69
+ const examples = includeExamples ? ` ${examplesId(id)}` : '';
70
+ return `${errorId(id)} ${descriptionId(id)} ${helpId(id)}${examples}`;
71
71
  }
72
72
 
73
73
  /** Return a consistent `id` for the `optionIndex`s of a `Radio` or `Checkboxes` widget
@@ -82,10 +82,10 @@ export function optionId(id: string, optionIndex: number) {
82
82
 
83
83
  /** Return a consistent `id` for the `btn` button element
84
84
  *
85
- * @param id - Either simple string id or an IdSchema from which to extract it
85
+ * @param id - Either simple string id or an FieldPathId from which to extract it
86
86
  * @param btn - The button type for which to generate the id
87
87
  * @returns - The consistent id for the button from the given `id` and `btn` type
88
88
  */
89
- export function buttonId<T = any>(id: IdSchema<T> | string, btn: 'add' | 'copy' | 'moveDown' | 'moveUp' | 'remove') {
90
- return idGenerator<T>(id, btn);
89
+ export function buttonId(id: FieldPathId | string, btn: 'add' | 'copy' | 'moveDown' | 'moveUp' | 'remove') {
90
+ return idGenerator(id, btn);
91
91
  }
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ import createSchemaUtils from './createSchemaUtils';
6
6
  import dataURItoBlob from './dataURItoBlob';
7
7
  import dateRangeOptions from './dateRangeOptions';
8
8
  import deepEquals from './deepEquals';
9
+ import shallowEquals from './shallowEquals';
9
10
  import englishStringTranslator from './englishStringTranslator';
10
11
  import enumOptionsDeselectValue from './enumOptionsDeselectValue';
11
12
  import enumOptionsIndexForValue from './enumOptionsIndexForValue';
@@ -58,6 +59,7 @@ import toConstant from './toConstant';
58
59
  import toDateString from './toDateString';
59
60
  import toErrorList from './toErrorList';
60
61
  import toErrorSchema from './toErrorSchema';
62
+ import toFieldPathId from './toFieldPathId';
61
63
  import unwrapErrorHandler from './unwrapErrorHandler';
62
64
  import utcToLocal from './utcToLocal';
63
65
  import validationDataMerge from './validationDataMerge';
@@ -130,6 +132,7 @@ export {
130
132
  rangeSpec,
131
133
  replaceStringParameters,
132
134
  schemaRequiresTrueValue,
135
+ shallowEquals,
133
136
  shouldRender,
134
137
  sortedJSONStringify,
135
138
  titleId,
@@ -137,8 +140,11 @@ export {
137
140
  toDateString,
138
141
  toErrorList,
139
142
  toErrorSchema,
143
+ toFieldPathId,
140
144
  unwrapErrorHandler,
141
145
  utcToLocal,
142
146
  validationDataMerge,
143
147
  withIdRefPrefix,
144
148
  };
149
+
150
+ export type { ComponentUpdateStrategy } from './shouldRender';
@@ -67,8 +67,22 @@ export default function mergeDefaultsWithFormData<T = any>(
67
67
  const keyValue = get(formData, key);
68
68
  const keyExistsInDefaults = isObject(defaults) && key in (defaults as GenericObjectType);
69
69
  const keyExistsInFormData = key in (formData as GenericObjectType);
70
+ const keyDefault = get(defaults, key) ?? {};
71
+ const defaultValueIsNestedObject = keyExistsInDefaults && Object.entries(keyDefault).some(([, v]) => isObject(v));
72
+
73
+ const keyDefaultIsObject = keyExistsInDefaults && isObject(get(defaults, key));
74
+ const keyHasFormDataObject = keyExistsInFormData && isObject(keyValue);
75
+
76
+ if (keyDefaultIsObject && keyHasFormDataObject && !defaultValueIsNestedObject) {
77
+ acc[key as keyof T] = {
78
+ ...get(defaults, key),
79
+ ...keyValue,
80
+ };
81
+ return acc;
82
+ }
83
+
70
84
  acc[key as keyof T] = mergeDefaultsWithFormData<T>(
71
- defaults ? get(defaults, key) : {},
85
+ get(defaults, key),
72
86
  keyValue,
73
87
  mergeExtraArrayDefaults,
74
88
  defaultSupercedesUndefined,
@@ -88,7 +102,7 @@ export default function mergeDefaultsWithFormData<T = any>(
88
102
  */
89
103
  if (
90
104
  (defaultSupercedesUndefined &&
91
- ((!isNil(defaults) && isNil(formData)) || (typeof formData === 'number' && isNaN(formData)))) ||
105
+ ((!(defaults === undefined) && isNil(formData)) || (typeof formData === 'number' && isNaN(formData)))) ||
92
106
  (overrideFormDataWithDefaults && !isNil(formData))
93
107
  ) {
94
108
  return defaults;
@@ -22,7 +22,7 @@ export const NOT_FOUND_SCHEMA = { title: '!@#$_UNKNOWN_$#@!' };
22
22
  *
23
23
  * @param validator - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
24
24
  * @param rootSchema - The root schema that will be forwarded to all the APIs
25
- // * @param schema - The node within the JSON schema in which to search
25
+ * @param schema - The node within the JSON schema in which to search
26
26
  * @param path - The keys in the path to the desired field
27
27
  * @param [formData={}] - The form data that is used to determine which anyOf/oneOf option to descend
28
28
  * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
@@ -84,6 +84,24 @@ export function getInnerSchemaForArrayItem<S extends StrictRJSFSchema = RJSFSche
84
84
  return {} as S;
85
85
  }
86
86
 
87
+ /** Checks if the given `schema` contains the `null` type along with another type AND if the `default` contained within
88
+ * the schema is `null` AND the `computedDefault` is empty. If all of those conditions are true, then the `schema`'s
89
+ * default should be `null` rather than `computedDefault`.
90
+ *
91
+ * @param schema - The schema to inspect
92
+ * @param computedDefault - The computed default for the schema
93
+ * @returns - Flag indicating whether a null should be returned instead of the computedDefault
94
+ */
95
+ export function computeDefaultBasedOnSchemaTypeAndDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema>(
96
+ schema: S,
97
+ computedDefault: T,
98
+ ) {
99
+ const { default: schemaDefault, type } = schema;
100
+ const shouldReturnNullAsDefault =
101
+ Array.isArray(type) && type.includes('null') && isEmpty(computedDefault) && schemaDefault === null;
102
+ return shouldReturnNullAsDefault ? (null as T) : computedDefault;
103
+ }
104
+
87
105
  /** Either add `computedDefault` at `key` into `obj` or not add it based on its value, the value of
88
106
  * `includeUndefinedValues`, the value of `emptyObjectFields` and if its parent field is required. Generally undefined
89
107
  * `computedDefault` values are added only when `includeUndefinedValues` is either true/"excludeObjectChildren". If `
@@ -115,10 +133,18 @@ function maybeAddDefaultToObject<T = any>(
115
133
  isConst = false,
116
134
  ) {
117
135
  const { emptyObjectFields = 'populateAllDefaults' } = experimental_defaultFormStateBehavior;
118
- if (includeUndefinedValues || isConst) {
119
- // If includeUndefinedValues
136
+
137
+ if (includeUndefinedValues === true || isConst) {
138
+ // If includeUndefinedValues is explicitly true
120
139
  // Or if the schema has a const property defined, then we should always return the computedDefault since it's coming from the const.
121
140
  obj[key] = computedDefault;
141
+ } else if (includeUndefinedValues === 'excludeObjectChildren') {
142
+ // Fix for Issue #4709: When in 'excludeObjectChildren' mode, don't set primitive fields to empty objects
143
+ // Only add the computed default if it's not an empty object placeholder for a primitive field
144
+ if (!isObject(computedDefault) || !isEmpty(computedDefault)) {
145
+ obj[key] = computedDefault;
146
+ }
147
+ // If computedDefault is an empty object {}, don't add it - let the field stay undefined
122
148
  } else if (emptyObjectFields !== 'skipDefaults') {
123
149
  // If isParentRequired is undefined, then we are at the root level of the schema so defer to the requiredness of
124
150
  // the field key itself in the `requiredField` list
@@ -204,7 +230,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
204
230
  required,
205
231
  shouldMergeDefaultsIntoFormData = false,
206
232
  } = computeDefaultsProps;
207
- const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
233
+ let formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
208
234
  const schema: S = isObject(rawSchema) ? rawSchema : ({} as S);
209
235
  // Compute the defaults recursively: give highest priority to deepest nodes.
210
236
  let defaults: T | T[] | undefined = parentDefaults;
@@ -212,9 +238,8 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
212
238
  let schemaToCompute: S | null = null;
213
239
  let experimental_dfsb_to_compute = experimental_defaultFormStateBehavior;
214
240
  let updatedRecurseList = _recurseList;
215
-
216
241
  if (
217
- schema[CONST_KEY] &&
242
+ schema[CONST_KEY] !== undefined &&
218
243
  experimental_defaultFormStateBehavior?.constAsDefaults !== 'never' &&
219
244
  !constIsAjvDataReference(schema)
220
245
  ) {
@@ -240,6 +265,13 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
240
265
  if (schemaToCompute && !defaults) {
241
266
  defaults = schema.default as T | undefined;
242
267
  }
268
+
269
+ // If shouldMergeDefaultsIntoFormData is true
270
+ // And the schemaToCompute is set and the rawFormData is not an object
271
+ // Then set the formData to the rawFormData
272
+ if (shouldMergeDefaultsIntoFormData && schemaToCompute && !isObject(rawFormData)) {
273
+ formData = rawFormData as T;
274
+ }
243
275
  } else if (DEPENDENCIES_KEY in schema) {
244
276
  // Get the default if set from properties to ensure the dependencies conditions are resolved based on it
245
277
  const defaultFormData: T = {
@@ -328,7 +360,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
328
360
  experimental_defaultFormStateBehavior: experimental_dfsb_to_compute,
329
361
  experimental_customMergeAllOf,
330
362
  parentDefaults: defaults as T | undefined,
331
- rawFormData: formData as T,
363
+ rawFormData: (rawFormData ?? formData) as T,
332
364
  required,
333
365
  shouldMergeDefaultsIntoFormData,
334
366
  });
@@ -432,7 +464,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
432
464
  required,
433
465
  shouldMergeDefaultsIntoFormData,
434
466
  }: ComputeDefaultsProps<T, S> = {},
435
- defaults?: T | T[] | undefined,
467
+ defaults?: T | T[],
436
468
  ): T {
437
469
  {
438
470
  const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
@@ -467,6 +499,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
467
499
  required: retrievedSchema.required?.includes(key),
468
500
  shouldMergeDefaultsIntoFormData,
469
501
  });
502
+
470
503
  maybeAddDefaultToObject<T>(
471
504
  acc,
472
505
  key,
@@ -477,6 +510,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
477
510
  experimental_defaultFormStateBehavior,
478
511
  hasConst,
479
512
  );
513
+
480
514
  return acc;
481
515
  },
482
516
  {},
@@ -523,7 +557,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
523
557
  );
524
558
  });
525
559
  }
526
- return objectDefaults;
560
+ return computeDefaultBasedOnSchemaTypeAndDefaults<T, S>(rawSchema, objectDefaults);
527
561
  }
528
562
  }
529
563
 
@@ -547,8 +581,8 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
547
581
  required,
548
582
  shouldMergeDefaultsIntoFormData,
549
583
  }: ComputeDefaultsProps<T, S> = {},
550
- defaults?: T | T[] | undefined,
551
- ): T | T[] | undefined {
584
+ defaults?: T[],
585
+ ): T[] | undefined {
552
586
  const schema: S = rawSchema;
553
587
 
554
588
  const arrayMinItemsStateBehavior = experimental_defaultFormStateBehavior?.arrayMinItems ?? {};
@@ -560,7 +594,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
560
594
  const computeSkipPopulate = arrayMinItemsStateBehavior?.computeSkipPopulate ?? (() => false);
561
595
  const isSkipEmptyDefaults = experimental_defaultFormStateBehavior?.emptyObjectFields === 'skipEmptyDefaults';
562
596
 
563
- const emptyDefault = isSkipEmptyDefaults ? undefined : [];
597
+ const emptyDefault: T[] | undefined = isSkipEmptyDefaults ? undefined : [];
564
598
 
565
599
  // Inject defaults into existing array defaults
566
600
  if (Array.isArray(defaults)) {
@@ -582,7 +616,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
582
616
  if (Array.isArray(rawFormData)) {
583
617
  const schemaItem: S = getInnerSchemaForArrayItem<S>(schema);
584
618
  if (neverPopulate) {
585
- defaults = rawFormData;
619
+ defaults = rawFormData as typeof defaults;
586
620
  } else {
587
621
  const itemDefaults = rawFormData.map((item: T, idx: number) => {
588
622
  return computeDefaults<T, S, F>(validator, schemaItem, {
@@ -619,6 +653,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
619
653
  }
620
654
  }
621
655
 
656
+ let arrayDefault: T[] | undefined;
622
657
  const defaultsLength = Array.isArray(defaults) ? defaults.length : 0;
623
658
  if (
624
659
  !schema.minItems ||
@@ -626,27 +661,29 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
626
661
  computeSkipPopulate<T, S, F>(validator, schema, rootSchema) ||
627
662
  schema.minItems <= defaultsLength
628
663
  ) {
629
- return defaults ? defaults : emptyDefault;
664
+ arrayDefault = defaults ? defaults : emptyDefault;
665
+ } else {
666
+ const defaultEntries: T[] = (defaults || []) as T[];
667
+ const fillerSchema: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Invert);
668
+ const fillerDefault = fillerSchema.default;
669
+
670
+ // Calculate filler entries for remaining items (minItems - existing raw data/defaults)
671
+ const fillerEntries: T[] = Array.from({ length: schema.minItems - defaultsLength }, () =>
672
+ computeDefaults<any, S, F>(validator, fillerSchema, {
673
+ parentDefaults: fillerDefault,
674
+ rootSchema,
675
+ _recurseList,
676
+ experimental_defaultFormStateBehavior,
677
+ experimental_customMergeAllOf,
678
+ required,
679
+ shouldMergeDefaultsIntoFormData,
680
+ }),
681
+ ) as T[];
682
+ // then fill up the rest with either the item default or empty, up to minItems
683
+ arrayDefault = defaultEntries.concat(fillerEntries);
630
684
  }
631
685
 
632
- const defaultEntries: T[] = (defaults || []) as T[];
633
- const fillerSchema: S = getInnerSchemaForArrayItem<S>(schema, AdditionalItemsHandling.Invert);
634
- const fillerDefault = fillerSchema.default;
635
-
636
- // Calculate filler entries for remaining items (minItems - existing raw data/defaults)
637
- const fillerEntries: T[] = new Array(schema.minItems - defaultsLength).fill(
638
- computeDefaults<any, S, F>(validator, fillerSchema, {
639
- parentDefaults: fillerDefault,
640
- rootSchema,
641
- _recurseList,
642
- experimental_defaultFormStateBehavior,
643
- experimental_customMergeAllOf,
644
- required,
645
- shouldMergeDefaultsIntoFormData,
646
- }),
647
- ) as T[];
648
- // then fill up the rest with either the item default or empty, up to minItems
649
- return defaultEntries.concat(fillerEntries);
686
+ return computeDefaultBasedOnSchemaTypeAndDefaults<T[] | undefined, S>(rawSchema, arrayDefault);
650
687
  }
651
688
 
652
689
  /** Computes the default value based on the schema type.
@@ -673,7 +710,7 @@ export function getDefaultBasedOnSchemaType<
673
710
  return getObjectDefaults(validator, rawSchema, computeDefaultsProps, defaults);
674
711
  }
675
712
  case 'array': {
676
- return getArrayDefaults(validator, rawSchema, computeDefaultsProps, defaults);
713
+ return getArrayDefaults(validator, rawSchema, computeDefaultsProps, defaults as T[]);
677
714
  }
678
715
  }
679
716
  }
@@ -722,6 +759,13 @@ export default function getDefaultFormState<
722
759
  shouldMergeDefaultsIntoFormData: true,
723
760
  });
724
761
 
762
+ if (schema.type !== 'object' && isObject(schema.default)) {
763
+ return {
764
+ ...defaults,
765
+ ...formData,
766
+ } as T;
767
+ }
768
+
725
769
  // If the formData is an object or an array, add additional properties from formData and override formData with
726
770
  // defaults since the defaults are already merged with formData.
727
771
  if (isObject(formData) || Array.isArray(formData)) {
@@ -52,10 +52,10 @@ export default function getDisplayLabel<
52
52
  if (schemaType === 'object') {
53
53
  displayLabel = false;
54
54
  }
55
- if (schemaType === 'boolean' && !uiSchema[UI_WIDGET_KEY]) {
55
+ if (schemaType === 'boolean' && uiSchema && !uiSchema[UI_WIDGET_KEY]) {
56
56
  displayLabel = false;
57
57
  }
58
- if (uiSchema[UI_FIELD_KEY]) {
58
+ if (uiSchema && uiSchema[UI_FIELD_KEY]) {
59
59
  displayLabel = false;
60
60
  }
61
61
  return displayLabel;
@@ -10,7 +10,6 @@ import isMultiSelect from './isMultiSelect';
10
10
  import isSelect from './isSelect';
11
11
  import retrieveSchema from './retrieveSchema';
12
12
  import sanitizeDataForNewSchema from './sanitizeDataForNewSchema';
13
- import toIdSchema from './toIdSchema';
14
13
  import toPathSchema from './toPathSchema';
15
14
 
16
15
  export {
@@ -26,6 +25,5 @@ export {
26
25
  isSelect,
27
26
  retrieveSchema,
28
27
  sanitizeDataForNewSchema,
29
- toIdSchema,
30
28
  toPathSchema,
31
29
  };
@@ -241,6 +241,7 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
241
241
  expandAllBranches,
242
242
  recurseList,
243
243
  formData,
244
+ experimental_customMergeAllOf,
244
245
  );
245
246
  if (updatedSchemas.length > 1 || updatedSchemas[0] !== schema) {
246
247
  // return the updatedSchemas array if it has either multiple schemas within it
@@ -255,6 +256,7 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
255
256
  expandAllBranches,
256
257
  recurseList,
257
258
  formData,
259
+ experimental_customMergeAllOf,
258
260
  );
259
261
  return resolvedSchemas.flatMap((s) => {
260
262
  return retrieveSchemaInternal<T, S, F>(
@@ -334,7 +336,7 @@ export function resolveReference<T = any, S extends StrictRJSFSchema = RJSFSchem
334
336
  * @param schema - The schema for which resolving all references is desired
335
337
  * @param rootSchema - The root schema that will be forwarded to all the APIs
336
338
  * @param recurseList - List of $refs already resolved to prevent recursion
337
- * @param baseURI - The base URI to be used for resolving relative references
339
+ * @param [baseURI] - The base URI to be used for resolving relative references
338
340
  * @returns - given schema will all references resolved or the original schema if no internal `$refs` were resolved
339
341
  */
340
342
  export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
@@ -430,9 +432,9 @@ export function stubExistingAdditionalProperties<
430
432
  if (!isEmpty(matchingProperties)) {
431
433
  schema.properties[key] = retrieveSchema<T, S, F>(
432
434
  validator,
433
- { allOf: Object.values(matchingProperties) } as S,
435
+ { [ALL_OF_KEY]: Object.values(matchingProperties) } as S,
434
436
  rootSchema,
435
- formData as T,
437
+ get(formData, [key]) as T,
436
438
  experimental_customMergeAllOf,
437
439
  );
438
440
  set(schema.properties, [key, ADDITIONAL_PROPERTY_FLAG], true);
@@ -445,7 +447,7 @@ export function stubExistingAdditionalProperties<
445
447
  if (REF_KEY in schema.additionalProperties!) {
446
448
  additionalProperties = retrieveSchema<T, S, F>(
447
449
  validator,
448
- { $ref: get(schema.additionalProperties, [REF_KEY]) } as S,
450
+ { [REF_KEY]: get(schema.additionalProperties, [REF_KEY]) } as S,
449
451
  rootSchema,
450
452
  formData as T,
451
453
  experimental_customMergeAllOf,
@@ -578,7 +580,7 @@ export function retrieveSchemaInternal<
578
580
  validator,
579
581
  { allOf: [schema.properties[key], ...Object.values(matchingProperties)] } as S,
580
582
  rootSchema,
581
- rawFormData as T,
583
+ get(rawFormData, [key]) as T,
582
584
  experimental_customMergeAllOf,
583
585
  );
584
586
  }