@jsonforms/core 3.6.0-alpha.1 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -106,6 +106,25 @@ export interface SchemaBasedCondition extends BaseCondition, Scoped {
106
106
  */
107
107
  failWhenUndefined?: boolean;
108
108
  }
109
+ /** A condition using a validation function to determine its fulfillment. */
110
+ export interface ValidateFunctionCondition extends BaseCondition, Scoped {
111
+ /**
112
+ * Validates whether the condition is fulfilled.
113
+ *
114
+ * @param data The data as resolved via the scope.
115
+ * @returns `true` if the condition is fulfilled */
116
+ validate: (context: ValidateFunctionContext) => boolean;
117
+ }
118
+ export interface ValidateFunctionContext {
119
+ /** The resolved data scoped to the `ValidateFunctionCondition`'s scope. */
120
+ data: unknown;
121
+ /** The full data of the form. */
122
+ fullData: unknown;
123
+ /** Optional instance path. Necessary when the actual data path can not be inferred via the scope alone as it is the case with nested controls. */
124
+ path: string | undefined;
125
+ /** The `UISchemaElement` containing the rule that uses the ValidateFunctionCondition, e.g. a `ControlElement` */
126
+ uischemaElement: UISchemaElement;
127
+ }
109
128
  /**
110
129
  * A composable condition.
111
130
  */
@@ -127,7 +146,7 @@ export interface AndCondition extends ComposableCondition {
127
146
  /**
128
147
  * A union of all available conditions.
129
148
  */
130
- export type Condition = BaseCondition | LeafCondition | OrCondition | AndCondition | SchemaBasedCondition;
149
+ export type Condition = BaseCondition | LeafCondition | OrCondition | AndCondition | SchemaBasedCondition | ValidateFunctionCondition;
131
150
  /**
132
151
  * Common base interface for any UI schema element.
133
152
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsonforms/core",
3
- "version": "3.6.0-alpha.1",
3
+ "version": "3.6.0",
4
4
  "description": "Core module of JSON Forms",
5
5
  "repository": "https://github.com/eclipsesource/jsonforms",
6
6
  "bugs": "https://github.com/eclipsesource/jsonforms/issues",
@@ -150,6 +150,27 @@ export interface SchemaBasedCondition extends BaseCondition, Scoped {
150
150
  failWhenUndefined?: boolean;
151
151
  }
152
152
 
153
+ /** A condition using a validation function to determine its fulfillment. */
154
+ export interface ValidateFunctionCondition extends BaseCondition, Scoped {
155
+ /**
156
+ * Validates whether the condition is fulfilled.
157
+ *
158
+ * @param data The data as resolved via the scope.
159
+ * @returns `true` if the condition is fulfilled */
160
+ validate: (context: ValidateFunctionContext) => boolean;
161
+ }
162
+
163
+ export interface ValidateFunctionContext {
164
+ /** The resolved data scoped to the `ValidateFunctionCondition`'s scope. */
165
+ data: unknown;
166
+ /** The full data of the form. */
167
+ fullData: unknown;
168
+ /** Optional instance path. Necessary when the actual data path can not be inferred via the scope alone as it is the case with nested controls. */
169
+ path: string | undefined;
170
+ /** The `UISchemaElement` containing the rule that uses the ValidateFunctionCondition, e.g. a `ControlElement` */
171
+ uischemaElement: UISchemaElement;
172
+ }
173
+
153
174
  /**
154
175
  * A composable condition.
155
176
  */
@@ -179,7 +200,8 @@ export type Condition =
179
200
  | LeafCondition
180
201
  | OrCondition
181
202
  | AndCondition
182
- | SchemaBasedCondition;
203
+ | SchemaBasedCondition
204
+ | ValidateFunctionCondition;
183
205
 
184
206
  /**
185
207
  * Common base interface for any UI schema element.
@@ -123,12 +123,8 @@ const resolveSchemaWithSegments = (
123
123
  pathSegments: string[],
124
124
  rootSchema: JsonSchema
125
125
  ): JsonSchema => {
126
- if (isEmpty(schema)) {
127
- return undefined;
128
- }
129
-
130
126
  // use typeof because schema can by of any type - check singleSegmentResolveSchema below
131
- if (typeof schema.$ref === 'string') {
127
+ if (typeof schema?.$ref === 'string') {
132
128
  schema = resolveSchema(rootSchema, schema.$ref, rootSchema);
133
129
  }
134
130
 
@@ -136,6 +132,10 @@ const resolveSchemaWithSegments = (
136
132
  return schema;
137
133
  }
138
134
 
135
+ if (isEmpty(schema)) {
136
+ return undefined;
137
+ }
138
+
139
139
  const [segment, ...remainingSegments] = pathSegments;
140
140
 
141
141
  if (invalidSegment(segment)) {
@@ -33,6 +33,7 @@ import {
33
33
  SchemaBasedCondition,
34
34
  Scopable,
35
35
  UISchemaElement,
36
+ ValidateFunctionCondition,
36
37
  } from '../models';
37
38
  import { resolveData } from './resolvers';
38
39
  import type Ajv from 'ajv';
@@ -51,24 +52,31 @@ const isSchemaCondition = (
51
52
  condition: Condition
52
53
  ): condition is SchemaBasedCondition => has(condition, 'schema');
53
54
 
55
+ const isValidateFunctionCondition = (
56
+ condition: Condition
57
+ ): condition is ValidateFunctionCondition =>
58
+ has(condition, 'validate') &&
59
+ typeof (condition as ValidateFunctionCondition).validate === 'function';
60
+
54
61
  const getConditionScope = (condition: Scopable, path: string): string => {
55
62
  return composeWithUi(condition, path);
56
63
  };
57
64
 
58
65
  const evaluateCondition = (
59
66
  data: any,
67
+ uischema: UISchemaElement,
60
68
  condition: Condition,
61
69
  path: string,
62
70
  ajv: Ajv
63
71
  ): boolean => {
64
72
  if (isAndCondition(condition)) {
65
73
  return condition.conditions.reduce(
66
- (acc, cur) => acc && evaluateCondition(data, cur, path, ajv),
74
+ (acc, cur) => acc && evaluateCondition(data, uischema, cur, path, ajv),
67
75
  true
68
76
  );
69
77
  } else if (isOrCondition(condition)) {
70
78
  return condition.conditions.reduce(
71
- (acc, cur) => acc || evaluateCondition(data, cur, path, ajv),
79
+ (acc, cur) => acc || evaluateCondition(data, uischema, cur, path, ajv),
72
80
  false
73
81
  );
74
82
  } else if (isLeafCondition(condition)) {
@@ -80,6 +88,15 @@ const evaluateCondition = (
80
88
  return false;
81
89
  }
82
90
  return ajv.validate(condition.schema, value) as boolean;
91
+ } else if (isValidateFunctionCondition(condition)) {
92
+ const value = resolveData(data, getConditionScope(condition, path));
93
+ const context = {
94
+ data: value,
95
+ fullData: data,
96
+ path,
97
+ uischemaElement: uischema,
98
+ };
99
+ return condition.validate(context);
83
100
  } else {
84
101
  // unknown condition
85
102
  return true;
@@ -93,7 +110,7 @@ const isRuleFulfilled = (
93
110
  ajv: Ajv
94
111
  ): boolean => {
95
112
  const condition = uischema.rule.condition;
96
- return evaluateCondition(data, condition, path, ajv);
113
+ return evaluateCondition(data, uischema, condition, path, ajv);
97
114
  };
98
115
 
99
116
  export const evalVisibility = (