Skip to content

Commit

Permalink
Merge pull request temando#73 from brendo/issue-36-handle-mixed-data-…
Browse files Browse the repository at this point in the history
…type

Support 'type' being an array. Closes temando#36
  • Loading branch information
quangkhoa authored May 26, 2017
2 parents e1543ba + 89e2ca5 commit 1433699
Show file tree
Hide file tree
Showing 16 changed files with 683 additions and 8,427 deletions.
2 changes: 1 addition & 1 deletion src/components/BodySchema/BodySchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ export default class BodySchema extends Component {
type={property.type}
subtype={property.subtype}
description={property.description}
required={property.required}
enumValues={property.enum}
defaultValue={property.defaultValue}
onClick={this.onClick.bind(this, property.name)}
isRequired={property.required}
isOpen={isOpen}
isLast={isLast}
/>
Expand Down
7 changes: 5 additions & 2 deletions src/components/Description/Description.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import markdown from 'markdown-it';
import PropTypes from 'prop-types';

const cm = markdown('commonmark');

Expand All @@ -14,7 +15,9 @@ export default class Description extends Component {
};

return (
<div className={isInline ? 'description description-inline' : 'description'} dangerouslySetInnerHTML={text} />
<div className={classNames('description', {
'description-inline': isInline
})} dangerouslySetInnerHTML={text} />
);
}
}
Expand Down
19 changes: 10 additions & 9 deletions src/components/Property/Property.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import './Property.scss';

