chore: add tslint + fix lint issues

This commit is contained in:
Roman Hotsiy 2018-01-22 20:30:53 +02:00
parent 3819ad7e6a
commit dc18743df4
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
95 changed files with 721 additions and 611 deletions

View File

@ -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());

View File

@ -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",

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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`

View File

@ -1,5 +1,6 @@
import styled, { css } from 'styled-components';
// tslint:disable-next-line
export const linkifyMixin = className => css`
${className} {
cursor: pointer;

View File

@ -6,7 +6,9 @@ export const deprecatedCss = css`
`;
export const hoverColor = color => {
if (!color) return '';
if (!color) {
return '';
}
return css`
&:hover {
color: ${color};

View File

@ -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';

View File

@ -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;

View File

@ -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;

View File

@ -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';

View File

@ -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,
}),
},
}}

View File

@ -1,6 +1,6 @@
import styled from '../../styled-components';
import { MiddlePanel, H1 } from '../../common-elements';
import { H1, MiddlePanel } from '../../common-elements';
const delimiterWidth = 15;

View File

@ -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 }} />

View File

@ -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> {

View File

@ -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;

View File

@ -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';

View File

@ -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);
}
}

View File

@ -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>

View File

@ -1,5 +1,5 @@
import { FieldDetails } from './FieldDetails';
import * as React from 'react';
import { FieldDetails } from './FieldDetails';
import { ClickablePropertyNameCell, RequiredLabel } from '../../common-elements/fields';

View File

@ -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>
{' '}

View File

@ -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>{' '}

View File

@ -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/';

View File

@ -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')) {

View File

@ -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 (

View File

@ -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 {

View File

@ -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(),

View File

@ -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';

View File

@ -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';

View File

@ -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 DropdownWithinHeader(props) {
return (
<UnderlinedHeader key="header">
Request Body schema: <DropdownOrLabel {...props} />
</UnderlinedHeader>
);
}
function BodyContent(props: { content: MediaContentModel }): JSX.Element {
const { content } = props;
return (
<MediaTypesSwitch
content={content}
renderDropdown={props => (
<UnderlinedHeader key="header">
Request Body schema: <DropdownOrLabel {...props} />
</UnderlinedHeader>
)}
>
<MediaTypesSwitch content={content} renderDropdown={DropdownWithinHeader}>
{({ schema }) => {
return <Schema skipReadOnly={true} key="schema" schema={schema} />;
}}

View File

@ -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}>

View File

@ -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>

View File

@ -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} />;
};
}

View File

@ -27,7 +27,6 @@ export const InvertedSimpleDropdown = styled(SimpleDropdown)`
}
`;
export const NoSampleLabel = styled.div`
font-family: ${props => props.theme.code.fontFamily};
font-size: 12px;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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>
);
};
}

View File

@ -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[];

View File

@ -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;

View File

@ -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>

View File

@ -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;

View File

@ -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() {

View File

@ -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);
};
}

View File

@ -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';

View File

@ -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]} />

View File

@ -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) {

View File

@ -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>

View File

@ -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>

View File

@ -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>
);

View File

@ -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> {

View File

@ -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[];

View File

@ -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';

View File

@ -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};
`,
};

View File

@ -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};

View File

@ -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;
}}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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(() => {

View File

@ -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,

View File

@ -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,

View File

@ -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();
}

View File

@ -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 &&

View File

@ -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);
}
}

View File

@ -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,9 +64,9 @@ 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) {

View File

@ -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
*/

View File

@ -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;

View File

@ -1,4 +1,4 @@
import { Referenced, OpenAPIExample } from '../../types';
import { OpenAPIExample, Referenced } from '../../types';
import { OpenAPIParser } from '../OpenAPIParser';
export class ExampleModel {

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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,
),
}),

View File

@ -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';

View File

@ -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;

View File

@ -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,

View File

@ -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;
});
}
}

View File

@ -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) || {};

View File

@ -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;

View File

@ -1,4 +1,4 @@
export type CodeSample = {
export interface CodeSample {
lang: string;
source: string;
};
}

View File

@ -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

View File

@ -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;

View File

@ -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,59 +21,58 @@ 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
// | {
{
summary?: string;
description?: string;
get?: OpenAPIOperation;
put?: OpenAPIOperation;
post?: OpenAPIOperation;
delete?: OpenAPIOperation;
options?: OpenAPIOperation;
head?: OpenAPIOperation;
patch?: OpenAPIOperation;
trace?: OpenAPIOperation;
servers?: OpenAPIServer[];
parameters?: Referenced<OpenAPIParameter>[];
};
export interface OpenAPIPath {
summary?: string;
description?: string;
get?: OpenAPIOperation;
put?: OpenAPIOperation;
post?: OpenAPIOperation;
delete?: OpenAPIOperation;
options?: OpenAPIOperation;
head?: OpenAPIOperation;
patch?: OpenAPIOperation;
trace?: OpenAPIOperation;
servers?: OpenAPIServer[];
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;
};
}

View File

@ -17,42 +17,42 @@ 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];
}
/**
* returns dirname of pointer
* if level > 1 returns corresponding dirname in the hierarchy
* @example
* // returns /path/0
* JsonPointerHelper.dirName('/path/0/subpath')
* // returns /path
* JsonPointerHelper.dirName('/path/foo/subpath', 2)
*/
* returns dirname of pointer
* if level > 1 returns corresponding dirname in the hierarchy
* @example
* // returns /path/0
* JsonPointerHelper.dirName('/path/0/subpath')
* // returns /path
* 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));
}
/**
* returns relative path tokens
* @example
* // returns ['subpath']
* JsonPointerHelper.relative('/path/0', '/path/0/subpath')
* // returns ['foo', 'subpath']
* JsonPointerHelper.relative('/path', '/path/foo/subpath')
*/
* returns relative path tokens
* @example
* // returns ['subpath']
* JsonPointerHelper.relative('/path/0', '/path/0/subpath')
* // returns ['foo', 'subpath']
* 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);
}
/**
* overridden JsonPointer original parse to take care of prefixing '#' symbol
* that is not valid JsonPointer
*/
* overridden JsonPointer original parse to take care of prefixing '#' symbol
* that is not valid JsonPointer
*/
static parse(pointer) {
let ptr = pointer;
if (ptr.charAt(0) === '#') {
@ -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);
}

View File

@ -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(' ');

View File

@ -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] = {};

View File

@ -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';

View File

@ -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, '&amp;')
@ -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>: ';

View File

@ -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);

View File

@ -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;
}

View File

@ -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
View 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"]
}
}

View File

@ -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"