Skip to content

Commit 04638ec

Browse files
eneufeldedgarmueller
authored andcommitted
Let deriveType return an array
* Rename deriveType to deriveTypes * schemaTypeIs is working for array types * Update AllOfRenderer rank to 3 * Update AnyOfRenderer rank to 3 Fixes eclipsesource#1355
1 parent c9cac3e commit 04638ec

File tree

8 files changed

+293
-208
lines changed

8 files changed

+293
-208
lines changed

packages/core/src/generators/uischema.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
UISchemaElement
3535
} from '../models/uischema';
3636
import { resolveSchema } from '../util/resolvers';
37-
import { deriveType } from '../util';
37+
import { deriveTypes } from '../util';
3838

3939
/**
4040
* Creates a new ILayout.
@@ -140,9 +140,18 @@ const generateUISchema = (
140140
return controlObject;
141141
}
142142

143-
const type = deriveType(jsonSchema);
143+
const types = deriveTypes(jsonSchema);
144+
if (types.length === 0) {
145+
return null;
146+
}
147+
148+
if (types.length > 1) {
149+
const controlObject: ControlElement = createControlElement(currentRef);
150+
schemaElements.push(controlObject);
151+
return controlObject;
152+
}
144153

145-
switch (type) {
154+
switch (types[0]) {
146155
case 'object':
147156
const layout: Layout = createLayout(layoutType);
148157
schemaElements.push(layout);
@@ -186,8 +195,6 @@ const generateUISchema = (
186195
schemaElements.push(controlObject);
187196

188197
return controlObject;
189-
case 'null':
190-
return null;
191198
default:
192199
throw new Error('Unknown type: ' + JSON.stringify(jsonSchema));
193200
}

packages/core/src/testers/index.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import {
3838
UISchemaElement
3939
} from '../models/uischema';
4040
import { resolveSchema } from '../util/resolvers';
41-
import { deriveType } from '../util';
41+
import { deriveTypes, isValidType } from '../util';
4242

4343
/**
4444
* Constant that indicates that a tester is not capable of handling
@@ -86,7 +86,7 @@ export const schemaMatches = (
8686
return false;
8787
}
8888
let currentDataSchema = schema;
89-
if (deriveType(schema) === 'object') {
89+
if (isValidType(schema, 'object')) {
9090
currentDataSchema = resolveSchema(schema, schemaPath);
9191
}
9292
if (currentDataSchema === undefined) {
@@ -127,7 +127,9 @@ export const schemaSubPathMatches = (
127127
* @param {string} expectedType the expected type of the resolved sub-schema
128128
*/
129129
export const schemaTypeIs = (expectedType: string): Tester =>
130-
schemaMatches(schema => !isEmpty(schema) && schema.type === expectedType);
130+
schemaMatches(
131+
schema => !isEmpty(schema) && isValidType(schema, expectedType)
132+
);
131133

132134
/**
133135
* Only applicable for Controls.
@@ -359,9 +361,9 @@ export const isDateTimeControl = and(
359361
*/
360362
export const isObjectArray = and(
361363
schemaMatches(
362-
schema => deriveType(schema) === 'array' && !Array.isArray(schema.items) // we don't care about tuples
364+
schema => isValidType(schema, 'array') && !Array.isArray(schema.items) // we don't care about tuples
363365
),
364-
schemaSubPathMatches('items', schema => deriveType(schema) === 'object')
366+
schemaSubPathMatches('items', schema => isValidType(schema, 'object'))
365367
);
366368

367369
/**
@@ -457,17 +459,16 @@ export const isArrayObjectControl = isObjectArrayControl;
457459
*/
458460
export const isPrimitiveArrayControl = and(
459461
uiTypeIs('Control'),
460-
schemaMatches(schema => {
462+
schemaMatches(
463+
schema => deriveTypes(schema).length !== 0 && !Array.isArray(schema.items) // we don't care about tuples
464+
),
465+
schemaSubPathMatches('items', schema => {
466+
const types = deriveTypes(schema);
461467
return (
462-
!isEmpty(schema) &&
463-
schema.type === 'array' &&
464-
!isEmpty(schema.items) &&
465-
!Array.isArray(schema.items)
466-
); // we don't care about tuples
467-
}),
468-
schemaSubPathMatches('items', schema =>
469-
includes(['integer', 'number', 'boolean', 'string'], schema.type)
470-
)
468+
types.length === 1 &&
469+
includes(['integer', 'number', 'boolean', 'string'], types[0])
470+
);
471+
})
471472
);
472473

