mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-08 14:14:56 +03:00
feat: new option showExtensions (support list of extensions)
This commit is contained in:
parent
3000b67637
commit
e92f00edb2
|
@ -1,35 +1,37 @@
|
|||
import * as React from 'react';
|
||||
import styled from '../../styled-components';
|
||||
|
||||
import { isRedocExtension } from '../../utils/openapi';
|
||||
import { OptionsContext } from '../OptionsProvider';
|
||||
|
||||
import { SchemaModel } from '../../services/models';
|
||||
import { FieldDetail } from './FieldDetail';
|
||||
import { StyledMarkdownBlock } from '../Markdown/styled.elements';
|
||||
|
||||
const Extension = styled(StyledMarkdownBlock)`
|
||||
opacity: 0.9;
|
||||
margin: 2px 0;
|
||||
`;
|
||||
|
||||
const ExtensionLable = styled.span`
|
||||
font-style: italic;
|
||||
`;
|
||||
|
||||
export interface ExtensionsProps {
|
||||
schema: SchemaModel;
|
||||
extensions: {
|
||||
[k: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export class Extensions extends React.PureComponent<ExtensionsProps> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.getExtensions = this.getExtensions.bind(this);
|
||||
}
|
||||
|
||||
getExtensions() {
|
||||
const { schema } = this.props;
|
||||
const fullSchema = schema.schema;
|
||||
return Object.keys(fullSchema).filter(key => key.startsWith('x-') && !isRedocExtension(key));
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<OptionsContext.Consumer>
|
||||
{options => (
|
||||
<>
|
||||
{options.showExtensions &&
|
||||
this.getExtensions().map(key => (
|
||||
<FieldDetail key={key} label={key} value={this.props.schema.schema[key]} />
|
||||
Object.keys(this.props.extensions).map(key => (
|
||||
<Extension key={key}>
|
||||
<ExtensionLable>{key}</ExtensionLable>:{' '}
|
||||
<code>{JSON.stringify(this.props.extensions[key])}</code>
|
||||
</Extension>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -52,7 +52,7 @@ export class FieldDetails extends React.PureComponent<FieldProps> {
|
|||
<FieldDetail label={'Default:'} value={schema.default} />
|
||||
{!renderDiscriminatorSwitch && <EnumValues type={schema.type} values={schema.enum} />}{' '}
|
||||
{showExamples && <FieldDetail label={'Example:'} value={example} />}
|
||||
{<Extensions schema={schema} />}
|
||||
{<Extensions extensions={{ ...field.extensions, ...schema.extensions }} />}
|
||||
<div>
|
||||
<Markdown compact={true} source={description} />
|
||||
</div>
|
||||
|
|
|
@ -18,6 +18,7 @@ import { ResponseSamples } from '../ResponseSamples/ResponseSamples';
|
|||
|
||||
import { OperationModel as OperationType } from '../../services/models';
|
||||
import styled from '../../styled-components';
|
||||
import { Extensions } from '../Fields/Extensions';
|
||||
|
||||
const OperationRow = styled(Row)`
|
||||
backface-visibility: hidden;
|
||||
|
@ -58,6 +59,7 @@ export class Operation extends React.Component<OperationProps> {
|
|||
{externalDocs && <ExternalDocumentation externalDocs={externalDocs} />}
|
||||
</Description>
|
||||
)}
|
||||
<Extensions extensions={operation.extensions} />
|
||||
<SecurityRequirements securities={operation.security} />
|
||||
<Parameters parameters={operation.parameters} body={operation.requestBody} />
|
||||
<ResponsesList responses={operation.responses} />
|
||||
|
|
|
@ -17,7 +17,7 @@ export interface RedocRawOptions {
|
|||
hideLoading?: boolean | string;
|
||||
hideDownloadButton?: boolean | string;
|
||||
disableSearch?: boolean | string;
|
||||
showExtensions?: boolean | string;
|
||||
showExtensions?: boolean | string | string[];
|
||||
|
||||
unstable_ignoreMimeParameters?: boolean;
|
||||
|
||||
|
@ -89,6 +89,21 @@ export class RedocNormalizedOptions {
|
|||
return () => 0;
|
||||
}
|
||||
|
||||
static normalizeShowExtensions(value: RedocRawOptions['showExtensions']): string[] | boolean {
|
||||
if (typeof value === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
if (value === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return value.split(',').map(ext => ext.trim());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
theme: ResolvedThemeInterface;
|
||||
scrollYOffset: () => number;
|
||||
hideHostname: boolean;
|
||||
|
@ -100,7 +115,7 @@ export class RedocNormalizedOptions {
|
|||
untrustedSpec: boolean;
|
||||
hideDownloadButton: boolean;
|
||||
disableSearch: boolean;
|
||||
showExtensions: boolean;
|
||||
showExtensions: boolean | string[];
|
||||
|
||||
/* tslint:disable-next-line */
|
||||
unstable_ignoreMimeParameters: boolean;
|
||||
|
@ -126,7 +141,7 @@ export class RedocNormalizedOptions {
|
|||
this.untrustedSpec = argValueToBoolean(raw.untrustedSpec);
|
||||
this.hideDownloadButton = argValueToBoolean(raw.hideDownloadButton);
|
||||
this.disableSearch = argValueToBoolean(raw.disableSearch);
|
||||
this.showExtensions = argValueToBoolean(raw.showExtensions);
|
||||
this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions);
|
||||
|
||||
this.unstable_ignoreMimeParameters = argValueToBoolean(raw.unstable_ignoreMimeParameters);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { action, observable } from 'mobx';
|
|||
import { OpenAPIParameter, Referenced } from '../../types';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
|
||||
import { extractExtensions } from '../../utils/openapi';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { SchemaModel } from './Schema';
|
||||
|
||||
|
@ -21,6 +22,7 @@ export class FieldModel {
|
|||
deprecated: boolean;
|
||||
in?: string;
|
||||
kind: string;
|
||||
extensions?: Dict<any>;
|
||||
|
||||
constructor(
|
||||
parser: OpenAPIParser,
|
||||
|
@ -40,6 +42,10 @@ export class FieldModel {
|
|||
|
||||
this.deprecated = info.deprecated === undefined ? !!this.schema.deprecated : info.deprecated;
|
||||
parser.exitRef(infoOrRef);
|
||||
|
||||
if (options.showExtensions) {
|
||||
this.extensions = extractExtensions(info, options.showExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
|
|
|
@ -7,6 +7,7 @@ import { SecurityRequirementModel } from './SecurityRequirement';
|
|||
import { OpenAPIExternalDocumentation, OpenAPIServer, OpenAPIXCodeSample } from '../../types';
|
||||
|
||||
import {
|
||||
extractExtensions,
|
||||
getOperationSummary,
|
||||
getStatusCodeType,
|
||||
isStatusCode,
|
||||
|
@ -56,6 +57,7 @@ export class OperationModel implements IMenuItem {
|
|||
servers: OpenAPIServer[];
|
||||
security: SecurityRequirementModel[];
|
||||
codeSamples: OpenAPIXCodeSample[];
|
||||
extensions: Dict<any>;
|
||||
|
||||
constructor(
|
||||
private parser: OpenAPIParser,
|
||||
|
@ -91,6 +93,10 @@ export class OperationModel implements IMenuItem {
|
|||
this.security = (operationSpec.security || parser.spec.security || []).map(
|
||||
security => new SecurityRequirementModel(security, parser),
|
||||
);
|
||||
|
||||
if (options.showExtensions) {
|
||||
this.extensions = extractExtensions(operationSpec, options.showExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
isPrimitiveType,
|
||||
JsonPointer,
|
||||
sortByRequired,
|
||||
extractExtensions,
|
||||
} from '../../utils/';
|
||||
|
||||
// TODO: refactor this model, maybe use getters instead of copying all the values
|
||||
|
@ -54,6 +55,7 @@ export class SchemaModel {
|
|||
|
||||
rawSchema: OpenAPISchema;
|
||||
schema: MergedOpenAPISchema;
|
||||
extensions?: Dict<any>;
|
||||
|
||||
/**
|
||||
* @param isChild if schema discriminator Child
|
||||
|
@ -77,6 +79,10 @@ export class SchemaModel {
|
|||
// exit all the refs visited during allOf traverse
|
||||
parser.exitRef({ $ref: parent$ref });
|
||||
}
|
||||
|
||||
if (options.showExtensions) {
|
||||
this.extensions = extractExtensions(this.schema, options.showExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -303,3 +303,17 @@ export function isRedocExtension(key: string): boolean {
|
|||
|
||||
return key in redocExtensions;
|
||||
}
|
||||
|
||||
export function extractExtensions(obj: object, showExtensions: string[] | true): Dict<any> {
|
||||
return Object.keys(obj)
|
||||
.filter(key => {
|
||||
if (showExtensions === true) {
|
||||
return key.startsWith('x-') && !isRedocExtension(key);
|
||||
}
|
||||
return key.startsWith('x-') && showExtensions.indexOf(key) > -1;
|
||||
})
|
||||
.reduce((acc, key) => {
|
||||
acc[key] = obj[key];
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user