@jsonforms/core 3.0.0-alpha.3 → 3.0.0-beta.2

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 (206) hide show
  1. package/docs/assets/js/search.json +1 -1
  2. package/docs/globals.html +207 -165
  3. package/docs/index.html +7 -4
  4. package/docs/interfaces/arraycontrolprops.html +21 -21
  5. package/docs/interfaces/arraylayoutprops.html +21 -21
  6. package/docs/interfaces/cellprops.html +12 -12
  7. package/docs/interfaces/combinatorrendererprops.html +143 -36
  8. package/docs/interfaces/controlprops.html +16 -16
  9. package/docs/interfaces/controlstate.html +2 -2
  10. package/docs/interfaces/controlwithdetailprops.html +17 -17
  11. package/docs/interfaces/dispatchcellprops.html +10 -10
  12. package/docs/interfaces/dispatchcellstateprops.html +10 -10
  13. package/docs/interfaces/dispatchpropsofarraycontrol.html +4 -4
  14. package/docs/interfaces/dispatchpropsofcontrol.html +1 -1
  15. package/docs/interfaces/dispatchpropsofmultienumcontrol.html +2 -2
  16. package/docs/interfaces/enumcellprops.html +13 -13
  17. package/docs/interfaces/enumoption.html +2 -2
  18. package/docs/interfaces/jsonformsprops.html +9 -9
  19. package/docs/interfaces/layoutprops.html +10 -10
  20. package/docs/interfaces/ownpropsofcell.html +9 -9
  21. package/docs/interfaces/ownpropsofcontrol.html +9 -12
  22. package/docs/interfaces/ownpropsofenum.html +1 -1
  23. package/docs/interfaces/ownpropsofenumcell.html +10 -10
  24. package/docs/interfaces/ownpropsofjsonformsrenderer.html +8 -8
  25. package/docs/interfaces/ownpropsoflayout.html +9 -9
  26. package/docs/interfaces/ownpropsofmasterlistitem.html +6 -6
  27. package/docs/interfaces/ownpropsofrenderer.html +8 -8
  28. package/docs/interfaces/rendererprops.html +9 -9
  29. package/docs/interfaces/statepropsofarraycontrol.html +17 -17
  30. package/docs/interfaces/statepropsofarraylayout.html +17 -17
  31. package/docs/interfaces/statepropsofcell.html +11 -11
  32. package/docs/interfaces/statepropsofcombinator.html +147 -40
  33. package/docs/interfaces/statepropsofcontrol.html +18 -15
  34. package/docs/interfaces/statepropsofcontrolwithdetail.html +16 -16
  35. package/docs/interfaces/statepropsofenumcell.html +12 -12
  36. package/docs/interfaces/statepropsofjsonformsrenderer.html +9 -9
  37. package/docs/interfaces/statepropsoflayout.html +10 -10
  38. package/docs/interfaces/statepropsofmasteritem.html +7 -7
  39. package/docs/interfaces/statepropsofrenderer.html +9 -9
  40. package/docs/interfaces/statepropsofscopedrenderer.html +12 -12
  41. package/docs/interfaces/withclassname.html +1 -1
  42. package/lib/Helpers.d.ts +5 -5
  43. package/lib/actions/actions.d.ts +181 -181
  44. package/lib/actions/index.d.ts +1 -1
  45. package/lib/configDefault.d.ts +6 -6
  46. package/lib/generators/Generate.d.ts +6 -6
  47. package/lib/generators/index.d.ts +3 -3
  48. package/lib/generators/schema.d.ts +8 -8
  49. package/lib/generators/uischema.d.ts +12 -12
  50. package/lib/i18n/i18nTypes.d.ts +15 -15
  51. package/lib/i18n/i18nUtil.d.ts +18 -18
  52. package/lib/i18n/index.d.ts +2 -2
  53. package/lib/index.d.ts +11 -11
  54. package/lib/jsonforms-core.cjs.js +2441 -0
  55. package/lib/jsonforms-core.cjs.js.map +1 -0
  56. package/lib/jsonforms-core.esm.js +2152 -0
  57. package/lib/jsonforms-core.esm.js.map +1 -0
  58. package/lib/models/draft4.d.ts +198 -198
  59. package/lib/models/index.d.ts +5 -5
  60. package/lib/models/jsonSchema.d.ts +3 -3
  61. package/lib/models/jsonSchema4.d.ts +110 -110
  62. package/lib/models/jsonSchema7.d.ts +119 -119
  63. package/lib/models/uischema.d.ts +201 -201
  64. package/lib/reducers/cells.d.ts +11 -11
  65. package/lib/reducers/config.d.ts +3 -3
  66. package/lib/reducers/core.d.ts +24 -24
  67. package/lib/reducers/default-data.d.ts +10 -10
  68. package/lib/reducers/i18n.d.ts +8 -8
  69. package/lib/reducers/index.d.ts +9 -9
  70. package/lib/reducers/reducers.d.ts +29 -29
  71. package/lib/reducers/renderers.d.ts +10 -10
  72. package/lib/reducers/selectors.d.ts +15 -15
  73. package/lib/reducers/uischemas.d.ts +10 -10
  74. package/lib/store.d.ts +53 -53
  75. package/lib/testers/index.d.ts +1 -1
  76. package/lib/testers/testers.d.ts +204 -203
  77. package/lib/util/Formatted.d.ts +19 -19
  78. package/lib/util/array.d.ts +3 -3
  79. package/lib/util/cell.d.ts +79 -79
  80. package/lib/util/combinators.d.ts +9 -10
  81. package/lib/util/ids.d.ts +3 -3
  82. package/lib/util/index.d.ts +15 -15
  83. package/lib/util/label.d.ts +9 -9
  84. package/lib/util/path.d.ts +35 -25
  85. package/lib/util/renderer.d.ts +398 -397
  86. package/lib/util/resolvers.d.ts +25 -25
  87. package/lib/util/runtime.d.ts +18 -18
  88. package/lib/util/schema.d.ts +1 -1
  89. package/lib/util/type.d.ts +174 -174
  90. package/lib/util/uischema.d.ts +5 -5
  91. package/lib/util/util.d.ts +31 -31
  92. package/lib/util/validator.d.ts +3 -3
  93. package/package.json +16 -13
  94. package/rollup.config.js +44 -0
  95. package/src/generators/uischema.ts +4 -4
  96. package/src/reducers/reducers.ts +14 -6
  97. package/src/testers/testers.ts +60 -33
  98. package/src/util/cell.ts +4 -4
  99. package/src/util/combinators.ts +17 -32
  100. package/src/util/label.ts +2 -2
  101. package/src/util/path.ts +18 -6
  102. package/src/util/renderer.ts +22 -36
  103. package/src/util/resolvers.ts +57 -68
  104. package/src/util/util.ts +1 -1
  105. package/stats.html +3279 -0
  106. package/test/generators/uischema.test.ts +18 -0
  107. package/test/testers.test.ts +208 -120
  108. package/test/util/path.test.ts +37 -20
  109. package/test/util/resolvers.test.ts +99 -8
  110. package/lib/Helpers.js +0 -33
  111. package/lib/Helpers.js.map +0 -1
  112. package/lib/actions/actions.js +0 -173
  113. package/lib/actions/actions.js.map +0 -1
  114. package/lib/actions/index.js +0 -29
  115. package/lib/actions/index.js.map +0 -1
  116. package/lib/configDefault.js +0 -48
  117. package/lib/configDefault.js.map +0 -1
  118. package/lib/generators/Generate.js +0 -35
  119. package/lib/generators/Generate.js.map +0 -1
  120. package/lib/generators/index.js +0 -31
  121. package/lib/generators/index.js.map +0 -1
  122. package/lib/generators/schema.js +0 -154
  123. package/lib/generators/schema.js.map +0 -1
  124. package/lib/generators/uischema.js +0 -169
  125. package/lib/generators/uischema.js.map +0 -1
  126. package/lib/i18n/i18nTypes.js +0 -3
  127. package/lib/i18n/i18nTypes.js.map +0 -1
  128. package/lib/i18n/i18nUtil.js +0 -71
  129. package/lib/i18n/i18nUtil.js.map +0 -1
  130. package/lib/i18n/index.js +0 -6
  131. package/lib/i18n/index.js.map +0 -1
  132. package/lib/index.js +0 -40
  133. package/lib/index.js.map +0 -1
  134. package/lib/jsonforms-core.js +0 -25
  135. package/lib/jsonforms-core.js.map +0 -1
  136. package/lib/models/draft4.js +0 -174
  137. package/lib/models/draft4.js.map +0 -1
  138. package/lib/models/index.js +0 -33
  139. package/lib/models/index.js.map +0 -1
  140. package/lib/models/jsonSchema.js +0 -27
  141. package/lib/models/jsonSchema.js.map +0 -1
  142. package/lib/models/jsonSchema4.js +0 -30
  143. package/lib/models/jsonSchema4.js.map +0 -1
  144. package/lib/models/jsonSchema7.js +0 -30
  145. package/lib/models/jsonSchema7.js.map +0 -1
  146. package/lib/models/uischema.js +0 -58
  147. package/lib/models/uischema.js.map +0 -1
  148. package/lib/reducers/cells.js +0 -42
  149. package/lib/reducers/cells.js.map +0 -1
  150. package/lib/reducers/config.js +0 -46
  151. package/lib/reducers/config.js.map +0 -1
  152. package/lib/reducers/core.js +0 -294
  153. package/lib/reducers/core.js.map +0 -1
  154. package/lib/reducers/default-data.js +0 -45
  155. package/lib/reducers/default-data.js.map +0 -1
  156. package/lib/reducers/i18n.js +0 -83
  157. package/lib/reducers/i18n.js.map +0 -1
  158. package/lib/reducers/index.js +0 -37
  159. package/lib/reducers/index.js.map +0 -1
  160. package/lib/reducers/reducers.js +0 -98
  161. package/lib/reducers/reducers.js.map +0 -1
  162. package/lib/reducers/renderers.js +0 -43
  163. package/lib/reducers/renderers.js.map +0 -1
  164. package/lib/reducers/selectors.js +0 -56
  165. package/lib/reducers/selectors.js.map +0 -1
  166. package/lib/reducers/uischemas.js +0 -60
  167. package/lib/reducers/uischemas.js.map +0 -1
  168. package/lib/store.js +0 -27
  169. package/lib/store.js.map +0 -1
  170. package/lib/testers/index.js +0 -29
  171. package/lib/testers/index.js.map +0 -1
  172. package/lib/testers/testers.js +0 -421
  173. package/lib/testers/testers.js.map +0 -1
  174. package/lib/util/Formatted.js +0 -27
  175. package/lib/util/Formatted.js.map +0 -1
  176. package/lib/util/array.js +0 -44
  177. package/lib/util/array.js.map +0 -1
  178. package/lib/util/cell.js +0 -148
  179. package/lib/util/cell.js.map +0 -1
  180. package/lib/util/combinators.js +0 -59
  181. package/lib/util/combinators.js.map +0 -1
  182. package/lib/util/ids.js +0 -54
  183. package/lib/util/ids.js.map +0 -1
  184. package/lib/util/index.js +0 -43
  185. package/lib/util/index.js.map +0 -1
  186. package/lib/util/label.js +0 -73
  187. package/lib/util/label.js.map +0 -1
  188. package/lib/util/path.js +0 -90
  189. package/lib/util/path.js.map +0 -1
  190. package/lib/util/renderer.js +0 -530
  191. package/lib/util/renderer.js.map +0 -1
  192. package/lib/util/resolvers.js +0 -169
  193. package/lib/util/resolvers.js.map +0 -1
  194. package/lib/util/runtime.js +0 -167
  195. package/lib/util/runtime.js.map +0 -1
  196. package/lib/util/schema.js +0 -42
  197. package/lib/util/schema.js.map +0 -1
  198. package/lib/util/type.js +0 -27
  199. package/lib/util/type.js.map +0 -1
  200. package/lib/util/uischema.js +0 -56
  201. package/lib/util/uischema.js.map +0 -1
  202. package/lib/util/util.js +0 -112
  203. package/lib/util/util.js.map +0 -1
  204. package/lib/util/validator.js +0 -37
  205. package/lib/util/validator.js.map +0 -1
  206. package/webpack.build.js +0 -13