export default class Property extends Component {
render() {
const { name, type, description, required, enumValues, defaultValue, onClick, isOpen, isLast } = this.props;
const { name, type, description, isRequired, enumValues, defaultValue, onClick, isOpen, isLast } = this.props;

let subtype;
if (type === 'array') {
if (type.includes('array')) {
subtype = this.props.subtype;
}

Expand All @@ -24,6 +24,7 @@ export default class Property extends Component {
if (isOpen) {
status = 'open';
}

return (
<tr
className={classNames('property', {
Expand All @@ -40,8 +41,8 @@ export default class Property extends Component {
}
</td>
<td className="property-info">
<span>{type}</span>{subtype && <span> of {subtype}</span>}
{required && <span className="property-required">Required</span>}
<span>{type.join(', ')}</span>{subtype && <span> of {subtype}</span>}
{isRequired && <span className="property-required">Required</span>}
{enumValues && this.renderEnumValues(enumValues)}
{defaultValue && this.renderDefaultValue(defaultValue)}
{description && <Description description={description}/>}
Expand Down Expand Up @@ -89,14 +90,14 @@ export default class Property extends Component {
}

Property.propTypes = {
name: PropTypes.string,
type: PropTypes.string,
name: PropTypes.string.isRequired,
type: PropTypes.arrayOf(PropTypes.string).isRequired,
subtype: PropTypes.string,
description: PropTypes.string,
required: PropTypes.bool,
enumValues: PropTypes.array,
defaultValue: PropTypes.any,
onClick: PropTypes.func,
isRequired: PropTypes.bool,
isOpen: PropTypes.bool,
isLast: PropTypes.bool
isLast: PropTypes.bool,
onClick: PropTypes.func
};
21 changes: 13 additions & 8 deletions src/parser/open-api/schemaParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { resolveAllOf } from './allOfResolver';
const literalTypes = ['string', 'integer', 'number', 'boolean'];

/**
* Construct UI ready property object from given inputs
* Construct UI ready property object from given inputs.
*
* @param {String} nodeName
* @param {Object} propertyNode
Expand All @@ -12,7 +12,11 @@ const literalTypes = ['string', 'integer', 'number', 'boolean'];
* @return {Object}
*/
function getPropertyNode(nodeName, propertyNode, required = false) {
const nodeType = propertyNode.type || 'string';
let nodeType = propertyNode.type || 'string';

if (!Array.isArray(nodeType)) {
nodeType = [ nodeType ];
}

const outputNode = {
name: nodeName,
Expand All @@ -28,24 +32,25 @@ function getPropertyNode(nodeName, propertyNode, required = false) {
outputNode.defaultValue = propertyNode.default;
}

if (literalTypes.indexOf(nodeType) >= 0) {
// Literal types
// Are all the possible types for this property literals?
// TODO: Currently do not handle multiple types that are not all literals
if (nodeType.every((type) => literalTypes.includes(type))) {
if (propertyNode.enum) {
outputNode.enum = propertyNode.enum;
}

return outputNode;
} else if (nodeType === 'object') {
// Object type
// Otherwise, let's see if there's an object in there..
} else if (nodeType.length === 1 && nodeType.includes('object')) {
const propertiesNode = getPropertiesNode(propertyNode.properties, propertyNode.required);

if (propertiesNode !== undefined && propertiesNode.length > 0) {
outputNode.properties = propertiesNode;
}

return outputNode;
} else if (nodeType === 'array') {
// Array type
// Is there an array?
} else if (nodeType.length === 1 && nodeType.includes('array')) {
if (propertyNode.items) {
const arrayItemType = propertyNode.items.type;

Expand Down
7 changes: 5 additions & 2 deletions src/parser/open-api/v3/open-api-v3-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,13 @@ function getUIParametersForLocation(parameters, location) {
required: parameter.required
};

// TODO: We set the type to be an array because the Property component
// handles this. Property should eventually be split and this won't be
// necessary...
if (parameter.type) {
uiParameter.type = parameter.type;
uiParameter.type = [ parameter.type ];
} else if (parameter.schema && parameter.schema.type) {
uiParameter.type = parameter.schema.type;
uiParameter.type = [ parameter.schema.type ];
}

if (parameter.schema && parameter.schema.default !== undefined) {
Expand Down
4 changes: 2 additions & 2 deletions test/components/Description.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('<Description />', () => {
const text = 'This method has zero markdown.';
const tree = renderer.create(
<Description description={text} />
).toJSON();
);

expect(tree).toMatchSnapshot();
});
Expand All @@ -16,7 +16,7 @@ describe('<Description />', () => {
const text = 'This method has some `var i = 0` _markdown_, including a [link](http://www.google.com).';
const tree = renderer.create(
<Description description={text} />
).toJSON();
);

expect(tree).toMatchSnapshot();
});
Expand Down
62 changes: 62 additions & 0 deletions test/components/Property.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import Property from './../../src/components/Property/Property';
import renderer from 'react-test-renderer';
import ReactShallowRenderer from 'react-test-renderer/shallow';

describe('<Property />', () => {
it('can render a basic property', () => {
const tree = renderer.create(
<Property name={'type'} type={['string']} isRequired isLast />
);

expect(tree).toMatchSnapshot();
});

it('can render a property with enum', () => {
const tree = renderer.create(
<Property
name={'packagingType'}
type={['string']}
enumValues={['box', 'carton']}
isRequired />
);

expect(tree).toMatchSnapshot();
});

it('can render a property with a subtype', () => {
const tree = renderer.create(
<Property
name={'data'}
type={['array']}
subtype={'object'}
isRequired={false} />
);

expect(tree).toMatchSnapshot();
});

it('can render a property with description', () => {
const shallow = new ReactShallowRenderer();
const tree = shallow.render(
<Property
name={'type'}
type={['string']}
description={'This is _markdown_ text'}
isRequired />
);

expect(tree).toMatchSnapshot();
});

it('can render a property with multiple types', () => {
const tree = renderer.create(
<Property
name={'value'}
type={['string', 'number']}
isRequired={false} />
);

expect(tree).toMatchSnapshot();
});
});
148 changes: 148 additions & 0 deletions test/components/__snapshots__/Property.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<Property /> can render a basic property 1`] = `
<tr
className="property last"
onClick={undefined}
>
<td
className="property-name"
>
<span>
type
</span>
</td>
<td
className="property-info"
>
<span>
string
</span>
<span
className="property-required"
>
Required
</span>
</td>
</tr>
`;

exports[`<Property /> can render a property with a subtype 1`] = `
<tr
className="property"
onClick={undefined}
>
<td
className="property-name"
>
<span>
data
</span>
</td>
<td
className="property-info"
>
<span>
array
</span>
<span>
of
object
</span>
</td>
</tr>
`;

exports[`<Property /> can render a property with description 1`] = `
<tr
className="property"
onClick={undefined}
>
<td
className="property-name"
>
<span>
type
</span>
</td>
<td
className="property-info"
>
<span>
string
</span>
<span
className="property-required"
>
Required
</span>
<Description
description="This is _markdown_ text"
/>
</td>
</tr>
`;

exports[`<Property /> can render a property with enum 1`] = `
<tr
className="property"
onClick={undefined}
>
<td
className="property-name"
>
<span>
packagingType
</span>
</td>
<td
className="property-info"
>
<span>
string
</span>
<span
className="property-required"
>
Required
</span>
<div>
<span>
Valid values:
</span>
<span
className="enum"
>
box
</span>
<span
className="enum"
>
carton
</span>
</div>
</td>
</tr>
`;

exports[`<Property /> can render a property with multiple types 1`] = `
<tr
className="property"
onClick={undefined}
>
<td
className="property-name"
>
<span>
value
</span>
</td>
<td
className="property-info"
>
<span>
string, number
</span>
</td>
</tr>
`;
Loading

0 comments on commit 1433699

Please sign in to comment.