@rjsf/utils 5.24.10 → 6.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/dist/index.js +605 -330
  2. package/dist/index.js.map +4 -4
  3. package/dist/utils.esm.js +575 -300
  4. package/dist/utils.esm.js.map +4 -4
  5. package/dist/utils.umd.js +519 -268
  6. package/lib/ErrorSchemaBuilder.d.ts +7 -3
  7. package/lib/ErrorSchemaBuilder.js +1 -0
  8. package/lib/ErrorSchemaBuilder.js.map +1 -1
  9. package/lib/allowAdditionalItems.js.map +1 -1
  10. package/lib/asNumber.js.map +1 -1
  11. package/lib/canExpand.js +1 -1
  12. package/lib/canExpand.js.map +1 -1
  13. package/lib/constants.d.ts +11 -3
  14. package/lib/constants.js +11 -3
  15. package/lib/constants.js.map +1 -1
  16. package/lib/createErrorHandler.js.map +1 -1
  17. package/lib/createSchemaUtils.js +31 -27
  18. package/lib/createSchemaUtils.js.map +1 -1
  19. package/lib/dataURItoBlob.js.map +1 -1
  20. package/lib/dateRangeOptions.js.map +1 -1
  21. package/lib/deepEquals.js.map +1 -1
  22. package/lib/enumOptionsDeselectValue.js.map +1 -1
  23. package/lib/enumOptionsIndexForValue.js.map +1 -1
  24. package/lib/enumOptionsIsSelected.js.map +1 -1
  25. package/lib/enumOptionsSelectValue.js.map +1 -1
  26. package/lib/enumOptionsValueForIndex.js.map +1 -1
  27. package/lib/enums.d.ts +2 -0
  28. package/lib/enums.js +2 -0
  29. package/lib/enums.js.map +1 -1
  30. package/lib/findSchemaDefinition.js.map +1 -1
  31. package/lib/getChangedFields.js.map +1 -1
  32. package/lib/getDateElementProps.js.map +1 -1
  33. package/lib/getDiscriminatorFieldFromSchema.js +2 -1
  34. package/lib/getDiscriminatorFieldFromSchema.js.map +1 -1
  35. package/lib/getInputProps.js.map +1 -1
  36. package/lib/getOptionMatchingSimpleDiscriminator.js.map +1 -1
  37. package/lib/getSchemaType.d.ts +1 -0
  38. package/lib/getSchemaType.js +2 -1
  39. package/lib/getSchemaType.js.map +1 -1
  40. package/lib/getSubmitButtonOptions.js.map +1 -1
  41. package/lib/getTemplate.js +9 -0
  42. package/lib/getTemplate.js.map +1 -1
  43. package/lib/getTestIds.d.ts +17 -0
  44. package/lib/getTestIds.js +34 -0
  45. package/lib/getTestIds.js.map +1 -0
  46. package/lib/getUiOptions.js.map +1 -1
  47. package/lib/getWidget.js.map +1 -1
  48. package/lib/guessType.d.ts +1 -1
  49. package/lib/guessType.js.map +1 -1
  50. package/lib/hasWidget.js.map +1 -1
  51. package/lib/hashForSchema.d.ts +22 -0
  52. package/lib/hashForSchema.js +24 -6
  53. package/lib/hashForSchema.js.map +1 -1
  54. package/lib/idGenerators.d.ts +7 -0
  55. package/lib/idGenerators.js +9 -0
  56. package/lib/idGenerators.js.map +1 -1
  57. package/lib/index.d.ts +5 -3
  58. package/lib/index.js +5 -3
  59. package/lib/index.js.map +1 -1
  60. package/lib/isObject.d.ts +1 -1
  61. package/lib/isObject.js.map +1 -1
  62. package/lib/lookupFromFormContext.d.ts +11 -0
  63. package/lib/lookupFromFormContext.js +20 -0
  64. package/lib/lookupFromFormContext.js.map +1 -0
  65. package/lib/mergeDefaultsWithFormData.js.map +1 -1
  66. package/lib/mergeObjects.js.map +1 -1
  67. package/lib/mergeSchemas.js.map +1 -1
  68. package/lib/optionsList.d.ts +8 -6
  69. package/lib/optionsList.js +29 -18
  70. package/lib/optionsList.js.map +1 -1
  71. package/lib/orderProperties.js.map +1 -1
  72. package/lib/pad.js.map +1 -1
  73. package/lib/parseDateString.js +1 -1
  74. package/lib/parseDateString.js.map +1 -1
  75. package/lib/parser/ParserValidator.js.map +1 -1
  76. package/lib/parser/schemaParser.js.map +1 -1
  77. package/lib/rangeSpec.js.map +1 -1
  78. package/lib/replaceStringParameters.js.map +1 -1
  79. package/lib/schema/findFieldInSchema.d.ts +19 -0
  80. package/lib/schema/findFieldInSchema.js +61 -0
  81. package/lib/schema/findFieldInSchema.js.map +1 -0
  82. package/lib/schema/findSelectedOptionInXxxOf.d.ts +16 -0
  83. package/lib/schema/findSelectedOptionInXxxOf.js +34 -0
  84. package/lib/schema/findSelectedOptionInXxxOf.js.map +1 -0
  85. package/lib/schema/getClosestMatchingOption.js.map +1 -1
  86. package/lib/schema/getDefaultFormState.js +2 -3
  87. package/lib/schema/getDefaultFormState.js.map +1 -1
  88. package/lib/schema/getDisplayLabel.js.map +1 -1
  89. package/lib/schema/getFirstMatchingOption.js +70 -2
  90. package/lib/schema/getFirstMatchingOption.js.map +1 -1
  91. package/lib/schema/getFromSchema.d.ts +14 -0
  92. package/lib/schema/getFromSchema.js +39 -0
  93. package/lib/schema/getFromSchema.js.map +1 -0
  94. package/lib/schema/index.d.ts +4 -3
  95. package/lib/schema/index.js +4 -3
  96. package/lib/schema/index.js.map +1 -1
  97. package/lib/schema/isFilesArray.js.map +1 -1
  98. package/lib/schema/isMultiSelect.js.map +1 -1
  99. package/lib/schema/isSelect.js.map +1 -1
  100. package/lib/schema/retrieveSchema.d.ts +7 -0
  101. package/lib/schema/retrieveSchema.js +65 -21
  102. package/lib/schema/retrieveSchema.js.map +1 -1
  103. package/lib/schema/sanitizeDataForNewSchema.js.map +1 -1
  104. package/lib/schema/toIdSchema.js +20 -19
  105. package/lib/schema/toIdSchema.js.map +1 -1
  106. package/lib/schema/toPathSchema.js +1 -1
  107. package/lib/schema/toPathSchema.js.map +1 -1
  108. package/lib/schemaRequiresTrueValue.js.map +1 -1
  109. package/lib/toConstant.js.map +1 -1
  110. package/lib/toErrorList.js.map +1 -1
  111. package/lib/toErrorSchema.js.map +1 -1
  112. package/lib/tsconfig.tsbuildinfo +1 -1
  113. package/lib/types.d.ts +127 -128
  114. package/lib/unwrapErrorHandler.js.map +1 -1
  115. package/lib/utcToLocal.js.map +1 -1
  116. package/lib/validationDataMerge.js.map +1 -1
  117. package/lib/withIdRefPrefix.js.map +1 -1
  118. package/package.json +35 -25
  119. package/src/ErrorSchemaBuilder.ts +10 -4
  120. package/src/canExpand.ts +2 -2
  121. package/src/constants.ts +12 -3
  122. package/src/createSchemaUtils.ts +79 -43
  123. package/src/dataURItoBlob.ts +1 -1
  124. package/src/dateRangeOptions.ts +1 -1
  125. package/src/enumOptionsDeselectValue.ts +1 -1
  126. package/src/enumOptionsIndexForValue.ts +1 -1
  127. package/src/enumOptionsIsSelected.ts +1 -1
  128. package/src/enumOptionsSelectValue.ts +1 -1
  129. package/src/enumOptionsValueForIndex.ts +1 -1
  130. package/src/enums.ts +2 -0
  131. package/src/findSchemaDefinition.ts +2 -2
  132. package/src/getDateElementProps.ts +2 -2
  133. package/src/getDiscriminatorFieldFromSchema.ts +2 -1
  134. package/src/getInputProps.ts +2 -2
  135. package/src/getOptionMatchingSimpleDiscriminator.ts +2 -2
  136. package/src/getSchemaType.ts +3 -2
  137. package/src/getSubmitButtonOptions.ts +1 -1
  138. package/src/getTemplate.ts +12 -1
  139. package/src/getTestIds.ts +40 -0
  140. package/src/getUiOptions.ts +2 -2
  141. package/src/getWidget.tsx +2 -2
  142. package/src/hasWidget.ts +1 -1
  143. package/src/hashForSchema.ts +26 -6
  144. package/src/idGenerators.ts +10 -0
  145. package/src/index.ts +19 -2
  146. package/src/isCustomWidget.ts +1 -1
  147. package/src/isObject.ts +1 -1
  148. package/src/labelValue.ts +2 -2
  149. package/src/lookupFromFormContext.ts +26 -0
  150. package/src/mergeDefaultsWithFormData.ts +3 -3
  151. package/src/mergeObjects.ts +24 -21
  152. package/src/optionsList.ts +31 -22
  153. package/src/parser/ParserValidator.ts +2 -2
  154. package/src/parser/schemaParser.ts +2 -2
  155. package/src/schema/findFieldInSchema.ts +138 -0
  156. package/src/schema/findSelectedOptionInXxxOf.ts +53 -0
  157. package/src/schema/getClosestMatchingOption.ts +8 -8
  158. package/src/schema/getDefaultFormState.ts +26 -25
  159. package/src/schema/getDisplayLabel.ts +2 -2
  160. package/src/schema/getFirstMatchingOption.ts +79 -4
  161. package/src/schema/getFromSchema.ts +100 -0
  162. package/src/schema/index.ts +6 -4
  163. package/src/schema/isFilesArray.ts +2 -2
  164. package/src/schema/isMultiSelect.ts +2 -2
  165. package/src/schema/isSelect.ts +1 -1
  166. package/src/schema/retrieveSchema.ts +135 -69
  167. package/src/schema/sanitizeDataForNewSchema.ts +10 -10
  168. package/src/schema/toIdSchema.ts +45 -44
  169. package/src/schema/toPathSchema.ts +10 -10
  170. package/src/toErrorList.ts +2 -2
  171. package/src/types.ts +233 -173
  172. package/src/validationDataMerge.ts +1 -1
  173. package/src/withIdRefPrefix.ts +1 -1
  174. package/LICENSE.md +0 -201
  175. package/lib/schema/getMatchingOption.d.ts +0 -14
  176. package/lib/schema/getMatchingOption.js +0 -85
  177. package/lib/schema/getMatchingOption.js.map +0 -1
  178. package/lib/schema/mergeValidationData.d.ts +0 -14
  179. package/lib/schema/mergeValidationData.js +0 -28
  180. package/lib/schema/mergeValidationData.js.map +0 -1
  181. package/src/schema/getMatchingOption.ts +0 -103
  182. package/src/schema/mergeValidationData.ts +0 -38
