@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.
- package/lib/jsonforms-core.cjs.js +22 -8
- package/lib/jsonforms-core.cjs.js.map +1 -1
- package/lib/jsonforms-core.esm.js +20 -8
- package/lib/jsonforms-core.esm.js.map +1 -1
- package/lib/models/uischema.d.ts +20 -1
- package/package.json +1 -1
- package/src/models/uischema.ts +23 -1
- package/src/util/resolvers.ts +5 -5
- package/src/util/runtime.ts +20 -3
package/lib/models/uischema.d.ts
CHANGED
|
@@ -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
package/src/models/uischema.ts
CHANGED
|
@@ -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.
|
package/src/util/resolvers.ts
CHANGED
|
@@ -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
|
|
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)) {
|
package/src/util/runtime.ts
CHANGED
|
@@ -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 = (
|