Skip to content

Commit

Permalink
Make schemaMatches more stable
Browse files Browse the repository at this point in the history
* moved deriveType to util
* schemaMatches doesn't expect a type property but uses deriveType
* added test case for improved schemaMatches behavior
  • Loading branch information
eneufeld authored and edgarmueller committed Mar 5, 2019
1 parent f390caa commit e9e0582
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 43 deletions.
41 changes: 1 addition & 40 deletions packages/core/src/generators/uischema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
THE SOFTWARE.
*/
import isEmpty from 'lodash/isEmpty';
import isArray from 'lodash/isArray';
import head from 'lodash/head';
import startCase from 'lodash/startCase';
import keys from 'lodash/keys';
import { JsonSchema } from '../models/jsonSchema';
Expand All @@ -36,6 +34,7 @@ import {
UISchemaElement
} from '../models/uischema';
import { resolveSchema } from '../util/resolvers';
import { deriveType } from '../util';

/**
* Creates a new ILayout.
Expand All @@ -47,44 +46,6 @@ const createLayout = (layoutType: string): Layout => ({
elements: []
});

/**
* Checks if the type of jsonSchema is a union of multiple types
*
* @param {JsonSchema} jsonSchema
* @returns {boolean}
*/
const isUnionType = (jsonSchema: JsonSchema): boolean =>
!isEmpty(jsonSchema) && !isEmpty(jsonSchema.type) && isArray(jsonSchema.type);

/**
* Derives the type of the jsonSchema element
*/
const deriveType = (jsonSchema: JsonSchema): string => {
if (
!isEmpty(jsonSchema) &&
!isEmpty(jsonSchema.type) &&
typeof jsonSchema.type === 'string'
) {
return jsonSchema.type;
}
if (isUnionType(jsonSchema)) {
return head(jsonSchema.type);
}
if (
!isEmpty(jsonSchema) &&
(!isEmpty(jsonSchema.properties) ||
!isEmpty(jsonSchema.additionalProperties))
) {
return 'object';
}
if (!isEmpty(jsonSchema) && !isEmpty(jsonSchema.items)) {
return 'array';
}

// ignore all remaining cases
return 'null';
};

/**
* Creates a IControlObject with the given label referencing the given ref
*/
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,17 @@ import {
uischemaRegistryReducer,
UISchemaTester
} from './uischemas';
import { ControlElement, Generate, JsonSchema, UISchemaElement } from '..';
import {
fetchLocale,
findLocalizedSchema,
findLocalizedUISchema,
i18nReducer
} from './i18n';

import { JsonSchema } from '../models/jsonSchema';
import { ControlElement, UISchemaElement } from '../models/uischema';
import { Generate } from '../generators';

export { rendererReducer, fieldReducer, coreReducer, UISchemaTester };

export const jsonformsReducer = (
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/testers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
UISchemaElement
} from '../models/uischema';
import { resolveSchema } from '../util/resolvers';
import { deriveType } from '../util';

/**
* Constant that indicates that a tester is not capable of handling
Expand Down Expand Up @@ -85,7 +86,7 @@ export const schemaMatches = (
return false;
}
let currentDataSchema = schema;
if (schema.type === 'object') {
if (deriveType(schema) === 'object') {
currentDataSchema = resolveSchema(schema, schemaPath);
}
if (currentDataSchema === undefined) {
Expand Down
43 changes: 42 additions & 1 deletion packages/core/src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
import isEmpty from 'lodash/isEmpty';
import isArray from 'lodash/isArray';
import head from 'lodash/head';
import {
JsonFormsState,
JsonSchema,
Expand Down Expand Up @@ -57,6 +60,44 @@ export const formatErrorMessage = (errors: string[]) => {
return errors.join('\n');
};

/**
* Checks if the type of jsonSchema is a union of multiple types
*
* @param {JsonSchema} jsonSchema
* @returns {boolean}
*/
const isUnionType = (jsonSchema: JsonSchema): boolean =>
!isEmpty(jsonSchema) && !isEmpty(jsonSchema.type) && isArray(jsonSchema.type);

/**
* Derives the type of the jsonSchema element
*/
const deriveType = (jsonSchema: JsonSchema): string => {
if (
!isEmpty(jsonSchema) &&
!isEmpty(jsonSchema.type) &&
typeof jsonSchema.type === 'string'
) {
return jsonSchema.type;
}
if (isUnionType(jsonSchema)) {
return head(jsonSchema.type);
}
if (
!isEmpty(jsonSchema) &&
(!isEmpty(jsonSchema.properties) ||
!isEmpty(jsonSchema.additionalProperties))
) {
return 'object';
}
if (!isEmpty(jsonSchema) && !isEmpty(jsonSchema.items)) {
return 'array';
}

// ignore all remaining cases
return 'null';
};

/**
* Convenience wrapper around resolveData and resolveSchema.
*/
Expand Down Expand Up @@ -93,7 +134,7 @@ const Runtime = {
return isVisible(props, state);
}
};
export { isEnabled, isVisible, Runtime };
export { isEnabled, isVisible, Runtime, deriveType };

export * from './renderer';
export * from './field';
Expand Down
15 changes: 15 additions & 0 deletions packages/core/test/testers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,21 @@ test('schemaMatches should check type sub-schema of control via predicate', t =>
);
});

test('schemaMatches should check type sub-schema of control via predicate also without explicit type', t => {
const schema: JsonSchema = {
properties: {
foo: { type: 'string' }
}
};
const uischema: ControlElement = {
type: 'Control',
scope: '#/properties/foo'
};
t.true(
schemaMatches(subSchema => subSchema.type === 'string')(uischema, schema)
);
});

test('schemaMatches should return false for non-control UI schema elements', t => {
const schema: JsonSchema = {
type: 'object',
Expand Down

0 comments on commit e9e0582

Please sign in to comment.