@@ -0,0 +1,53 @@
1
+ import get from 'lodash/get';
2
+ import isEqual from 'lodash/isEqual';
3
+
4
+ import { CONST_KEY, DEFAULT_KEY, PROPERTIES_KEY } from '../constants';
5
+ import { Experimental_CustomMergeAllOf, FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
6
+ import retrieveSchema from './retrieveSchema';
7
+ import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema';
8
+
9
+ /** Finds the option inside the `schema['any/oneOf']` list which has the `properties[selectorField].default` or
10
+ * `properties[selectorField].const` that matches the `formData[selectorField]` value. For the purposes of this
11
+ * function, `selectorField` is either `schema.discriminator.propertyName` or `fallbackField`. The `LayoutGridField`
12
+ * works directly with schemas in a recursive manner, making this faster than `getFirstMatchingOption()`.
13
+ *
14
+ * @param validator - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
15
+ * @param rootSchema - The root schema that will be forwarded to all the APIs
16
+ * @param schema - The schema element in which to search for the selected anyOf/oneOf option
17
+ * @param fallbackField - The field to use as a backup selector field if the schema does not have a required field
18
+ * @param xxx - Either `anyOf` or `oneOf`, defines which value is being sought
19
+ * @param [formData={}] - The form data that is used to determine which anyOf/oneOf option to descend
20
+ * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
21
+ * @returns - The anyOf/oneOf option that matches the selector field in the schema or undefined if nothing is selected
22
+ */
23
+ export default function findSelectedOptionInXxxOf<
24
+ T = any,
25
+ S extends StrictRJSFSchema = RJSFSchema,
26
+ F extends FormContextType = any,
27
+ >(
28
+ validator: ValidatorType<T, S, F>,
29
+ rootSchema: S,
30
+ schema: S,
31
+ fallbackField: string,
32
+ xxx: 'anyOf' | 'oneOf',
33
+ formData: T = {} as T,
34
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
35
+ ): S | undefined {
36
+ if (Array.isArray(schema[xxx])) {
37
+ const discriminator = getDiscriminatorFieldFromSchema<S>(schema);
38
+ const selectorField = discriminator || fallbackField;
39
+ const xxxOfs = schema[xxx]!.map((xxxOf) =>
40
+ retrieveSchema<T, S, F>(validator, xxxOf as S, rootSchema, formData, experimental_customMergeAllOf),
41
+ );
42
+ const data = get(formData, selectorField);
43
+ if (data !== undefined) {
44
+ return xxxOfs.find((xxx) => {
45
+ return isEqual(
46
+ get(xxx, [PROPERTIES_KEY, selectorField, DEFAULT_KEY], get(xxx, [PROPERTIES_KEY, selectorField, CONST_KEY])),
47
+ data,
48
+ );
49
+ });
50
+ }
51
+ }
52
+ return undefined;
53
+ }
@@ -53,7 +53,7 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
53
53
  rootSchema: S,
54
54
  schema?: S,
55
55
  formData?: any,
56
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
56
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
57
57
  ): number {
58
58
  let totalScore = 0;
59
59
  if (schema) {
@@ -71,7 +71,7 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
71
71
  value as S,
72
72
  rootSchema,
73
73
  formValue,
74
- experimental_customMergeAllOf
74
+ experimental_customMergeAllOf,
75
75
  );
76
76
  return (
77
77
  score +
@@ -80,7 +80,7 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
80
80
  rootSchema,
81
81
  newSchema,
82
82
  formValue || {},
83
- experimental_customMergeAllOf
83
+ experimental_customMergeAllOf,
84
84
  )
85
85
  );
