Merge remote-tracking branch 'source/master' into develop

This commit is contained in:
Jason Ibrahim 2019-03-12 16:04:02 -07:00
commit 965778d3b0
17 changed files with 2637 additions and 2581 deletions

View File

@ -13,7 +13,7 @@ import * as zlib from 'zlib';
// @ts-ignore // @ts-ignore
import { createStore, loadAndBundleSpec, Redoc } from 'redoc'; import { createStore, loadAndBundleSpec, Redoc } from 'redoc';
import {watch} from 'chokidar'; import { watch } from 'chokidar';
import { createReadStream, existsSync, readFileSync, ReadStream, writeFileSync } from 'fs'; import { createReadStream, existsSync, readFileSync, ReadStream, writeFileSync } from 'fs';
import * as mkdirp from 'mkdirp'; import * as mkdirp from 'mkdirp';
@ -25,6 +25,7 @@ interface Options {
cdn?: boolean; cdn?: boolean;
output?: string; output?: string;
title?: string; title?: string;
port?: number;
templateFileName?: string; templateFileName?: string;
templateOptions?: any; templateOptions?: any;
redocOptions?: any; redocOptions?: any;
@ -62,16 +63,16 @@ YargsParser.command(
return yargs; return yargs;
}, },
async argv => { async argv => {
const config = { const config: Options = {
ssr: argv.ssr, ssr: argv.ssr as boolean,
watch: argv.watch, watch: argv.watch as boolean,
templateFileName: argv.template, templateFileName: argv.template as string,
templateOptions: argv.templateOptions || {}, templateOptions: argv.templateOptions || {},
redocOptions: argv.options || {}, redocOptions: argv.options || {},
}; };
try { try {
await serve(argv.port, argv.spec, config); await serve(argv.port as number, argv.spec as string, config);
} catch (e) { } catch (e) {
handleError(e); handleError(e);
} }
@ -108,12 +109,12 @@ YargsParser.command(
return yargs; return yargs;
}, },
async argv => { async argv => {
const config = { const config: Options = {
ssr: true, ssr: true,
output: argv.o, output: argv.o as string,
cdn: argv.cdn, cdn: argv.cdn as boolean,
title: argv.title, title: argv.title as string,
templateFileName: argv.template, templateFileName: argv.template as string,
templateOptions: argv.templateOptions || {}, templateOptions: argv.templateOptions || {},
redocOptions: argv.options || {}, redocOptions: argv.options || {},
}; };
@ -132,7 +133,8 @@ YargsParser.command(
type: 'string', type: 'string',
}) })
.options('templateOptions', { .options('templateOptions', {
describe: 'Additional options that you want pass to template. Use dot notation, e.g. templateOptions.metaDescription', describe:
'Additional options that you want pass to template. Use dot notation, e.g. templateOptions.metaDescription',
}) })
.options('options', { .options('options', {
describe: 'ReDoc options, use dot notation, e.g. options.nativeScrollbars', describe: 'ReDoc options, use dot notation, e.g. options.nativeScrollbars',
@ -190,7 +192,8 @@ async function serve(port: number, pathToSpec: string, options: Options = {}) {
log('Updated successfully'); log('Updated successfully');
} catch (e) { } catch (e) {
console.error('Error while updating: ', e.message); console.error('Error while updating: ', e.message);
}}) }
})
.on('error', error => console.error(`Watcher error: ${error}`)) .on('error', error => console.error(`Watcher error: ${error}`))
.on('ready', () => log(`👀 Watching ${pathToSpecDirectory} for changes...`)); .on('ready', () => log(`👀 Watching ${pathToSpecDirectory} for changes...`));
} }
@ -247,13 +250,13 @@ async function getPageHTML(
ssr ssr
? 'hydrate(__redoc_state, container);' ? 'hydrate(__redoc_state, container);'
: `init("spec.json", ${JSON.stringify(redocOptions)}, container)` : `init("spec.json", ${JSON.stringify(redocOptions)}, container)`
}; };
</script>`, </script>`,
redocHead: ssr redocHead: ssr
? (cdn ? (cdn
? '<script src="https://unpkg.com/redoc@next/bundles/redoc.standalone.js"></script>' ? '<script src="https://unpkg.com/redoc@next/bundles/redoc.standalone.js"></script>'
: `<script>${redocStandaloneSrc}</script>`) + css : `<script>${redocStandaloneSrc}</script>`) + css
: '<script src="redoc.standalone.js"></script>', : '<script src="redoc.standalone.js"></script>',
title, title,
templateOptions, templateOptions,

