mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-10 19:06:34 +03:00
chore: add tslint + fix lint issues
This commit is contained in:
parent
3819ad7e6a
commit
dc18743df4
|
@ -5,8 +5,8 @@ import { AppContainer } from 'react-hot-loader';
|
|||
|
||||
import { Redoc, RedocProps } from '../../src/components/Redoc/Redoc';
|
||||
import { AppStore } from '../../src/services/AppStore';
|
||||
import { loadAndBundleSpec } from '../../src/utils/loadAndBundleSpec';
|
||||
import { RedocRawOptions } from '../../src/services/RedocNormalizedOptions';
|
||||
import { loadAndBundleSpec } from '../../src/utils/loadAndBundleSpec';
|
||||
|
||||
const renderRoot = (Component: typeof Redoc, props: RedocProps) =>
|
||||
render(
|
||||
|
@ -19,7 +19,7 @@ const renderRoot = (Component: typeof Redoc, props: RedocProps) =>
|
|||
);
|
||||
|
||||
const big = window.location.search.indexOf('big') > -1;
|
||||
const swagger = window.location.search.indexOf('swagger') > -1; //compatibility mode ?
|
||||
const swagger = window.location.search.indexOf('swagger') > -1; // compatibility mode ?
|
||||
|
||||
const specUrl = swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml';
|
||||
|
||||
|
@ -29,7 +29,7 @@ const options: RedocRawOptions = {};
|
|||
async function init() {
|
||||
const spec = await loadAndBundleSpec(specUrl);
|
||||
store = new AppStore(spec, specUrl, options);
|
||||
renderRoot(Redoc, { store: store });
|
||||
renderRoot(Redoc, { store });
|
||||
}
|
||||
|
||||
init();
|
||||
|
@ -44,7 +44,7 @@ if (module.hot) {
|
|||
store = AppStore.fromJS(state);
|
||||
}
|
||||
|
||||
renderRoot(Redoc, { store: store });
|
||||
renderRoot(Redoc, { store });
|
||||
};
|
||||
|
||||
module.hot.accept(['../../src/components/Redoc/Redoc'], reload());
|
||||
|
|
14
package.json
14
package.json
|
@ -7,8 +7,7 @@
|
|||
"start": "webpack-dev-server --hot",
|
||||
"start:perf": "webpack-dev-server --env.prod --env.perf",
|
||||
"start:prod": "webpack-dev-server --env.prod",
|
||||
"dev": "webpack-dashboard -- webpack-dev-server --hot",
|
||||
"test": "npm run unit && npm run e2e",
|
||||
"test": "npm run lint && npm run unit && npm run e2e",
|
||||
"unit": "jest",
|
||||
"e2e": "npm run e2e:clean && npm run e2e:tsc && cypress run",
|
||||
"e2e:tsc": "tsc -p tsconfig.e2e.json",
|
||||
|
@ -20,8 +19,8 @@
|
|||
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:standalone",
|
||||
"stats": "webpack -p --env.lib --env.standalone --env.prod --json --profile > stats.json",
|
||||
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
|
||||
"http-server": "http-server .",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1"
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
|
||||
"lint": "tslint --project tsconfig.json"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
|
@ -51,7 +50,6 @@
|
|||
"enzyme-adapter-react-16": "^1.0.4",
|
||||
"enzyme-to-json": "^3.2.2",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"http-server": "^0.10.0",
|
||||
"jest": "^21.1.0",
|
||||
"mobx-react-devtools": "^4.2.15",
|
||||
"prettier": "^1.5.3",
|
||||
|
@ -59,14 +57,14 @@
|
|||
"puppeteer": "^0.10.2",
|
||||
"raf": "^3.4.0",
|
||||
"react-dev-utils": "^4.1.0",
|
||||
"react-hot-loader": "3.0.0-beta.6",
|
||||
"rimraf": "^2.6.2",
|
||||
"source-map-loader": "^0.2.1",
|
||||
"style-loader": "^0.18.2",
|
||||
"ts-jest": "^21.0.1",
|
||||
"ts-node": "^3.3.0",
|
||||
"tslint": "^5.7.0",
|
||||
"typescript": "^2.4.2",
|
||||
"tslint-react": "^3.4.0",
|
||||
"typescript": "^2.6.2",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-dev-server": "^2.9.5",
|
||||
"webpack-node-externals": "^1.6.0"
|
||||
|
@ -84,9 +82,11 @@
|
|||
"mobx": "^3.3.0",
|
||||
"mobx-react": "^4.3.3",
|
||||
"openapi-sampler": "1.0.0-beta.8",
|
||||
"perfect-scrollbar": "^1.3.0",
|
||||
"prismjs": "^1.8.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-dropdown": "^1.3.0",
|
||||
"react-hot-loader": "3.0.0-beta.6",
|
||||
"react-perfect-scrollbar": "^0.2.2",
|
||||
"react-tabs": "^2.0.0",
|
||||
"remarkable": "^1.7.1",
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import Dropdown from 'react-dropdown';
|
||||
|
||||
import styled from '../styled-components';
|
||||
import { withProps } from '../styled-components';
|
||||
import styled, { withProps } from '../styled-components';
|
||||
|
||||
export type DropdownOption = { label: string; value: string };
|
||||
export interface DropdownOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type DropdownProps = {
|
||||
export interface DropdownProps {
|
||||
options: DropdownOption[];
|
||||
value: DropdownOption;
|
||||
onChange: (val: DropdownOption) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const StyledDropdown = withProps<DropdownProps>(styled(Dropdown))`
|
||||
min-width: 100px;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import styled from '../styled-components';
|
||||
import { deprecatedCss } from './mixins';
|
||||
import { transparentizeHex } from '../utils/styled';
|
||||
import { deprecatedCss } from './mixins';
|
||||
|
||||
export const PropertiesTableCaption = styled.caption`
|
||||
text-align: right;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import styled from 'styled-components';
|
||||
import { PropertyNameCell } from './fields-layout';
|
||||
import { transparentizeHex } from '../utils/styled';
|
||||
import { PropertyNameCell } from './fields-layout';
|
||||
|
||||
export const ClickablePropertyNameCell = PropertyNameCell.extend`
|
||||
cursor: pointer;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import styled, { css } from '../styled-components';
|
||||
|
||||
const headerFontSize = {
|
||||
'1': '1.85714em',
|
||||
'2': '1.57143em',
|
||||
'3': '1.27em',
|
||||
1: '1.85714em',
|
||||
2: '1.57143em',
|
||||
3: '1.27em',
|
||||
};
|
||||
|
||||
export const headerCommonMixin = level => css`
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import styled, { css } from 'styled-components';
|
||||
|
||||
// tslint:disable-next-line
|
||||
export const linkifyMixin = className => css`
|
||||
${className} {
|
||||
cursor: pointer;
|
||||
|
|
|
@ -6,7 +6,9 @@ export const deprecatedCss = css`
|
|||
`;
|
||||
|
||||
export const hoverColor = color => {
|
||||
if (!color) return '';
|
||||
if (!color) {
|
||||
return '';
|
||||
}
|
||||
return css`
|
||||
&:hover {
|
||||
color: ${color};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import psStyles from 'perfect-scrollbar/css/perfect-scrollbar.css';
|
||||
import styled, { injectGlobal } from '../styled-components';
|
||||
import psStyles from 'perfect-scrollbar/dist/css/perfect-scrollbar.css';
|
||||
|
||||
import PerfectScrollbarOriginal from 'react-perfect-scrollbar';
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import styled from '../styled-components';
|
||||
import { withProps } from '../styled-components';
|
||||
import styled, { withProps } from '../styled-components';
|
||||
|
||||
export const OneOfList = styled.ul`
|
||||
margin: 0;
|
||||
|
|
|
@ -8,7 +8,7 @@ const directionMap = {
|
|||
down: '0',
|
||||
};
|
||||
|
||||
class _ShelfIcon extends React.PureComponent<{
|
||||
class IntShelfIcon extends React.PureComponent<{
|
||||
className?: string;
|
||||
float?: 'left' | 'right';
|
||||
size?: string;
|
||||
|
@ -33,7 +33,7 @@ class _ShelfIcon extends React.PureComponent<{
|
|||
}
|
||||
}
|
||||
|
||||
export const ShelfIcon = styled(_ShelfIcon)`
|
||||
export const ShelfIcon = styled(IntShelfIcon)`
|
||||
height: ${props => props.size || '18px'};
|
||||
width: ${props => props.size || '18px'};
|
||||
vertical-align: middle;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import styled from '../styled-components';
|
||||
import { Tabs as ReactTabs } from 'react-tabs';
|
||||
import styled from '../styled-components';
|
||||
|
||||
export { Tab, TabList, TabPanel } from 'react-tabs';
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { AppStore } from '../../services/AppStore';
|
||||
|
||||
import { SecurityDefs } from '../SecuritySchemes/SecuritySchemes';
|
||||
import { DarkRightPanel, MiddlePanel, Row } from '../../common-elements/';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { MiddlePanel, DarkRightPanel, Row } from '../../common-elements/';
|
||||
import { SecurityDefs } from '../SecuritySchemes/SecuritySchemes';
|
||||
|
||||
import {
|
||||
ApiHeader,
|
||||
DownloadButton,
|
||||
InfoSpan,
|
||||
InfoSpanBoxWrap,
|
||||
InfoSpanBox,
|
||||
InfoSpanBoxWrap,
|
||||
} from './styled.elements';
|
||||
|
||||
interface ApiInfoProps {
|
||||
|
@ -101,8 +101,8 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
|
|||
components={{
|
||||
'security-definitions': {
|
||||
component: SecurityDefs,
|
||||
propsSelector: store => ({
|
||||
securitySchemes: store!.spec.securitySchemes,
|
||||
propsSelector: _store => ({
|
||||
securitySchemes: _store!.spec.securitySchemes,
|
||||
}),
|
||||
},
|
||||
}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import styled from '../../styled-components';
|
||||
|
||||
import { MiddlePanel, H1 } from '../../common-elements';
|
||||
import { H1, MiddlePanel } from '../../common-elements';
|
||||
|
||||
const delimiterWidth = 15;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { OpenAPIInfo } from '../../types';
|
||||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { OpenAPIInfo } from '../../types';
|
||||
import { LogoImgEl, LogoWrap } from './styled.elements';
|
||||
|
||||
const LinkWrap = url => Component => <a href={url}>{Component}</a>;
|
||||
|
@ -10,7 +10,9 @@ export class ApiLogo extends React.Component<{ info: OpenAPIInfo }> {
|
|||
render() {
|
||||
const { info } = this.props;
|
||||
const logoInfo = info['x-logo'];
|
||||
if (!logoInfo || !logoInfo.url) return null;
|
||||
if (!logoInfo || !logoInfo.url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const logo = (
|
||||
<LogoImgEl src={logoInfo.url} style={{ backgroundColor: logoInfo.backgroundColor }} />
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { SECTION_ATTR } from '../../services/MenuStore';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
|
||||
import { DarkRightPanel, H1, MiddlePanel, ShareLink, Row } from '../../common-elements';
|
||||
import { Operation } from '../Operation/Operation';
|
||||
import { DarkRightPanel, H1, MiddlePanel, Row, ShareLink } from '../../common-elements';
|
||||
import { ContentItemModel } from '../../services/MenuBuilder';
|
||||
import { OperationModel } from '../../services/models';
|
||||
import { Operation } from '../Operation/Operation';
|
||||
|
||||
@observer
|
||||
export class ContentItems extends React.Component<{
|
||||
|
@ -15,14 +15,16 @@ export class ContentItems extends React.Component<{
|
|||
}> {
|
||||
render() {
|
||||
const items = this.props.items;
|
||||
if (items.length === 0) return null;
|
||||
if (items.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return items.map(item => <ContentItem item={item} key={item.id} />);
|
||||
}
|
||||
}
|
||||
|
||||
type ContentItemProps = {
|
||||
interface ContentItemProps {
|
||||
item: ContentItemModel;
|
||||
};
|
||||
}
|
||||
|
||||
@observer
|
||||
export class ContentItem extends React.Component<ContentItemProps> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { MimeLabel, SimpleDropdown, DropdownProps } from '../../common-elements/dropdown';
|
||||
import { DropdownProps, MimeLabel, SimpleDropdown } from '../../common-elements/dropdown';
|
||||
|
||||
export interface DropdownOrLabelProps extends DropdownProps {
|
||||
Label?: React.ComponentClass;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
import * as React from 'react';
|
||||
import { OperationModel } from '../../services';
|
||||
import { ShelfIcon } from '../../common-elements';
|
||||
import { OperationModel } from '../../services';
|
||||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
import { SelectOnClick } from '../SelectOnClick/SelectOnClick';
|
||||
|
||||
import {
|
||||
OperationEndpointWrap,
|
||||
EndpointInfo,
|
||||
HttpVerb,
|
||||
OperationEndpointWrap,
|
||||
ServerItem,
|
||||
ServerRelativeURL,
|
||||
ServersOverlay,
|
||||
ServerItem,
|
||||
ServerUrl,
|
||||
} from './styled.elements';
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as React from 'react';
|
||||
import { Children } from 'react';
|
||||
import styled from '../styled-components';
|
||||
|
||||
const ErrorWrapper = styled.div`
|
||||
|
@ -14,7 +13,7 @@ export class ErrorBoundary extends React.Component<{}, { error?: Error }> {
|
|||
}
|
||||
|
||||
componentDidCatch(error) {
|
||||
this.setState({ error: error });
|
||||
this.setState({ error });
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -35,6 +34,6 @@ export class ErrorBoundary extends React.Component<{}, { error?: Error }> {
|
|||
</ErrorWrapper>
|
||||
);
|
||||
}
|
||||
return Children.only(this.props.children);
|
||||
return React.Children.only(this.props.children);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ export interface EnumValuesProps {
|
|||
export class EnumValues extends React.PureComponent<EnumValuesProps> {
|
||||
render() {
|
||||
const { values, type } = this.props;
|
||||
if (!values.length) return null;
|
||||
if (!values.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { FieldDetails } from './FieldDetails';
|
||||
import * as React from 'react';
|
||||
import { FieldDetails } from './FieldDetails';
|
||||
|
||||
import { ClickablePropertyNameCell, RequiredLabel } from '../../common-elements/fields';
|
||||
|
||||
|
|
|
@ -7,7 +7,9 @@ export interface ConstraintsViewProps {
|
|||
|
||||
export class ConstraintsView extends React.PureComponent<ConstraintsViewProps> {
|
||||
render() {
|
||||
if (this.props.constraints.length === 0) return null;
|
||||
if (this.props.constraints.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
{' '}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ExampleValue, FieldLabel } from '../../common-elements/fields';
|
||||
import * as React from 'react';
|
||||
import { ExampleValue, FieldLabel } from '../../common-elements/fields';
|
||||
|
||||
export interface FieldDetailProps {
|
||||
value?: any;
|
||||
|
@ -8,7 +8,9 @@ export interface FieldDetailProps {
|
|||
|
||||
export class FieldDetail extends React.PureComponent<FieldDetailProps> {
|
||||
render() {
|
||||
if (this.props.value === undefined) return null;
|
||||
if (this.props.value === undefined) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<FieldLabel> {this.props.label} </FieldLabel>{' '}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { FieldProps } from './Field';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { EnumValues } from './EnumValues';
|
||||
import { FieldDetail } from './FieldDetail';
|
||||
import { ConstraintsView } from './FieldContstraints';
|
||||
import {
|
||||
RecursiveLabel,
|
||||
NullableLabel,
|
||||
PatternLabel,
|
||||
RecursiveLabel,
|
||||
TypeFormat,
|
||||
TypeName,
|
||||
TypeTitle,
|
||||
TypePrefix,
|
||||
TypeTitle,
|
||||
} from '../../common-elements/fields';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { EnumValues } from './EnumValues';
|
||||
import { FieldProps } from './Field';
|
||||
import { ConstraintsView } from './FieldContstraints';
|
||||
import { FieldDetail } from './FieldDetail';
|
||||
|
||||
import { Badge } from '../../common-elements/';
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ class Json extends React.PureComponent<JsonProps> {
|
|||
}
|
||||
|
||||
clickListener = (event: MouseEvent) => {
|
||||
var collapsed,
|
||||
target = event.target as HTMLElement;
|
||||
let collapsed;
|
||||
const target = event.target as HTMLElement;
|
||||
if (target.className === 'collapser') {
|
||||
collapsed = target.parentElement!.getElementsByClassName('collapsible')[0];
|
||||
if (collapsed.parentElement.classList.contains('collapsed')) {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import * as React from 'react';
|
||||
import styled from '../../styled-components';
|
||||
|
||||
import * as DOMPurify from 'dompurify';
|
||||
import { AppStore, MarkdownRenderer } from '../../services';
|
||||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
import * as DOMPurify from 'dompurify';
|
||||
|
||||
import { markdownCss } from './styles';
|
||||
|
||||
export type MDComponent = {
|
||||
export interface MDComponent {
|
||||
component: React.ComponentClass;
|
||||
propsSelector: (store?: AppStore) => any;
|
||||
attrs?: object;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MarkdownProps {
|
||||
source: string;
|
||||
|
@ -29,7 +29,7 @@ class InternalMarkdown extends ComponentWithOptions<MarkdownProps> {
|
|||
super(props);
|
||||
|
||||
if (props.components && props.inline) {
|
||||
throw new Error(`Markdown Component: "inline" mode doesn't support "components"`);
|
||||
throw new Error('Markdown Component: "inline" mode doesn\'t support "components"');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,24 +40,27 @@ class InternalMarkdown extends ComponentWithOptions<MarkdownProps> {
|
|||
throw new Error('When using components with Markdwon in ReDoc, store prop must be provided');
|
||||
}
|
||||
|
||||
let sanitize: (string) => string;
|
||||
|
||||
if (this.props.sanitize || this.options.untrustedSpec) {
|
||||
sanitize = html => DOMPurify.sanitize(html);
|
||||
} else {
|
||||
sanitize = html => html;
|
||||
}
|
||||
const sanitize =
|
||||
this.props.sanitize || this.options.untrustedSpec
|
||||
? (html: string) => DOMPurify.sanitize(html)
|
||||
: (html: string) => html;
|
||||
|
||||
const renderer = new MarkdownRenderer();
|
||||
const parts = components
|
||||
? renderer.renderMdWithComponents(source, components, raw)
|
||||
: [renderer.renderMd(source, raw)];
|
||||
|
||||
if (!parts.length) return null;
|
||||
if (!parts.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let appendClass = ' redoc-markdown';
|
||||
if (dense) appendClass += ' -dense';
|
||||
if (inline) appendClass += ' -inline';
|
||||
if (dense) {
|
||||
appendClass += ' -dense';
|
||||
}
|
||||
if (inline) {
|
||||
appendClass += ' -inline';
|
||||
}
|
||||
|
||||
if (inline) {
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { css } from '../../styled-components';
|
||||
import { headerCommonMixin, linkifyMixin } from '../../common-elements';
|
||||
import { css } from '../../styled-components';
|
||||
|
||||
export const markdownCss = css`
|
||||
p {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { MediaContentModel, SchemaModel, MediaTypeModel } from '../../services/models';
|
||||
import { DropdownProps } from '../../common-elements/dropdown';
|
||||
import { MediaContentModel, MediaTypeModel, SchemaModel } from '../../services/models';
|
||||
|
||||
export interface MediaTypeChildProps {
|
||||
schema: SchemaModel;
|
||||
|
@ -18,15 +18,19 @@ export interface MediaTypesSwitchProps {
|
|||
@observer
|
||||
export class MediaTypesSwitch extends React.Component<MediaTypesSwitchProps> {
|
||||
switchMedia = ({ value }) => {
|
||||
this.props.content && this.props.content.activate(parseInt(value));
|
||||
if (this.props.content) {
|
||||
this.props.content.activate(parseInt(value, 10));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { content } = this.props;
|
||||
if (!content || !content.mediaTypes || !content.mediaTypes.length) return null;
|
||||
if (!content || !content.mediaTypes || !content.mediaTypes.length) {
|
||||
return null;
|
||||
}
|
||||
const activeMimeIdx = content.activeMimeIdx;
|
||||
|
||||
let options = content.mediaTypes.map((mime, idx) => {
|
||||
const options = content.mediaTypes.map((mime, idx) => {
|
||||
return {
|
||||
label: mime.name,
|
||||
value: idx.toString(),
|
||||
|
|
|
@ -8,13 +8,13 @@ import { Badge, DarkRightPanel, H2, MiddlePanel, Row } from '../../common-elemen
|
|||
|
||||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { Parameters } from '../Parameters/Parameters';
|
||||
import { ResponsesList } from '../Responses/ResponsesList';
|
||||
import { RequestSamples } from '../RequestSamples/RequestSamples';
|
||||
import { ResponseSamples } from '../ResponseSamples/ResponseSamples';
|
||||
import { ShareLink } from '../../common-elements/linkify';
|
||||
import { Endpoint } from '../Endpoint/Endpoint';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { Parameters } from '../Parameters/Parameters';
|
||||
import { RequestSamples } from '../RequestSamples/RequestSamples';
|
||||
import { ResponsesList } from '../Responses/ResponsesList';
|
||||
import { ResponseSamples } from '../ResponseSamples/ResponseSamples';
|
||||
|
||||
import { OperationModel as OperationType } from '../../services/models';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
|
||||
import { RedocNormalizedOptions } from '../services/RedocNormalizedOptions';
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import * as React from 'react';
|
||||
import { DropdownOrLabel } from '../DropdownOrLabel/DropdownOrLabel';
|
||||
import { ParametersGroup } from './ParametersGroup';
|
||||
import * as React from 'react';
|
||||
|
||||
import { UnderlinedHeader } from '../../common-elements';
|
||||
|
||||
import { Schema } from '../Schema';
|
||||
import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
|
||||
import { FieldModel, RequestBodyModel } from '../../services/models';
|
||||
import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
|
||||
import { Schema } from '../Schema';
|
||||
|
||||
import { MediaContentModel } from '../../services';
|
||||
|
||||
function safePush(obj, prop, item) {
|
||||
if (!obj[prop]) obj[prop] = [];
|
||||
if (!obj[prop]) {
|
||||
obj[prop] = [];
|
||||
}
|
||||
obj[prop].push(item);
|
||||
}
|
||||
|
||||
|
@ -24,7 +26,7 @@ const PARAM_PLACES = ['path', 'query', 'cookie', 'header'];
|
|||
|
||||
export class Parameters extends React.PureComponent<ParametersProps> {
|
||||
orderParams(params: FieldModel[]): Dict<FieldModel[]> {
|
||||
let res = {};
|
||||
const res = {};
|
||||
params.forEach(param => {
|
||||
safePush(res, param.in, param);
|
||||
});
|
||||
|
@ -37,7 +39,7 @@ export class Parameters extends React.PureComponent<ParametersProps> {
|
|||
return null;
|
||||
}
|
||||
|
||||
let paramsMap = this.orderParams(parameters);
|
||||
const paramsMap = this.orderParams(parameters);
|
||||
|
||||
const paramsPlaces = parameters.length > 0 ? PARAM_PLACES : [];
|
||||
|
||||
|
@ -54,17 +56,18 @@ export class Parameters extends React.PureComponent<ParametersProps> {
|
|||
}
|
||||
}
|
||||
|
||||
function BodyContent(props: { content: MediaContentModel }): JSX.Element {
|
||||
const { content } = props;
|
||||
function DropdownWithinHeader(props) {
|
||||
return (
|
||||
<MediaTypesSwitch
|
||||
content={content}
|
||||
renderDropdown={props => (
|
||||
<UnderlinedHeader key="header">
|
||||
Request Body schema: <DropdownOrLabel {...props} />
|
||||
</UnderlinedHeader>
|
||||
)}
|
||||
>
|
||||
);
|
||||
}
|
||||
|
||||
function BodyContent(props: { content: MediaContentModel }): JSX.Element {
|
||||
const { content } = props;
|
||||
return (
|
||||
<MediaTypesSwitch content={content} renderDropdown={DropdownWithinHeader}>
|
||||
{({ schema }) => {
|
||||
return <Schema skipReadOnly={true} key="schema" schema={schema} />;
|
||||
}}
|
||||
|
|
|
@ -16,7 +16,9 @@ export interface ParametersGroupProps {
|
|||
export class ParametersGroup extends React.PureComponent<ParametersGroupProps, any> {
|
||||
render() {
|
||||
const { place, parameters } = this.props;
|
||||
if (!parameters || !parameters.length) return null;
|
||||
if (!parameters || !parameters.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={place}>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { SmallTabs, Tab, TabList, TabPanel } from '../../common-elements';
|
||||
import { MediaTypeModel } from '../../services/models';
|
||||
import { StyledJson } from '../JsonViewer/JsonViewer';
|
||||
import { SourceCode } from '../SourceCode/SourceCode';
|
||||
import { SmallTabs, TabList, TabPanel, Tab } from '../../common-elements';
|
||||
import { NoSampleLabel } from './styled.elements';
|
||||
|
||||
import { isJsonLike, langFromMime } from '../../utils';
|
||||
|
@ -24,7 +24,9 @@ export class MediaTypeSamples extends React.Component<PayloadSamplesProps> {
|
|||
(sample && <SourceCode lang={langFromMime(mimeType)} source={sample} />) || { noSample };
|
||||
|
||||
const examplesNames = Object.keys(examples);
|
||||
if (examplesNames.length === 0) return noSample;
|
||||
if (examplesNames.length === 0) {
|
||||
return noSample;
|
||||
}
|
||||
if (examplesNames.length > 1) {
|
||||
return (
|
||||
<SmallTabs>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { MediaTypeSamples } from './MediaTypeSamples';
|
||||
import * as React from 'react'
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { MediaTypeSamples } from './MediaTypeSamples';
|
||||
|
||||
import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
|
||||
|
||||
|
@ -16,15 +16,18 @@ export interface PayloadSamplesProps {
|
|||
export class PayloadSamples extends React.Component<PayloadSamplesProps> {
|
||||
render() {
|
||||
const mimeContent = this.props.content;
|
||||
if (mimeContent === undefined) return null;
|
||||
if (mimeContent === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MediaTypesSwitch
|
||||
content={mimeContent}
|
||||
renderDropdown={props => <DropdownOrLabel Label={MimeLabel} Dropdown={InvertedSimpleDropdown} {...props} />}
|
||||
>
|
||||
<MediaTypesSwitch content={mimeContent} renderDropdown={this.renderDropdown}>
|
||||
{mediaType => <MediaTypeSamples key="samples" mediaType={mediaType} />}
|
||||
</MediaTypesSwitch>
|
||||
);
|
||||
}
|
||||
|
||||
private renderDropdown = props => {
|
||||
return <DropdownOrLabel Label={MimeLabel} Dropdown={InvertedSimpleDropdown} {...props} />;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ export const InvertedSimpleDropdown = styled(SimpleDropdown)`
|
|||
}
|
||||
`;
|
||||
|
||||
|
||||
export const NoSampleLabel = styled.div`
|
||||
font-family: ${props => props.theme.code.fontFamily};
|
||||
font-size: 12px;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
|
||||
import { ThemeProvider } from '../../styled-components';
|
||||
|
||||
import { ApiInfo } from '../ApiInfo/ApiInfo';
|
||||
import { RedocWrap, ApiContent } from './elements';
|
||||
import { ApiLogo } from '../ApiLogo/ApiLogo';
|
||||
import { SideMenu } from '../SideMenu/SideMenu';
|
||||
import { ContentItems } from '../ContentItems/ContentItems';
|
||||
import { AppStore } from '../../services';
|
||||
import { ApiInfo } from '../ApiInfo/ApiInfo';
|
||||
import { ApiLogo } from '../ApiLogo/ApiLogo';
|
||||
import { ContentItems } from '../ContentItems/ContentItems';
|
||||
import { OptionsProvider } from '../OptionsProvider';
|
||||
import { SideMenu } from '../SideMenu/SideMenu';
|
||||
import { StickySidebar } from '../StickySidebar/StickySidebar';
|
||||
import { ApiContent, RedocWrap } from './elements';
|
||||
|
||||
export interface RedocProps {
|
||||
store: AppStore;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Loading } from './Loading/Loading';
|
||||
import { StoreProvider } from './StoreProvider';
|
||||
import { ErrorBoundary } from './ErrorBoundary';
|
||||
import { Redoc } from './Redoc/Redoc';
|
||||
import { RedocNormalizedOptions, RedocRawOptions } from '../services/RedocNormalizedOptions';
|
||||
import { ErrorBoundary } from './ErrorBoundary';
|
||||
import { Loading } from './Loading/Loading';
|
||||
import { Redoc } from './Redoc/Redoc';
|
||||
import { StoreProvider } from './StoreProvider';
|
||||
|
||||
export interface RedocStandaloneProps {
|
||||
spec?: object;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { SourceCode } from '../SourceCode/SourceCode';
|
||||
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
||||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { OperationModel } from '../../services/models';
|
||||
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
||||
import { SourceCode } from '../SourceCode/SourceCode';
|
||||
|
||||
import { Tab, Tabs, TabList, TabPanel } from '../../common-elements';
|
||||
import { Tab, TabList, TabPanel, Tabs } from '../../common-elements';
|
||||
|
||||
export interface RequestSamplesProps {
|
||||
operation: OperationModel;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { MediaContentModel, OperationModel } from '../../services/models';
|
||||
|
||||
import { Tab, Tabs, TabList, TabPanel } from '../../common-elements';
|
||||
import { Tab, TabList, TabPanel, Tabs } from '../../common-elements';
|
||||
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
|
||||
|
||||
export interface ResponseSampleProps {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { ResponseModel } from '../../services/models';
|
||||
|
||||
import { UnderlinedHeader } from '../../common-elements';
|
||||
import { Schema } from '../Schema';
|
||||
import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
|
||||
import { DropdownOrLabel } from '../DropdownOrLabel/DropdownOrLabel';
|
||||
import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
|
||||
import { Schema } from '../Schema';
|
||||
|
||||
import { ResponseHeaders } from './ResponseHeaders';
|
||||
import { ResponseDetailsWrap, StyledResponseTitle } from './styled.elements';
|
||||
|
@ -38,14 +38,7 @@ export class ResponseView extends React.Component<{ response: ResponseModel }> {
|
|||
!empty && (
|
||||
<ResponseDetailsWrap>
|
||||
<ResponseHeaders headers={headers} />
|
||||
<MediaTypesSwitch
|
||||
content={content}
|
||||
renderDropdown={props => (
|
||||
<UnderlinedHeader key="header">
|
||||
Response Schema: <DropdownOrLabel {...props} />
|
||||
</UnderlinedHeader>
|
||||
)}
|
||||
>
|
||||
<MediaTypesSwitch content={content} renderDropdown={this.renderDropdown}>
|
||||
{({ schema }) => {
|
||||
return <Schema skipWriteOnly={true} key="schema" schema={schema} />;
|
||||
}}
|
||||
|
@ -55,4 +48,12 @@ export class ResponseView extends React.Component<{ response: ResponseModel }> {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderDropdown = props => {
|
||||
return (
|
||||
<UnderlinedHeader key="header">
|
||||
Response Schema: <DropdownOrLabel {...props} />
|
||||
</UnderlinedHeader>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { PropertiesTable } from '../../common-elements/fields-layout';
|
||||
import * as React from 'react';
|
||||
import { PropertiesTable } from '../../common-elements/fields-layout';
|
||||
|
||||
import { HeadersCaption } from './styled.elements';
|
||||
import { mapWithLast } from '../../utils';
|
||||
import { FieldModel } from '../../services/models';
|
||||
import { mapWithLast } from '../../utils';
|
||||
import { Field } from '../Fields/Field';
|
||||
import { HeadersCaption } from './styled.elements';
|
||||
|
||||
export interface ResponseHeadersProps {
|
||||
headers?: FieldModel[];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { ShelfIcon } from '../../common-elements';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
|
||||
export interface ResponseTitleProps {
|
||||
code: string;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { ResponseView } from './Response';
|
||||
import { ResponseModel } from '../../services/models';
|
||||
import { ResponseView } from './Response';
|
||||
|
||||
const ResponsesHeader = styled.h3`
|
||||
font-size: 18px;
|
||||
|
@ -19,7 +19,9 @@ export class ResponsesList extends React.PureComponent<ResponseListProps> {
|
|||
render() {
|
||||
const { responses } = this.props;
|
||||
|
||||
if (!responses || responses.length === 0) return null;
|
||||
if (!responses || responses.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import styled from '../../styled-components';
|
||||
|
||||
import { ResponseTitle } from './ResponseTitle';
|
||||
import { UnderlinedHeader } from '../../common-elements';
|
||||
import { transparentizeHex } from '../../utils';
|
||||
import { ResponseTitle } from './ResponseTitle';
|
||||
|
||||
export const StyledResponseTitle = styled(ResponseTitle)`
|
||||
padding: 10px;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { SchemaProps, Schema } from './Schema';
|
||||
import { Schema, SchemaProps } from './Schema';
|
||||
|
||||
import { ArrayOpenningLabel, ArrayClosingLabel } from '../../common-elements';
|
||||
import { ArrayClosingLabel, ArrayOpenningLabel } from '../../common-elements';
|
||||
|
||||
export class ArraySchema extends React.PureComponent<SchemaProps> {
|
||||
render() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { StyledDropdown, DropdownOption } from '../../common-elements/dropdown';
|
||||
import { DropdownOption, StyledDropdown } from '../../common-elements/dropdown';
|
||||
import { SchemaModel } from '../../services/models';
|
||||
|
||||
@observer
|
||||
|
@ -10,7 +10,9 @@ export class DiscriminatorDropdown extends React.Component<{
|
|||
enumValues: string[];
|
||||
}> {
|
||||
sortOptions(options: DropdownOption[], enumValues: string[]): void {
|
||||
if (enumValues.length === 0) return;
|
||||
if (enumValues.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enumOrder = {};
|
||||
|
||||
|
@ -48,7 +50,7 @@ export class DiscriminatorDropdown extends React.Component<{
|
|||
}
|
||||
|
||||
changeActiveChild = ({ value }) => {
|
||||
const idx = parseInt(value);
|
||||
const idx = parseInt(value, 10);
|
||||
this.props.parent.activateOneOf(idx);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { SchemaModel, FieldModel } from '../../services/models';
|
||||
import { FieldModel, SchemaModel } from '../../services/models';
|
||||
|
||||
import { Field } from '../Fields/Field';
|
||||
import { DiscriminatorDropdown } from './DiscriminatorDropdown';
|
||||
import { Schema, SchemaProps } from './Schema';
|
||||
import {
|
||||
InnerPropertiesWrap,
|
||||
PropertiesTable,
|
||||
PropertiesTableCaption,
|
||||
PropertyCellWithInner,
|
||||
} from '../../common-elements/fields-layout';
|
||||
import { Field } from '../Fields/Field';
|
||||
import { DiscriminatorDropdown } from './DiscriminatorDropdown';
|
||||
import { Schema, SchemaProps } from './Schema';
|
||||
|
||||
import { mapWithLast } from '../../utils';
|
||||
|
||||
|
|
|
@ -1,8 +1,33 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { OneOfButton, OneOfLabel, OneOfList } from '../../common-elements/schema';
|
||||
import { SchemaProps, Schema } from './Schema';
|
||||
import {
|
||||
OneOfButton as StyledOneOfButton,
|
||||
OneOfLabel,
|
||||
OneOfList,
|
||||
} from '../../common-elements/schema';
|
||||
import { SchemaModel } from '../../services/models';
|
||||
import { Schema, SchemaProps } from './Schema';
|
||||
|
||||
export interface OneOfButtonProps {
|
||||
subSchema: SchemaModel;
|
||||
idx: number;
|
||||
schema: SchemaModel;
|
||||
}
|
||||
export class OneOfButton extends React.PureComponent<OneOfButtonProps> {
|
||||
render() {
|
||||
const { idx, schema, subSchema } = this.props;
|
||||
return (
|
||||
<StyledOneOfButton active={idx === schema.activeOneOf} onClick={this.activateOneOf}>
|
||||
{subSchema.title || subSchema.displayType}
|
||||
</StyledOneOfButton>
|
||||
);
|
||||
}
|
||||
|
||||
activateOneOf() {
|
||||
this.props.schema.activateOneOf(this.props.idx);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
export class OneOfSchema extends React.Component<SchemaProps> {
|
||||
|
@ -17,13 +42,7 @@ export class OneOfSchema extends React.Component<SchemaProps> {
|
|||
<OneOfLabel> {schema.oneOfType} </OneOfLabel>
|
||||
<OneOfList>
|
||||
{oneOf.map((subSchema, idx) => (
|
||||
<OneOfButton
|
||||
key={subSchema._$ref}
|
||||
active={idx === schema.activeOneOf}
|
||||
onClick={() => schema.activateOneOf(idx)}
|
||||
>
|
||||
{subSchema.title || subSchema.displayType}
|
||||
</OneOfButton>
|
||||
<OneOfButton key={subSchema._$ref} schema={schema} subSchema={subSchema} idx={idx} />
|
||||
))}
|
||||
</OneOfList>
|
||||
<Schema schema={oneOf[schema.activeOneOf]} />
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { FieldDetails } from '../Fields/FieldDetails';
|
||||
import { RecursiveLabel, TypeName, TypeTitle } from '../../common-elements/fields';
|
||||
import { FieldDetails } from '../Fields/FieldDetails';
|
||||
|
||||
import { SchemaModel } from '../../services/models';
|
||||
|
||||
import { ArraySchema } from './ArraySchema';
|
||||
import { ObjectSchema } from './ObjectSchema';
|
||||
import { OneOfSchema } from './OneOfSchema';
|
||||
import { ArraySchema } from './ArraySchema';
|
||||
|
||||
export interface SchemaProps {
|
||||
schema: SchemaModel;
|
||||
|
@ -21,7 +21,9 @@ export interface SchemaProps {
|
|||
export class Schema extends React.Component<Partial<SchemaProps>> {
|
||||
render() {
|
||||
const { schema } = this.props;
|
||||
if (!schema) return <em> Schema not provided </em>;
|
||||
if (!schema) {
|
||||
return <em> Schema not provided </em>;
|
||||
}
|
||||
const { type, oneOf, discriminatorProp, isCircular } = schema;
|
||||
|
||||
if (isCircular) {
|
||||
|
|
|
@ -2,8 +2,8 @@ import * as React from 'react';
|
|||
import styled from '../../styled-components';
|
||||
import { transparentizeHex } from '../../utils/styled';
|
||||
|
||||
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
|
||||
import { UnderlinedHeader } from '../../common-elements/headers';
|
||||
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
|
||||
|
||||
const ScopeName = styled.code`
|
||||
font-size: ${props => props.theme.code.fontSize};
|
||||
|
@ -57,7 +57,9 @@ export interface SecurityRequirementsProps {
|
|||
export class SecurityRequirements extends React.PureComponent<SecurityRequirementsProps> {
|
||||
render() {
|
||||
const securities = this.props.securities;
|
||||
if (!securities.length) return null;
|
||||
if (!securities.length) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<AuthHeaderColumn>
|
||||
|
|
|
@ -2,10 +2,10 @@ import * as React from 'react';
|
|||
|
||||
import { SecuritySchemesModel } from '../../services/models';
|
||||
|
||||
import styled from '../../styled-components';
|
||||
import { H2, ShareLink } from '../../common-elements';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import styled from '../../styled-components';
|
||||
import { OpenAPISecurityScheme } from '../../types';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
|
||||
const AUTH_TYPES = {
|
||||
oauth2: 'OAuth2',
|
||||
|
@ -76,7 +76,9 @@ export interface SecurityDefsProps {
|
|||
|
||||
export class SecurityDefs extends React.PureComponent<SecurityDefsProps> {
|
||||
render() {
|
||||
if (!this.props.securitySchemes) return null;
|
||||
if (!this.props.securitySchemes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -3,6 +3,7 @@ import * as React from 'react';
|
|||
import { ClipboardService } from '../../services';
|
||||
|
||||
export class SelectOnClick extends React.PureComponent {
|
||||
private child: HTMLDivElement | null;
|
||||
handleClick = () => {
|
||||
ClipboardService.selectElement(this.refs.child);
|
||||
};
|
||||
|
@ -10,7 +11,7 @@ export class SelectOnClick extends React.PureComponent {
|
|||
render() {
|
||||
const { children } = this.props;
|
||||
return (
|
||||
<div ref="child" onClick={this.handleClick}>
|
||||
<div ref={el => (this.child = el)} onClick={this.handleClick}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { IMenuItem, OperationModel } from '../../services';
|
||||
import { MenuItemLabel, MenuItemLi, MenuItemTitle, OperationBadge } from './styled.elements';
|
||||
import { ShelfIcon } from '../../common-elements/shelfs';
|
||||
import { IMenuItem, OperationModel } from '../../services';
|
||||
import { MenuItems } from './MenuItems';
|
||||
import { MenuItemLabel, MenuItemLi, MenuItemTitle, OperationBadge } from './styled.elements';
|
||||
|
||||
interface MenuItemProps {
|
||||
item: IMenuItem;
|
||||
|
@ -42,9 +42,9 @@ export class MenuItem extends React.Component<MenuItemProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export type OperationMenuItemContentProps = {
|
||||
export interface OperationMenuItemContentProps {
|
||||
item: OperationModel;
|
||||
};
|
||||
}
|
||||
|
||||
@observer
|
||||
class OperationMenuItemContent extends React.Component<OperationMenuItemContentProps> {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { IMenuItem } from '../../services';
|
||||
|
||||
import { MenuItemUl } from './styled.elements';
|
||||
import { MenuItem } from './MenuItem';
|
||||
import { MenuItemUl } from './styled.elements';
|
||||
|
||||
interface MenuItemsProps {
|
||||
items: IMenuItem[];
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
import * as React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import * as React from 'react';
|
||||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
|
||||
import { MenuStore, IMenuItem } from '../../services/MenuStore';
|
||||
import { IMenuItem, MenuStore } from '../../services/MenuStore';
|
||||
import { MenuItems } from './MenuItems';
|
||||
|
||||
import { PerfectScrollbar } from '../../common-elements/perfect-scrollbar';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { deprecatedCss } from '../../common-elements';
|
||||
import styled, { withProps, css } from '../../styled-components';
|
||||
import styled, { css, withProps } from '../../styled-components';
|
||||
|
||||
export const OperationBadge = withProps<{ type: string }>(styled.span).attrs({
|
||||
className: props => `operation-type ${props.type}`,
|
||||
|
@ -88,7 +88,7 @@ export const MenuItemLi = withProps<{ depth: number }>(styled.li)`
|
|||
`;
|
||||
|
||||
export const menuItemDepth = {
|
||||
'0': css`
|
||||
0: css`
|
||||
opacity: 0.7;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8em;
|
||||
|
@ -96,14 +96,14 @@ export const menuItemDepth = {
|
|||
cursor: default;
|
||||
color: ${props => props.theme.colors.text};
|
||||
`,
|
||||
'1': css`
|
||||
1: css`
|
||||
font-size: 0.929em;
|
||||
text-transform: uppercase;
|
||||
&:hover {
|
||||
color: ${props => props.theme.colors.main};
|
||||
}
|
||||
`,
|
||||
'2': css`
|
||||
2: css`
|
||||
color: ${props => props.theme.colors.text};
|
||||
`,
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from 'react';
|
||||
import { highlight } from '../../utils';
|
||||
import styled from '../../styled-components';
|
||||
import { highlight } from '../../utils';
|
||||
|
||||
const StyledPre = styled.pre`
|
||||
font-family: ${props => props.theme.code.fontFamily};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
import { RedocNormalizedOptions, RedocRawOptions } from '../../services/RedocNormalizedOptions';
|
||||
import styled from '../../styled-components';
|
||||
import { ComponentWithOptions } from '../OptionsProvider';
|
||||
|
||||
let Stickyfill;
|
||||
if (typeof window !== 'undefined') {
|
||||
|
@ -34,11 +34,15 @@ export class StickySidebar extends ComponentWithOptions<StickySidebarProps> {
|
|||
stickyElement: Element;
|
||||
|
||||
componentDidMount() {
|
||||
stickyfill && stickyfill.add(this.stickyElement);
|
||||
if (stickyfill) {
|
||||
stickyfill.add(this.stickyElement);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
stickyfill && stickyfill.remove(this.stickyElement);
|
||||
if (stickyfill) {
|
||||
stickyfill.remove(this.stickyElement);
|
||||
}
|
||||
}
|
||||
|
||||
get scrollYOffset() {
|
||||
|
@ -52,7 +56,7 @@ export class StickySidebar extends ComponentWithOptions<StickySidebarProps> {
|
|||
}
|
||||
|
||||
render() {
|
||||
let top = this.scrollYOffset;
|
||||
const top = this.scrollYOffset;
|
||||
|
||||
const height = `calc(100vh - ${top})`;
|
||||
|
||||
|
@ -60,6 +64,7 @@ export class StickySidebar extends ComponentWithOptions<StickySidebarProps> {
|
|||
<StyledStickySidebar
|
||||
className={this.props.className}
|
||||
style={{ top, height }}
|
||||
// tslint:disable-next-line
|
||||
innerRef={el => {
|
||||
this.stickyElement = el;
|
||||
}}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Component } from 'react';
|
||||
|
||||
import { AppStore } from '../services/';
|
||||
import { loadAndBundleSpec } from '../utils';
|
||||
import { RedocRawOptions } from '../services/RedocNormalizedOptions';
|
||||
import { loadAndBundleSpec } from '../utils';
|
||||
|
||||
interface StoreProviderProps {
|
||||
specUrl?: string;
|
||||
|
@ -36,7 +36,7 @@ export class StoreProvider extends Component<StoreProviderProps, StoreProviderSt
|
|||
}
|
||||
|
||||
async load() {
|
||||
let { specUrl, spec, options } = this.props;
|
||||
const { specUrl, spec, options } = this.props;
|
||||
|
||||
this.setState({
|
||||
loading: true,
|
||||
|
@ -62,7 +62,9 @@ export class StoreProvider extends Component<StoreProviderProps, StoreProviderSt
|
|||
}
|
||||
|
||||
render() {
|
||||
if (this.state.error) throw this.state.error;
|
||||
if (this.state.error) {
|
||||
throw this.state.error;
|
||||
}
|
||||
return this.props.children(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { OpenAPISpec } from '../types';
|
||||
import { SpecStore } from './models';
|
||||
import { MenuStore } from './MenuStore';
|
||||
import { ScrollService } from './ScrollService';
|
||||
import { loadAndBundleSpec } from '../utils/loadAndBundleSpec';
|
||||
import { MenuStore } from './MenuStore';
|
||||
import { SpecStore } from './models';
|
||||
import { RedocNormalizedOptions, RedocRawOptions } from './RedocNormalizedOptions';
|
||||
import { ScrollService } from './ScrollService';
|
||||
|
||||
type StoreData = {
|
||||
interface StoreData {
|
||||
menu: {
|
||||
activeItemIdx: number;
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ type StoreData = {
|
|||
data: any;
|
||||
};
|
||||
options: RedocRawOptions;
|
||||
};
|
||||
}
|
||||
|
||||
export async function createStore(
|
||||
spec: object,
|
||||
|
@ -26,6 +26,18 @@ export async function createStore(
|
|||
}
|
||||
|
||||
export class AppStore {
|
||||
/**
|
||||
* deserialize store
|
||||
* **SUPER HACKY AND NOT OPTIMAL IMPLEMENTATION**
|
||||
*/
|
||||
// TODO:
|
||||
static fromJS(state: StoreData): AppStore {
|
||||
const inst = new AppStore(state.spec.data, state.spec.url, state.options);
|
||||
inst.menu.activeItemIdx = state.menu.activeItemIdx || 0;
|
||||
inst.menu.activate(inst.menu.flatItems[inst.menu.activeItemIdx]);
|
||||
return inst;
|
||||
}
|
||||
|
||||
menu: MenuStore;
|
||||
spec: SpecStore;
|
||||
rawOptions: RedocRawOptions;
|
||||
|
@ -63,15 +75,4 @@ export class AppStore {
|
|||
options: this.rawOptions,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* deserialize store
|
||||
* **SUPER HACKY AND NOT OPTIMAL IMPLEMENTATION**
|
||||
*/
|
||||
// TODO:
|
||||
static fromJS(state: StoreData): AppStore {
|
||||
const inst = new AppStore(state.spec.data, state.spec.url, state.options);
|
||||
inst.menu.activeItemIdx = state.menu.activeItemIdx || 0;
|
||||
inst.menu.activate(inst.menu.flatItems[inst.menu.activeItemIdx]);
|
||||
return inst;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ export class ClipboardService {
|
|||
static selectElement(element: any): void {
|
||||
let range;
|
||||
let selection;
|
||||
if ((<any>document.body).createTextRange) {
|
||||
range = (<any>document.body).createTextRange();
|
||||
if ((document.body as any).createTextRange) {
|
||||
range = (document.body as any).createTextRange();
|
||||
range.moveToElementText(element);
|
||||
range.select();
|
||||
} else if (document.createRange && window.getSelection) {
|
||||
|
@ -25,8 +25,8 @@ export class ClipboardService {
|
|||
}
|
||||
|
||||
static deselect(): void {
|
||||
if ((<any>document).selection) {
|
||||
(<any>document).selection.empty();
|
||||
if ((document as any).selection) {
|
||||
(document as any).selection.empty();
|
||||
} else if (window.getSelection) {
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
|
@ -44,13 +44,15 @@ export class ClipboardService {
|
|||
|
||||
static copyElement(element: any): boolean {
|
||||
ClipboardService.selectElement(element);
|
||||
let res = ClipboardService.copySelected();
|
||||
if (res) ClipboardService.deselect();
|
||||
const res = ClipboardService.copySelected();
|
||||
if (res) {
|
||||
ClipboardService.deselect();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static copyCustom(text: string): boolean {
|
||||
let textArea = document.createElement('textarea');
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.top = '0';
|
||||
textArea.style.left = '0';
|
||||
|
@ -77,7 +79,7 @@ export class ClipboardService {
|
|||
|
||||
textArea.select();
|
||||
|
||||
let res = ClipboardService.copySelected();
|
||||
const res = ClipboardService.copySelected();
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
return res;
|
||||
|
|
|
@ -8,7 +8,7 @@ function isSameHash(a: string, b: string): boolean {
|
|||
return a === b || '#' + a === b || a === '#' + b;
|
||||
}
|
||||
|
||||
class _HistoryService {
|
||||
class IntHistoryService {
|
||||
private causedHashChange: boolean = false;
|
||||
private _emiter;
|
||||
|
||||
|
@ -50,7 +50,9 @@ class _HistoryService {
|
|||
@bind
|
||||
@debounce
|
||||
update(hash: string | null, rewriteHistory: boolean = false) {
|
||||
if (hash == null || isSameHash(hash, this.hash)) return;
|
||||
if (hash == null || isSameHash(hash, this.hash)) {
|
||||
return;
|
||||
}
|
||||
if (rewriteHistory) {
|
||||
if (isBrowser) {
|
||||
window.history.replaceState(null, '', window.location.href.split('#')[0] + '#' + hash);
|
||||
|
@ -64,7 +66,7 @@ class _HistoryService {
|
|||
}
|
||||
}
|
||||
|
||||
export const HistoryService = new _HistoryService();
|
||||
export const HistoryService = new IntHistoryService();
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.dispose(() => {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import * as Remarkable from 'remarkable';
|
||||
|
||||
import { MDComponent } from '../components/Markdown/Markdown';
|
||||
import { highlight, html2Str } from '../utils';
|
||||
import { IMenuItem, SECTION_ATTR } from './MenuStore';
|
||||
import { GroupModel } from './models';
|
||||
import { highlight, html2Str } from '../utils';
|
||||
|
||||
const md = new Remarkable('default', {
|
||||
html: true,
|
||||
|
@ -20,14 +20,14 @@ export function buildComponentComment(name: string) {
|
|||
return `<!-- ReDoc-Inject: <${name}> -->`;
|
||||
}
|
||||
|
||||
type MarkdownHeading = {
|
||||
interface MarkdownHeading {
|
||||
name: string;
|
||||
children?: MarkdownHeading[];
|
||||
content?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class MarkdownRenderer {
|
||||
public headings: GroupModel[] = [];
|
||||
headings: GroupModel[] = [];
|
||||
currentTopHeading: GroupModel;
|
||||
|
||||
private _origRules: any = {};
|
||||
|
@ -52,9 +52,11 @@ export class MarkdownRenderer {
|
|||
}
|
||||
|
||||
flattenHeadings(container?: MarkdownHeading[]): MarkdownHeading[] {
|
||||
if (container === undefined) return [];
|
||||
let res: MarkdownHeading[] = [];
|
||||
for (let heading of container) {
|
||||
if (container === undefined) {
|
||||
return [];
|
||||
}
|
||||
const res: MarkdownHeading[] = [];
|
||||
for (const heading of container) {
|
||||
res.push(heading);
|
||||
res.push(...this.flattenHeadings(heading.children));
|
||||
}
|
||||
|
@ -64,14 +66,16 @@ export class MarkdownRenderer {
|
|||
attachHeadingsContent(rawText: string) {
|
||||
const buildRegexp = heading => new RegExp(`<h\\d ${SECTION_ATTR}="section/${heading.id}">`);
|
||||
|
||||
let flatHeadings = this.flattenHeadings(this.headings);
|
||||
if (flatHeadings.length < 1) return;
|
||||
const flatHeadings = this.flattenHeadings(this.headings);
|
||||
if (flatHeadings.length < 1) {
|
||||
return;
|
||||
}
|
||||
let prevHeading = flatHeadings[0];
|
||||
|
||||
let prevPos = rawText.search(buildRegexp(prevHeading));
|
||||
for (let i = 1; i < flatHeadings.length; i++) {
|
||||
let heading = flatHeadings[i];
|
||||
let currentPos = rawText.substr(prevPos + 1).search(buildRegexp(heading)) + prevPos + 1;
|
||||
const heading = flatHeadings[i];
|
||||
const currentPos = rawText.substr(prevPos + 1).search(buildRegexp(heading)) + prevPos + 1;
|
||||
prevHeading.content = html2Str(rawText.substring(prevPos, currentPos));
|
||||
|
||||
prevHeading = heading;
|
||||
|
@ -84,17 +88,17 @@ export class MarkdownRenderer {
|
|||
if (tokens[idx].hLevel > 2) {
|
||||
return this._origRules.open(tokens, idx);
|
||||
} else {
|
||||
let content = tokens[idx + 1].content;
|
||||
const content = tokens[idx + 1].content;
|
||||
if (tokens[idx].hLevel === 1) {
|
||||
this.currentTopHeading = this.saveHeading(content);
|
||||
let id = this.currentTopHeading.id;
|
||||
const id = this.currentTopHeading.id;
|
||||
return (
|
||||
`<a name="${id}"></a>` +
|
||||
`<h${tokens[idx].hLevel} ${SECTION_ATTR}="${id}" id="${id}">` +
|
||||
`<a class="share-link" href="#${id}"></a>`
|
||||
);
|
||||
} else if (tokens[idx].hLevel === 2) {
|
||||
let { id } = this.saveHeading(content, this.currentTopHeading.items);
|
||||
const { id } = this.saveHeading(content, this.currentTopHeading.items);
|
||||
return (
|
||||
`<a name="${id}"></a>` +
|
||||
`<h${tokens[idx].hLevel} ${SECTION_ATTR}="${id}" id="${id}">` +
|
||||
|
@ -119,9 +123,9 @@ export class MarkdownRenderer {
|
|||
md.renderer.rules.heading_close = this.headingCloseRule;
|
||||
}
|
||||
|
||||
let text = rawText;
|
||||
const text = rawText;
|
||||
|
||||
let res = md.render(text);
|
||||
const res = md.render(text);
|
||||
|
||||
this.attachHeadingsContent(res);
|
||||
|
||||
|
@ -142,17 +146,18 @@ export class MarkdownRenderer {
|
|||
rawText: string,
|
||||
components: Dict<MDComponent>,
|
||||
raw: boolean = true,
|
||||
): (string | MDComponent)[] {
|
||||
let componentDefs: string[] = [];
|
||||
let match;
|
||||
let anyCompRegexp = new RegExp(COMPONENT_REGEXP.replace('{component}', '(.*?)'), 'gmi');
|
||||
while ((match = anyCompRegexp.exec(rawText))) {
|
||||
): Array<string | MDComponent> {
|
||||
const componentDefs: string[] = [];
|
||||
const anyCompRegexp = new RegExp(COMPONENT_REGEXP.replace('{component}', '(.*?)'), 'gmi');
|
||||
let match = anyCompRegexp.exec(rawText);
|
||||
while (match) {
|
||||
componentDefs.push(match[1]);
|
||||
match = anyCompRegexp.exec(rawText);
|
||||
}
|
||||
|
||||
let splitCompRegexp = new RegExp(COMPONENT_REGEXP.replace('{component}', '.*?'), 'mi');
|
||||
let htmlParts = rawText.split(splitCompRegexp);
|
||||
let res: any[] = [];
|
||||
const splitCompRegexp = new RegExp(COMPONENT_REGEXP.replace('{component}', '.*?'), 'mi');
|
||||
const htmlParts = rawText.split(splitCompRegexp);
|
||||
const res: any[] = [];
|
||||
for (let i = 0; i < htmlParts.length; i++) {
|
||||
const htmlPart = htmlParts[i];
|
||||
if (htmlPart) {
|
||||
|
@ -160,10 +165,12 @@ export class MarkdownRenderer {
|
|||
}
|
||||
if (componentDefs[i]) {
|
||||
const { componentName, attrs } = parseComponent(componentDefs[i]);
|
||||
if (!componentName) continue;
|
||||
if (!componentName) {
|
||||
continue;
|
||||
}
|
||||
res.push({
|
||||
...components[componentName],
|
||||
attrs: attrs,
|
||||
attrs,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +185,9 @@ function parseComponent(
|
|||
attrs: any;
|
||||
} {
|
||||
const match = /<([\w_-]+).*?>/.exec(htmlTag);
|
||||
if (match === null || match.length <= 1) return { componentName: undefined, attrs: {} };
|
||||
if (match === null || match.length <= 1) {
|
||||
return { componentName: undefined, attrs: {} };
|
||||
}
|
||||
const componentName = match[1];
|
||||
return {
|
||||
componentName,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { OpenAPIParser } from './OpenAPIParser';
|
||||
import { GroupModel, OperationModel } from './models';
|
||||
import { JsonPointer, isOperationName } from '../utils';
|
||||
import { OpenAPIOperation, OpenAPIParameter, OpenAPISpec, OpenAPITag, Referenced } from '../types';
|
||||
import { isOperationName, JsonPointer } from '../utils';
|
||||
import { MarkdownRenderer } from './MarkdownRenderer';
|
||||
import { GroupModel, OperationModel } from './models';
|
||||
import { OpenAPIParser } from './OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||
|
||||
export type TagInfo = OpenAPITag & {
|
||||
|
@ -13,7 +13,7 @@ export type TagInfo = OpenAPITag & {
|
|||
export type ExtendedOpenAPIOperation = {
|
||||
_$ref: string;
|
||||
httpVerb: string;
|
||||
pathParameters: Referenced<OpenAPIParameter>[];
|
||||
pathParameters: Array<Referenced<OpenAPIParameter>>;
|
||||
} & OpenAPIOperation;
|
||||
|
||||
export type TagsInfoMap = Dict<TagInfo>;
|
||||
|
@ -70,9 +70,9 @@ export class MenuBuilder {
|
|||
tags: TagsInfoMap,
|
||||
options: RedocNormalizedOptions,
|
||||
): GroupModel[] {
|
||||
let res: GroupModel[] = [];
|
||||
for (let group of groups) {
|
||||
let item = new GroupModel('group', group, parent);
|
||||
const res: GroupModel[] = [];
|
||||
for (const group of groups) {
|
||||
const item = new GroupModel('group', group, parent);
|
||||
item.depth = GROUP_DEPTH;
|
||||
item.items = MenuBuilder.getTagsItems(parser, tags, item, group, options);
|
||||
res.push(item);
|
||||
|
@ -111,16 +111,18 @@ export class MenuBuilder {
|
|||
return tagsMap[tagName];
|
||||
});
|
||||
|
||||
let res: (GroupModel | OperationModel)[] = [];
|
||||
for (let tag of tags) {
|
||||
if (!tag) continue;
|
||||
let item = new GroupModel('tag', tag, parent);
|
||||
const res: Array<GroupModel | OperationModel> = [];
|
||||
for (const tag of tags) {
|
||||
if (!tag) {
|
||||
continue;
|
||||
}
|
||||
const item = new GroupModel('tag', tag, parent);
|
||||
item.depth = GROUP_DEPTH + 1;
|
||||
item.items = this.getOperationsItems(parser, item, tag, item.depth + 1, options);
|
||||
|
||||
// don't put empty tag into content, instead put its operations
|
||||
if (tag.name === '') {
|
||||
let items = this.getOperationsItems(parser, undefined, tag, item.depth + 1, options);
|
||||
const items = this.getOperationsItems(parser, undefined, tag, item.depth + 1, options);
|
||||
res.push(...items);
|
||||
continue;
|
||||
}
|
||||
|
@ -147,9 +149,9 @@ export class MenuBuilder {
|
|||
return [];
|
||||
}
|
||||
|
||||
let res: OperationModel[] = [];
|
||||
for (let operationInfo of tag.operations) {
|
||||
let operation = new OperationModel(parser, operationInfo, parent, options);
|
||||
const res: OperationModel[] = [];
|
||||
for (const operationInfo of tag.operations) {
|
||||
const operation = new OperationModel(parser, operationInfo, parent, options);
|
||||
operation.depth = depth;
|
||||
res.push(operation);
|
||||
}
|
||||
|
@ -161,16 +163,15 @@ export class MenuBuilder {
|
|||
*/
|
||||
static getTagsWithOperations(spec: OpenAPISpec): TagsInfoMap {
|
||||
const tags: TagsInfoMap = {};
|
||||
for (let tag of spec.tags || []) {
|
||||
tags[tag.name] = Object.assign(tag);
|
||||
tags[tag.name].operations = [];
|
||||
for (const tag of spec.tags || []) {
|
||||
tags[tag.name] = { ...tag, operations: [] };
|
||||
}
|
||||
|
||||
const paths = spec.paths;
|
||||
for (let pathName of Object.keys(paths)) {
|
||||
for (const pathName of Object.keys(paths)) {
|
||||
const path = paths[pathName];
|
||||
const operations = Object.keys(path).filter(isOperationName);
|
||||
for (let operationName of operations) {
|
||||
for (const operationName of operations) {
|
||||
const operationInfo = path[operationName];
|
||||
let operationTags = operationInfo.tags;
|
||||
|
||||
|
@ -179,7 +180,7 @@ export class MenuBuilder {
|
|||
operationTags = [''];
|
||||
}
|
||||
const operationPointer = JsonPointer.compile(['paths', pathName, operationName]);
|
||||
for (let tagName of operationTags) {
|
||||
for (const tagName of operationTags) {
|
||||
let tag = tags[tagName];
|
||||
if (tag === undefined) {
|
||||
tag = {
|
||||
|
@ -188,7 +189,9 @@ export class MenuBuilder {
|
|||
};
|
||||
tags[tagName] = tag;
|
||||
}
|
||||
if (tag['x-traitTag']) continue;
|
||||
if (tag['x-traitTag']) {
|
||||
continue;
|
||||
}
|
||||
tag.operations.push({
|
||||
...operationInfo,
|
||||
_$ref: operationPointer,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { action, computed } from 'mobx';
|
||||
import { querySelector } from '../utils/dom';
|
||||
import { OperationModel, GroupModel, SpecStore } from './models';
|
||||
import { computed, action } from 'mobx';
|
||||
import { GroupModel, OperationModel, SpecStore } from './models';
|
||||
|
||||
import { ScrollService } from './ScrollService';
|
||||
import { HistoryService } from './HistoryService';
|
||||
import { ScrollService } from './ScrollService';
|
||||
|
||||
import { GROUP_DEPTH } from './MenuBuilder';
|
||||
import { flattenByProp } from '../utils';
|
||||
import { GROUP_DEPTH } from './MenuBuilder';
|
||||
|
||||
export type MenuItemGroupType = 'group' | 'tag' | 'section';
|
||||
export type MenuItemType = MenuItemGroupType | 'operation';
|
||||
|
@ -18,7 +18,7 @@ export interface IMenuItem {
|
|||
name: string;
|
||||
depth: number;
|
||||
active: boolean;
|
||||
items: Array<IMenuItem>;
|
||||
items: IMenuItem[];
|
||||
parent?: IMenuItem;
|
||||
deprecated?: boolean;
|
||||
type: MenuItemType;
|
||||
|
@ -34,18 +34,18 @@ export const SECTION_ATTR = 'data-section-id';
|
|||
* Stores all side-menu related information
|
||||
*/
|
||||
export class MenuStore {
|
||||
/**
|
||||
* cached flattened menu items to support absolute indexing
|
||||
*/
|
||||
private _unsubscribe: Function;
|
||||
private _hashUnsubscribe: Function;
|
||||
private _items?: (GroupModel | OperationModel)[];
|
||||
|
||||
/**
|
||||
* active item absolute index (when flattened). -1 means nothing is selected
|
||||
*/
|
||||
activeItemIdx: number = -1;
|
||||
|
||||
/**
|
||||
* cached flattened menu items to support absolute indexing
|
||||
*/
|
||||
private _unsubscribe: () => void;
|
||||
private _hashUnsubscribe: () => void;
|
||||
private _items?: Array<GroupModel | OperationModel>;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param spec [SpecStore](#SpecStore) which contains page content structure
|
||||
|
@ -107,13 +107,15 @@ export class MenuStore {
|
|||
*/
|
||||
@action.bound
|
||||
updateOnHash(hash: string = HistoryService.hash): boolean {
|
||||
if (!hash) return false;
|
||||
if (!hash) {
|
||||
return false;
|
||||
}
|
||||
let item: IMenuItem | undefined;
|
||||
hash = hash.substr(1);
|
||||
let namespace = hash.split('/')[0];
|
||||
const namespace = hash.split('/')[0];
|
||||
let ptr = decodeURIComponent(hash.substr(namespace.length + 1));
|
||||
if (namespace === 'section' || namespace === 'tag') {
|
||||
let sectionId = ptr.split('/')[0];
|
||||
const sectionId = ptr.split('/')[0];
|
||||
ptr = ptr.substr(sectionId.length);
|
||||
|
||||
let searchId;
|
||||
|
@ -123,14 +125,14 @@ export class MenuStore {
|
|||
searchId = ptr || namespace + '/' + sectionId;
|
||||
}
|
||||
|
||||
item = this.flatItems.find(item => item.id === searchId);
|
||||
item = this.flatItems.find(i => i.id === searchId);
|
||||
if (item === undefined) {
|
||||
this._scrollService.scrollIntoViewBySelector(`[${SECTION_ATTR}="${searchId}"]`);
|
||||
return false;
|
||||
}
|
||||
} else if (namespace === 'operation') {
|
||||
item = this.flatItems.find(item => {
|
||||
return (item as OperationModel).operationId === ptr;
|
||||
item = this.flatItems.find(i => {
|
||||
return (i as OperationModel).operationId === ptr;
|
||||
});
|
||||
}
|
||||
if (item) {
|
||||
|
@ -219,7 +221,11 @@ export class MenuStore {
|
|||
* @see MenuStore.activate
|
||||
*/
|
||||
@action
|
||||
activateAndScroll(item: IMenuItem | undefined, updateHash: boolean, rewriteHistory?: boolean) {
|
||||
activateAndScroll(
|
||||
item: IMenuItem | undefined,
|
||||
updateHash: boolean,
|
||||
rewriteHistory?: boolean,
|
||||
) {
|
||||
this.activate(item, updateHash, rewriteHistory);
|
||||
this.scrollToActive();
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@ import { resolve as urlResolve } from 'url';
|
|||
|
||||
import { OpenAPIRef, OpenAPISchema, OpenAPISpec, Referenced } from '../types';
|
||||
|
||||
import { appendToMdHeading, isBrowser } from '../utils/';
|
||||
import { JsonPointer } from '../utils/JsonPointer';
|
||||
import { isNamedDefinition } from '../utils/openapi';
|
||||
import { COMPONENT_REGEXP, buildComponentComment } from './MarkdownRenderer';
|
||||
import { buildComponentComment, COMPONENT_REGEXP } from './MarkdownRenderer';
|
||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||
import { appendToMdHeading, isBrowser } from '../utils/';
|
||||
|
||||
export type MergedOpenAPISchema = OpenAPISchema & { parentRefs?: string[] };
|
||||
|
||||
|
@ -16,7 +16,7 @@ export type MergedOpenAPISchema = OpenAPISchema & { parentRefs?: string[] };
|
|||
* endless recursion because of circular refs
|
||||
*/
|
||||
class RefCounter {
|
||||
public _counter = {};
|
||||
_counter = {};
|
||||
|
||||
reset(): void {
|
||||
this._counter = {};
|
||||
|
@ -42,6 +42,8 @@ export class OpenAPIParser {
|
|||
@observable specUrl: string;
|
||||
@observable.ref spec: OpenAPISpec;
|
||||
|
||||
private _refCounter: RefCounter = new RefCounter();
|
||||
|
||||
constructor(
|
||||
spec: OpenAPISpec,
|
||||
specUrl: string | undefined,
|
||||
|
@ -60,8 +62,6 @@ export class OpenAPIParser {
|
|||
}
|
||||
}
|
||||
|
||||
private _refCounter: RefCounter = new RefCounter();
|
||||
|
||||
validate(spec: any) {
|
||||
if (spec.openapi === undefined) {
|
||||
throw new Error('Document must be valid OpenAPI 3.0.0 definition');
|
||||
|
@ -93,8 +93,12 @@ export class OpenAPIParser {
|
|||
*/
|
||||
byRef = <T extends any = any>(ref: string): T | undefined => {
|
||||
let res;
|
||||
if (this.spec === undefined) return;
|
||||
if (ref.charAt(0) !== '#') ref = '#' + ref;
|
||||
if (!this.spec) {
|
||||
return;
|
||||
}
|
||||
if (ref.charAt(0) !== '#') {
|
||||
ref = '#' + ref;
|
||||
}
|
||||
ref = decodeURIComponent(ref);
|
||||
try {
|
||||
res = JsonPointer.get(this.spec, ref);
|
||||
|
@ -120,7 +124,7 @@ export class OpenAPIParser {
|
|||
resetVisited() {
|
||||
if (__DEV__) {
|
||||
// check in dev mode
|
||||
for (let k in this._refCounter._counter) {
|
||||
for (const k in this._refCounter._counter) {
|
||||
if (this._refCounter._counter[k] > 0) {
|
||||
console.warn('Not exited reference: ' + k);
|
||||
}
|
||||
|
@ -130,7 +134,9 @@ export class OpenAPIParser {
|
|||
}
|
||||
|
||||
exitRef<T>(ref: Referenced<T>) {
|
||||
if (!this.isRef(ref)) return;
|
||||
if (!this.isRef(ref)) {
|
||||
return;
|
||||
}
|
||||
this._refCounter.exit(ref.$ref);
|
||||
}
|
||||
|
||||
|
@ -146,6 +152,7 @@ export class OpenAPIParser {
|
|||
this._refCounter.visit(obj.$ref);
|
||||
if (visited && !forceCircular) {
|
||||
// circular reference detected
|
||||
// tslint:disable-next-line
|
||||
return Object.assign({}, resolved, { 'x-circular-ref': true });
|
||||
}
|
||||
// deref again in case one more $ref is here
|
||||
|
@ -191,7 +198,7 @@ export class OpenAPIParser {
|
|||
};
|
||||
});
|
||||
|
||||
for (let { $ref: subSchemaRef, schema: subSchema } of allOfSchemas) {
|
||||
for (const { $ref: subSchemaRef, schema: subSchema } of allOfSchemas) {
|
||||
if (
|
||||
receiver.type !== subSchema.type &&
|
||||
receiver.type !== undefined &&
|
||||
|
@ -244,7 +251,7 @@ export class OpenAPIParser {
|
|||
findDerived($refs: string[]): Dict<string> {
|
||||
const res: Dict<string> = {};
|
||||
const schemas = (this.spec.components && this.spec.components.schemas) || {};
|
||||
for (let defName in schemas) {
|
||||
for (const defName in schemas) {
|
||||
const def = this.deref(schemas[defName]);
|
||||
if (
|
||||
def.allOf !== undefined &&
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { ThemeInterface } from '../theme';
|
||||
import { isNumeric, mergeObjects } from '../utils/helpers';
|
||||
import defaultTheme, { ThemeInterface } from '../theme';
|
||||
import { querySelector } from '../utils/dom';
|
||||
import defaultTheme from '../theme';
|
||||
import { isNumeric, mergeObjects } from '../utils/helpers';
|
||||
|
||||
export interface RedocRawOptions {
|
||||
theme?: ThemeInterface;
|
||||
scrollYOffset?: number | string | Function;
|
||||
scrollYOffset?: number | string | (() => number);
|
||||
hideHostname?: boolean | string;
|
||||
expandResponses?: string | 'all';
|
||||
requiredPropsFirst?: boolean | string;
|
||||
|
@ -17,34 +16,16 @@ export interface RedocRawOptions {
|
|||
}
|
||||
|
||||
function argValueToBoolean(val?: string | boolean): boolean {
|
||||
if (val === undefined) return false;
|
||||
if (typeof val === 'string') return true;
|
||||
if (val === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (typeof val === 'string') {
|
||||
return true;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
export class RedocNormalizedOptions {
|
||||
theme: ThemeInterface;
|
||||
scrollYOffset: () => number;
|
||||
hideHostname: boolean;
|
||||
expandResponses: { [code: string]: boolean } | 'all';
|
||||
requiredPropsFirst: boolean;
|
||||
noAutoAuth: boolean;
|
||||
nativeScrollbars: boolean;
|
||||
pathInMiddlePanel: boolean;
|
||||
untrustedSpec: boolean;
|
||||
|
||||
constructor(raw: RedocRawOptions) {
|
||||
this.theme = mergeObjects({} as any, defaultTheme, raw.theme || {});
|
||||
this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset);
|
||||
this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname);
|
||||
this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses);
|
||||
this.requiredPropsFirst = argValueToBoolean(raw.requiredPropsFirst);
|
||||
this.noAutoAuth = argValueToBoolean(raw.noAutoAuth);
|
||||
this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars);
|
||||
this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel);
|
||||
this.untrustedSpec = argValueToBoolean(raw.untrustedSpec);
|
||||
}
|
||||
|
||||
static normalizeExpandResponses(value: RedocRawOptions['expandResponses']) {
|
||||
if (value === 'all') {
|
||||
return 'all';
|
||||
|
@ -98,4 +79,26 @@ export class RedocNormalizedOptions {
|
|||
|
||||
return () => 0;
|
||||
}
|
||||
|
||||
theme: ThemeInterface;
|
||||
scrollYOffset: () => number;
|
||||
hideHostname: boolean;
|
||||
expandResponses: { [code: string]: boolean } | 'all';
|
||||
requiredPropsFirst: boolean;
|
||||
noAutoAuth: boolean;
|
||||
nativeScrollbars: boolean;
|
||||
pathInMiddlePanel: boolean;
|
||||
untrustedSpec: boolean;
|
||||
|
||||
constructor(raw: RedocRawOptions) {
|
||||
this.theme = mergeObjects({} as any, defaultTheme, raw.theme || {});
|
||||
this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset);
|
||||
this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname);
|
||||
this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses);
|
||||
this.requiredPropsFirst = argValueToBoolean(raw.requiredPropsFirst);
|
||||
this.noAutoAuth = argValueToBoolean(raw.noAutoAuth);
|
||||
this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars);
|
||||
this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel);
|
||||
this.untrustedSpec = argValueToBoolean(raw.untrustedSpec);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { debounce, bind } from 'decko';
|
||||
import { bind, debounce } from 'decko';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
|
||||
import { querySelector, isBrowser } from '../utils';
|
||||
import { isBrowser, querySelector } from '../utils';
|
||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||
|
||||
const EVENT = 'scroll';
|
||||
|
@ -18,11 +18,15 @@ export class ScrollService {
|
|||
|
||||
bind() {
|
||||
this._prevOffsetY = this.scrollY();
|
||||
this._scrollParent && this._scrollParent.addEventListener('scroll', this.handleScroll);
|
||||
if (this._scrollParent) {
|
||||
this._scrollParent.addEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._scrollParent && this._scrollParent.removeEventListener('scroll', this.handleScroll);
|
||||
if (this._scrollParent) {
|
||||
this._scrollParent.removeEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
this._emiter.removeAllListeners(EVENT);
|
||||
}
|
||||
|
||||
|
@ -37,12 +41,16 @@ export class ScrollService {
|
|||
}
|
||||
|
||||
isElementBellow(el: Element | null) {
|
||||
if (el === null) return;
|
||||
if (el === null) {
|
||||
return;
|
||||
}
|
||||
return el.getBoundingClientRect().top > this.options.scrollYOffset();
|
||||
}
|
||||
|
||||
isElementAbove(el: Element | null) {
|
||||
if (el === null) return;
|
||||
if (el === null) {
|
||||
return;
|
||||
}
|
||||
return Math.trunc(el.getBoundingClientRect().top) <= this.options.scrollYOffset();
|
||||
}
|
||||
|
||||
|
@ -56,10 +64,10 @@ export class ScrollService {
|
|||
return;
|
||||
}
|
||||
element.scrollIntoView();
|
||||
this._scrollParent &&
|
||||
this._scrollParent.scrollBy &&
|
||||
if (this._scrollParent && this._scrollParent.scrollBy) {
|
||||
(this._scrollParent.scrollBy as any)(0, -this.options.scrollYOffset());
|
||||
}
|
||||
}
|
||||
|
||||
scrollIntoViewBySelector(selector: string) {
|
||||
const element = querySelector(selector);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { computed, observable } from 'mobx';
|
||||
import { OpenAPISpec } from '../types';
|
||||
import { observable, computed } from 'mobx';
|
||||
|
||||
// import { OpenAPIExternalDocumentation, OpenAPIInfo } from '../types';
|
||||
|
||||
import { MenuBuilder } from './MenuBuilder';
|
||||
import { OpenAPIParser } from './OpenAPIParser';
|
||||
import { ApiInfoModel } from './models/ApiInfo';
|
||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||
import { SecuritySchemesModel } from './models/SecuritySchemes';
|
||||
import { OpenAPIParser } from './OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||
/**
|
||||
* Store that containts all the specification related information in the form of tree
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { OpenAPIContact, OpenAPIInfo, OpenAPILicense } from '../../types';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { isBrowser } from '../../utils/';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
|
||||
export class ApiInfoModel implements OpenAPIInfo {
|
||||
title: string;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Referenced, OpenAPIExample } from '../../types';
|
||||
import { OpenAPIExample, Referenced } from '../../types';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
|
||||
export class ExampleModel {
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import { observable, action } from 'mobx';
|
||||
import { action, observable } from 'mobx';
|
||||
|
||||
import { OpenAPIParameter, Referenced } from '../../types';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
|
||||
import { SchemaModel } from './Schema';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { SchemaModel } from './Schema';
|
||||
|
||||
/**
|
||||
* Field or Parameter model ready to be used by components
|
||||
*/
|
||||
export class FieldModel {
|
||||
@observable public expanded: boolean = false;
|
||||
@observable expanded: boolean = false;
|
||||
|
||||
public schema: SchemaModel;
|
||||
public name: string;
|
||||
public required: boolean;
|
||||
public description: string;
|
||||
public example?: string;
|
||||
public deprecated: boolean;
|
||||
public in?: string;
|
||||
schema: SchemaModel;
|
||||
name: string;
|
||||
required: boolean;
|
||||
description: string;
|
||||
example?: string;
|
||||
deprecated: boolean;
|
||||
in?: string;
|
||||
|
||||
constructor(
|
||||
parser: OpenAPIParser,
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { observable, action } from 'mobx';
|
||||
import { action, observable } from 'mobx';
|
||||
import slugify from 'slugify';
|
||||
|
||||
import { OpenAPIExternalDocumentation, OpenAPITag } from '../../types';
|
||||
import { ContentItemModel } from '../MenuBuilder';
|
||||
import { IMenuItem, MenuItemGroupType } from '../MenuStore';
|
||||
|
||||
const slugify = require('slugify');
|
||||
|
||||
/**
|
||||
* Operations Group model ready to be used by components
|
||||
*/
|
||||
|
@ -17,7 +16,7 @@ export class GroupModel implements IMenuItem {
|
|||
description?: string;
|
||||
type: MenuItemGroupType;
|
||||
|
||||
items: Array<ContentItemModel> = [];
|
||||
items: ContentItemModel[] = [];
|
||||
parent?: GroupModel;
|
||||
externalDocs?: OpenAPIExternalDocumentation;
|
||||
|
||||
|
@ -48,7 +47,9 @@ export class GroupModel implements IMenuItem {
|
|||
@action
|
||||
deactivate() {
|
||||
// disallow deactivating groups
|
||||
if (this.type === 'group') return;
|
||||
if (this.type === 'group') {
|
||||
return;
|
||||
}
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { observable, action, computed } from 'mobx';
|
||||
import { action, computed, observable } from 'mobx';
|
||||
|
||||
import { OpenAPIMediaType } from '../../types';
|
||||
import { MediaTypeModel } from './MediaType';
|
||||
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
|
||||
/**
|
||||
* MediaContent model ready to be sued by React components
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import * as Sampler from 'openapi-sampler';
|
||||
|
||||
import { OpenAPIExample, OpenAPIMediaType } from '../../types';
|
||||
import { SchemaModel } from './Schema';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
import { SchemaModel } from './Schema';
|
||||
|
||||
import { mapValues, isJsonLike } from '../../utils';
|
||||
import { isJsonLike, mapValues } from '../../utils';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { ExampleModel } from './Example';
|
||||
|
||||
|
@ -39,14 +39,13 @@ export class MediaTypeModel {
|
|||
}
|
||||
|
||||
generateExample(parser: OpenAPIParser, info: OpenAPIMediaType) {
|
||||
const { schema, isRequestType } = this;
|
||||
if (schema && schema.oneOf) {
|
||||
if (this.schema && this.schema.oneOf) {
|
||||
this.examples = {};
|
||||
for (let subSchema of schema.oneOf) {
|
||||
for (const subSchema of this.schema.oneOf) {
|
||||
this.examples[subSchema.title] = {
|
||||
value: Sampler.sample(
|
||||
subSchema.rawSchema,
|
||||
{ skipReadOnly: isRequestType, skipReadWrite: !isRequestType },
|
||||
{ skipReadOnly: this.isRequestType, skipReadWrite: !this.isRequestType },
|
||||
parser.spec,
|
||||
),
|
||||
};
|
||||
|
@ -56,7 +55,7 @@ export class MediaTypeModel {
|
|||
default: new ExampleModel(parser, {
|
||||
value: Sampler.sample(
|
||||
info.schema,
|
||||
{ skipReadOnly: isRequestType, skipReadWrite: !isRequestType },
|
||||
{ skipReadOnly: this.isRequestType, skipReadWrite: !this.isRequestType },
|
||||
parser.spec,
|
||||
),
|
||||
}),
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { observable, action } from 'mobx';
|
||||
import { action, observable } from 'mobx';
|
||||
import { join as joinPaths } from 'path';
|
||||
import { parse as urlParse } from 'url';
|
||||
|
||||
import { IMenuItem } from '../MenuStore';
|
||||
import { SecurityRequirementModel } from './SecurityRequirement';
|
||||
import { GroupModel } from './Group.model';
|
||||
import { SecurityRequirementModel } from './SecurityRequirement';
|
||||
|
||||
import { OpenAPIExternalDocumentation, OpenAPIServer } from '../../types';
|
||||
|
||||
import { FieldModel } from './Field';
|
||||
import { ResponseModel } from './Response';
|
||||
import { RequestBodyModel } from './RequestBody';
|
||||
import { CodeSample } from './types';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { getOperationSummary, isAbsolutePath, JsonPointer, stripTrailingSlash } from '../../utils';
|
||||
import { ContentItemModel, ExtendedOpenAPIOperation } from '../MenuBuilder';
|
||||
import { JsonPointer, getOperationSummary, isAbsolutePath, stripTrailingSlash } from '../../utils';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
import { FieldModel } from './Field';
|
||||
import { RequestBodyModel } from './RequestBody';
|
||||
import { ResponseModel } from './Response';
|
||||
import { CodeSample } from './types';
|
||||
|
||||
/**
|
||||
* Operation model ready to be used by components
|
||||
|
@ -30,7 +30,7 @@ export class OperationModel implements IMenuItem {
|
|||
|
||||
parent?: GroupModel;
|
||||
externalDocs?: OpenAPIExternalDocumentation;
|
||||
items: Array<ContentItemModel> = [];
|
||||
items: ContentItemModel[] = [];
|
||||
|
||||
depth: number;
|
||||
|
||||
|
@ -80,7 +80,7 @@ export class OperationModel implements IMenuItem {
|
|||
let hasSuccessResponses = false;
|
||||
this.responses = Object.keys(operationSpec.responses || [])
|
||||
.filter(code => {
|
||||
if (parseInt(code) >= 100 && parseInt(code) <= 399) {
|
||||
if (parseInt(code, 10) >= 100 && parseInt(code, 10) <= 399) {
|
||||
hasSuccessResponses = true;
|
||||
}
|
||||
return isNumeric(code) || code === 'default';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { OpenAPIRequestBody, Referenced } from '../../types';
|
||||
|
||||
import { MediaContentModel } from './MediaContent';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
import { MediaContentModel } from './MediaContent';
|
||||
|
||||
export class RequestBodyModel {
|
||||
description: string;
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { observable, action } from 'mobx';
|
||||
import { action, observable } from 'mobx';
|
||||
|
||||
import { OpenAPIResponse, Referenced } from '../../types';
|
||||
|
||||
import { getStatusCodeType } from '../../utils';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
import { FieldModel } from './Field';
|
||||
import { MediaContentModel } from './MediaContent';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { getStatusCodeType } from '../../utils';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
|
||||
export class ResponseModel {
|
||||
@observable public expanded: boolean;
|
||||
@observable expanded: boolean;
|
||||
|
||||
public content?: MediaContentModel;
|
||||
public code: string;
|
||||
public description: string;
|
||||
public type: string;
|
||||
public headers: FieldModel[] = [];
|
||||
content?: MediaContentModel;
|
||||
code: string;
|
||||
description: string;
|
||||
type: string;
|
||||
headers: FieldModel[] = [];
|
||||
|
||||
constructor(
|
||||
parser: OpenAPIParser,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { observable, action } from 'mobx';
|
||||
import { action, observable } from 'mobx';
|
||||
|
||||
import { OpenAPISchema, Referenced } from '../../types';
|
||||
|
||||
import { FieldModel } from './Field';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
import { FieldModel } from './Field';
|
||||
|
||||
import { MergedOpenAPISchema } from '../';
|
||||
import {
|
||||
detectType,
|
||||
humanizeConstraints,
|
||||
|
@ -13,7 +14,6 @@ import {
|
|||
isPrimitiveType,
|
||||
JsonPointer,
|
||||
} from '../../utils/';
|
||||
import { MergedOpenAPISchema } from '../';
|
||||
|
||||
// TODO: refactor this model, maybe use getters instead of copying all the values
|
||||
export class SchemaModel {
|
||||
|
@ -69,9 +69,9 @@ export class SchemaModel {
|
|||
|
||||
parser.exitRef(schemaOrRef);
|
||||
|
||||
for (let $ref of this.schema.parentRefs || []) {
|
||||
for (const parent$ref of this.schema.parentRefs || []) {
|
||||
// exit all the refs visited during allOf traverse
|
||||
parser.exitRef({ $ref });
|
||||
parser.exitRef({ $ref: parent$ref });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,23 +174,25 @@ export class SchemaModel {
|
|||
const derived = parser.findDerived([...(schema.namedParents || []), this._$ref]);
|
||||
|
||||
if (schema.oneOf) {
|
||||
for (let variant of schema.oneOf) {
|
||||
if (variant.$ref === undefined) continue;
|
||||
for (const variant of schema.oneOf) {
|
||||
if (variant.$ref === undefined) {
|
||||
continue;
|
||||
}
|
||||
const name = JsonPointer.dirName(variant.$ref);
|
||||
derived[variant.$ref] = name;
|
||||
}
|
||||
}
|
||||
|
||||
const mapping = schema.discriminator!.mapping || {};
|
||||
for (let name in mapping) {
|
||||
for (const name in mapping) {
|
||||
derived[mapping[name]] = name;
|
||||
}
|
||||
|
||||
const refs = Object.keys(derived);
|
||||
this.oneOf = refs.map(ref => {
|
||||
const schema = new SchemaModel(parser, parser.byRef(ref)!, ref, this.options, true);
|
||||
schema.title = derived[ref];
|
||||
return schema;
|
||||
const innerSchema = new SchemaModel(parser, parser.byRef(ref)!, ref, this.options, true);
|
||||
innerSchema.title = derived[ref];
|
||||
return innerSchema;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { OpenAPISecurityRequirement } from '../../types';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { SECURITY_SCHEMES_SECTION } from '../../utils/openapi';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
|
||||
export class SecurityRequirementModel {
|
||||
schemes: {
|
||||
schemes: Array<{
|
||||
id: string;
|
||||
sectionId: string;
|
||||
type: string;
|
||||
scopes: string[];
|
||||
}[];
|
||||
}>;
|
||||
|
||||
constructor(requirement: OpenAPISecurityRequirement, parser: OpenAPIParser) {
|
||||
const schemes = (parser.spec.components && parser.spec.components.securitySchemes) || {};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { OpenAPISecurityScheme, Referenced } from '../../types';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { SECURITY_SCHEMES_SECTION } from '../../utils/openapi';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
|
||||
export class SecuritySchemeModel {
|
||||
id: string;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export type CodeSample = {
|
||||
export interface CodeSample {
|
||||
lang: string;
|
||||
source: string;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import { render } from 'react-dom';
|
||||
import * as React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
|
||||
import { querySelector } from './utils/dom';
|
||||
import { RedocStandalone } from './components/RedocStandalone';
|
||||
import { querySelector } from './utils/dom';
|
||||
|
||||
export const version = __REDOC_VERSION__;
|
||||
export const revision = __REDOC_REVISION__;
|
||||
|
||||
function attributesMap(element: Element) {
|
||||
var res = {};
|
||||
var elAttrs = element.attributes;
|
||||
const res = {};
|
||||
const elAttrs = element.attributes;
|
||||
// tslint:disable-next-line
|
||||
for (let i = 0; i < elAttrs.length; i++) {
|
||||
var attrib = elAttrs[i];
|
||||
const attrib = elAttrs[i];
|
||||
res[attrib.name] = attrib.value;
|
||||
}
|
||||
return res;
|
||||
|
@ -20,7 +21,7 @@ function attributesMap(element: Element) {
|
|||
function parseOptionsFromElement(element: Element) {
|
||||
const attrMap = attributesMap(element);
|
||||
const res = {};
|
||||
for (let attrName in attrMap) {
|
||||
for (const attrName in attrMap) {
|
||||
const optionName = attrName.replace(/-(.)/g, (_, $1) => $1.toUpperCase());
|
||||
res[optionName] = attrMap[attrName];
|
||||
// TODO: normalize options
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as styledComponents from 'styled-components';
|
||||
import { ThemedStyledComponentsModule } from 'styled-components';
|
||||
|
||||
import { ThemeInterface } from './theme';
|
||||
|
||||
|
@ -18,9 +17,9 @@ const {
|
|||
keyframes,
|
||||
ThemeProvider,
|
||||
withTheme,
|
||||
} = (styledComponents as ThemedStyledComponentsModule<any>) as ThemedStyledComponentsModule<
|
||||
ThemeInterface
|
||||
>;
|
||||
} = (styledComponents as styledComponents.ThemedStyledComponentsModule<
|
||||
any
|
||||
>) as styledComponents.ThemedStyledComponentsModule<ThemeInterface>;
|
||||
|
||||
export { css, injectGlobal, keyframes, ThemeProvider, withTheme, withProps };
|
||||
export default styled;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Omit } from './';
|
||||
|
||||
export type OpenAPISpec = {
|
||||
export interface OpenAPISpec {
|
||||
openapi: string;
|
||||
info: OpenAPIInfo;
|
||||
servers?: OpenAPIServer[];
|
||||
|
@ -9,7 +9,7 @@ export type OpenAPISpec = {
|
|||
security?: OpenAPISecurityRequirement[];
|
||||
tags?: OpenAPITag[];
|
||||
externalDocs?: OpenAPIExternalDocumentation;
|
||||
};
|
||||
}
|
||||
|
||||
export interface OpenAPIInfo {
|
||||
title: string;
|
||||
|
@ -21,29 +21,28 @@ export interface OpenAPIInfo {
|
|||
license?: OpenAPILicense;
|
||||
}
|
||||
|
||||
export type OpenAPIServer = {
|
||||
export interface OpenAPIServer {
|
||||
url: string;
|
||||
description?: string;
|
||||
variables?: { [name: string]: OpenAPIServerVariable };
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIServerVariable = {
|
||||
export interface OpenAPIServerVariable {
|
||||
enum?: string[];
|
||||
default: string;
|
||||
description?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIPaths = { [path: string]: OpenAPIPath };
|
||||
export type OpenAPIRef = {
|
||||
export interface OpenAPIPaths {
|
||||
[path: string]: OpenAPIPath;
|
||||
}
|
||||
export interface OpenAPIRef {
|
||||
$ref: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type Referenced<T> = OpenAPIRef | T;
|
||||
|
||||
export type OpenAPIPath =
|
||||
// | OpenAPIRef // paths can't be external in redoc because they are prebundled
|
||||
// | {
|
||||
{
|
||||
export interface OpenAPIPath {
|
||||
summary?: string;
|
||||
description?: string;
|
||||
get?: OpenAPIOperation;
|
||||
|
@ -55,25 +54,25 @@ export type OpenAPIPath =
|
|||
patch?: OpenAPIOperation;
|
||||
trace?: OpenAPIOperation;
|
||||
servers?: OpenAPIServer[];
|
||||
parameters?: Referenced<OpenAPIParameter>[];
|
||||
};
|
||||
parameters?: Array<Referenced<OpenAPIParameter>>;
|
||||
}
|
||||
|
||||
export type OpenAPIOperation = {
|
||||
export interface OpenAPIOperation {
|
||||
tags?: string[];
|
||||
summary?: string;
|
||||
description?: string;
|
||||
externalDocs?: OpenAPIExternalDocumentation;
|
||||
operationId?: string;
|
||||
parameters?: Referenced<OpenAPIParameter>[];
|
||||
parameters?: Array<Referenced<OpenAPIParameter>>;
|
||||
requestBody?: Referenced<OpenAPIRequestBody>;
|
||||
responses: OpenAPIResponses;
|
||||
callbacks?: { [name: string]: Referenced<OpenAPICallback> };
|
||||
deprecated?: boolean;
|
||||
security?: OpenAPISecurityRequirement[];
|
||||
servers?: OpenAPIServer[];
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIParameter = {
|
||||
export interface OpenAPIParameter {
|
||||
name: string;
|
||||
in?: OpenAPIParameterLocation;
|
||||
description?: string;
|
||||
|
@ -87,16 +86,16 @@ export type OpenAPIParameter = {
|
|||
example?: any;
|
||||
examples?: { [media: string]: Referenced<OpenAPIExample> };
|
||||
content?: { [media: string]: OpenAPIMediaType };
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIExample = {
|
||||
export interface OpenAPIExample {
|
||||
value: any;
|
||||
summary?: string;
|
||||
description?: string;
|
||||
externalValue?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPISchema = {
|
||||
export interface OpenAPISchema {
|
||||
$ref?: string;
|
||||
type?: string;
|
||||
properties?: { [name: string]: OpenAPISchema };
|
||||
|
@ -133,27 +132,27 @@ export type OpenAPISchema = {
|
|||
minProperties?: number;
|
||||
enum?: any[];
|
||||
example?: any;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIDiscriminator = {
|
||||
export interface OpenAPIDiscriminator {
|
||||
propertyName: string;
|
||||
mapping?: { [name: string]: string };
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIMediaType = {
|
||||
export interface OpenAPIMediaType {
|
||||
schema?: Referenced<OpenAPISchema>;
|
||||
example?: any;
|
||||
examples?: { [name: string]: Referenced<OpenAPIExample> };
|
||||
encoding?: { [field: string]: OpenAPIEncoding };
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIEncoding = {
|
||||
export interface OpenAPIEncoding {
|
||||
contentType: string;
|
||||
headers?: { [name: string]: Referenced<OpenAPIHeader> };
|
||||
style: OpenAPIParameterStyle;
|
||||
explode: boolean;
|
||||
allowReserved: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIParameterLocation = 'query' | 'header' | 'path' | 'cookie';
|
||||
export type OpenAPIParameterStyle =
|
||||
|
@ -165,30 +164,34 @@ export type OpenAPIParameterStyle =
|
|||
| 'pipeDelimited'
|
||||
| 'deepObject';
|
||||
|
||||
export type OpenAPIRequestBody = {
|
||||
export interface OpenAPIRequestBody {
|
||||
description?: string;
|
||||
required?: boolean;
|
||||
content: { [mime: string]: OpenAPIMediaType };
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIResponses = {
|
||||
export interface OpenAPIResponses {
|
||||
[code: string]: OpenAPIResponse;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIResponse = {
|
||||
export interface OpenAPIResponse {
|
||||
description?: string;
|
||||
headers?: { [name: string]: Referenced<OpenAPIHeader> };
|
||||
content?: { [mime: string]: OpenAPIMediaType };
|
||||
links?: { [name: string]: Referenced<OpenAPILink> };
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPILink = {};
|
||||
export interface OpenAPILink {
|
||||
$ref?: string;
|
||||
}
|
||||
|
||||
export type OpenAPIHeader = Omit<OpenAPIParameter, 'in' | 'name'>;
|
||||
|
||||
export type OpenAPICallback = {};
|
||||
export interface OpenAPICallback {
|
||||
$ref?: string;
|
||||
}
|
||||
|
||||
export type OpenAPIComponents = {
|
||||
export interface OpenAPIComponents {
|
||||
schemas?: { [name: string]: Referenced<OpenAPISchema> };
|
||||
responses?: { [name: string]: Referenced<OpenAPIResponse> };
|
||||
parameters?: { [name: string]: Referenced<OpenAPIParameter> };
|
||||
|
@ -198,13 +201,13 @@ export type OpenAPIComponents = {
|
|||
securitySchemes?: { [name: string]: Referenced<OpenAPISecurityScheme> };
|
||||
links?: { [name: string]: Referenced<OpenAPILink> };
|
||||
callbacks?: { [name: string]: Referenced<OpenAPICallback> };
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPISecurityRequirement = {
|
||||
export interface OpenAPISecurityRequirement {
|
||||
[name: string]: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPISecurityScheme = {
|
||||
export interface OpenAPISecurityScheme {
|
||||
type: 'apiKey' | 'http' | 'oauth2' | 'openIdConnect';
|
||||
description?: string;
|
||||
name?: string;
|
||||
|
@ -234,27 +237,27 @@ export type OpenAPISecurityScheme = {
|
|||
};
|
||||
};
|
||||
openIdConnectUrl?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPITag = {
|
||||
export interface OpenAPITag {
|
||||
name: string;
|
||||
description?: string;
|
||||
externalDocs?: OpenAPIExternalDocumentation;
|
||||
'x-displayName'?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIExternalDocumentation = {
|
||||
export interface OpenAPIExternalDocumentation {
|
||||
description?: string;
|
||||
url?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPIContact = {
|
||||
export interface OpenAPIContact {
|
||||
name?: string;
|
||||
url?: string;
|
||||
email?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OpenAPILicense = {
|
||||
export interface OpenAPILicense {
|
||||
name: string;
|
||||
url?: string;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export class JsonPointer {
|
|||
* JsonPointerHelper.baseName('/path/foo/subpath', 2)
|
||||
*/
|
||||
static baseName(pointer, level = 1) {
|
||||
let tokens = JsonPointer.parse(pointer);
|
||||
const tokens = JsonPointer.parse(pointer);
|
||||
return tokens[tokens.length - level];
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ export class JsonPointer {
|
|||
* JsonPointerHelper.dirName('/path/foo/subpath', 2)
|
||||
*/
|
||||
static dirName(pointer, level = 1) {
|
||||
let tokens = JsonPointer.parse(pointer);
|
||||
const tokens = JsonPointer.parse(pointer);
|
||||
return JsonPointerLib.compile(tokens.slice(0, tokens.length - level));
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,8 @@ export class JsonPointer {
|
|||
* JsonPointerHelper.relative('/path', '/path/foo/subpath')
|
||||
*/
|
||||
static relative(from, to): string[] {
|
||||
let fromTokens = JsonPointer.parse(from);
|
||||
let toTokens = JsonPointer.parse(to);
|
||||
const fromTokens = JsonPointer.parse(from);
|
||||
const toTokens = JsonPointer.parse(to);
|
||||
return toTokens.slice(fromTokens.length);
|
||||
}
|
||||
|
||||
|
@ -70,12 +70,12 @@ export class JsonPointer {
|
|||
*/
|
||||
static join(base, tokens) {
|
||||
// TODO: optimize
|
||||
let baseTokens = JsonPointer.parse(base);
|
||||
let resTokens = baseTokens.concat(tokens);
|
||||
const baseTokens = JsonPointer.parse(base);
|
||||
const resTokens = baseTokens.concat(tokens);
|
||||
return JsonPointerLib.compile(resTokens);
|
||||
}
|
||||
|
||||
static get(object: Object, pointer: string) {
|
||||
static get(object: object, pointer: string) {
|
||||
return JsonPointerLib.get(object, pointer);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@ export function querySelector(selector: string): Element | null {
|
|||
export function html2Str(html: string): string {
|
||||
return html
|
||||
.split(/<[^>]+>/)
|
||||
.map(function(chunk) {
|
||||
.map(chunk => {
|
||||
return chunk.trim();
|
||||
})
|
||||
.filter(function(trimmedChunk) {
|
||||
.filter(trimmedChunk => {
|
||||
return trimmedChunk.length > 0;
|
||||
})
|
||||
.join(' ');
|
||||
|
|
|
@ -25,7 +25,7 @@ export function mapValues<T, P>(
|
|||
iteratee: (val: T, key: string, obj: Dict<T>) => P,
|
||||
): Dict<P> {
|
||||
const res: { [key: string]: P } = {};
|
||||
for (let key in object) {
|
||||
for (const key in object) {
|
||||
if (object.hasOwnProperty(key)) {
|
||||
res[key] = iteratee(object[key], key, object);
|
||||
}
|
||||
|
@ -35,21 +35,23 @@ export function mapValues<T, P>(
|
|||
|
||||
/**
|
||||
* flattens collection using `prop` field as a children
|
||||
* @param items collection items
|
||||
* @param collectionItems collection items
|
||||
* @param prop item property with child elements
|
||||
*/
|
||||
export function flattenByProp<T extends object, P extends keyof T>(items: T[], prop: P): T[] {
|
||||
export function flattenByProp<T extends object, P extends keyof T>(
|
||||
collectionItems: T[],
|
||||
prop: P,
|
||||
): T[] {
|
||||
const res: T[] = [];
|
||||
const iterate = (items: T[]) => {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
for (const item of items) {
|
||||
res.push(item);
|
||||
if (item[prop]) {
|
||||
iterate(item[prop]);
|
||||
}
|
||||
}
|
||||
};
|
||||
iterate(items);
|
||||
iterate(collectionItems);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -64,7 +66,7 @@ export function isAbsolutePath(path: string): boolean {
|
|||
return /^(?:[a-z]+:)?/i.test(path);
|
||||
}
|
||||
|
||||
export function isNumeric(n: any): n is Number {
|
||||
export function isNumeric(n: any): n is number {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
}
|
||||
|
||||
|
@ -92,7 +94,7 @@ export const mergeObjects = <T extends object = object>(target: T, ...sources: T
|
|||
}
|
||||
|
||||
if (isMergebleObject(target) && isMergebleObject(source)) {
|
||||
Object.keys(source).forEach(function(key: string) {
|
||||
Object.keys(source).forEach((key: string) => {
|
||||
if (isMergebleObject(source[key])) {
|
||||
if (!target[key]) {
|
||||
target[key] = {};
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import * as Prism from 'prismjs';
|
||||
import 'prismjs/components/prism-actionscript.js';
|
||||
import 'prismjs/components/prism-bash.js';
|
||||
import 'prismjs/components/prism-c.js';
|
||||
import 'prismjs/components/prism-coffeescript.js';
|
||||
import 'prismjs/components/prism-cpp.js';
|
||||
import 'prismjs/components/prism-csharp.js';
|
||||
import 'prismjs/components/prism-php.js';
|
||||
import 'prismjs/components/prism-coffeescript.js';
|
||||
import 'prismjs/components/prism-go.js';
|
||||
import 'prismjs/components/prism-haskell.js';
|
||||
import 'prismjs/components/prism-java.js';
|
||||
import 'prismjs/components/prism-lua.js';
|
||||
import 'prismjs/components/prism-markup.js'; // xml
|
||||
import 'prismjs/components/prism-matlab.js';
|
||||
import 'prismjs/components/prism-objectivec.js';
|
||||
import 'prismjs/components/prism-perl.js';
|
||||
import 'prismjs/components/prism-php.js';
|
||||
import 'prismjs/components/prism-python.js';
|
||||
import 'prismjs/components/prism-r.js';
|
||||
import 'prismjs/components/prism-ruby.js';
|
||||
import 'prismjs/components/prism-bash.js';
|
||||
import 'prismjs/components/prism-swift.js';
|
||||
import 'prismjs/components/prism-objectivec.js';
|
||||
import 'prismjs/components/prism-scala.js';
|
||||
import 'prismjs/components/prism-markup.js'; // xml
|
||||
import 'prismjs/components/prism-swift.js';
|
||||
|
||||
import { injectGlobal } from '../styled-components';
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ const COLLAPSE_LEVEL = 2;
|
|||
|
||||
export function jsonToHTML(json) {
|
||||
level = 1;
|
||||
var output = '';
|
||||
let output = '';
|
||||
output += '<div class="redoc-json">';
|
||||
output += valueToHTML(json);
|
||||
output += '</div>';
|
||||
|
@ -11,7 +11,7 @@ export function jsonToHTML(json) {
|
|||
}
|
||||
|
||||
function htmlEncode(t) {
|
||||
return t != undefined
|
||||
return t !== undefined
|
||||
? t
|
||||
.toString()
|
||||
.replace(/&/g, '&')
|
||||
|
@ -26,9 +26,9 @@ function decorateWithSpan(value, className) {
|
|||
}
|
||||
|
||||
function valueToHTML(value) {
|
||||
var valueType = typeof value,
|
||||
output = '';
|
||||
if (value == undefined) {
|
||||
const valueType = typeof value;
|
||||
let output = '';
|
||||
if (value === undefined || value === null) {
|
||||
output += decorateWithSpan('null', 'type-null');
|
||||
} else if (value && value.constructor === Array) {
|
||||
level++;
|
||||
|
@ -63,12 +63,12 @@ function valueToHTML(value) {
|
|||
}
|
||||
|
||||
function arrayToHTML(json) {
|
||||
var collapsed = level > COLLAPSE_LEVEL ? 'collapsed' : '';
|
||||
var i, length;
|
||||
var output =
|
||||
const collapsed = level > COLLAPSE_LEVEL ? 'collapsed' : '';
|
||||
let output =
|
||||
'<div class="collapser"></div>[<span class="ellipsis"></span><ul class="array collapsible">';
|
||||
var hasContents = false;
|
||||
for (i = 0, length = json.length; i < length; i++) {
|
||||
let hasContents = false;
|
||||
const length = json.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
hasContents = true;
|
||||
output += '<li><div class="hoverable ' + collapsed + '">';
|
||||
output += valueToHTML(json[i]);
|
||||
|
@ -85,16 +85,14 @@ function arrayToHTML(json) {
|
|||
}
|
||||
|
||||
function objectToHTML(json) {
|
||||
var collapsed = level > COLLAPSE_LEVEL ? 'collapsed' : '';
|
||||
var i,
|
||||
key,
|
||||
length,
|
||||
keys = Object.keys(json);
|
||||
var output =
|
||||
const collapsed = level > COLLAPSE_LEVEL ? 'collapsed' : '';
|
||||
const keys = Object.keys(json);
|
||||
const length = keys.length;
|
||||
let output =
|
||||
'<div class="collapser"></div>{<span class="ellipsis"></span><ul class="obj collapsible">';
|
||||
var hasContents = false;
|
||||
for (i = 0, length = keys.length; i < length; i++) {
|
||||
key = keys[i];
|
||||
let hasContents = false;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const key = keys[i];
|
||||
hasContents = true;
|
||||
output += '<li><div class="hoverable ' + collapsed + '">';
|
||||
output += '<span class="property">"' + htmlEncode(key) + '"</span>: ';
|
||||
|
|
|
@ -3,8 +3,8 @@ import { convertObj } from 'swagger2openapi';
|
|||
import { OpenAPISpec } from '../types';
|
||||
|
||||
export async function loadAndBundleSpec(specUrlOrObject: object | string): Promise<OpenAPISpec> {
|
||||
const _parser = new JsonSchemaRefParser();
|
||||
const spec = await _parser.bundle(specUrlOrObject, {
|
||||
const parser = new JsonSchemaRefParser();
|
||||
const spec = await parser.bundle(specUrlOrObject, {
|
||||
resolve: { http: { withCredentials: false } },
|
||||
} as object);
|
||||
|
||||
|
|
|
@ -70,9 +70,8 @@ export function detectType(schema: OpenAPISchema): string {
|
|||
return schema.type;
|
||||
}
|
||||
const keywords = Object.keys(schemaKeywordTypes);
|
||||
for (var i = 0; i < keywords.length; i++) {
|
||||
let keyword = keywords[i];
|
||||
let type = schemaKeywordTypes[keyword];
|
||||
for (const keyword of keywords) {
|
||||
const type = schemaKeywordTypes[keyword];
|
||||
if (schema[keyword] !== undefined) {
|
||||
return type;
|
||||
}
|
||||
|
@ -127,9 +126,9 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
|
|||
} else {
|
||||
stringRange = `[ ${schema.minLength} .. ${schema.maxLength} ] characters`;
|
||||
}
|
||||
} else if (schema.maxLength != undefined) {
|
||||
} else if (schema.maxLength !== undefined) {
|
||||
stringRange = `<= ${schema.maxLength} characters`;
|
||||
} else if (schema.minLength != undefined) {
|
||||
} else if (schema.minLength !== undefined) {
|
||||
if (schema.minLength === 1) {
|
||||
stringRange = 'non-empty';
|
||||
} else {
|
||||
|
@ -147,10 +146,10 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
|
|||
numberRange += ' .. ';
|
||||
numberRange += schema.maximum;
|
||||
numberRange += schema.exclusiveMaximum ? ' )' : ' ]';
|
||||
} else if (schema.maximum != undefined) {
|
||||
} else if (schema.maximum !== undefined) {
|
||||
numberRange = schema.exclusiveMaximum ? '< ' : '<= ';
|
||||
numberRange += schema.maximum;
|
||||
} else if (schema.minimum != undefined) {
|
||||
} else if (schema.minimum !== undefined) {
|
||||
numberRange = schema.exclusiveMinimum ? '> ' : '>= ';
|
||||
numberRange += schema.minimum;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
export function hexToRgb(hex: string): { r: number; g: number; b: number } {
|
||||
hex = hex.replace('#', '');
|
||||
var r = parseInt(hex.length == 3 ? hex.slice(0, 1).repeat(2) : hex.slice(0, 2), 16);
|
||||
var g = parseInt(hex.length == 3 ? hex.slice(1, 2).repeat(2) : hex.slice(2, 4), 16);
|
||||
var b = parseInt(hex.length == 3 ? hex.slice(2, 3).repeat(2) : hex.slice(4, 6), 16);
|
||||
const r = parseInt(hex.length === 3 ? hex.slice(0, 1).repeat(2) : hex.slice(0, 2), 16);
|
||||
const g = parseInt(hex.length === 3 ? hex.slice(1, 2).repeat(2) : hex.slice(2, 4), 16);
|
||||
const b = parseInt(hex.length === 3 ? hex.slice(2, 3).repeat(2) : hex.slice(4, 6), 16);
|
||||
return { r, g, b };
|
||||
}
|
||||
|
||||
|
|
26
tslint.json
Normal file
26
tslint.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"extends": ["tslint:latest", "tslint-react"],
|
||||
"rules": {
|
||||
"interface-name": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"jsx-no-multiline-js": false,
|
||||
"jsx-wrap-multiline": false,
|
||||
"max-classes-per-file": false,
|
||||
"forin": false,
|
||||
"prefer-conditional-expression": false,
|
||||
"no-var-requires": false,
|
||||
"no-object-literal-type-assertion": false,
|
||||
"no-console": false,
|
||||
"jsx-curly-spacing": false,
|
||||
"max-line-length": false,
|
||||
|
||||
"quotemark": [true, "single", "avoid-template", "jsx-double"],
|
||||
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
|
||||
"arrow-parens": [true, "ban-single-arg-parens"],
|
||||
"no-submodule-imports": [true, "prismjs", "perfect-scrollbar"],
|
||||
"object-literal-key-quotes": [true, "as-needed"],
|
||||
"no-unused-expression": [true, "allow-tagged-template"],
|
||||
"semicolon": [true, "always", "ignore-bound-class-methods"],
|
||||
"member-access": [true, "no-public"]
|
||||
}
|
||||
}
|
78
yarn.lock
78
yarn.lock
|
@ -1190,10 +1190,6 @@ colors@0.5.x:
|
|||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
|
||||
|
||||
colors@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
|
||||
|
||||
colors@^1.1.2, colors@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
|
||||
|
@ -1456,10 +1452,6 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
corser@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87"
|
||||
|
||||
cpx@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cpx/-/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f"
|
||||
|
@ -1999,15 +1991,6 @@ ecc-jsbn@~0.1.1:
|
|||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
|
||||
ecstatic@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-2.2.1.tgz#b5087fad439dd9dd49d31e18131454817fe87769"
|
||||
dependencies:
|
||||
he "^1.1.1"
|
||||
mime "^1.2.11"
|
||||
minimist "^1.1.0"
|
||||
url-join "^2.0.2"
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
|
@ -3107,7 +3090,7 @@ hawk@~6.0.2:
|
|||
hoek "4.x.x"
|
||||
sntp "2.x.x"
|
||||
|
||||
he@1.1.x, he@^1.1.1:
|
||||
he@1.1.x:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
|
||||
|
@ -3245,26 +3228,13 @@ http-proxy-middleware@~0.17.4:
|
|||
lodash "^4.17.2"
|
||||
micromatch "^2.3.11"
|
||||
|
||||
http-proxy@^1.16.2, http-proxy@^1.8.1:
|
||||
http-proxy@^1.16.2:
|
||||
version "1.16.2"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742"
|
||||
dependencies:
|
||||
eventemitter3 "1.x.x"
|
||||
requires-port "1.x.x"
|
||||
|
||||
http-server@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.10.0.tgz#b2a446b16a9db87ed3c622ba9beb1b085b1234a7"
|
||||
dependencies:
|
||||
colors "1.0.3"
|
||||
corser "~2.0.0"
|
||||
ecstatic "^2.0.0"
|
||||
http-proxy "^1.8.1"
|
||||
opener "~1.4.0"
|
||||
optimist "0.6.x"
|
||||
portfinder "^1.0.13"
|
||||
union "~0.4.3"
|
||||
|
||||
http-signature@~1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
|
||||
|
@ -4503,7 +4473,7 @@ mime@1.4.1:
|
|||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||
|
||||
mime@^1.2.11, mime@^1.3.4, mime@^1.5.0:
|
||||
mime@^1.3.4, mime@^1.5.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
|
||||
|
@ -4917,17 +4887,13 @@ openapi-sampler@1.0.0-beta.8:
|
|||
dependencies:
|
||||
json-pointer "^0.6.0"
|
||||
|
||||
opener@~1.4.0:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
|
||||
|
||||
opn@5.1.0, opn@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/opn/-/opn-5.1.0.tgz#72ce2306a17dbea58ff1041853352b4a8fc77519"
|
||||
dependencies:
|
||||
is-wsl "^1.1.0"
|
||||
|
||||
optimist@0.6.x, optimist@^0.6.1:
|
||||
optimist@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
|
||||
dependencies:
|
||||
|
@ -5142,6 +5108,10 @@ perfect-scrollbar@^0.7.1:
|
|||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-0.7.1.tgz#0c256fb9c5cee401d60a299687a3f9a61487e0d5"
|
||||
|
||||
perfect-scrollbar@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.3.0.tgz#61da56f94b58870d8e0a617bce649cee17d1e3b2"
|
||||
|
||||
performance-now@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
|
||||
|
@ -5178,7 +5148,7 @@ pluralize@^7.0.0:
|
|||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
|
||||
|
||||
portfinder@^1.0.13, portfinder@^1.0.9:
|
||||
portfinder@^1.0.9:
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
|
||||
dependencies:
|
||||
|
@ -5591,10 +5561,6 @@ qs@6.5.1, qs@~6.5.1:
|
|||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||
|
||||
qs@~2.3.3:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404"
|
||||
|
||||
qs@~6.4.0:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
|
||||
|
@ -6974,6 +6940,16 @@ tslib@^1.7.1, tslib@^1.8.0:
|
|||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac"
|
||||
|
||||
tslib@^1.8.1:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
|
||||
|
||||
tslint-react@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-3.4.0.tgz#12ed3fc7063f3df988370206736b50acbce07e59"
|
||||
dependencies:
|
||||
tsutils "^2.13.1"
|
||||
|
||||
tslint@^5.7.0:
|
||||
version "5.8.0"
|
||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.8.0.tgz#1f49ad5b2e77c76c3af4ddcae552ae4e3612eb13"
|
||||
|
@ -6996,6 +6972,12 @@ tsutils@^2.12.1:
|
|||
dependencies:
|
||||
tslib "^1.8.0"
|
||||
|
||||
tsutils@^2.13.1:
|
||||
version "2.19.1"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.19.1.tgz#76d7ebdea9d7a7bf4a05f50ead3701b0168708d7"
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
tty-browserify@0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
|
||||
|
@ -7099,12 +7081,6 @@ union-value@^1.0.0:
|
|||
is-extendable "^0.1.1"
|
||||
set-value "^0.4.3"
|
||||
|
||||
union@~0.4.3:
|
||||
version "0.4.6"
|
||||
resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0"
|
||||
dependencies:
|
||||
qs "~2.3.3"
|
||||
|
||||
uniq@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
|
||||
|
@ -7142,10 +7118,6 @@ urix@^0.1.0:
|
|||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||
|
||||
url-join@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.2.tgz#c072756967ad24b8b59e5741551caac78f50b8b7"
|
||||
|
||||
url-parse@1.0.x:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b"
|
||||
|
|
Loading…
Reference in New Issue
Block a user