86
86
  }
@@ -96,7 +96,7 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
96
96
  get(value, key) as S[],
97
97
  -1,
98
98
  discriminator,
99
- experimental_customMergeAllOf
99
+ experimental_customMergeAllOf,
100
100
  )
101
101
  );
102
102
  }
@@ -127,7 +127,7 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
127
127
  }
128
128
  return score;
129
129
  },
130
- 0
130
+ 0,
131
131
  );
132
132
  } else if (isString(schema.type) && schema.type === guessType(formData)) {
133
133
  totalScore += 1;
@@ -162,7 +162,7 @@ export function calculateIndexScore<T = any, S extends StrictRJSFSchema = RJSFSc
162
162
  export default function getClosestMatchingOption<
163
163
  T = any,
164
164
  S extends StrictRJSFSchema = RJSFSchema,
165
- F extends FormContextType = any
165
+ F extends FormContextType = any,
166
166
  >(
167
167
  validator: ValidatorType<T, S, F>,
168
168
  rootSchema: S,
@@ -170,7 +170,7 @@ export default function getClosestMatchingOption<
170
170
  options: S[],
171
171
  selectedOption = -1,
172
172
  discriminatorField?: string,
173
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
173
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
174
174
  ): number {
175
175
  // First resolve any refs in the options
176
176
  const resolvedOptions = options.map((option) => {
@@ -215,7 +215,7 @@ export default function getClosestMatchingOption<
215
215
  }
216
216
  return scoreData;
217
217
  },
218
- { bestIndex: selectedOption, bestScore: 0 }
218
+ { bestIndex: selectedOption, bestScore: 0 },
219
219
  );
220
220
  // if all scores are the same go with selectedOption
221
221
  if (scoreCount.size === 1 && selectedOption >= 0) {
@@ -66,7 +66,7 @@ export enum AdditionalItemsHandling {
66
66
  export function getInnerSchemaForArrayItem<S extends StrictRJSFSchema = RJSFSchema>(
67
67
  schema: S,
68
68
  additionalItems: AdditionalItemsHandling = AdditionalItemsHandling.Ignore,
69
- idx = -1
69
+ idx = -1,
70
70
  ): S {
71
71
  if (idx >= 0) {
72
72
  if (Array.isArray(schema.items) && idx < schema.items.length) {
@@ -112,7 +112,7 @@ function maybeAddDefaultToObject<T = any>(
112
112
  isParentRequired?: boolean,
113
113
  requiredFields: string[] = [],
114
114
  experimental_defaultFormStateBehavior: Experimental_DefaultFormStateBehavior = {},
115
- isConst = false
115
+ isConst = false,
116
116
  ) {
117
117
  const { emptyObjectFields = 'populateAllDefaults' } = experimental_defaultFormStateBehavior;
118
118
  if (includeUndefinedValues || isConst) {
@@ -191,7 +191,7 @@ interface ComputeDefaultsProps<T = any, S extends StrictRJSFSchema = RJSFSchema>
191
191
  export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
192
192
  validator: ValidatorType<T, S, F>,
193
193
  rawSchema: S,
194
- computeDefaultsProps: ComputeDefaultsProps<T, S> = {}
194
+ computeDefaultsProps: ComputeDefaultsProps<T, S> = {},
195
195
  ): T | T[] | undefined {
196
196
  const {
197
197
  parentDefaults,
@@ -247,7 +247,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
247
247
  false,
248
248
  [],
249
249
  defaultFormData,
250
- experimental_customMergeAllOf
250
+ experimental_customMergeAllOf,
251
251
  );
252
252
  schemaToCompute = resolvedSchema[0]; // pick the first element from resolve dependencies
253
253
  } else if (isFixedItems(schema)) {
@@ -262,7 +262,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
262
262
  rawFormData: formData as T,
263
263
  required,
264
264
  shouldMergeDefaultsIntoFormData,
265
- })
265
+ }),
266
266
  ) as T[];
267
267
  } else if (ONE_OF_KEY in schema) {
268
268
  const { oneOf, ...remaining } = schema;
@@ -290,7 +290,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
290
290
  oneOf as S[],
291
291
  0,
292
292
  discriminator,
293
- experimental_customMergeAllOf
293
+ experimental_customMergeAllOf,
294
294
  )
295
295
  ] as S;
296
296
  schemaToCompute = mergeSchemas(remaining, schemaToCompute) as S;
@@ -308,7 +308,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
308
308
  anyOf as S[],
309
309
  0,
310
310
  discriminator,
311
- experimental_customMergeAllOf
311
+ experimental_customMergeAllOf,
312
312
  )