View File

@ -5,13 +5,13 @@
Serve remote spec by URL: Serve remote spec by URL:
docker run -it --rm -p 80:80 \ docker run -it --rm -p 80:80 \
-e SPEC_URL='http://localhost:8000/swagger.yaml' redoc -e SPEC_URL='http://localhost:8000/swagger.yaml' redocly/redoc
Serve local file: Serve local file:
docker run -it --rm -p 80:80 \ docker run -it --rm -p 80:80 \
-v $(PWD)/demo/swagger.yaml:/usr/share/nginx/html/swagger.yaml \ -v $(pwd)/demo/swagger.yaml:/usr/share/nginx/html/swagger.yaml \
-e SPEC_URL=swagger.yaml redoc -e SPEC_URL=swagger.yaml redocly/redoc
## Runtime configuration options ## Runtime configuration options
@ -23,4 +23,4 @@ Serve local file:
## Build ## Build
docker build -t redoc . docker build -t redocly/redoc .

2
custom.d.ts vendored
View File

@ -18,6 +18,8 @@ declare module '*.css' {
declare var __REDOC_VERSION__: string; declare var __REDOC_VERSION__: string;
declare var __REDOC_REVISION__: string; declare var __REDOC_REVISION__: string;
declare var reactHotLoaderGlobal: any;
interface Element { interface Element {
scrollIntoViewIfNeeded(centerIfNeeded?: boolean): void; scrollIntoViewIfNeeded(centerIfNeeded?: boolean): void;
} }

View File

@ -57,8 +57,8 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
env.playground env.playground
? 'playground/hmr-playground.tsx' ? 'playground/hmr-playground.tsx'
: env.bench : env.bench
? '../benchmark/index.tsx' ? '../benchmark/index.tsx'
: 'index.tsx', : 'index.tsx',
), ),
], ],
output: { output: {
@ -77,6 +77,12 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
resolve: { resolve: {
extensions: ['.ts', '.tsx', '.js', '.json'], extensions: ['.ts', '.tsx', '.js', '.json'],
alias:
mode !== 'production'
? {
'react-dom': '@hot-loader/react-dom',
}
: {},
}, },
node: { node: {
@ -105,7 +111,6 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
loader: 'css-loader', loader: 'css-loader',
options: { options: {
sourceMap: true, sourceMap: true,
minimize: true,
}, },
}, },
}, },
@ -136,8 +141,8 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
template: env.playground template: env.playground
? 'demo/playground/index.html' ? 'demo/playground/index.html'
: env.bench : env.bench
? 'benchmark/index.html' ? 'benchmark/index.html'
: 'demo/index.html', : 'demo/index.html',
}), }),
new ForkTsCheckerWebpackPlugin(), new ForkTsCheckerWebpackPlugin(),
ignore(/js-yaml\/dumper\.js$/), ignore(/js-yaml\/dumper\.js$/),

View File

