mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-08 06:04:56 +03:00
Support for required additionalProperties
This commit is contained in:
parent
dc5430e53d
commit
ceaa2ead53
|
@ -398,10 +398,16 @@ paths:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
allOf:
|
||||||
additionalProperties:
|
- type: object
|
||||||
type: integer
|
additionalProperties:
|
||||||
format: int32
|
x-additionalPropertiesName: status
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
- required:
|
||||||
|
- inStock
|
||||||
|
- soldOut
|
||||||
|
|
||||||
security:
|
security:
|
||||||
- api_key: []
|
- api_key: []
|
||||||
/store/order:
|
/store/order:
|
||||||
|
|
|
@ -45,6 +45,16 @@ export const RequiredLabel = styled(FieldLabel.withComponent('div'))`
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const RequiredImplicitFieldName = styled(FieldLabel.withComponent('div'))`
|
||||||
|
line-height: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 1em;
|
||||||
|
font-family: ${props => props.theme.typography.code.fontFamily};
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
margin-left: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
export const RecursiveLabel = styled(FieldLabel)`
|
export const RecursiveLabel = styled(FieldLabel)`
|
||||||
color: ${({ theme }) => theme.colors.warning.main};
|
color: ${({ theme }) => theme.colors.warning.main};
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { ClickablePropertyNameCell, RequiredLabel } from '../../common-elements/fields';
|
import {
|
||||||
|
ClickablePropertyNameCell,
|
||||||
|
RequiredImplicitFieldName,
|
||||||
|
RequiredLabel,
|
||||||
|
} from '../../common-elements/fields';
|
||||||
import { FieldDetails } from './FieldDetails';
|
import { FieldDetails } from './FieldDetails';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -34,7 +38,7 @@ export class Field extends React.Component<FieldProps> {
|
||||||
};
|
};
|
||||||
render() {
|
render() {
|
||||||
const { className, field, isLast } = this.props;
|
const { className, field, isLast } = this.props;
|
||||||
const { name, expanded, deprecated, required, kind } = field;
|
const { name, expanded, deprecated, required, requiredNames, kind } = field;
|
||||||
const withSubSchema = !field.schema.isPrimitive && !field.schema.isCircular;
|
const withSubSchema = !field.schema.isPrimitive && !field.schema.isCircular;
|
||||||
|
|
||||||
const paramName = withSubSchema ? (
|
const paramName = withSubSchema ? (
|
||||||
|
@ -53,6 +57,13 @@ export class Field extends React.Component<FieldProps> {
|
||||||
<PropertyNameCell className={deprecated ? 'deprecated' : undefined} kind={kind} title={name}>
|
<PropertyNameCell className={deprecated ? 'deprecated' : undefined} kind={kind} title={name}>
|
||||||
<PropertyBullet />
|
<PropertyBullet />
|
||||||
{name}
|
{name}
|
||||||
|
{requiredNames && (
|
||||||
|
requiredNames.map((value, idx) => {
|
||||||
|
return (
|
||||||
|
<RequiredImplicitFieldName key={idx}> {value} </RequiredImplicitFieldName>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
{required && <RequiredLabel> required </RequiredLabel>}
|
{required && <RequiredLabel> required </RequiredLabel>}
|
||||||
</PropertyNameCell>
|
</PropertyNameCell>
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,6 +15,7 @@ exports[`Components SchemaView discriminator should correctly render discriminat
|
||||||
"kind": "field",
|
"kind": "field",
|
||||||
"name": "packSize",
|
"name": "packSize",
|
||||||
"required": false,
|
"required": false,
|
||||||
|
"requiredNames": undefined,
|
||||||
"schema": SchemaModel {
|
"schema": SchemaModel {
|
||||||
"activeOneOf": 0,
|
"activeOneOf": 0,
|
||||||
"constraints": Array [],
|
"constraints": Array [],
|
||||||
|
@ -65,6 +66,7 @@ exports[`Components SchemaView discriminator should correctly render discriminat
|
||||||
"kind": "field",
|
"kind": "field",
|
||||||
"name": "type",
|
"name": "type",
|
||||||
"required": true,
|
"required": true,
|
||||||
|
"requiredNames": undefined,
|
||||||
"schema": SchemaModel {
|
"schema": SchemaModel {
|
||||||
"activeOneOf": 0,
|
"activeOneOf": 0,
|
||||||
"constraints": Array [],
|
"constraints": Array [],
|
||||||
|
|
|
@ -35,6 +35,7 @@ export class FieldModel {
|
||||||
schema: SchemaModel;
|
schema: SchemaModel;
|
||||||
name: string;
|
name: string;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
|
requiredNames?: string[];
|
||||||
description: string;
|
description: string;
|
||||||
example?: string;
|
example?: string;
|
||||||
deprecated: boolean;
|
deprecated: boolean;
|
||||||
|
@ -57,6 +58,7 @@ export class FieldModel {
|
||||||
this.name = infoOrRef.name || info.name;
|
this.name = infoOrRef.name || info.name;
|
||||||
this.in = info.in;
|
this.in = info.in;
|
||||||
this.required = !!info.required;
|
this.required = !!info.required;
|
||||||
|
this.requiredNames = info.requiredNames;
|
||||||
|
|
||||||
let fieldSchema = info.schema;
|
let fieldSchema = info.schema;
|
||||||
let serializationMime = '';
|
let serializationMime = '';
|
||||||
|
|
|
@ -287,16 +287,22 @@ function buildFields(
|
||||||
sortByRequired(fields, !options.sortPropsAlphabetically ? schema.required : undefined);
|
sortByRequired(fields, !options.sortPropsAlphabetically ? schema.required : undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const explicitFieldNames = fields.map(field => field.name);
|
||||||
|
const implicitRequiredNames = schema.required === undefined ? [] :
|
||||||
|
schema.required.filter(fieldName => !explicitFieldNames.includes(fieldName));
|
||||||
|
|
||||||
if (typeof additionalProps === 'object' || additionalProps === true) {
|
if (typeof additionalProps === 'object' || additionalProps === true) {
|
||||||
|
const additionalPropertiesName = typeof additionalProps === 'object'
|
||||||
|
? additionalProps['x-additionalPropertiesName'] || 'property name'
|
||||||
|
: 'property name';
|
||||||
|
|
||||||
fields.push(
|
fields.push(
|
||||||
new FieldModel(
|
new FieldModel(
|
||||||
parser,
|
parser,
|
||||||
{
|
{
|
||||||
name: (typeof additionalProps === 'object'
|
name: additionalPropertiesName.concat('*'),
|
||||||
? additionalProps['x-additionalPropertiesName'] || 'property name'
|
requiredNames: implicitRequiredNames,
|
||||||
: 'property name'
|
required: implicitRequiredNames.length > 0,
|
||||||
).concat('*'),
|
|
||||||
required: false,
|
|
||||||
schema: additionalProps === true ? {} : additionalProps,
|
schema: additionalProps === true ? {} : additionalProps,
|
||||||
kind: 'additionalProperties',
|
kind: 'additionalProperties',
|
||||||
},
|
},
|
||||||
|
@ -304,6 +310,23 @@ function buildFields(
|
||||||
options,
|
options,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} else if (implicitRequiredNames.length > 0) {
|
||||||
|
const firstImplicitName = additionalProps === false ? '(incorrectly required)' :
|
||||||
|
(implicitRequiredNames.shift() || '');
|
||||||
|
fields.push(
|
||||||
|
new FieldModel(
|
||||||
|
parser,
|
||||||
|
{
|
||||||
|
name: firstImplicitName,
|
||||||
|
requiredNames: implicitRequiredNames,
|
||||||
|
required: true,
|
||||||
|
schema: {},
|
||||||
|
kind: 'field',
|
||||||
|
},
|
||||||
|
$ref + '/properties/' + firstImplicitName,
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
|
|
1
src/types/open-api.d.ts
vendored
1
src/types/open-api.d.ts
vendored
|
@ -84,6 +84,7 @@ export interface OpenAPIParameter {
|
||||||
in?: OpenAPIParameterLocation;
|
in?: OpenAPIParameterLocation;
|
||||||
description?: string;
|
description?: string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
|
requiredNames?: string[];
|
||||||
deprecated?: boolean;
|
deprecated?: boolean;
|
||||||
allowEmptyValue?: boolean;
|
allowEmptyValue?: boolean;
|
||||||
style?: OpenAPIParameterStyle;
|
style?: OpenAPIParameterStyle;
|
||||||
|
|
|
@ -114,6 +114,9 @@ export function isPrimitiveType(schema: OpenAPISchema, type: string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'object') {
|
if (type === 'object') {
|
||||||
|
if (schema.required !== undefined && schema.required.length !== 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return schema.properties !== undefined
|
return schema.properties !== undefined
|
||||||
? Object.keys(schema.properties).length === 0
|
? Object.keys(schema.properties).length === 0
|
||||||
: schema.additionalProperties === undefined;
|
: schema.additionalProperties === undefined;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user