313
313
  ] as S;
314
314
  schemaToCompute = mergeSchemas(remaining, schemaToCompute) as S;
@@ -347,7 +347,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
347
347
  rootSchema,
348
348
  rawFormData,
349
349
  experimental_defaultFormStateBehavior,
350
- experimental_customMergeAllOf
350
+ experimental_customMergeAllOf,
351
351
  );
352
352
  if (!isObject(rawFormData) || ALL_OF_KEY in schema) {
353
353
  // If the formData is not an object which means it's a primitive field, then we need to merge the defaults into the formData.
@@ -356,7 +356,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
356
356
  defaultsWithFormData as T,
357
357
  matchingFormData as T,
358
358
  mergeExtraDefaults,
359
- true
359
+ true,
360
360
  ) as T;
361
361
  }
362
362
  }
@@ -378,19 +378,20 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
378
378
  export function ensureFormDataMatchingSchema<
379
379
  T = any,
380
380
  S extends StrictRJSFSchema = RJSFSchema,
381
- F extends FormContextType = any
381
+ F extends FormContextType = any,
382
382
  >(
383
383
  validator: ValidatorType<T, S, F>,
384
384
  schema: S,
385
385
  rootSchema: S,
386
386
  formData: T | undefined,
387
387
  experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior,
388
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
388
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
389
389
  ): T | T[] | undefined {
390
- const isSelectField = !isConstant(schema) && isSelect(validator, schema, rootSchema, experimental_customMergeAllOf);
390
+ const isSelectField =
391
+ !isConstant<S>(schema) && isSelect<T, S, F>(validator, schema, rootSchema, experimental_customMergeAllOf);
391
392
  let validFormData: T | T[] | undefined = formData;
392
393
  if (isSelectField) {
393
- const getOptionsList = optionsList(schema);
394
+ const getOptionsList = optionsList<T, S, F>(schema);
394
395
  const isValid = getOptionsList?.some((option) => deepEquals(option.value, formData));
395
396
  validFormData = isValid ? formData : undefined;
396
397
  }
@@ -425,7 +426,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
425
426
  required,
426
427
  shouldMergeDefaultsIntoFormData,
427
428
  }: ComputeDefaultsProps<T, S> = {},
