@jsonforms/core 3.1.0 → 3.2.0-alpha.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/i18n/combinatorTranslations.d.ts +14 -0
- package/lib/i18n/i18nUtil.d.ts +2 -0
- package/lib/i18n/index.d.ts +1 -0
- package/lib/jsonforms-core.cjs.js +59 -17
- package/lib/jsonforms-core.cjs.js.map +1 -1
- package/lib/jsonforms-core.esm.js +52 -16
- package/lib/jsonforms-core.esm.js.map +1 -1
- package/lib/models/uischema.d.ts +12 -0
- package/lib/util/renderer.d.ts +2 -1
- package/package.json +11 -11
- package/src/i18n/combinatorTranslations.ts +28 -0
- package/src/i18n/i18nUtil.ts +18 -0
- package/src/i18n/index.ts +1 -0
- package/src/models/uischema.ts +13 -0
- package/src/reducers/core.ts +14 -5
- package/src/util/combinators.ts +9 -16
- package/src/util/renderer.ts +17 -5
- package/src/util/runtime.ts +3 -0
package/lib/models/uischema.d.ts
CHANGED
|
@@ -93,6 +93,18 @@ export interface LeafCondition extends Condition, Scoped {
|
|
|
93
93
|
}
|
|
94
94
|
export interface SchemaBasedCondition extends Condition, Scoped {
|
|
95
95
|
schema: JsonSchema;
|
|
96
|
+
/**
|
|
97
|
+
* When the scope resolves to undefined and `failWhenUndefined` is set to `true`, the condition
|
|
98
|
+
* will fail. Therefore the reverse effect will be applied.
|
|
99
|
+
*
|
|
100
|
+
* Background:
|
|
101
|
+
* Most JSON Schemas will successfully validate against `undefined` data. Specifying that a
|
|
102
|
+
* condition shall fail when data is `undefined` requires to lift the scope to being able to use
|
|
103
|
+
* JSON Schema's `required`.
|
|
104
|
+
*
|
|
105
|
+
* Using `failWhenUndefined` allows to more conveniently express this condition.
|
|
106
|
+
*/
|
|
107
|
+
failWhenUndefined?: boolean;
|
|
96
108
|
}
|
|
97
109
|
/**
|
|
98
110
|
* A composable condition.
|
package/lib/util/renderer.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { AnyAction, Dispatch } from './type';
|
|
|
6
6
|
import { CoreActions } from '../actions';
|
|
7
7
|
import type { ErrorObject } from 'ajv';
|
|
8
8
|
import type { JsonFormsState } from '../store';
|
|
9
|
-
import { Translator } from '../i18n';
|
|
9
|
+
import { Translator, CombinatorTranslations } from '../i18n';
|
|
10
10
|
import { ArrayTranslations } from '../i18n/arrayTranslations';
|
|
11
11
|
/**
|
|
12
12
|
* Adds an asterisk to the given label string based
|
|
@@ -375,6 +375,7 @@ export interface StatePropsOfCombinator extends StatePropsOfControl {
|
|
|
375
375
|
indexOfFittingSchema: number;
|
|
376
376
|
uischemas: JsonFormsUISchemaRegistryEntry[];
|
|
377
377
|
data: any;
|
|
378
|
+
translations: CombinatorTranslations;
|
|
378
379
|
}
|
|
379
380
|
export declare const mapStateToCombinatorRendererProps: (state: JsonFormsState, ownProps: OwnPropsOfControl, keyword: CombinatorKeyword) => StatePropsOfCombinator;
|
|
380
381
|
export interface CombinatorRendererProps extends StatePropsOfCombinator, DispatchPropsOfControl {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsonforms/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0-alpha.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",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"lint": "eslint .",
|
|
43
43
|
"lint:fix": "eslint --fix .",
|
|
44
44
|
"report": "nyc report --reporter=html",
|
|
45
|
-
"test": "
|
|
46
|
-
"test-cov": "rimraf -rf .nyc_output &&
|
|
47
|
-
"doc": "typedoc --name 'JSON Forms Core' --
|
|
45
|
+
"test": "ava",
|
|
46
|
+
"test-cov": "rimraf -rf .nyc_output && nyc ava",
|
|
47
|
+
"doc": "typedoc --name 'JSON Forms Core' --excludeExternals --theme ../../typedoc-jsonforms --out docs src"
|
|
48
48
|
},
|
|
49
49
|
"ava": {
|
|
50
50
|
"files": [
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"ts"
|
|
56
56
|
],
|
|
57
57
|
"require": [
|
|
58
|
-
"ts-node
|
|
58
|
+
"./test-config/ts-node.config.js",
|
|
59
59
|
"source-map-support/register"
|
|
60
60
|
]
|
|
61
61
|
},
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"@types/json-schema": "^7.0.3",
|
|
70
70
|
"ajv": "^8.6.1",
|
|
71
71
|
"ajv-formats": "^2.1.0",
|
|
72
|
-
"lodash": "^4.17.
|
|
72
|
+
"lodash": "^4.17.21"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
|
@@ -77,13 +77,12 @@
|
|
|
77
77
|
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
|
78
78
|
"@typescript-eslint/parser": "^5.54.1",
|
|
79
79
|
"ava": "~2.4.0",
|
|
80
|
-
"cross-env": "^7.0.2",
|
|
81
80
|
"document-register-element": "^1.14.3",
|
|
82
81
|
"eslint": "^7.32.0",
|
|
83
82
|
"eslint-config-prettier": "^8.7.0",
|
|
84
83
|
"eslint-plugin-import": "^2.27.5",
|
|
85
84
|
"eslint-plugin-prettier": "^4.2.1",
|
|
86
|
-
"jsdom": "^
|
|
85
|
+
"jsdom": "^22.0.0",
|
|
87
86
|
"jsdom-global": "^3.0.2",
|
|
88
87
|
"nyc": "^15.1.0",
|
|
89
88
|
"prettier": "^2.8.4",
|
|
@@ -92,12 +91,13 @@
|
|
|
92
91
|
"rimraf": "^3.0.2",
|
|
93
92
|
"rollup": "^2.78.0",
|
|
94
93
|
"rollup-plugin-cleanup": "^3.2.1",
|
|
95
|
-
"rollup-plugin-typescript2": "^0.
|
|
94
|
+
"rollup-plugin-typescript2": "^0.34.1",
|
|
96
95
|
"rollup-plugin-visualizer": "^5.4.1",
|
|
97
96
|
"source-map-support": "0.5.16",
|
|
98
97
|
"ts-node": "^10.4.0",
|
|
99
|
-
"
|
|
98
|
+
"tslib": "^2.5.0",
|
|
99
|
+
"typedoc": "~0.21.9",
|
|
100
100
|
"typescript": "4.2.3"
|
|
101
101
|
},
|
|
102
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "9146b0fdf5913d2251fadd5435d2c7e813db6f71"
|
|
103
103
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface CombinatorDefaultTranslation {
|
|
2
|
+
key: CombinatorTranslationEnum;
|
|
3
|
+
default: (variable?: string) => string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export enum CombinatorTranslationEnum {
|
|
7
|
+
clearDialogTitle = 'clearDialogTitle',
|
|
8
|
+
clearDialogMessage = 'clearDialogMessage',
|
|
9
|
+
clearDialogAccept = 'clearDialogAccept',
|
|
10
|
+
clearDialogDecline = 'clearDialogDecline',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type CombinatorTranslations = {
|
|
14
|
+
[key in CombinatorTranslationEnum]?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const combinatorDefaultTranslations: CombinatorDefaultTranslation[] = [
|
|
18
|
+
{
|
|
19
|
+
key: CombinatorTranslationEnum.clearDialogTitle,
|
|
20
|
+
default: () => 'Clear form?',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
key: CombinatorTranslationEnum.clearDialogMessage,
|
|
24
|
+
default: () => 'Your data will be cleared. Do you want to proceed?',
|
|
25
|
+
},
|
|
26
|
+
{ key: CombinatorTranslationEnum.clearDialogAccept, default: () => 'Yes' },
|
|
27
|
+
{ key: CombinatorTranslationEnum.clearDialogDecline, default: () => 'No' },
|
|
28
|
+
];
|
package/src/i18n/i18nUtil.ts
CHANGED
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
ArrayDefaultTranslation,
|
|
8
8
|
ArrayTranslations,
|
|
9
9
|
} from './arrayTranslations';
|
|
10
|
+
import {
|
|
11
|
+
CombinatorDefaultTranslation,
|
|
12
|
+
CombinatorTranslations,
|
|
13
|
+
} from './combinatorTranslations';
|
|
10
14
|
|
|
11
15
|
export const getI18nKeyPrefixBySchema = (
|
|
12
16
|
schema: i18nJsonSchema | undefined,
|
|
@@ -173,3 +177,17 @@ export const getArrayTranslations = (
|
|
|
173
177
|
});
|
|
174
178
|
return translations;
|
|
175
179
|
};
|
|
180
|
+
|
|
181
|
+
export const getCombinatorTranslations = (
|
|
182
|
+
t: Translator,
|
|
183
|
+
defaultTranslations: CombinatorDefaultTranslation[],
|
|
184
|
+
i18nKeyPrefix: string,
|
|
185
|
+
label: string
|
|
186
|
+
): CombinatorTranslations => {
|
|
187
|
+
const translations: CombinatorTranslations = {};
|
|
188
|
+
defaultTranslations.forEach((controlElement) => {
|
|
189
|
+
const key = addI18nKeyToPrefix(i18nKeyPrefix, controlElement.key);
|
|
190
|
+
translations[controlElement.key] = t(key, controlElement.default(label));
|
|
191
|
+
});
|
|
192
|
+
return translations;
|
|
193
|
+
};
|
package/src/i18n/index.ts
CHANGED
package/src/models/uischema.ts
CHANGED
|
@@ -135,6 +135,19 @@ export interface LeafCondition extends Condition, Scoped {
|
|
|
135
135
|
|
|
136
136
|
export interface SchemaBasedCondition extends Condition, Scoped {
|
|
137
137
|
schema: JsonSchema;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* When the scope resolves to undefined and `failWhenUndefined` is set to `true`, the condition
|
|
141
|
+
* will fail. Therefore the reverse effect will be applied.
|
|
142
|
+
*
|
|
143
|
+
* Background:
|
|
144
|
+
* Most JSON Schemas will successfully validate against `undefined` data. Specifying that a
|
|
145
|
+
* condition shall fail when data is `undefined` requires to lift the scope to being able to use
|
|
146
|
+
* JSON Schema's `required`.
|
|
147
|
+
*
|
|
148
|
+
* Using `failWhenUndefined` allows to more conveniently express this condition.
|
|
149
|
+
*/
|
|
150
|
+
failWhenUndefined?: boolean;
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
/**
|
package/src/reducers/core.ts
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import cloneDeep from 'lodash/cloneDeep';
|
|
27
27
|
import setFp from 'lodash/fp/set';
|
|
28
|
+
import unsetFp from 'lodash/fp/unset';
|
|
28
29
|
import get from 'lodash/get';
|
|
29
30
|
import filter from 'lodash/filter';
|
|
30
31
|
import isEqual from 'lodash/isEqual';
|
|
@@ -285,11 +286,19 @@ export const coreReducer: Reducer<JsonFormsCore, CoreActions> = (
|
|
|
285
286
|
} else {
|
|
286
287
|
const oldData: any = get(state.data, action.path);
|
|
287
288
|
const newData = action.updater(cloneDeep(oldData));
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
289
|
+
let newState: any;
|
|
290
|
+
if (newData !== undefined) {
|
|
291
|
+
newState = setFp(
|
|
292
|
+
action.path,
|
|
293
|
+
newData,
|
|
294
|
+
state.data === undefined ? {} : state.data
|
|
295
|
+
);
|
|
296
|
+
} else {
|
|
297
|
+
newState = unsetFp(
|
|
298
|
+
action.path,
|
|
299
|
+
state.data === undefined ? {} : state.data
|
|
300
|
+
);
|
|
301
|
+
}
|
|
293
302
|
const errors = validate(state.validator, newState);
|
|
294
303
|
return {
|
|
295
304
|
...state,
|
package/src/util/combinators.ts
CHANGED
|
@@ -35,18 +35,6 @@ export interface CombinatorSubSchemaRenderInfo {
|
|
|
35
35
|
|
|
36
36
|
export type CombinatorKeyword = 'anyOf' | 'oneOf' | 'allOf';
|
|
37
37
|
|
|
38
|
-
const createLabel = (
|
|
39
|
-
subSchema: JsonSchema,
|
|
40
|
-
subSchemaIndex: number,
|
|
41
|
-
keyword: CombinatorKeyword
|
|
42
|
-
): string => {
|
|
43
|
-
if (subSchema.title) {
|
|
44
|
-
return subSchema.title;
|
|
45
|
-
} else {
|
|
46
|
-
return keyword + '-' + subSchemaIndex;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
38
|
export const createCombinatorRenderInfos = (
|
|
51
39
|
combinatorSubSchemas: JsonSchema[],
|
|
52
40
|
rootSchema: JsonSchema,
|
|
@@ -56,9 +44,11 @@ export const createCombinatorRenderInfos = (
|
|
|
56
44
|
uischemas: JsonFormsUISchemaRegistryEntry[]
|
|
57
45
|
): CombinatorSubSchemaRenderInfo[] =>
|
|
58
46
|
combinatorSubSchemas.map((subSchema, subSchemaIndex) => {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
const resolvedSubSchema =
|
|
48
|
+
subSchema.$ref && Resolve.schema(rootSchema, subSchema.$ref, rootSchema);
|
|
49
|
+
|
|
50
|
+
const schema = resolvedSubSchema ?? subSchema;
|
|
51
|
+
|
|
62
52
|
return {
|
|
63
53
|
schema,
|
|
64
54
|
uischema: findUISchema(
|
|
@@ -70,6 +60,9 @@ export const createCombinatorRenderInfos = (
|
|
|
70
60
|
control,
|
|
71
61
|
rootSchema
|
|
72
62
|
),
|
|
73
|
-
label:
|
|
63
|
+
label:
|
|
64
|
+
subSchema.title ??
|
|
65
|
+
resolvedSubSchema?.title ??
|
|
66
|
+
`${keyword}-${subSchemaIndex}`,
|
|
74
67
|
};
|
|
75
68
|
});
|
package/src/util/renderer.ts
CHANGED
|
@@ -70,6 +70,9 @@ import {
|
|
|
70
70
|
getI18nKeyPrefixBySchema,
|
|
71
71
|
getArrayTranslations,
|
|
72
72
|
Translator,
|
|
73
|
+
CombinatorTranslations,
|
|
74
|
+
getCombinatorTranslations,
|
|
75
|
+
combinatorDefaultTranslations,
|
|
73
76
|
} from '../i18n';
|
|
74
77
|
import {
|
|
75
78
|
arrayDefaultTranslations,
|
|
@@ -796,7 +799,7 @@ export const mapDispatchToArrayControlProps = (
|
|
|
796
799
|
dispatch(
|
|
797
800
|
update(path, (array) => {
|
|
798
801
|
toDelete
|
|
799
|
-
.sort()
|
|
802
|
+
.sort((a, b) => a - b)
|
|
800
803
|
.reverse()
|
|
801
804
|
.forEach((s) => array.splice(s, 1));
|
|
802
805
|
return array;
|
|
@@ -970,6 +973,7 @@ export interface StatePropsOfCombinator extends StatePropsOfControl {
|
|
|
970
973
|
indexOfFittingSchema: number;
|
|
971
974
|
uischemas: JsonFormsUISchemaRegistryEntry[];
|
|
972
975
|
data: any;
|
|
976
|
+
translations: CombinatorTranslations;
|
|
973
977
|
}
|
|
974
978
|
|
|
975
979
|
export const mapStateToCombinatorRendererProps = (
|
|
@@ -977,12 +981,17 @@ export const mapStateToCombinatorRendererProps = (
|
|
|
977
981
|
ownProps: OwnPropsOfControl,
|
|
978
982
|
keyword: CombinatorKeyword
|
|
979
983
|
): StatePropsOfCombinator => {
|
|
980
|
-
const { data, schema, rootSchema, ...props } =
|
|
981
|
-
state,
|
|
982
|
-
ownProps
|
|
983
|
-
);
|
|
984
|
+
const { data, schema, rootSchema, i18nKeyPrefix, label, ...props } =
|
|
985
|
+
mapStateToControlProps(state, ownProps);
|
|
984
986
|
|
|
985
987
|
const ajv = state.jsonforms.core.ajv;
|
|
988
|
+
const t = getTranslator()(state);
|
|
989
|
+
const translations = getCombinatorTranslations(
|
|
990
|
+
t,
|
|
991
|
+
combinatorDefaultTranslations,
|
|
992
|
+
i18nKeyPrefix,
|
|
993
|
+
label
|
|
994
|
+
);
|
|
986
995
|
const structuralKeywords = [
|
|
987
996
|
'required',
|
|
988
997
|
'additionalProperties',
|
|
@@ -1025,8 +1034,11 @@ export const mapStateToCombinatorRendererProps = (
|
|
|
1025
1034
|
schema,
|
|
1026
1035
|
rootSchema,
|
|
1027
1036
|
...props,
|
|
1037
|
+
i18nKeyPrefix,
|
|
1038
|
+
label,
|
|
1028
1039
|
indexOfFittingSchema,
|
|
1029
1040
|
uischemas: getUISchemas(state),
|
|
1041
|
+
translations,
|
|
1030
1042
|
};
|
|
1031
1043
|
};
|
|
1032
1044
|
|
package/src/util/runtime.ts
CHANGED
|
@@ -79,6 +79,9 @@ const evaluateCondition = (
|
|
|
79
79
|
return value === condition.expectedValue;
|
|
80
80
|
} else if (isSchemaCondition(condition)) {
|
|
81
81
|
const value = resolveData(data, getConditionScope(condition, path));
|
|
82
|
+
if (condition.failWhenUndefined && value === undefined) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
82
85
|
return ajv.validate(condition.schema, value) as boolean;
|
|
83
86
|
} else {
|
|
84
87
|
// unknown condition
|