@@ -35,7 +35,7 @@ import {
35
35
  Layout,
36
36
  UISchemaElement
37
37
  } from '../models';
38
- import { deriveTypes, resolveSchema } from '../util';
38
+ import { deriveTypes, encode, resolveSchema } from '../util';
39
39
 
40
40
  /**
41
41
  * Creates a new ILayout.
@@ -122,7 +122,7 @@ const generateUISchema = (
122
122
  ): UISchemaElement => {
123
123
  if (!isEmpty(jsonSchema) && jsonSchema.$ref !== undefined) {
124
124
  return generateUISchema(
125
- resolveSchema(rootSchema, jsonSchema.$ref),
125
+ resolveSchema(rootSchema, jsonSchema.$ref, rootSchema),
126
126
  schemaElements,
127
127
  currentRef,
128
128
  schemaName,
@@ -162,9 +162,9 @@ const generateUISchema = (
162
162
  const nextRef: string = currentRef + '/properties';
163
163
  Object.keys(jsonSchema.properties).map(propName => {
164
164
  let value = jsonSchema.properties[propName];
165
- const ref = `${nextRef}/${propName}`;
165
+ const ref = `${nextRef}/${encode(propName)}`;
166
166
  if (value.$ref !== undefined) {
167
- value = resolveSchema(rootSchema, value.$ref);
167
+ value = resolveSchema(rootSchema, value.$ref, rootSchema);
168
168
  }
169
169
  generateUISchema(
170
170
  value,
@@ -32,9 +32,9 @@ import {
32
32
  import { defaultDataReducer } from './default-data';
33
33
  import { rendererReducer } from './renderers';
34
34
  import { JsonFormsState } from '../store';
35
+ import type { JsonFormsUISchemaRegistryEntry } from './uischemas';
35
36
  import {
36
37
  findMatchingUISchema,
37
- JsonFormsUISchemaRegistryEntry,
38
38
  uischemaRegistryReducer,
39
39
  } from './uischemas';
40
40
  import {
@@ -59,7 +59,7 @@ export const jsonFormsReducerConfig = {
59
59
  config: configReducer,
60
60
  uischemas: uischemaRegistryReducer,
61
61
  defaultData: defaultDataReducer,
62
- i18n: i18nReducer
62
+ i18n: i18nReducer,
63
63
  };
64
64
 
65
65
  /**
@@ -67,7 +67,7 @@ export const jsonFormsReducerConfig = {
67
67
  * @param schema the JSON schema describing the data to be rendered
68
68
  * @param schemaPath the according schema path
69
69
  * @param path the instance path
70
- * @param fallbackLayoutType the type of the layout to use
70
+ * @param fallback the type of the layout to use or a UI-schema-generator function
71
71
  * @param control may be checked for embedded inline uischema options
72
72
  */
