@jsonforms/core 3.0.0-beta.1 → 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.
- package/docs/assets/js/search.json +1 -1
- package/docs/globals.html +203 -161
- package/docs/index.html +7 -4
- package/docs/interfaces/arraycontrolprops.html +21 -21
- package/docs/interfaces/arraylayoutprops.html +21 -21
- package/docs/interfaces/cellprops.html +12 -12
- package/docs/interfaces/combinatorrendererprops.html +143 -36
- package/docs/interfaces/controlprops.html +16 -16
- package/docs/interfaces/controlstate.html +2 -2
- package/docs/interfaces/controlwithdetailprops.html +17 -17
- package/docs/interfaces/dispatchcellprops.html +10 -10
- package/docs/interfaces/dispatchcellstateprops.html +10 -10
- package/docs/interfaces/dispatchpropsofarraycontrol.html +4 -4
- package/docs/interfaces/dispatchpropsofcontrol.html +1 -1
- package/docs/interfaces/dispatchpropsofmultienumcontrol.html +2 -2
- package/docs/interfaces/enumcellprops.html +13 -13
- package/docs/interfaces/enumoption.html +2 -2
- package/docs/interfaces/jsonformsprops.html +9 -9
- package/docs/interfaces/layoutprops.html +10 -10
- package/docs/interfaces/ownpropsofcell.html +9 -9
- package/docs/interfaces/ownpropsofcontrol.html +9 -12
- package/docs/interfaces/ownpropsofenum.html +1 -1
- package/docs/interfaces/ownpropsofenumcell.html +10 -10
- package/docs/interfaces/ownpropsofjsonformsrenderer.html +8 -8
- package/docs/interfaces/ownpropsoflayout.html +9 -9
- package/docs/interfaces/ownpropsofmasterlistitem.html +6 -6
- package/docs/interfaces/ownpropsofrenderer.html +8 -8
- package/docs/interfaces/rendererprops.html +9 -9
- package/docs/interfaces/statepropsofarraycontrol.html +17 -17
- package/docs/interfaces/statepropsofarraylayout.html +17 -17
- package/docs/interfaces/statepropsofcell.html +11 -11
- package/docs/interfaces/statepropsofcombinator.html +147 -40
- package/docs/interfaces/statepropsofcontrol.html +18 -15
- package/docs/interfaces/statepropsofcontrolwithdetail.html +16 -16
- package/docs/interfaces/statepropsofenumcell.html +12 -12
- package/docs/interfaces/statepropsofjsonformsrenderer.html +9 -9
- package/docs/interfaces/statepropsoflayout.html +10 -10
- package/docs/interfaces/statepropsofmasteritem.html +7 -7
- package/docs/interfaces/statepropsofrenderer.html +9 -9
- package/docs/interfaces/statepropsofscopedrenderer.html +12 -12
- package/docs/interfaces/withclassname.html +1 -1
- package/lib/jsonforms-core.cjs.js +160 -164
- package/lib/jsonforms-core.cjs.js.map +1 -1
- package/lib/jsonforms-core.esm.js +142 -154
- package/lib/jsonforms-core.esm.js.map +1 -1
- package/lib/reducers/reducers.d.ts +2 -2
- package/lib/testers/testers.d.ts +8 -7
- package/lib/util/combinators.d.ts +0 -1
- package/lib/util/path.d.ts +10 -0
- package/lib/util/renderer.d.ts +2 -2
- package/lib/util/resolvers.d.ts +1 -1
- package/lib/util/util.d.ts +1 -1
- package/package.json +2 -2
- package/src/generators/uischema.ts +4 -4
- package/src/reducers/reducers.ts +12 -4
- package/src/testers/testers.ts +60 -33
- package/src/util/combinators.ts +17 -32
- package/src/util/label.ts +2 -2
- package/src/util/path.ts +18 -6
- package/src/util/renderer.ts +14 -29
- package/src/util/resolvers.ts +57 -68
- package/src/util/util.ts +1 -1
- package/stats.html +1 -1
- package/test/generators/uischema.test.ts +18 -0
- package/test/testers.test.ts +208 -120
- package/test/util/path.test.ts +37 -20
- package/test/util/resolvers.test.ts +99 -8
|
@@ -17,10 +17,10 @@ export declare const jsonFormsReducerConfig: {
|
|
|
17
17
|
* @param schema the JSON schema describing the data to be rendered
|
|
18
18
|
* @param schemaPath the according schema path
|
|
19
19
|
* @param path the instance path
|
|
20
|
-
* @param
|
|
20
|
+
* @param fallback the type of the layout to use or a UI-schema-generator function
|
|
21
21
|
* @param control may be checked for embedded inline uischema options
|
|
22
22
|
*/
|
|
23
|
-
export declare const findUISchema: (uischemas: JsonFormsUISchemaRegistryEntry[], schema: JsonSchema, schemaPath: string, path: string,
|
|
23
|
+
export declare const findUISchema: (uischemas: JsonFormsUISchemaRegistryEntry[], schema: JsonSchema, schemaPath: string, path: string, fallback?: string | (() => UISchemaElement), control?: ControlElement, rootSchema?: JsonSchema) => UISchemaElement;
|
|
24
24
|
export declare const getErrorAt: (instancePath: string, schema: JsonSchema) => (state: JsonFormsState) => import("ajv").ErrorObject<string, Record<string, any>, unknown>[];
|
|
25
25
|
export declare const getSubErrorsAt: (instancePath: string, schema: JsonSchema) => (state: JsonFormsState) => import("ajv").ErrorObject<string, Record<string, any>, unknown>[];
|
|
26
26
|
export declare const getConfig: (state: JsonFormsState) => any;
|
package/lib/testers/testers.d.ts
CHANGED
|
@@ -7,12 +7,13 @@ import { Categorization, ControlElement, JsonSchema, UISchemaElement } from '../
|
|
|
7
7
|
export declare const NOT_APPLICABLE = -1;
|
|
8
8
|
/**
|
|
9
9
|
* A tester is a function that receives an UI schema and a JSON schema and returns a boolean.
|
|
10
|
+
* The rootSchema is handed over as context. Can be used to resolve references.
|
|
10
11
|
*/
|
|
11
|
-
export declare type Tester = (uischema: UISchemaElement, schema: JsonSchema) => boolean;
|
|
12
|
+
export declare type Tester = (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema) => boolean;
|
|
12
13
|
/**
|
|
13
14
|
* A ranked tester associates a tester with a number.
|
|
14
15
|
*/
|
|
15
|
-
export declare type RankedTester = (uischema: UISchemaElement, schema: JsonSchema) => number;
|
|
16
|
+
export declare type RankedTester = (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema) => number;
|
|
16
17
|
export declare const isControl: (uischema: any) => uischema is ControlElement;
|
|
17
18
|
/**
|
|
18
19
|
* Only applicable for Controls.
|
|
@@ -24,8 +25,8 @@ export declare const isControl: (uischema: any) => uischema is ControlElement;
|
|
|
24
25
|
* @param {(JsonSchema) => boolean} predicate the predicate that should be
|
|
25
26
|
* applied to the resolved sub-schema
|
|
26
27
|
*/
|
|
27
|
-
export declare const schemaMatches: (predicate: (schema: JsonSchema) => boolean) => Tester;
|
|
28
|
-
export declare const schemaSubPathMatches: (subPath: string, predicate: (schema: JsonSchema) => boolean) => Tester;
|
|
28
|
+
export declare const schemaMatches: (predicate: (schema: JsonSchema, rootSchema: JsonSchema) => boolean) => Tester;
|
|
29
|
+
export declare const schemaSubPathMatches: (subPath: string, predicate: (schema: JsonSchema, rootSchema: JsonSchema) => boolean) => Tester;
|
|
29
30
|
/**
|
|
30
31
|
* Only applicable for Controls.
|
|
31
32
|
*
|
|
@@ -96,8 +97,8 @@ export declare const or: (...testers: Tester[]) => Tester;
|
|
|
96
97
|
* @param {number} rank the rank to be returned in case the tester returns true
|
|
97
98
|
* @param {Tester} tester a tester
|
|
98
99
|
*/
|
|
99
|
-
export declare const rankWith: (rank: number, tester: Tester) => (uischema: UISchemaElement, schema: JsonSchema) => number;
|
|
100
|
-
export declare const withIncreasedRank: (by: number, rankedTester: RankedTester) => (uischema: UISchemaElement, schema: JsonSchema) => number;
|
|
100
|
+
export declare const rankWith: (rank: number, tester: Tester) => (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema) => number;
|
|
101
|
+
export declare const withIncreasedRank: (by: number, rankedTester: RankedTester) => (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema) => number;
|
|
101
102
|
/**
|
|
102
103
|
* Default tester for boolean.
|
|
103
104
|
* @type {RankedTester}
|
|
@@ -172,7 +173,7 @@ export declare const isObjectArray: Tester;
|
|
|
172
173
|
* @type {Tester}
|
|
173
174
|
*/
|
|
174
175
|
export declare const isObjectArrayControl: Tester;
|
|
175
|
-
export declare const isObjectArrayWithNesting: (uischema: UISchemaElement, schema: JsonSchema) => boolean;
|
|
176
|
+
export declare const isObjectArrayWithNesting: (uischema: UISchemaElement, schema: JsonSchema, rootSchema: JsonSchema) => boolean;
|
|
176
177
|
/**
|
|
177
178
|
* Synonym for isObjectArrayControl
|
|
178
179
|
*/
|
|
@@ -6,5 +6,4 @@ export interface CombinatorSubSchemaRenderInfo {
|
|
|
6
6
|
label: string;
|
|
7
7
|
}
|
|
8
8
|
export declare type CombinatorKeyword = 'anyOf' | 'oneOf' | 'allOf';
|
|
9
|
-
export declare const resolveSubSchemas: (schema: JsonSchema, rootSchema: JsonSchema, keyword: CombinatorKeyword) => JsonSchema;
|
|
10
9
|
export declare const createCombinatorRenderInfos: (combinatorSubSchemas: JsonSchema[], rootSchema: JsonSchema, keyword: CombinatorKeyword, control: ControlElement, path: string, uischemas: JsonFormsUISchemaRegistryEntry[]) => CombinatorSubSchemaRenderInfo[];
|
package/lib/util/path.d.ts
CHANGED
|
@@ -23,3 +23,13 @@ export declare const toDataPathSegments: (schemaPath: string) => string[];
|
|
|
23
23
|
*/
|
|
24
24
|
export declare const toDataPath: (schemaPath: string) => string;
|
|
25
25
|
export declare const composeWithUi: (scopableUi: Scopable, path: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Encodes the given segment to be used as part of a JSON Pointer
|
|
28
|
+
*
|
|
29
|
+
* JSON Pointer has special meaning for "/" and "~", therefore these must be encoded
|
|
30
|
+
*/
|
|
31
|
+
export declare const encode: (segment: string) => string;
|
|
32
|
+
/**
|
|
33
|
+
* Decodes a given JSON Pointer segment to its "normal" representation
|
|
34
|
+
*/
|
|
35
|
+
export declare const decode: (pointerSegment: string) => string;
|
package/lib/util/renderer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ControlElement, JsonSchema, UISchemaElement } from '../models';
|
|
2
|
-
import
|
|
2
|
+
import { JsonFormsCellRendererRegistryEntry, JsonFormsRendererRegistryEntry } from '../reducers';
|
|
3
3
|
import { JsonFormsUISchemaRegistryEntry } from '../reducers';
|
|
4
4
|
import { RankedTester } from '../testers';
|
|
5
5
|
import { CombinatorKeyword } from './combinators';
|
|
@@ -359,7 +359,7 @@ export declare const controlDefaultProps: {
|
|
|
359
359
|
path: string;
|
|
360
360
|
direction: 'row' | 'column';
|
|
361
361
|
};
|
|
362
|
-
export interface StatePropsOfCombinator extends
|
|
362
|
+
export interface StatePropsOfCombinator extends StatePropsOfControl {
|
|
363
363
|
rootSchema: JsonSchema;
|
|
364
364
|
path: string;
|
|
365
365
|
id: string;
|
package/lib/util/resolvers.d.ts
CHANGED
|
@@ -22,4 +22,4 @@ export declare const findAllRefs: (schema: JsonSchema, result?: ReferenceSchemaM
|
|
|
22
22
|
* @param {JsonSchema} rootSchema the actual root schema
|
|
23
23
|
* @returns {JsonSchema} the resolved sub-schema
|
|
24
24
|
*/
|
|
25
|
-
export declare const resolveSchema: (schema: JsonSchema, schemaPath: string, rootSchema
|
|
25
|
+
export declare const resolveSchema: (schema: JsonSchema, schemaPath: string, rootSchema: JsonSchema) => JsonSchema;
|
package/lib/util/util.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export declare const deriveTypes: (jsonSchema: JsonSchema) => string[];
|
|
|
18
18
|
* Convenience wrapper around resolveData and resolveSchema.
|
|
19
19
|
*/
|
|
20
20
|
export declare const Resolve: {
|
|
21
|
-
schema(schema: JsonSchema, schemaPath: string, rootSchema
|
|
21
|
+
schema(schema: JsonSchema, schemaPath: string, rootSchema: JsonSchema): JsonSchema;
|
|
22
22
|
data(data: any, path: string): any;
|
|
23
23
|
};
|
|
24
24
|
export declare const Paths: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsonforms/core",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.2",
|
|
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",
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"typedoc": "^0.19.2",
|
|
89
89
|
"typescript": "4.2.3"
|
|
90
90
|
},
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "8e9c14dcf049ee4b31baf9c40a86b394cba33139"
|
|
92
92
|
}
|
|
@@ -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,
|
package/src/reducers/reducers.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
};
|
package/src/testers/testers.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
389
|
+
(schema, rootSchema) => hasType(schema, 'array') && !Array.isArray(resolveSchema(schema, 'items', rootSchema)) // we don't care about tuples
|
|
384
390
|
),
|
|
385
|
-
schemaSubPathMatches('items',
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
571
|
+
schema: JsonSchema,
|
|
572
|
+
rootSchema: JsonSchema
|
|
573
|
+
|
|
574
|
+
) => !tester(uischema, schema, rootSchema);
|
package/src/util/combinators.ts
CHANGED
|
@@ -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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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(/
|
|
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
|
|
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,
|
|
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/, '~');
|