feat: show minProperties maxProperties (#2015)

This commit is contained in:
Anastasiia Derymarko 2022-05-20 11:57:04 +03:00 committed by GitHub
parent 0aafee1131
commit 82712c5b40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 128 additions and 13 deletions

View File

@ -88,7 +88,7 @@ paths:
parameters:
- name: Accept-Language
in: header
description: "The language you prefer for messages. Supported values are en-AU, en-CA, en-GB, en-US"
description: 'The language you prefer for messages. Supported values are en-AU, en-CA, en-GB, en-US'
example: en-US
required: false
schema:
@ -254,7 +254,7 @@ paths:
required: false
schema:
type: string
example: "Bearer <TOKEN>"
example: 'Bearer <TOKEN>'
- name: petId
in: path
description: Pet id to delete
@ -401,6 +401,7 @@ paths:
application/json:
schema:
type: object
minProperties: 2
additionalProperties:
type: integer
format: int32
@ -429,7 +430,7 @@ paths:
application/json:
example:
status: 400
message: "Invalid Order"
message: 'Invalid Order'
requestBody:
content:
application/json:
@ -877,11 +878,11 @@ paths:
type: string
examples:
response:
value: <Message> OK </Message>
value: <Message> OK </Message>
text/plain:
examples:
response:
value: OK
value: OK
'400':
description: Invalid username/password supplied
/user/logout:
@ -1027,8 +1028,8 @@ components:
properties:
id:
externalDocs:
description: "Find more info here"
url: "https://example.com"
description: 'Find more info here'
url: 'https://example.com'
description: Pet ID
allOf:
- $ref: '#/components/schemas/Id'
@ -1201,7 +1202,7 @@ x-webhooks:
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
$ref: '#/components/schemas/Pet'
responses:
"200":
'200':
description: Return a 200 status to indicate that the data was received successfully

View File

@ -10,6 +10,7 @@ import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
import { Schema } from '../Schema';
import { Markdown } from '../Markdown/Markdown';
import { ConstraintsView } from '../Fields/FieldContstraints';
function safePush(obj, prop, item) {
if (!obj[prop]) {
@ -79,6 +80,7 @@ export function BodyContent(props: {
return (
<>
{description !== undefined && <Markdown source={description} />}
<ConstraintsView constraints={schema?.constraints || []} />
<Schema
skipReadOnly={isRequestType}
skipWriteOnly={!isRequestType}

View File

@ -10,6 +10,7 @@ import { Schema } from '../Schema';
import { Extensions } from '../Fields/Extensions';
import { Markdown } from '../Markdown/Markdown';
import { ResponseHeaders } from './ResponseHeaders';
import { ConstraintsView } from '../Fields/FieldContstraints';
export class ResponseDetails extends React.PureComponent<{ response: ResponseModel }> {
render() {
@ -21,7 +22,12 @@ export class ResponseDetails extends React.PureComponent<{ response: ResponseMod
<ResponseHeaders headers={headers} />
<MediaTypesSwitch content={content} renderDropdown={this.renderDropdown}>
{({ schema }) => {
return <Schema skipWriteOnly={true} key="schema" schema={schema} />;
return (
<>
<ConstraintsView constraints={schema?.constraints || []} />
<Schema skipWriteOnly={true} key="schema" schema={schema} />
</>
);
}}
</MediaTypesSwitch>
</>

View File

@ -8,6 +8,7 @@ import {
} from '../../common-elements/schema';
import { Badge } from '../../common-elements/shelfs';
import { SchemaModel } from '../../services/models';
import { ConstraintsView } from '../Fields/FieldContstraints';
import { Schema, SchemaProps } from './Schema';
export interface OneOfButtonProps {
@ -47,6 +48,8 @@ export class OneOfSchema extends React.Component<SchemaProps> {
if (oneOf === undefined) {
return null;
}
const activeSchema = oneOf[schema.activeOneOf];
return (
<div>
<OneOfLabel> {schema.oneOfType} </OneOfLabel>
@ -58,7 +61,8 @@ export class OneOfSchema extends React.Component<SchemaProps> {
<div>
{oneOf[schema.activeOneOf].deprecated && <Badge type="warning">Deprecated</Badge>}
</div>
<Schema {...this.props} schema={oneOf[schema.activeOneOf]} />
<ConstraintsView constraints={activeSchema.constraints} />
<Schema {...this.props} schema={activeSchema} />
</div>
);
}

View File

@ -53,5 +53,30 @@ describe('Components', () => {
expect(component.render()).toMatchSnapshot();
});
});
describe('Show minProperties/maxProperties constraints oneOf', () => {
const schema = new SchemaModel(
parser,
{
oneOf: [
{
type: 'object',
description: 'Test description',
minProperties: 1,
maxProperties: 1,
additionalProperties: {
type: 'string',
description: 'The name and value o',
},
},
],
},
'',
options,
);
const component = shallow(withTheme(<Schema schema={schema} />));
expect(component.html().includes('= 1 properties')).toBe(true);
});
});
});

View File

@ -0,0 +1,67 @@
/* tslint:disable:no-implicit-dependencies */
import { shallow } from 'enzyme';
import * as React from 'react';
import { Schema } from '../';
import { OpenAPIParser, SchemaModel } from '../../services';
import { RedocNormalizedOptions } from '../../services/RedocNormalizedOptions';
import { withTheme } from '../testProviders';
const options = new RedocNormalizedOptions({});
describe('Components', () => {
describe('SchemaView', () => {
const parser = new OpenAPIParser(
{ openapi: '3.0', info: { title: 'test', version: '0' }, paths: {} },
undefined,
options,
);
describe('Show minProperties/maxProperties constraints', () => {
const schema = new SchemaModel(
parser,
{
properties: {
name: {
type: 'object',
minProperties: 1,
properties: {
address: {
type: 'string',
},
},
},
},
},
'',
options,
);
const component = shallow(withTheme(<Schema schema={schema} />));
expect(component.html().includes('non-empty')).toBe(true);
});
describe('Show range minProperties/maxProperties constraints', () => {
const schema = new SchemaModel(
parser,
{
properties: {
name: {
type: 'object',
minProperties: 2,
maxProperties: 10,
additionalProperties: {
type: 'string',
},
},
},
},
'',
options,
);
it('should includes [ 2 .. 10 ] properties', () => {
const component = shallow(withTheme(<Schema schema={schema} />));
expect(component.html().includes('[ 2 .. 10 ] properties')).toBe(true);
});
});
});
});

View File

@ -966,6 +966,7 @@ try {
"format": "int32",
"type": "integer",
},
"minProperties": 2,
"type": "object",
},
},

View File

@ -553,7 +553,7 @@ describe('Utils', () => {
});
it('should have a humanized constraint when minItems and maxItems are the same', () => {
expect(humanizeConstraints(itemConstraintSchema(7, 7))).toContain('7 items');
expect(humanizeConstraints(itemConstraintSchema(7, 7))).toContain('= 7 items');
});
it('should have a humanized constraint when justMinItems is set, and it is equal to 1', () => {

View File

@ -423,7 +423,7 @@ function humanizeRangeConstraint(
let stringRange;
if (min !== undefined && max !== undefined) {
if (min === max) {
stringRange = `${min} ${description}`;
stringRange = `= ${min} ${description}`;
} else {
stringRange = `[ ${min} .. ${max} ] ${description}`;
}
@ -476,6 +476,15 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
res.push(arrayRange);
}
const propertiesRange = humanizeRangeConstraint(
'properties',
schema.minProperties,
schema.maxProperties,
);
if (propertiesRange !== undefined) {
res.push(propertiesRange);
}
const multipleOfConstraint = humanizeMultipleOfConstraint(schema.multipleOf);
if (multipleOfConstraint !== undefined) {
res.push(multipleOfConstraint);