473474
/**

packages/core/src/util/index.ts

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
import isEmpty from 'lodash/isEmpty';
2626
import isArray from 'lodash/isArray';
27-
import head from 'lodash/head';
27+
import includes from 'lodash/includes';
2828
import find from 'lodash/find';
2929
import { JsonSchema, Scopable, UISchemaElement } from '../';
3030
import { resolveData, resolveSchema } from './resolvers';
@@ -56,52 +56,45 @@ export const formatErrorMessage = (errors: string[]) => {
5656
return errors.join('\n');
5757
};
5858

59-
/**
60-
* Checks if the type of jsonSchema is a union of multiple types
61-
*
62-
* @param {JsonSchema} jsonSchema
63-
* @returns {boolean}
64-
*/
65-
const isUnionType = (jsonSchema: JsonSchema): boolean =>
66-
!isEmpty(jsonSchema) && !isEmpty(jsonSchema.type) && isArray(jsonSchema.type);
59+
const isValidType = (jsonSchema: JsonSchema, expected: string): boolean => {
60+
return includes(deriveTypes(jsonSchema), expected);
61+
};
6762

6863
/**
6964
* Derives the type of the jsonSchema element
7065
*/
71-
const deriveType = (jsonSchema: JsonSchema): string => {
72-
if (
73-
!isEmpty(jsonSchema) &&
74-
!isEmpty(jsonSchema.type) &&
75-
typeof jsonSchema.type === 'string'
76-
) {
77-
return jsonSchema.type;
66+
const deriveTypes = (jsonSchema: JsonSchema): string[] => {
67+
if (isEmpty(jsonSchema)) {
68+
return [];
7869
}
79-
if (isUnionType(jsonSchema)) {
80-
return head(jsonSchema.type);
70+
if (!isEmpty(jsonSchema.type) && typeof jsonSchema.type === 'string') {
71+
return [jsonSchema.type];
72+
}
73+
if (isArray(jsonSchema.type)) {
74+
return jsonSchema.type;
8175
}
8276
if (
83-
!isEmpty(jsonSchema) &&
84-
(!isEmpty(jsonSchema.properties) ||
85-
!isEmpty(jsonSchema.additionalProperties))
77+
!isEmpty(jsonSchema.properties) ||
78+
!isEmpty(jsonSchema.additionalProperties)
8679
) {
87-
return 'object';
80+
return ['object'];
8881
}
89-
if (!isEmpty(jsonSchema) && !isEmpty(jsonSchema.items)) {
90-
return 'array';
82+
if (!isEmpty(jsonSchema.items)) {
83+
return ['array'];
9184
}
9285

93-
if (!isEmpty(jsonSchema) && !isEmpty(jsonSchema.allOf)) {
86+
if (!isEmpty(jsonSchema.allOf)) {
9487
const allOfType = find(
9588
jsonSchema.allOf,
96-
(schema: JsonSchema) => deriveType(schema) !== 'null'
89+
(schema: JsonSchema) => deriveTypes(schema).length !== 0
9790
);
9891

9992
if (allOfType) {
100-
return deriveType(allOfType);
93+
return deriveTypes(allOfType);
10194
}
10295
}
10396
// ignore all remaining cases
104-
return 'null';
97+
return [];
10598
};
10699

107100
/**
@@ -140,7 +133,7 @@ const Runtime = {
140133
return isVisible(uischema, data);
141134
}
142135
};
143-
export { isEnabled, isVisible, Runtime, deriveType };
136+
export { isEnabled, isVisible, Runtime, deriveTypes, isValidType };
144137

145138
export * from './renderer';
146139
export * from './cell';

packages/core/test/testers.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,21 @@ test('schemaTypeIs should return false for control pointing to invalid sub-schem
104104
t.false(schemaTypeIs('string')(uischema, schema));
105105
});
106106

107+
test('schemaTypeIs should return true for array type', t => {
108+
const schema: JsonSchema = {
109+
type: 'object',
110+
properties: {
111+
foo: { type: ['string', 'integer'] }
112+
}
113+
};
114+
const uischema: ControlElement = {
115+
type: 'Control',
116+
scope: '#/properties/foo'
117+
};
118+
t.true(schemaTypeIs('string')(uischema, schema));
119+
t.true(schemaTypeIs('integer')(uischema, schema));
120+
});
121+
107122
test('formatIs should check the format of a resolved sub-schema', t => {
108123
const uischema: ControlElement = {
109124
type: 'Control',

packages/core/test/util/derivetype.test.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@
2525
import test from 'ava';
2626

2727
import { JsonSchema } from '../../src/models/jsonSchema';
28-
import { deriveType } from '../../src/util/index';
28+
import { deriveTypes } from '../../src/util/index';
2929

3030
test('derive type with type', t => {
3131
const schema: JsonSchema = {
3232
type: 'string'
3333
};
34-
t.is(deriveType(schema), 'string');
34+
t.is(deriveTypes(schema).length, 1);
35+
t.is(deriveTypes(schema)[0], 'string');
3536
});
3637

3738
test('derive type w/o type - properties object', t => {
@@ -40,7 +41,8 @@ test('derive type w/o type - properties object', t => {
4041
foo: { type: 'string' }
4142
}
4243
};
43-
t.is(deriveType(schema), 'object');
44+
t.is(deriveTypes(schema).length, 1);
45+
t.is(deriveTypes(schema)[0], 'object');
4446
});
4547

4648
test('derive type w/o type - additionalProperties object', t => {
@@ -49,7 +51,8 @@ test('derive type w/o type - additionalProperties object', t => {
4951
type: 'string'
5052
}
5153
};
52-
t.is(deriveType(schema), 'object');
54+
t.is(deriveTypes(schema).length, 1);
55+
t.is(deriveTypes(schema)[0], 'object');
5356
});
5457

5558
test('derive type w/o type - items array', t => {
@@ -58,29 +61,33 @@ test('derive type w/o type - items array', t => {
5861
type: 'string'
5962
}
6063
};
61-
t.is(deriveType(schema), 'array');
64+
t.is(deriveTypes(schema).length, 1);
65+
t.is(deriveTypes(schema)[0], 'array');
6266
});
6367

6468
test('derive type with type - union', t => {
6569
const schema: JsonSchema = {
6670
type: ['string', 'number']
6771
};
72+
t.is(deriveTypes(schema).length, 2);
6873
// we just take the first, as derive type returns exactly one value
69-
t.is(deriveType(schema), 'string');
74+
t.is(deriveTypes(schema), schema.type);
7075
});
7176

7277
test('derive type with type - allOf first has type', t => {
7378
const schema: JsonSchema = {
7479
allOf: [{ type: 'string' }, { enum: ['foo', 'bar'] }]
7580
};
76-
t.is(deriveType(schema), 'string');
81+
t.is(deriveTypes(schema).length, 1);
82+
t.is(deriveTypes(schema)[0], 'string');
7783
});
7884

7985
test('derive type with type - allOf other has type', t => {
8086
const schema: JsonSchema = {
8187
allOf: [{ enum: ['foo', 'bar'] }, { type: 'string' }]
8288
};
83-
t.is(deriveType(schema), 'string');
89+
t.is(deriveTypes(schema).length, 1);
90+
t.is(deriveTypes(schema)[0], 'string');
8491
});
8592

8693
test('derive type w/o type - allOf other has type', t => {
@@ -90,5 +97,6 @@ test('derive type w/o type - allOf other has type', t => {
9097
{ properties: { bar: { type: 'string' } } }
9198
]
9299
};
93-
t.is(deriveType(schema), 'object');
100+
t.is(deriveTypes(schema).length, 1);
101+
t.is(deriveTypes(schema)[0], 'object');
94102
});

packages/material/src/complex/MaterialAllOfRenderer.tsx

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,41 @@ import {
3838
} from '@jsonforms/core';
3939
import { ResolvedJsonForms } from '@jsonforms/react';
4040

41-
class MaterialAllOfRenderer extends React.Component<StatePropsOfCombinator, any> {
42-
41+
class MaterialAllOfRenderer extends React.Component<
42+
StatePropsOfCombinator,
43+
any
44+
> {
4345
render() {
44-
45-
const {
46-
schema,
47-
rootSchema,
48-
path,
49-
visible
50-
} = this.props;
46+
const { schema, rootSchema, path, visible } = this.props;
5147

5248
const _schema = resolveSubSchemas(schema, rootSchema, 'allOf');
53-
const allOfRenderInfos = createCombinatorRenderInfos((_schema as JsonSchema).allOf, rootSchema, 'allOf');
49+
const allOfRenderInfos = createCombinatorRenderInfos(
50+
(_schema as JsonSchema).allOf,
51+
rootSchema,
52+
'allOf'
53+
);
5454

5555
return (
5656
<Hidden xsUp={!visible}>
57-
{
58-
allOfRenderInfos.map((allOfRenderInfo, allOfIndex) => (
59-
<ResolvedJsonForms
60-
key={allOfIndex}
61-
schema={allOfRenderInfo.schema}
62-
uischema={allOfRenderInfo.uischema}
63-
path={path}
64-
/>
65-
))
66-
}
57+
{allOfRenderInfos.map((allOfRenderInfo, allOfIndex) => (
58+
<ResolvedJsonForms
59+
key={allOfIndex}
60+
schema={allOfRenderInfo.schema}
61+
uischema={allOfRenderInfo.uischema}
62+
path={path}
63+
/>
64+
))}
6765
</Hidden>
6866
);
6967
}
7068
}
7169

72-
const ConnectedMaterialAllOfRenderer = connect(
73-
mapStateToAllOfProps
74-
)(MaterialAllOfRenderer);
70+
const ConnectedMaterialAllOfRenderer = connect(mapStateToAllOfProps)(
71+
MaterialAllOfRenderer
72+
);
7573

76-
export const materialAllOfControlTester: RankedTester = rankWith(2, isAllOfControl);
74+
export const materialAllOfControlTester: RankedTester = rankWith(
75+
3,
76+
isAllOfControl
77+
);
7778
export default ConnectedMaterialAllOfRenderer;

0 commit comments

Comments
 (0)