428
- defaults?: T | T[] | undefined
429
+ defaults?: T | T[] | undefined,
429
430
  ): T {
430
431
  {
431
432
  const formData: T = (isObject(rawFormData) ? rawFormData : {}) as T;
@@ -439,7 +440,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
439
440
  const parentConst = retrievedSchema[CONST_KEY];
440
441
  const objectDefaults = Object.keys(retrievedSchema.properties || {}).reduce(
441
442
  (acc: GenericObjectType, key: string) => {
442
- const propertySchema = get(retrievedSchema, [PROPERTIES_KEY, key]);
443
+ const propertySchema: S = get(retrievedSchema, [PROPERTIES_KEY, key], {}) as S;
443
444
  // Check if the parent schema has a const property defined AND we are supporting const as defaults, then we
444
445
  // should always return the computedDefault since it's coming from the const.
445
446
  const hasParentConst = isObject(parentConst) && (parentConst as JSONSchema7Object)[key] !== undefined;
@@ -468,11 +469,11 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
468
469
  required,
469
470
  retrievedSchema.required,
470
471
  experimental_defaultFormStateBehavior,
471
- hasConst
472
+ hasConst,
472
473
  );
473
474
  return acc;
474
475
  },
475
- {}
476
+ {},
476
477
  ) as T;
477
478
  if (retrievedSchema.additionalProperties) {
478
479
  // as per spec additionalProperties may be either schema or boolean
@@ -512,7 +513,7 @@ export function getObjectDefaults<T = any, S extends StrictRJSFSchema = RJSFSche
512
513
  computedDefault,
513
514
  includeUndefinedValues,
514
515
  required,
515
- formDataRequired
516
+ formDataRequired,
516
517
  );
517
518
  });
518
519
  }
@@ -540,7 +541,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
540
541
  required,
541
542
  shouldMergeDefaultsIntoFormData,
542
543
  }: ComputeDefaultsProps<T, S> = {},
543
- defaults?: T | T[] | undefined
544
+ defaults?: T | T[] | undefined,
544
545
  ): T | T[] | undefined {
545
546
  const schema: S = rawSchema;
546
547
 
@@ -636,7 +637,7 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
636
637
  experimental_customMergeAllOf,
637
638
  required,
638
639
  shouldMergeDefaultsIntoFormData,
639
- })
640
+ }),
640
641
  ) as T[];
641
642
  // then fill up the rest with either the item default or empty, up to minItems
642
643
  return defaultEntries.concat(fillerEntries);