73
73
  export const findUISchema = (
@@ -75,7 +75,7 @@ export const findUISchema = (
75
75
  schema: JsonSchema,
76
76
  schemaPath: string,
77
77
  path: string,
78
- fallbackLayoutType = 'VerticalLayout',
78
+ fallback: string | (() => UISchemaElement) = 'VerticalLayout',
79
79
  control?: ControlElement,
80
80
  rootSchema?: JsonSchema
81
81
  ): UISchemaElement => {
@@ -83,8 +83,12 @@ export const findUISchema = (
83
83
  if (control && control.options && control.options.detail) {
84
84
  if (typeof control.options.detail === 'string') {
85
85
  if (control.options.detail.toUpperCase() === 'GENERATE') {
86
+ //use fallback generation function
87
+ if(typeof fallback === "function"){
88
+ return fallback();
89
+ }
86
90
  // force generation of uischema
87
- return Generate.uiSchema(schema, fallbackLayoutType);
91
+ return Generate.uiSchema(schema, fallback);
88
92
  }
89
93
  } else if (typeof control.options.detail === 'object') {
90
94
  // check if detail is a valid uischema
@@ -99,7 +103,11 @@ export const findUISchema = (
99
103
  // default
100
104
  const uiSchema = findMatchingUISchema(uischemas)(schema, schemaPath, path);
101
105
  if (uiSchema === undefined) {
102
- return Generate.uiSchema(schema, fallbackLayoutType, '#', rootSchema);
106
+ //use fallback generation function
107
+ if(typeof fallback === 'function'){
108
+ return fallback();
109
+ }
110
+ return Generate.uiSchema(schema, fallback, '#', rootSchema);
103
111
  }
104
112
  return uiSchema;
105
113
  };
@@ -47,15 +47,17 @@ import { deriveTypes, hasType, resolveSchema } from '../util';
47
47
  export const NOT_APPLICABLE = -1;
48
48
  /**
49
49
  * A tester is a function that receives an UI schema and a JSON schema and returns a boolean.
50
+ * The rootSchema is handed over as context. Can be used to resolve references.
50
51
  */
51
- export type Tester = (uischema: UISchemaElement, schema: JsonSchema) => boolean;
52
+ export type Tester = (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema) => boolean;
52
53
 
53
54
  /**
54
55
  * A ranked tester associates a tester with a number.
55
56
  */
56
57
  export type RankedTester = (
57
58
  uischema: UISchemaElement,
58
- schema: JsonSchema
59
+ schema: JsonSchema,
60
+ rootSchema: JsonSchema
59
61
  ) => number;
60
62
 
61
63
  export const isControl = (uischema: any): uischema is ControlElement =>
@@ -72,8 +74,8 @@ export const isControl = (uischema: any): uischema is ControlElement =>
72
74
  * applied to the resolved sub-schema
73
75
  */
74
76
  export const schemaMatches = (
75
- predicate: (schema: JsonSchema) => boolean
76
- ): Tester => (uischema: UISchemaElement, schema: JsonSchema): boolean => {
77
+ predicate: (schema: JsonSchema, rootSchema: JsonSchema) => boolean
78
+ ): Tester => (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema): boolean => {
77
79
  if (isEmpty(uischema) || !isControl(uischema)) {
78
80
  return false;
79
81
  }
@@ -86,26 +88,26 @@ export const schemaMatches = (
86
88
  }
87
89
  let currentDataSchema = schema;
88
90
  if (hasType(schema, 'object')) {
89
- currentDataSchema = resolveSchema(schema, schemaPath);
91
+ currentDataSchema = resolveSchema(schema, schemaPath, rootSchema);
90
92
  }
91
93
  if (currentDataSchema === undefined) {
92
94
  return false;
93
95
  }
94
96
 
95
- return predicate(currentDataSchema);
97
+ return predicate(currentDataSchema, rootSchema);
96
98
  };
97
99
 
98
100
  export const schemaSubPathMatches = (
99
101
  subPath: string,
100
- predicate: (schema: JsonSchema) => boolean
101
- ): Tester => (uischema: UISchemaElement, schema: JsonSchema): boolean => {
102
+ predicate: (schema: JsonSchema, rootSchema: JsonSchema) => boolean
103
+ ): Tester => (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema): boolean => {
102
104
  if (isEmpty(uischema) || !isControl(uischema)) {
103
105
  return false;
104
106
  }
105
107
  const schemaPath = uischema.scope;
106
108
  let currentDataSchema: JsonSchema = schema;
107
109
  if (hasType(schema, 'object')) {
108
- currentDataSchema = resolveSchema(schema, schemaPath);
110
+ currentDataSchema = resolveSchema(schema, schemaPath, rootSchema);
109
111
  }
110
112
  currentDataSchema = get(currentDataSchema, subPath);
111
113
 
@@ -113,7 +115,7 @@ export const schemaSubPathMatches = (
113
115
  return false;
114
116
  }
115
117
 
116
- return predicate(currentDataSchema);
118
+ return predicate(currentDataSchema, rootSchema);
117
119
  };
118
120
 
119
121
  /**
@@ -215,8 +217,9 @@ export const scopeEndIs = (expected: string): Tester => (
215
217
  */
216
218
  export const and = (...testers: Tester[]): Tester => (
217
219
  uischema: UISchemaElement,
218
- schema: JsonSchema
219
- ) => testers.reduce((acc, tester) => acc && tester(uischema, schema), true);
220
+ schema: JsonSchema,
221
+ rootSchema: JsonSchema
222
+ ) => testers.reduce((acc, tester) => acc && tester(uischema, schema, rootSchema), true);
220
223
 
221
224
  /**
222
225
  * A tester that allow composing other testers by || them.
@@ -225,8 +228,9 @@ export const and = (...testers: Tester[]): Tester => (
225
228
  */
226
229
  export const or = (...testers: Tester[]): Tester => (
227
230
  uischema: UISchemaElement,
228
- schema: JsonSchema
229
- ) => testers.reduce((acc, tester) => acc || tester(uischema, schema), false);
231
+ schema: JsonSchema,
232
+ rootSchema: JsonSchema
233
+ ) => testers.reduce((acc, tester) => acc || tester(uischema, schema, rootSchema), false);
230
234
  /**
231
235
  * Create a ranked tester that will associate a number with a given tester, if the
232
236
  * latter returns true.
@@ -236,9 +240,10 @@ export const or = (...testers: Tester[]): Tester => (
236
240
  */
237
241
  export const rankWith = (rank: number, tester: Tester) => (
238
242
  uischema: UISchemaElement,
239
- schema: JsonSchema
243
+ schema: JsonSchema,
244
+ rootSchema: JsonSchema
240
245
  ): number => {
241
- if (tester(uischema, schema)) {
246
+ if (tester(uischema, schema, rootSchema)) {
242
247
  return rank;
243
248
  }
244
249
 
@@ -247,9 +252,10 @@ export const rankWith = (rank: number, tester: Tester) => (
247
252
 
248
253
  export const withIncreasedRank = (by: number, rankedTester: RankedTester) => (
249
254
  uischema: UISchemaElement,
250
- schema: JsonSchema
255
+ schema: JsonSchema,
256
+ rootSchema: JsonSchema
251
257
  ): number => {
252
- const rank = rankedTester(uischema, schema);
258
+ const rank = rankedTester(uischema, schema, rootSchema);
253
259
  if (rank === NOT_APPLICABLE) {
254
260
  return NOT_APPLICABLE;
255
261
  }
@@ -380,9 +386,12 @@ export const isDateTimeControl = and(
380
386
  */
381
387
  export const isObjectArray = and(
382
388
  schemaMatches(
383
- schema => hasType(schema, 'array') && !Array.isArray(schema.items) // we don't care about tuples
389
+ (schema, rootSchema) => hasType(schema, 'array') && !Array.isArray(resolveSchema(schema, 'items', rootSchema)) // we don't care about tuples
384
390
  ),
385
- schemaSubPathMatches('items', schema => hasType(schema, 'object'))
391
+ schemaSubPathMatches('items', (schema, rootSchema) => {
392
+ const resolvedSchema = schema.$ref ? resolveSchema(rootSchema, schema.$ref, rootSchema) : schema;
393
+ return hasType(resolvedSchema, 'object')
394
+ })
386
395
  );
387
396
 
388
397
  /**
@@ -394,22 +403,31 @@ export const isObjectArrayControl = and(uiTypeIs('Control'), isObjectArray);
394
403
 
395
404
  const traverse = (
396
405
  any: JsonSchema | JsonSchema[],
397
- pred: (obj: JsonSchema) => boolean
406
+ pred: (obj: JsonSchema) => boolean,
407
+ rootSchema: JsonSchema
398
408
  ): boolean => {
399
409
  if (isArray(any)) {
400
- return reduce(any, (acc, el) => acc || traverse(el, pred), false);
410
+ return reduce(any, (acc, el) => acc || traverse(el, pred, rootSchema), false);
401
411
  }
402
412
 
403
413
  if (pred(any)) {
404
414
  return true;
405
415
  }
416
+
417
+ if (any.$ref) {
418
+ const toTraverse = resolveSchema(rootSchema, any.$ref, rootSchema);
419
+ if (toTraverse && !toTraverse.$ref) {
420
+ return traverse(toTraverse, pred, rootSchema);
421
+ }
422
+ }
423
+
406
424
  if (any.items) {
407
- return traverse(any.items, pred);
425
+ return traverse(any.items, pred, rootSchema);
408
426
  }
409
427
  if (any.properties) {
410
428
  return reduce(
411
429
  toPairs(any.properties),
412
- (acc, [_key, val]) => acc || traverse(val, pred),
430
+ (acc, [_key, val]) => acc || traverse(val, pred, rootSchema),
413
431
  false
414
432
  );
415
433
  }
@@ -419,13 +437,14 @@ const traverse = (
419
437
 
420
438
  export const isObjectArrayWithNesting = (
421
439
  uischema: UISchemaElement,
422
- schema: JsonSchema
440
+ schema: JsonSchema,
441
+ rootSchema: JsonSchema
423
442
  ): boolean => {
424
- if (!uiTypeIs('Control')(uischema, schema)) {
443
+ if (!uiTypeIs('Control')(uischema, schema, rootSchema)) {
425
444
  return false;
426
445
  }
427
446
  const schemaPath = (uischema as ControlElement).scope;
428
- const resolvedSchema = resolveSchema(schema, schemaPath);
447
+ const resolvedSchema = resolveSchema(schema, schemaPath, rootSchema ?? schema);
429
448
  const wantedNestingByType: { [key: string]: number } = {
430
449
  object: 2,
431
450
  array: 1
@@ -437,6 +456,9 @@ export const isObjectArrayWithNesting = (
437
456
  if (val === schema) {
438
457
  return false;
439
458
  }
459
+ if (val.$ref !== undefined) {
460
+ return false;
461
+ }
440
462
  // we don't support multiple types
441
463
  if (typeof val.type !== 'string') {
442
464
  return true;
@@ -447,7 +469,7 @@ export const isObjectArrayWithNesting = (
447
469
  }
448
470
  wantedNestingByType[val.type] = typeCount - 1;
449
471
  return wantedNestingByType[val.type] === 0;
450
- })
472
+ }, rootSchema)
451
473
  ) {
452
474
  return true;
453
475
  }
@@ -479,10 +501,13 @@ export const isArrayObjectControl = isObjectArrayControl;
479
501
  export const isPrimitiveArrayControl = and(
480
502
  uiTypeIs('Control'),
481
503
  schemaMatches(
482
- schema => deriveTypes(schema).length !== 0 && !Array.isArray(schema.items) // we don't care about tuples
504
+ (schema, rootSchema) =>
505
+ deriveTypes(schema).length !== 0 &&
506
+ !Array.isArray(resolveSchema(schema, 'items', rootSchema)) // we don't care about tuples
483
507
  ),
484
- schemaSubPathMatches('items', schema => {
485
- const types = deriveTypes(schema);
508
+ schemaSubPathMatches('items', (schema, rootSchema) => {
509
+ const resolvedSchema = schema.$ref ? resolveSchema(rootSchema, schema.$ref, rootSchema) : schema;
510
+ const types = deriveTypes(resolvedSchema);
486
511
  return (
487
512
  types.length === 1 &&
488
513
  includes(['integer', 'number', 'boolean', 'string'], types[0])
@@ -543,5 +568,7 @@ export const categorizationHasCategory = (uischema: UISchemaElement) =>
543
568
 
544
569
  export const not = (tester: Tester): Tester => (
545
570
  uischema: UISchemaElement,
546
- schema: JsonSchema
547
- ) => !tester(uischema, schema);
571
+ schema: JsonSchema,
572
+ rootSchema: JsonSchema
573
+
574
+ ) => !tester(uischema, schema, rootSchema);
package/src/util/cell.ts CHANGED
@@ -25,14 +25,14 @@
25
25
 
26
26
  import isEmpty from 'lodash/isEmpty';
27
27
  import union from 'lodash/union';
28
+ import type { JsonFormsCellRendererRegistryEntry } from '../reducers';
28
29
  import {
30
+ getAjv,
29
31
  getConfig,
30
32
  getData,
31
33
  getErrorAt,
32
34
  getSchema,
33
- getAjv,
34
- JsonFormsCellRendererRegistryEntry,
35
- getTranslator
35
+ getTranslator,
36
36
  } from '../reducers';
37
37
  import { AnyAction, Dispatch } from './type';
38
38
  import {
@@ -57,7 +57,7 @@ import { JsonFormsState } from '../store';
57
57
  import { JsonSchema } from '../models';
58
58
  import { getI18nKeyPrefix } from '../i18n';
59
59
 
60
- export { JsonFormsCellRendererRegistryEntry };
60
+ export type { JsonFormsCellRendererRegistryEntry };
61
61
 
62
62
  export interface OwnPropsOfCell extends OwnPropsOfControl {
63
63
  data?: any;
@@ -24,8 +24,8 @@
24
24
  */
25
25
 
26
26
  import { ControlElement, JsonSchema, UISchemaElement } from '../models';
27
- import { resolveSchema } from './resolvers';
28
27
  import { findUISchema, JsonFormsUISchemaRegistryEntry } from '../reducers';
28
+ import { Resolve } from './util';
29
29
 
30
30
  export interface CombinatorSubSchemaRenderInfo {
31
31
  schema: JsonSchema;
@@ -47,24 +47,6 @@ const createLabel = (
47
47
  }
48
48
  };
49
49
 
50
- export const resolveSubSchemas = (
51
- schema: JsonSchema,
52
- rootSchema: JsonSchema,
53
- keyword: CombinatorKeyword
54
- ) => {
55
- // resolve any $refs, otherwise the generated UI schema can't match the schema???
56
- const schemas = schema[keyword] as any[];
57
- if (schemas.findIndex(e => e.$ref !== undefined) !== -1) {
58
- return {
59
- ...schema,
60
- [keyword]: (schema[keyword] as any[]).map(e =>
61
- e.$ref ? resolveSchema(rootSchema, e.$ref) : e
62
- )
63
- };
64
- }
65
- return schema;
66
- };
67
-
68
50
  export const createCombinatorRenderInfos = (
69
51
  combinatorSubSchemas: JsonSchema[],
70
52
  rootSchema: JsonSchema,
@@ -73,16 +55,19 @@ export const createCombinatorRenderInfos = (
73
55
  path: string,
74
56
  uischemas: JsonFormsUISchemaRegistryEntry[]
75
57
  ): CombinatorSubSchemaRenderInfo[] =>
76
- combinatorSubSchemas.map((subSchema, subSchemaIndex) => ({
77
- schema: subSchema,
78
- uischema: findUISchema(
79
- uischemas,
80
- subSchema,
81
- control.scope,
82
- path,
83
- undefined,
84
- control,
85
- rootSchema
86
- ),
87
- label: createLabel(subSchema, subSchemaIndex, keyword)
88
- }));
58
+ combinatorSubSchemas.map((subSchema, subSchemaIndex) => {
59
+ const schema = subSchema.$ref ? Resolve.schema(rootSchema, subSchema.$ref, rootSchema) : subSchema;
60
+ return {
61
+ schema,
62
+ uischema: findUISchema(
63
+ uischemas,
64
+ schema,
65
+ control.scope,
66
+ path,
67
+ undefined,
68
+ control,
69
+ rootSchema
70
+ ),
71
+ label: createLabel(subSchema, subSchemaIndex, keyword)
72
+ }
73
+ });
package/src/util/label.ts CHANGED
@@ -26,6 +26,7 @@
26
26
  import startCase from 'lodash/startCase';
27
27
 
28
28
  import { ControlElement, JsonSchema, LabelDescription } from '../models';
29
+ import { decode } from './path';
29
30
 
30
31
  const deriveLabel = (
31
32
  controlElement: ControlElement,
@@ -36,8 +37,7 @@ const deriveLabel = (
36
37
  }
37
38
  if (typeof controlElement.scope === 'string') {
38
39
  const ref = controlElement.scope;
39
- const label = ref.substr(ref.lastIndexOf('/') + 1);
40
-
40
+ const label = decode(ref.substr(ref.lastIndexOf('/') + 1));
41
41
  return startCase(label);
42
42
  }
43
43
 
package/src/util/path.ts CHANGED
@@ -57,14 +57,15 @@ export { compose as composePaths };
57
57
  */
58
58
  export const toDataPathSegments = (schemaPath: string): string[] => {
59
59
  const s = schemaPath
60
- .replace(/anyOf\/[\d]\//g, '')
61
- .replace(/allOf\/[\d]\//g, '')
62
- .replace(/oneOf\/[\d]\//g, '');
60
+ .replace(/(anyOf|allOf|oneOf)\/[\d]\//g, '')
61
+ .replace(/(then|else)\//g, '');
63
62
  const segments = s.split('/');
64
63
 
65
- const startFromRoot = segments[0] === '#' || segments[0] === '';
64
+ const decodedSegments = segments.map(decode);
65
+
66
+ const startFromRoot = decodedSegments[0] === '#' || decodedSegments[0] === '';
66
67
  const startIndex = startFromRoot ? 2 : 1;
67
- return range(startIndex, segments.length, 2).map(idx => segments[idx]);
68
+ return range(startIndex, decodedSegments.length, 2).map(idx => decodedSegments[idx]);
68
69
  };
69
70
 
70
71
  /**
@@ -77,7 +78,7 @@ export const toDataPathSegments = (schemaPath: string): string[] => {
77
78
  */
78
79
  export const toDataPath = (schemaPath: string): string => {
79
80
  return toDataPathSegments(schemaPath).join('.');
80
- };
81
+ };
81
82
 
82
83
  export const composeWithUi = (scopableUi: Scopable, path: string): string => {
83
84
  const segments = toDataPathSegments(scopableUi.scope);
@@ -88,3 +89,14 @@ export const composeWithUi = (scopableUi: Scopable, path: string): string => {
88
89
 
89
90
  return isEmpty(segments) ? path : compose(path, segments.join('.'));
90
91
  };
92
+
93
+ /**
94
+ * Encodes the given segment to be used as part of a JSON Pointer
95
+ *
96
+ * JSON Pointer has special meaning for "/" and "~", therefore these must be encoded
97
+ */
98
+ export const encode = (segment: string) => segment?.replace(/~/g, '~0').replace(/\//g, '~1');
99
+ /**
100
+ * Decodes a given JSON Pointer segment to its "normal" representation
101
+ */
102
+ export const decode = (pointerSegment: string) => pointerSegment?.replace(/~1/g, '/').replace(/~0/, '~');
@@ -26,6 +26,11 @@
26
26
  import get from 'lodash/get';
27
27
  import { ControlElement, JsonSchema, UISchemaElement } from '../models';
28
28
  import find from 'lodash/find';
29
+ import {
30
+ getUISchemas,
31
+ JsonFormsCellRendererRegistryEntry,
32
+ JsonFormsRendererRegistryEntry,
33
+ } from '../reducers';
29
34
  import {
30
35
  findUISchema,
31
36
  getAjv,
@@ -39,19 +44,16 @@ import {
39
44
  getSubErrorsAt,
40
45
  getTranslator,
41
46
  getUiSchema,
42
- JsonFormsCellRendererRegistryEntry,
43
- JsonFormsRendererRegistryEntry,
44
47
  JsonFormsUISchemaRegistryEntry,
45
48
  } from '../reducers';
46
49
  import { RankedTester } from '../testers';
47
- import { isInherentlyEnabled, hasShowRule } from './runtime';
50
+ import { hasShowRule, isInherentlyEnabled, isVisible } from './runtime';
48
51
  import { createLabelDescriptionFrom } from './label';
49
- import { CombinatorKeyword, resolveSubSchemas } from './combinators';
52
+ import { CombinatorKeyword } from './combinators';
50
53
  import { moveDown, moveUp } from './array';
51
54
  import { AnyAction, Dispatch } from './type';
52
55
  import { Resolve } from './util';
53
56
  import { composePaths, composeWithUi } from './path';
54
- import { isVisible } from './runtime';
55
57
  import { CoreActions, update } from '../actions';
56
58
  import { ErrorObject } from 'ajv';
57
59
  import { JsonFormsState } from '../store';
@@ -64,6 +66,7 @@ const isRequired = (
64
66
  ): boolean => {
65
67
  const pathSegments = schemaPath.split('/');
66
68
  const lastSegment = pathSegments[pathSegments.length - 1];
69
+ // Skip "properties", "items" etc. to resolve the parent
67
70
  const nextHigherSchemaSegments = pathSegments.slice(
68
71
  0,
69
72
  pathSegments.length - 2
@@ -86,17 +89,17 @@ const isRequired = (
86
89
  * Adds an asterisk to the given label string based
87
90
  * on the required parameter.
88
91
  *
89
- * @param {string} label the label string
92
+ * @param {string | undefined} label the label string
90
93
  * @param {boolean} required whether the label belongs to a control which is required
91
94
  * @param {boolean} hideRequiredAsterisk applied UI Schema option
92
95
  * @returns {string} the label string
93
96
  */
94
97
  export const computeLabel = (
95
- label: string,
98
+ label: string | undefined,
96
99
  required: boolean,
97
100
  hideRequiredAsterisk: boolean
98
101
  ): string => {
99
- return required && !hideRequiredAsterisk ? label + '*' : label;
102
+ return `${label ?? ''}${ required && !hideRequiredAsterisk ? '*' : ''}`;
100
103
  };
101
104
 
102
105
  /**
@@ -154,7 +157,7 @@ export const createDefaultValue = (schema: JsonSchema) => {
154
157
  */
155
158
  export const isDescriptionHidden = (
156
159
  visible: boolean,
157
- description: string,
160
+ description: string | undefined,
158
161
  isFocused: boolean,
159
162
  showUnfocusedDescription: boolean
160
163
  ): boolean => {
@@ -864,7 +867,8 @@ export const mapStateToLayoutProps = (
864
867
  data,
865
868
  uischema: ownProps.uischema,
866
869
  schema: ownProps.schema,
867
- direction: ownProps.direction ?? getDirection(uischema)
870
+ direction: ownProps.direction ?? getDirection(uischema),
871
+ config
868
872
  };
869
873
  };
870
874
 
@@ -912,7 +916,7 @@ export const controlDefaultProps = {
912
916
  errors: [] as string[]
913
917
  };
914
918
 
915
- export interface StatePropsOfCombinator extends OwnPropsOfControl {
919
+ export interface StatePropsOfCombinator extends StatePropsOfControl {
916
920
  rootSchema: JsonSchema;
917
921
  path: string;
918
922
  id: string;
@@ -926,25 +930,12 @@ export const mapStateToCombinatorRendererProps = (
926
930
  ownProps: OwnPropsOfControl,
927
931
  keyword: CombinatorKeyword
928
932
  ): StatePropsOfCombinator => {
929
- const { uischema } = ownProps;
930
- const path = composeWithUi(uischema, ownProps.path);
931
- const rootSchema = getSchema(state);
932
- const resolvedSchema = Resolve.schema(
933
- ownProps.schema || rootSchema,
934
- uischema.scope,
935
- rootSchema
933
+ const { data, schema, ...props } = mapStateToControlProps(
934
+ state,
935
+ ownProps
936
936
  );
937
- const visible: boolean =
938
- ownProps.visible === undefined || hasShowRule(uischema)
939
- ? isVisible(uischema, getData(state), ownProps.path, getAjv(state))
940
- : ownProps.visible;
941
- const id = ownProps.id;
942
-
943
- const data = Resolve.data(getData(state), path);
944
937
 
945
938
  const ajv = state.jsonforms.core.ajv;
946
- const schema = resolvedSchema || rootSchema;
947
- const _schema = resolveSubSchemas(schema, rootSchema, keyword);
948
939
  const structuralKeywords = [
949
940
  'required',
950
941
  'additionalProperties',
@@ -963,9 +954,9 @@ export const mapStateToCombinatorRendererProps = (
963
954
  // TODO instead of compiling the combinator subschemas we can compile the original schema
964
955
  // without the combinator alternatives and then revalidate and check the errors for the
965
956
  // element
966
- for (let i = 0; i < _schema[keyword].length; i++) {
957
+ for (let i = 0; i < schema[keyword]?.length; i++) {
967
958
  try {
968
- const valFn = ajv.compile(_schema[keyword][i]);
959
+ const valFn = ajv.compile(schema[keyword][i]);
969
960
  valFn(data);
970
961
  if (dataIsValid(valFn.errors)) {
971
962
  indexOfFittingSchema = i;
@@ -978,14 +969,10 @@ export const mapStateToCombinatorRendererProps = (
978
969
 
979
970
  return {
980
971
  data,
981
- path,
982
972
  schema,
983
- rootSchema,
984
- visible,
985
- id,
973
+ ...props,
986
974
  indexOfFittingSchema,
987
- uischemas: state.jsonforms.uischemas,
988
- uischema
975
+ uischemas: getUISchemas(state)
989
976
  };
990
977
  };
991
978
 
@@ -1043,7 +1030,6 @@ export const mapStateToArrayLayoutProps = (
1043
1030
 
1044
1031
  const resolvedSchema = Resolve.schema(schema, 'items', props.rootSchema);
1045
1032
 
1046
- // TODO Does not consider a specialized '.custom' error message overriding all other error messages
1047
1033
  // TODO Does not consider 'i18n' keys which are specified in the ui schemas of the sub errors
1048
1034
  const childErrors = getCombinedErrorMessage(
1049
1035
  getSubErrorsAt(path, resolvedSchema)(state),