@ -52,74 +52,75 @@
"docker:build": "docker build -f config/docker/Dockerfile -t redoc ." "docker:build": "docker build -f config/docker/Dockerfile -t redoc ."
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.1.6", "@babel/core": "7.3.4",
"@babel/plugin-syntax-decorators": "7.1.0", "@babel/plugin-syntax-decorators": "7.2.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-syntax-jsx": "7.0.0", "@babel/plugin-syntax-jsx": "7.2.0",
"@babel/plugin-syntax-typescript": "7.1.5", "@babel/plugin-syntax-typescript": "7.3.3",
"@cypress/webpack-preprocessor": "4.0.2", "@cypress/webpack-preprocessor": "4.0.3",
"@hot-loader/react-dom": "^16.8.4",
"@types/chai": "4.1.7", "@types/chai": "4.1.7",
"@types/dompurify": "^0.0.32", "@types/dompurify": "^0.0.32",
"@types/enzyme": "^3.1.15", "@types/enzyme": "^3.9.0",
"@types/enzyme-to-json": "^1.5.2", "@types/enzyme-to-json": "^1.5.3",
"@types/jest": "^23.3.9", "@types/jest": "^24.0.11",
"@types/json-pointer": "^1.0.30", "@types/json-pointer": "^1.0.30",
"@types/lodash": "^4.14.118", "@types/lodash": "^4.14.122",
"@types/lunr": "^2.1.6", "@types/lunr": "^2.3.2",
"@types/mark.js": "^8.11.1", "@types/mark.js": "^8.11.3",
"@types/marked": "^0.6.0", "@types/marked": "^0.6.3",
"@types/prismjs": "^1.6.4", "@types/prismjs": "^1.9.1",
"@types/prop-types": "^15.5.6", "@types/prop-types": "^15.7.0",
"@types/react": "^16.7.7", "@types/react": "^16.8.7",
"@types/react-dom": "^16.0.10", "@types/react-dom": "^16.8.2",
"@types/react-hot-loader": "^4.1.0", "@types/react-hot-loader": "^4.1.0",
"@types/react-tabs": "^2.3.0", "@types/react-tabs": "^2.3.1",
"@types/styled-components": "^4.1.1", "@types/styled-components": "^4.1.12",
"@types/tapable": "1.0.4", "@types/tapable": "1.0.4",
"@types/webpack": "^4.4.19", "@types/webpack": "^4.4.25",
"@types/webpack-env": "^1.13.0", "@types/webpack-env": "^1.13.9",
"@types/yargs": "^12.0.1", "@types/yargs": "^12.0.9",
"babel-loader": "8.0.4", "babel-loader": "8.0.5",
"babel-plugin-styled-components": "^1.9.0", "babel-plugin-styled-components": "^1.10.0",
"beautify-benchmark": "^0.2.4", "beautify-benchmark": "^0.2.4",
"bundlesize": "^0.17.0", "bundlesize": "^0.17.1",
"conventional-changelog-cli": "^2.0.11", "conventional-changelog-cli": "^2.0.12",
"copy-webpack-plugin": "^4.6.0", "copy-webpack-plugin": "^5.0.0",
"core-js": "^2.5.7", "core-js": "^2.6.5",
"coveralls": "^3.0.2", "coveralls": "^3.0.3",
"css-loader": "^1.0.1", "css-loader": "^2.1.1",
"cypress": "~3.1.2", "cypress": "~3.1.5",
"deploy-to-gh-pages": "^1.3.6", "deploy-to-gh-pages": "^1.3.6",
"enzyme": "^3.7.0", "enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.7.0", "enzyme-adapter-react-16": "^1.10.0",
"enzyme-to-json": "^3.3.4", "enzyme-to-json": "^3.3.5",
"fork-ts-checker-webpack-plugin": "0.5.0", "fork-ts-checker-webpack-plugin": "1.0.0",
"html-webpack-plugin": "^3.1.0", "html-webpack-plugin": "^3.1.0",
"jest": "^23.6.0", "jest": "^24.3.1",
"license-checker": "^24.0.1", "license-checker": "^25.0.1",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"mobx": "^4.3.1", "mobx": "^4.3.1",
"prettier": "^1.15.2", "prettier": "^1.16.4",
"prettier-eslint": "^8.8.2", "prettier-eslint": "^8.8.2",
"puppeteer": "^1.10.0", "puppeteer": "^1.13.0",
"raf": "^3.4.1", "raf": "^3.4.1",
"react": "^16.6.3", "react": "^16.8.4",
"react-dom": "^16.6.3", "react-dom": "^16.8.4",
"rimraf": "^2.6.2", "rimraf": "^2.6.3",
"shelljs": "^0.8.3", "shelljs": "^0.8.3",
"source-map-loader": "^0.2.4", "source-map-loader": "^0.2.4",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"styled-components": "^4.1.1", "styled-components": "^4.1.3",
"swagger2openapi": "^3.2.14", "swagger2openapi": "^5.2.3",
"ts-jest": "23.10.5", "ts-jest": "24.0.0",
"ts-loader": "5.3.1", "ts-loader": "5.3.3",
"ts-node": "^7.0.1", "ts-node": "^8.0.3",
"tslint": "^5.11.0", "tslint": "^5.13.1",
"tslint-react": "^3.4.0", "tslint-react": "^3.4.0",
"typescript": "^3.1.6", "typescript": "^3.3.3333",
"webpack": "^4.26.1", "webpack": "^4.29.6",
"webpack-cli": "^3.1.2", "webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.1.10", "webpack-dev-server": "^3.2.1",
"webpack-node-externals": "^1.6.0", "webpack-node-externals": "^1.6.0",
"workerize-loader": "^1.0.4", "workerize-loader": "^1.0.4",
"yaml-js": "^0.2.3" "yaml-js": "^0.2.3"
@ -133,24 +134,24 @@
"dependencies": { "dependencies": {
"classnames": "^2.2.6", "classnames": "^2.2.6",
"decko": "^1.2.0", "decko": "^1.2.0",
"dompurify": "^1.0.7", "dompurify": "^1.0.10",
"eventemitter3": "^3.0.0", "eventemitter3": "^3.0.0",
"json-pointer": "^0.6.0", "json-pointer": "^0.6.0",
"json-schema-ref-parser": "^6.0.1", "json-schema-ref-parser": "^6.1.0",
"lunr": "^2.3.2", "lunr": "^2.3.6",
"mark.js": "^8.11.1", "mark.js": "^8.11.1",
"marked": "^0.6.0", "marked": "^0.6.1",
"memoize-one": "^4.0.0", "memoize-one": "^5.0.0",
"mobx-react": "^5.2.5", "mobx-react": "^5.4.3",
"openapi-sampler": "1.0.0-beta.14", "openapi-sampler": "1.0.0-beta.14",
"perfect-scrollbar": "^1.4.0", "perfect-scrollbar": "^1.4.0",
"polished": "^2.0.2", "polished": "^3.0.3",
"prismjs": "^1.15.0", "prismjs": "^1.15.0",
"prop-types": "^15.6.2", "prop-types": "^15.7.2",
"react-dropdown": "^1.6.2", "react-dropdown": "^1.6.4",
"react-hot-loader": "^4.3.5", "react-hot-loader": "^4.8.0",
"react-tabs": "^2.0.0", "react-tabs": "^3.0.0",
"slugify": "^1.3.1", "slugify": "^1.3.4",
"stickyfill": "^1.1.1", "stickyfill": "^1.1.1",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
@ -161,7 +162,7 @@
} }
], ],
"jest": { "jest": {
"setupTestFrameworkScriptFile": "<rootDir>/src/setupTests.ts", "setupFilesAfterEnv": ["<rootDir>/src/setupTests.ts"],
"preset": "ts-jest", "preset": "ts-jest",
"collectCoverageFrom": [ "collectCoverageFrom": [
"src/**/*.{ts,tsx}" "src/**/*.{ts,tsx}"

View File

@ -1,4 +1,5 @@
import styled from '../styled-components'; import styled from '../styled-components';
import { PrismDiv } from './PrismDiv';
export const SampleControls = styled.div` export const SampleControls = styled.div`
opacity: 0.4; opacity: 0.4;
@ -21,3 +22,12 @@ export const SampleControlsWrap = styled.div`
opacity: 1; opacity: 1;
} }
`; `;
export const StyledPre = styled(PrismDiv.withComponent('pre'))`
font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize};
overflow-x: auto;
margin: 0;
white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
`;

View File

@ -0,0 +1,52 @@
import * as React from 'react';
import { StyledPre } from '../../common-elements/samples';
import { ExampleModel } from '../../services/models';
import { isJsonLike, langFromMime } from '../../utils';
import { JsonViewer } from '../JsonViewer/JsonViewer';
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
import { ExampleValue } from './ExampleValue';
import { useExternalExample } from './exernalExampleHook';
export interface ExampleProps {
example: ExampleModel;
mimeType: string;
}
export function Example({ example, mimeType }: ExampleProps) {
if (example.value === undefined && example.externalValueUrl) {
return <ExternalExample example={example} mimeType={mimeType} />;
} else {
return <ExampleValue value={example.value} mimeType={mimeType} />;
}
}
export function ExternalExample({ example, mimeType }: ExampleProps) {
let value = useExternalExample(example, mimeType);
if (value === undefined) {
return <span>Loading...</span>;
}
if (value instanceof Error) {
console.log(value);
return (
<StyledPre>
Error loading external example: <br />
<a className={'token string'} href={example.externalValueUrl} target="_blank">
{example.externalValueUrl}
</a>
</StyledPre>
);
}
if (isJsonLike(mimeType)) {
return <JsonViewer data={value} />;
} else {
if (typeof value === 'object') {
// just in case example was cached as json but used as non-json
value = JSON.stringify(value, null, 2);
}
return <SourceCodeWithCopy lang={langFromMime(mimeType)} source={value} />;
}
}

View File

@ -0,0 +1,18 @@
import * as React from 'react';
import { isJsonLike, langFromMime } from '../../utils/openapi';
import { JsonViewer } from '../JsonViewer/JsonViewer';
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
export interface ExampleValueProps {
value: any;
mimeType: string;
}
export function ExampleValue({ value, mimeType }: ExampleValueProps) {
if (isJsonLike(mimeType)) {
return <JsonViewer data={value} />;
} else {
return <SourceCodeWithCopy lang={langFromMime(mimeType)} source={value} />;
}
}

View File

@ -2,11 +2,9 @@ import * as React from 'react';
import { SmallTabs, Tab, TabList, TabPanel } from '../../common-elements'; import { SmallTabs, Tab, TabList, TabPanel } from '../../common-elements';
import { MediaTypeModel } from '../../services/models'; import { MediaTypeModel } from '../../services/models';
import { JsonViewer } from '../JsonViewer/JsonViewer';
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
import { NoSampleLabel } from './styled.elements';
import { isJsonLike, langFromMime } from '../../utils'; import { Example } from './Example';
import { NoSampleLabel } from './styled.elements';
export interface PayloadSamplesProps { export interface PayloadSamplesProps {
mediaType: MediaTypeModel; mediaType: MediaTypeModel;
@ -18,13 +16,6 @@ export class MediaTypeSamples extends React.Component<PayloadSamplesProps> {
const mimeType = this.props.mediaType.name; const mimeType = this.props.mediaType.name;
const noSample = <NoSampleLabel>No sample</NoSampleLabel>; const noSample = <NoSampleLabel>No sample</NoSampleLabel>;
const sampleView = isJsonLike(mimeType)
? sample => <JsonViewer data={sample} />
: sample =>
(sample !== undefined && (
<SourceCodeWithCopy lang={langFromMime(mimeType)} source={sample} />
)) ||
noSample;
const examplesNames = Object.keys(examples); const examplesNames = Object.keys(examples);
if (examplesNames.length === 0) { if (examplesNames.length === 0) {
@ -39,13 +30,19 @@ export class MediaTypeSamples extends React.Component<PayloadSamplesProps> {
))} ))}
</TabList> </TabList>
{examplesNames.map(name => ( {examplesNames.map(name => (
<TabPanel key={name}>{sampleView(examples[name].value)}</TabPanel> <TabPanel key={name}>
<Example example={examples[name]} mimeType={mimeType} />
</TabPanel>
))} ))}
</SmallTabs> </SmallTabs>
); );
} else { } else {
const name = examplesNames[0]; const name = examplesNames[0];
return <div>{sampleView(examples[name].value)}</div>; return (
<div>
<Example example={examples[name]} mimeType={mimeType} />
</div>
);
} }
} }
} }

View File

@ -0,0 +1,34 @@
import { useEffect, useRef, useState } from 'react';
import { ExampleModel } from '../../services/models/Example';
export function useExternalExample(example: ExampleModel, mimeType: string) {
const [, setIsLoading] = useState(true); // to trigger component reload
const value = useRef<any>(undefined);
const prevRef = useRef<ExampleModel | undefined>(undefined);
if (prevRef.current !== example) {
value.current = undefined;
}
prevRef.current = example;
useEffect(
() => {
const load = async () => {
setIsLoading(true);
try {
value.current = await example.getExternalValue(mimeType);
} catch (e) {
value.current = e;
}
setIsLoading(false);
};
load();
},
[example, mimeType],
);
return value.current;
}

View File

@ -1,19 +1,8 @@
import * as React from 'react'; import * as React from 'react';
import { highlight } from '../../utils'; import { highlight } from '../../utils';
import { SampleControls, SampleControlsWrap } from '../../common-elements'; import { SampleControls, SampleControlsWrap, StyledPre } from '../../common-elements';
import { CopyButtonWrapper } from '../../common-elements/CopyButtonWrapper'; import { CopyButtonWrapper } from '../../common-elements/CopyButtonWrapper';
import { PrismDiv } from '../../common-elements/PrismDiv';
import styled from '../../styled-components';
const StyledPre = styled(PrismDiv.withComponent('pre'))`
font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize};
overflow-x: auto;
margin: 0;
white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
`;
export interface SourceCodeProps { export interface SourceCodeProps {
source: string; source: string;

View File

@ -5,7 +5,9 @@ import defaultTheme from '../theme';
export default class TestThemeProvider extends React.Component { export default class TestThemeProvider extends React.Component {
render() { render() {
return ( return (
<ThemeProvider theme={defaultTheme}>{React.Children.only(this.props.children)}</ThemeProvider> <ThemeProvider theme={defaultTheme}>
{React.Children.only(this.props.children as any)}
</ThemeProvider>
); );
} }
} }

View File

@ -1,14 +1,55 @@
import { resolve as urlResolve } from 'url';
import { OpenAPIExample, Referenced } from '../../types'; import { OpenAPIExample, Referenced } from '../../types';
import { isJsonLike } from '../../utils/openapi';
import { OpenAPIParser } from '../OpenAPIParser'; import { OpenAPIParser } from '../OpenAPIParser';
const externalExamplesCache: { [url: string]: Promise<any> } = {};
export class ExampleModel { export class ExampleModel {
value: any; value: any;
summary?: string; summary?: string;
description?: string; description?: string;
externalValue?: string; externalValueUrl?: string;
constructor(parser: OpenAPIParser, infoOrRef: Referenced<OpenAPIExample>) { constructor(parser: OpenAPIParser, infoOrRef: Referenced<OpenAPIExample>) {
Object.assign(this, parser.deref(infoOrRef)); const example = parser.deref(infoOrRef);
this.value = example.value;
this.summary = example.summary;
this.description = example.description;
if (example.externalValue) {
this.externalValueUrl = urlResolve(parser.specUrl || '', example.externalValue);
}
parser.exitRef(infoOrRef); parser.exitRef(infoOrRef);
} }
getExternalValue(mimeType: string): Promise<any> {
if (!this.externalValueUrl) {
return Promise.resolve(undefined);
}
if (externalExamplesCache[this.externalValueUrl]) {
return externalExamplesCache[this.externalValueUrl];
}
externalExamplesCache[this.externalValueUrl] = fetch(this.externalValueUrl).then(res => {
return res.text().then(txt => {
if (!res.ok) {
return Promise.reject(new Error(txt));
}
if (isJsonLike(mimeType)) {
try {
return JSON.parse(txt);
} catch (e) {
return txt;
}
} else {
return txt;
}
});
});
return externalExamplesCache[this.externalValueUrl];
}
} }

View File

@ -1,6 +1,6 @@
import * as Sampler from 'openapi-sampler'; import * as Sampler from 'openapi-sampler';
import { OpenAPIExample, OpenAPIMediaType } from '../../types'; import { OpenAPIMediaType } from '../../types';
import { RedocNormalizedOptions } from '../RedocNormalizedOptions'; import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
import { SchemaModel } from './Schema'; import { SchemaModel } from './Schema';
@ -9,7 +9,7 @@ import { OpenAPIParser } from '../OpenAPIParser';
import { ExampleModel } from './Example'; import { ExampleModel } from './Example';
export class MediaTypeModel { export class MediaTypeModel {
examples?: { [name: string]: OpenAPIExample }; examples?: { [name: string]: ExampleModel };
schema?: SchemaModel; schema?: SchemaModel;
name: string; name: string;
isRequestType: boolean; isRequestType: boolean;
@ -33,7 +33,7 @@ export class MediaTypeModel {
this.examples = mapValues(info.examples, example => new ExampleModel(parser, example)); this.examples = mapValues(info.examples, example => new ExampleModel(parser, example));
} else if (info.example !== undefined) { } else if (info.example !== undefined) {
this.examples = { this.examples = {
default: new ExampleModel(parser, { value: info.example }), default: new ExampleModel(parser, { value: parser.shalowDeref(info.example) }),
}; };
} else if (isJsonLike(name)) { } else if (isJsonLike(name)) {
this.generateExample(parser, info); this.generateExample(parser, info);
@ -49,28 +49,20 @@ export class MediaTypeModel {
if (this.schema && this.schema.oneOf) { if (this.schema && this.schema.oneOf) {
this.examples = {}; this.examples = {};
for (const subSchema of this.schema.oneOf) { for (const subSchema of this.schema.oneOf) {
const sample = Sampler.sample( const sample = Sampler.sample(subSchema.rawSchema, samplerOptions, parser.spec);
subSchema.rawSchema,
samplerOptions,
parser.spec,
);
if (this.schema.discriminatorProp && typeof sample === 'object' && sample) { if (this.schema.discriminatorProp && typeof sample === 'object' && sample) {
sample[this.schema.discriminatorProp] = subSchema.title; sample[this.schema.discriminatorProp] = subSchema.title;
} }
this.examples[subSchema.title] = { this.examples[subSchema.title] = new ExampleModel(parser, {
value: sample, value: sample,
}; });
} }
} else if (this.schema) { } else if (this.schema) {
this.examples = { this.examples = {
default: new ExampleModel(parser, { default: new ExampleModel(parser, {
value: Sampler.sample( value: Sampler.sample(info.schema, samplerOptions, parser.spec),
info.schema,
samplerOptions,
parser.spec,
),
}), }),
}; };
} }

View File

@ -18,4 +18,15 @@ declare module 'styled-components' {
...interpolations: SimpleInterpolation[] ...interpolations: SimpleInterpolation[]
): Keyframes; ): Keyframes;
} }
export interface BaseThemedCssFunction<T extends object> {
<P extends object>(
first:
| TemplateStringsArray
| CSSObject
| InterpolationFunction<ThemedStyledProps<P, T>>
| string[],
...interpolations: Array<Interpolation<ThemedStyledProps<P, T>>>
): FlattenInterpolation<ThemedStyledProps<P, T>>;
}
} }

View File

@ -134,7 +134,6 @@ export default (env: { standalone?: boolean } = {}, { mode }) => ({
loader: 'css-loader', loader: 'css-loader',
options: { options: {
sourceMap: false, sourceMap: false,
minimize: true,
}, },
}, },
}, },

4794
yarn.lock

File diff suppressed because it is too large Load Diff