@@ -653,12 +654,12 @@ export function getArrayDefaults<T = any, S extends StrictRJSFSchema = RJSFSchem
653
654
  export function getDefaultBasedOnSchemaType<
654
655
  T = any,
655
656
  S extends StrictRJSFSchema = RJSFSchema,
656
- F extends FormContextType = any
657
+ F extends FormContextType = any,
657
658
  >(
658
659
  validator: ValidatorType<T, S, F>,
659
660
  rawSchema: S,
660
661
  computeDefaultsProps: ComputeDefaultsProps<T, S> = {},
661
- defaults?: T | T[] | undefined
662
+ defaults?: T | T[] | undefined,
662
663
  ): T | T[] | void {
663
664
  switch (getSchemaType<S>(rawSchema)) {
664
665
  // We need to recurse for object schema inner default values.
@@ -688,7 +689,7 @@ export function getDefaultBasedOnSchemaType<
688
689
  export default function getDefaultFormState<
689
690
  T = any,
690
691
  S extends StrictRJSFSchema = RJSFSchema,
691
- F extends FormContextType = any
692
+ F extends FormContextType = any,
692
693
  >(
693
694
  validator: ValidatorType<T, S, F>,
694
695
  theSchema: S,
@@ -696,7 +697,7 @@ export default function getDefaultFormState<
696
697
  rootSchema?: S,
697
698
  includeUndefinedValues: boolean | 'excludeObjectChildren' = false,
698
699
  experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior,
699
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
700
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
700
701
  ) {
701
702
  if (!isObject(theSchema)) {
702
703
  throw new Error('Invalid schema: ' + theSchema);
@@ -725,7 +726,7 @@ export default function getDefaultFormState<
725
726
  formData,
726
727
  true, // set to true to add any additional default array entries.
727
728
  defaultSupercedesUndefined,
728
- true // set to true to override formData with defaults if they exist.
729
+ true, // set to true to override formData with defaults if they exist.
729
730
  );
730
731
  return result;
731
732
  }
@@ -28,14 +28,14 @@ import isMultiSelect from './isMultiSelect';
28
28
  export default function getDisplayLabel<
29
29
  T = any,
30
30
  S extends StrictRJSFSchema = RJSFSchema,
31
- F extends FormContextType = any
31
+ F extends FormContextType = any,
32
32
  >(
33
33
  validator: ValidatorType<T, S, F>,
34
34
  schema: S,
35
35
  uiSchema: UiSchema<T, S, F> = {},
36
36
  rootSchema?: S,
37
37
  globalOptions?: GlobalUISchemaOptions,
38
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
38
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
39
39
  ): boolean {
40
40
  const uiOptions = getUiOptions<T, S, F>(uiSchema, globalOptions);
41
41
  const { label = true } = uiOptions;
@@ -1,4 +1,9 @@
1
- import getMatchingOption from './getMatchingOption';
1
+ import get from 'lodash/get';
2
+ import has from 'lodash/has';
3
+ import isNumber from 'lodash/isNumber';
4
+
5
+ import { PROPERTIES_KEY } from '../constants';
6
+ import getOptionMatchingSimpleDiscriminator from '../getOptionMatchingSimpleDiscriminator';
2
7
  import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
3
8
 
4
9
  /** Given the `formData` and list of `options`, attempts to find the index of the first option that matches the data.
@@ -15,13 +20,83 @@ import { FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '..
15
20
  export default function getFirstMatchingOption<
16
21
  T = any,
17
22
  S extends StrictRJSFSchema = RJSFSchema,
18
- F extends FormContextType = any
23
+ F extends FormContextType = any,
19
24
  >(
20
25
  validator: ValidatorType<T, S, F>,
21
26
  formData: T | undefined,
22
27
  options: S[],
23
28
  rootSchema: S,
24
- discriminatorField?: string
29
+ discriminatorField?: string,
25
30
  ): number {
26
- return getMatchingOption<T, S, F>(validator, formData, options, rootSchema, discriminatorField);
31
+ // For performance, skip validating subschemas if formData is undefined. We just
32
+ // want to get the first option in that case.
33
+ if (formData === undefined) {
34
+ return 0;
35
+ }
36
+
37
+ const simpleDiscriminatorMatch = getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField);
38
+ if (isNumber(simpleDiscriminatorMatch)) {
39
+ return simpleDiscriminatorMatch;
40
+ }
41
+
42
+ for (let i = 0; i < options.length; i++) {
43
+ const option = options[i];
44
+
45
+ // If we have a discriminator field, then we will use this to make the determination
46
+ if (discriminatorField && has(option, [PROPERTIES_KEY, discriminatorField])) {
47
+ const value = get(formData, discriminatorField);
48
+ const discriminator: S = get(option, [PROPERTIES_KEY, discriminatorField], {}) as S;
49
+ if (validator.isValid(discriminator, value, rootSchema)) {
50
+ return i;
51
+ }
52
+ } else if (option[PROPERTIES_KEY]) {
53
+ // If the schema describes an object then we need to add slightly more
54
+ // strict matching to the schema, because unless the schema uses the
55
+ // "requires" keyword, an object will match the schema as long as it
56
+ // doesn't have matching keys with a conflicting type. To do this we use an
57
+ // "anyOf" with an array of requires. This augmentation expresses that the
58
+ // schema should match if any of the keys in the schema are present on the
59
+ // object and pass validation.
60
+ //
61
+ // Create an "anyOf" schema that requires at least one of the keys in the
62
+ // "properties" object
63
+ const requiresAnyOf = {
64
+ anyOf: Object.keys(option[PROPERTIES_KEY]).map((key) => ({
65
+ required: [key],
66
+ })),
67
+ };
68
+
69
+ let augmentedSchema;
70
+
71
+ // If the "anyOf" keyword already exists, wrap the augmentation in an "allOf"
72
+ if (option.anyOf) {
73
+ // Create a shallow clone of the option
74
+ const { ...shallowClone } = option;
75
+
76
+ if (!shallowClone.allOf) {
77
+ shallowClone.allOf = [];
78
+ } else {
79
+ // If "allOf" already exists, shallow clone the array
80
+ shallowClone.allOf = shallowClone.allOf.slice();
81
+ }
82
+
83
+ shallowClone.allOf.push(requiresAnyOf);
84
+
85
+ augmentedSchema = shallowClone;
86
+ } else {
87
+ augmentedSchema = Object.assign({}, option, requiresAnyOf);
88
+ }
89
+
90
+ // Remove the "required" field as it's likely that not all fields have
91
+ // been filled in yet, which will mean that the schema is not valid
92
+ delete augmentedSchema.required;
93
+
94
+ if (validator.isValid(augmentedSchema, formData, rootSchema)) {
95
+ return i;
96
+ }
97
+ } else if (validator.isValid(option, formData, rootSchema)) {
98
+ return i;
99
+ }
100
+ }
101
+ return 0;
27
102
  }
@@ -0,0 +1,100 @@
1
+ import get from 'lodash/get';
2
+ import has from 'lodash/has';
3
+ import isEmpty from 'lodash/isEmpty';
4
+
5
+ import retrieveSchema from './retrieveSchema';
6
+ import { Experimental_CustomMergeAllOf, FormContextType, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types';
7
+ import { REF_KEY } from '../constants';
8
+
9
+ /** Internal helper function that acts like lodash's `get` but additionally retrieves `$ref`s as needed to get the path
10
+ * for schemas containing potentially nested `$ref`s.
11
+ *
12
+ * @param validator - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
13
+ * @param rootSchema - The root schema that will be forwarded to all the APIs
14
+ * @param schema - The current node within the JSON schema recursion
15
+ * @param path - The remaining keys in the path to the desired property
16
+ * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
17
+ * @returns - The internal schema from the `schema` for the given `path` or undefined if not found
18
+ */
19
+ function getFromSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
20
+ validator: ValidatorType<T, S, F>,
21
+ rootSchema: S,
22
+ schema: S,
23
+ path: string | string[],
24
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
25
+ ): T | S | undefined {
26
+ let fieldSchema = schema;
27
+ if (has(schema, REF_KEY)) {
28
+ fieldSchema = retrieveSchema<T, S, F>(validator, schema, rootSchema, undefined, experimental_customMergeAllOf);
29
+ }
30
+ if (isEmpty(path)) {
31
+ return fieldSchema;
32
+ }
33
+ const pathList = Array.isArray(path) ? path : path.split('.');
34
+ const [part, ...nestedPath] = pathList;
35
+ if (part && has(fieldSchema, part)) {
36
+ fieldSchema = get(fieldSchema, part) as S;
37
+ return getFromSchemaInternal<T, S, F>(
38
+ validator,
39
+ rootSchema,
40
+ fieldSchema,
41
+ nestedPath,
42
+ experimental_customMergeAllOf,
43
+ );
44
+ }
45
+ return undefined;
46
+ }
47
+
48
+ /** Helper that acts like lodash's `get` but additionally retrieves `$ref`s as needed to get the path for schemas
49
+ * containing potentially nested `$ref`s.
50
+ *
51
+ * @param validator - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs
52
+ * @param rootSchema - The root schema that will be forwarded to all the APIs
53
+ * @param schema - The current node within the JSON schema recursion
54
+ * @param path - The keys in the path to the desired field
55
+ * @param defaultValue - The value to return if a value is not found for the `pathList` path
56
+ * @param [experimental_customMergeAllOf] - Optional function that allows for custom merging of `allOf` schemas
57
+ * @returns - The inner schema from the `schema` for the given `path` or the `defaultValue` if not found
58
+ */
59
+ export default function getFromSchema<
60
+ T = any,
61
+ S extends StrictRJSFSchema = RJSFSchema,
62
+ F extends FormContextType = any,
63
+ >(
64
+ validator: ValidatorType<T, S, F>,
65
+ rootSchema: S,
66
+ schema: S,
67
+ path: string | string[],
68
+ defaultValue: T,
69
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
70
+ ): T;
71
+ export default function getFromSchema<
72
+ T = any,
73
+ S extends StrictRJSFSchema = RJSFSchema,
74
+ F extends FormContextType = any,
75
+ >(
76
+ validator: ValidatorType<T, S, F>,
77
+ rootSchema: S,
78
+ schema: S,
79
+ path: string | string[],
80
+ defaultValue: S,
81
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
82
+ ): S;
83
+ export default function getFromSchema<
84
+ T = any,
85
+ S extends StrictRJSFSchema = RJSFSchema,
86
+ F extends FormContextType = any,
87
+ >(
88
+ validator: ValidatorType<T, S, F>,
89
+ rootSchema: S,
90
+ schema: S,
91
+ path: string | string[],
92
+ defaultValue: T | S,
93
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
94
+ ): T | S {
95
+ const result = getFromSchemaInternal(validator, rootSchema, schema, path, experimental_customMergeAllOf);
96
+ if (result === undefined) {
97
+ return defaultValue;
98
+ }
99
+ return result;
100
+ }
@@ -1,27 +1,29 @@
1
+ import findFieldInSchema from './findFieldInSchema';
2
+ import findSelectedOptionInXxxOf from './findSelectedOptionInXxxOf';
1
3
  import getDefaultFormState from './getDefaultFormState';
2
4
  import getDisplayLabel from './getDisplayLabel';
3
5
  import getClosestMatchingOption from './getClosestMatchingOption';
4
6
  import getFirstMatchingOption from './getFirstMatchingOption';
5
- import getMatchingOption from './getMatchingOption';
7
+ import getFromSchema from './getFromSchema';
6
8
  import isFilesArray from './isFilesArray';
7
9
  import isMultiSelect from './isMultiSelect';
8
10
  import isSelect from './isSelect';
9
- import mergeValidationData from './mergeValidationData';
10
11
  import retrieveSchema from './retrieveSchema';
11
12
  import sanitizeDataForNewSchema from './sanitizeDataForNewSchema';
12
13
  import toIdSchema from './toIdSchema';
13
14
  import toPathSchema from './toPathSchema';
14
15
 
15
16
  export {
17
+ findFieldInSchema,
18
+ findSelectedOptionInXxxOf,
16
19
  getDefaultFormState,
17
20
  getDisplayLabel,
18
21
  getClosestMatchingOption,
19
22
  getFirstMatchingOption,
20
- getMatchingOption,
23
+ getFromSchema,
21
24
  isFilesArray,
22
25
  isMultiSelect,
23
26
  isSelect,
24
- mergeValidationData,
25
27
  retrieveSchema,
26
28
  sanitizeDataForNewSchema,
27
29
  toIdSchema,
@@ -23,7 +23,7 @@ export default function isFilesArray<T = any, S extends StrictRJSFSchema = RJSFS
23
23
  schema: S,
24
24
  uiSchema: UiSchema<T, S, F> = {},
25
25
  rootSchema?: S,
26
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
26
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
27
27
  ) {
28
28
  if (uiSchema[UI_WIDGET_KEY] === 'files') {
29
29
  return true;
@@ -34,7 +34,7 @@ export default function isFilesArray<T = any, S extends StrictRJSFSchema = RJSFS
34
34
  schema.items as S,
35
35
  rootSchema,
36
36
  undefined,
37
- experimental_customMergeAllOf
37
+ experimental_customMergeAllOf,
38
38
  );
39
39
  return itemsSchema.type === 'string' && itemsSchema.format === 'data-url';
40
40
  }
@@ -13,12 +13,12 @@ import isSelect from './isSelect';
13
13
  export default function isMultiSelect<
14
14
  T = any,
15
15
  S extends StrictRJSFSchema = RJSFSchema,
16
- F extends FormContextType = any
16
+ F extends FormContextType = any,
17
17
  >(
18
18
  validator: ValidatorType<T, S, F>,
19
19
  schema: S,
20
20
  rootSchema?: S,
21
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
21
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
22
22
  ) {
23
23
  if (!schema.uniqueItems || !schema.items || typeof schema.items === 'boolean') {
24
24
  return false;
@@ -14,7 +14,7 @@ export default function isSelect<T = any, S extends StrictRJSFSchema = RJSFSchem
14
14
  validator: ValidatorType<T, S, F>,
15
15
  theSchema: S,
16
16
  rootSchema: S = {} as S,
17
- experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>
17
+ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>,
18
18
  ) {
19
19
  const schema = retrieveSchema<T, S, F>(validator, theSchema, rootSchema, undefined, experimental_customMergeAllOf);
20
20
  const altSchemas = schema.oneOf || schema.anyOf;