mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-22 00:26:34 +03:00
chore: modernize build pipeline (#1635)
This commit is contained in:
parent
92387bc653
commit
c09cf9dbbe
|
@ -26,6 +26,7 @@
|
|||
- The widest OpenAPI v2.0 features support (yes, it supports even `discriminator`) <br>
|
||||
![](docs/images/discriminator-demo.gif)
|
||||
- OpenAPI 3.0 support
|
||||
- Basic OpenAPI 3.1 support
|
||||
- Neat **interactive** documentation for nested objects <br>
|
||||
![](docs/images/nested-demo.gif)
|
||||
- Code samples support (via vendor extension) <br>
|
||||
|
@ -43,7 +44,6 @@
|
|||
- [x] ~~React rewrite~~
|
||||
- [x] ~~docs pre-rendering (performance and SEO)~~
|
||||
- [ ] ability to simple branding/styling
|
||||
- [ ] built-in API Console
|
||||
|
||||
## Releases
|
||||
**Important:** all the 2.x releases are deployed to npm and can be used via jsdeliver:
|
||||
|
@ -58,6 +58,7 @@ Additionally, all the 1.x releases are hosted on our GitHub Pages-based CDN **(d
|
|||
## Version Guidance
|
||||
| ReDoc Release | OpenAPI Specification |
|
||||
|:--------------|:----------------------|
|
||||
| 2.0.0-alpha.54| 3.1, 3.0.x, 2.0 |
|
||||
| 2.0.0-alpha.x | 3.0, 2.0 |
|
||||
| 1.19.x | 2.0 |
|
||||
| 1.18.x | 2.0 |
|
||||
|
|
690
cli/npm-shrinkwrap.json
generated
690
cli/npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -17,8 +17,8 @@
|
|||
"mkdirp": "^1.0.4",
|
||||
"mobx": "^6.3.2",
|
||||
"node-libs-browser": "^2.2.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^16.8.4",
|
||||
"react-dom": "^16.8.4",
|
||||
"redoc": "2.0.0-rc.53",
|
||||
"styled-components": "^5.3.0",
|
||||
"tslib": "^2.2.0",
|
||||
|
|
46
config/webpack-utils.ts
Normal file
46
config/webpack-utils.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import * as webpack from 'webpack';
|
||||
|
||||
export function getBabelLoader({useBuiltIns, hot}: {useBuiltIns: boolean, hot?: boolean}) {
|
||||
return {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
babelrc: false,
|
||||
sourceType: 'unambiguous',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
useBuiltIns: useBuiltIns ? 'usage' : false,
|
||||
corejs: 3,
|
||||
exclude: ['transform-typeof-symbol'],
|
||||
targets: 'defaults',
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
['@babel/preset-react', { development: false, runtime: 'classic' }],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: [
|
||||
['@babel/plugin-proposal-decorators', { legacy: true }],
|
||||
['@babel/plugin-proposal-class-properties', { loose: false }],
|
||||
[
|
||||
'@babel/plugin-transform-runtime',
|
||||
{
|
||||
corejs: false,
|
||||
helpers: true,
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
version: require('@babel/runtime/package.json').version,
|
||||
regenerator: true,
|
||||
},
|
||||
],
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
'@babel/plugin-proposal-nullish-coalescing-operator',
|
||||
hot ? 'react-hot-loader/babel' : undefined,
|
||||
].filter(Boolean)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function webpackIgnore(regexp) {
|
||||
return new webpack.NormalModuleReplacementPlugin(regexp, require.resolve('lodash/noop.js'));
|
||||
}
|
|
@ -31,7 +31,7 @@ const DropDownList = styled.ul`
|
|||
list-style: none;
|
||||
margin: 4px 0 0 0;
|
||||
padding: 5px 0;
|
||||
font-family: 'Lato';
|
||||
font-family: Roboto,sans-serif;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ const demos = [
|
|||
label: 'Google Calendar',
|
||||
},
|
||||
{ value: 'https://api.apis.guru/v2/specs/slack.com/1.5.0/openapi.yaml', label: 'Slack' },
|
||||
{ value: 'https://api.apis.guru/v2/specs/zoom.us/2.0.0/swagger.yaml', label: 'Zoom.us' },
|
||||
{ value: 'https://api.apis.guru/v2/specs/zoom.us/2.0.0/openapi.yaml', label: 'Zoom.us' },
|
||||
{ value: 'https://docs.graphhopper.com/openapi.json', label: 'GraphHopper' },
|
||||
];
|
||||
|
||||
|
@ -154,7 +154,7 @@ const Heading = styled.nav`
|
|||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: 'Lato';
|
||||
font-family: Roboto, sans-serif;
|
||||
`;
|
||||
|
||||
const Logo = styled.img`
|
||||
|
|
|
@ -1,21 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
// tslint:disable-next-line
|
||||
import { AppContainer } from 'react-hot-loader';
|
||||
// import DevTools from 'mobx-react-devtools';
|
||||
|
||||
import { Redoc, RedocProps } from '../../src/components/Redoc/Redoc';
|
||||
import { AppStore } from '../../src/services/AppStore';
|
||||
import { RedocRawOptions } from '../../src/services/RedocNormalizedOptions';
|
||||
import { loadAndBundleSpec } from '../../src/utils/loadAndBundleSpec';
|
||||
|
||||
const renderRoot = (props: RedocProps) =>
|
||||
render(
|
||||
<AppContainer>
|
||||
<Redoc {...props} />
|
||||
</AppContainer>,
|
||||
document.getElementById('example'),
|
||||
);
|
||||
import type { RedocRawOptions } from '../../src/services/RedocNormalizedOptions';
|
||||
import RedocStandalone from './hot';
|
||||
|
||||
const big = window.location.search.indexOf('big') > -1;
|
||||
const swagger = window.location.search.indexOf('swagger') > -1;
|
||||
|
@ -25,30 +11,6 @@ const userUrl = window.location.search.match(/url=(.*)$/);
|
|||
const specUrl =
|
||||
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
|
||||
|
||||
let store;
|
||||
const options: RedocRawOptions = { nativeScrollbars: false, maxDisplayedEnumValues: 3 };
|
||||
|
||||
async function init() {
|
||||
const spec = await loadAndBundleSpec(specUrl);
|
||||
store = new AppStore(spec, specUrl, options);
|
||||
renderRoot({ store });
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
if (module.hot) {
|
||||
const reload = (reloadStore = false) => async () => {
|
||||
if (reloadStore) {
|
||||
// create a new Store
|
||||
store.dispose();
|
||||
|
||||
const state = await store.toJS();
|
||||
store = AppStore.fromJS(state);
|
||||
}
|
||||
|
||||
renderRoot({ store });
|
||||
};
|
||||
|
||||
module.hot.accept(['../../src/components/Redoc/Redoc'], reload());
|
||||
module.hot.accept(['../../src/services/AppStore'], reload(true));
|
||||
}
|
||||
render(<RedocStandalone specUrl={specUrl} options={options} />, document.getElementById('example'));
|
||||
|
|
10
demo/playground/hot.tsx
Normal file
10
demo/playground/hot.tsx
Normal file
|
@ -0,0 +1,10 @@
|
|||
import * as React from 'react';
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import { RedocStandalone as RedocStandaloneOrig, RedocStandaloneProps } from '../../src';
|
||||
|
||||
const RedocStandalone = function (props: RedocStandaloneProps) {
|
||||
return <RedocStandaloneOrig {...props} />;
|
||||
}
|
||||
|
||||
export default hot(RedocStandalone);
|
|
@ -1,9 +1,9 @@
|
|||
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
|
||||
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
import * as HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import { compact } from 'lodash';
|
||||
import { resolve } from 'path';
|
||||
import * as webpack from 'webpack';
|
||||
import { getBabelLoader, webpackIgnore } from '../config/webpack-utils';
|
||||
|
||||
const VERSION = JSON.stringify(require('../package.json').version);
|
||||
const REVISION = JSON.stringify(
|
||||
|
@ -14,38 +14,6 @@ function root(filename) {
|
|||
return resolve(__dirname + '/' + filename);
|
||||
}
|
||||
|
||||
const tsLoader = (env) => ({
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
compilerOptions: {
|
||||
module: env.bench ? 'esnext' : 'es2015',
|
||||
declaration: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const babelLoader = () => ({
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
generatorOpts: {
|
||||
decoratorsBeforeExport: true,
|
||||
},
|
||||
plugins: compact([
|
||||
['@babel/plugin-syntax-typescript', { isTSX: true }],
|
||||
['@babel/plugin-syntax-decorators', { legacy: true }],
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-syntax-jsx',
|
||||
]),
|
||||
},
|
||||
});
|
||||
|
||||
const babelHotLoader = {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
plugins: ['react-hot-loader/babel'],
|
||||
},
|
||||
};
|
||||
|
||||
export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) => ({
|
||||
entry: [
|
||||
root('../src/polyfills.ts'),
|
||||
|
@ -57,6 +25,7 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
|
|||
: 'index.tsx',
|
||||
),
|
||||
],
|
||||
target: 'web',
|
||||
output: {
|
||||
filename: 'redoc-demo.bundle.js',
|
||||
path: root('dist'),
|
||||
|
@ -69,22 +38,25 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
|
|||
port: 9090,
|
||||
disableHostCheck: true,
|
||||
stats: 'minimal',
|
||||
hot: true,
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
||||
fallback: {
|
||||
path: require.resolve('path-browserify'),
|
||||
http: false,
|
||||
fs: false,
|
||||
os: false,
|
||||
},
|
||||
alias:
|
||||
mode !== 'production'
|
||||
? {
|
||||
'react-dom': '@hot-loader/react-dom',
|
||||
}
|
||||
'react-dom': '@hot-loader/react-dom',
|
||||
}
|
||||
: {},
|
||||
},
|
||||
|
||||
node: {
|
||||
fs: 'empty',
|
||||
},
|
||||
|
||||
performance: false,
|
||||
|
||||
externals: {
|
||||
|
@ -101,12 +73,23 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
|
|||
{ test: [/\.eot$/, /\.gif$/, /\.woff$/, /\.svg$/, /\.ttf$/], use: 'null-loader' },
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: compact([
|
||||
mode !== 'production' ? babelHotLoader : undefined,
|
||||
tsLoader(env),
|
||||
babelLoader(),
|
||||
]),
|
||||
exclude: [/node_modules/],
|
||||
use: [getBabelLoader({useBuiltIns: true, hot: true} )],
|
||||
exclude: {
|
||||
and: [/node_modules/],
|
||||
not: {
|
||||
or: [
|
||||
/swagger2openapi/,
|
||||
/reftools/,
|
||||
/openapi-sampler/,
|
||||
/mobx/,
|
||||
/oas-resolver/,
|
||||
/oas-kit-common/,
|
||||
/oas-schema-walker/,
|
||||
/\@redocly\/openapi-core/,
|
||||
/colorette/,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
|
@ -117,29 +100,18 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /node_modules\/(swagger2openapi|reftools|oas-resolver|oas-kit-common|oas-schema-walker)\/.*\.js$/,
|
||||
use: {
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
instance: 'ts2js-transpiler-only',
|
||||
compilerOptions: {
|
||||
allowJs: true,
|
||||
declaration: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
__REDOC_VERSION__: VERSION,
|
||||
__REDOC_REVISION__: REVISION,
|
||||
'process.env': '{}',
|
||||
'process.platform': '"browser"',
|
||||
'process.stdout': 'null',
|
||||
}),
|
||||
new webpack.NamedModulesPlugin(),
|
||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
// new webpack.NamedModulesPlugin(),
|
||||
// new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
template: env.playground
|
||||
? 'demo/playground/index.html'
|
||||
|
@ -147,16 +119,12 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
|
|||
? 'benchmark/index.html'
|
||||
: 'demo/index.html',
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin(),
|
||||
ignore(/js-yaml\/dumper\.js$/),
|
||||
ignore(/json-schema-ref-parser\/lib\/dereference\.js/),
|
||||
ignore(/^\.\/SearchWorker\.worker$/),
|
||||
new ForkTsCheckerWebpackPlugin({ logger: { infrastructure: 'silent', issues: 'console' } }),
|
||||
webpackIgnore(/js-yaml\/dumper\.js$/),
|
||||
webpackIgnore(/json-schema-ref-parser\/lib\/dereference\.js/),
|
||||
webpackIgnore(/^\.\/SearchWorker\.worker$/),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: ['demo/openapi.yaml'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
function ignore(regexp) {
|
||||
return new webpack.NormalModuleReplacementPlugin(regexp, require.resolve('lodash/noop.js'));
|
||||
}
|
||||
|
|
20334
package-lock.json
generated
20334
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
52
package.json
52
package.json
|
@ -6,6 +6,10 @@
|
|||
"type": "git",
|
||||
"url": "git://github.com/Redocly/redoc"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults",
|
||||
"ie 11"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=6.9",
|
||||
"npm": ">=3.0.0"
|
||||
|
@ -25,9 +29,9 @@
|
|||
"main": "bundles/redoc.lib.js",
|
||||
"types": "typings/index.d.ts",
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --mode=development --env.playground --hot --config demo/webpack.config.ts",
|
||||
"start:prod": "webpack-dev-server --env.playground --mode=production --config demo/webpack.config.ts",
|
||||
"start:benchmark": "webpack-dev-server --mode=production --env.bench --config demo/webpack.config.ts",
|
||||
"start": "webpack serve --mode=development --env playground --hot --config demo/webpack.config.ts",
|
||||
"start:prod": "webpack serve --env playground --mode=production --config demo/webpack.config.ts",
|
||||
"start:benchmark": "webpack serve --mode=production --env.bench --config demo/webpack.config.ts",
|
||||
"test": "npm run lint && npm run unit && npm run license-check",
|
||||
"unit": "jest --coverage",
|
||||
"e2e": "cypress run",
|
||||
|
@ -36,16 +40,16 @@
|
|||
"ts-check": "tsc --noEmit --skipLibCheck",
|
||||
"cy:open": "cypress open",
|
||||
"bundle:clean": "rimraf bundles",
|
||||
"bundle:standalone": "webpack --env.standalone --mode=production",
|
||||
"bundle:standalone": "webpack --env production --env standalone --mode=production",
|
||||
"bundle:lib": "webpack --mode=production && npm run declarations",
|
||||
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:standalone",
|
||||
"declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/",
|
||||
"stats": "webpack --env.standalone --json --profile --mode=production > stats.json",
|
||||
"stats": "webpack --env production --env standalone --json --profile --mode=production > stats.json",
|
||||
"prettier": "prettier --write \"cli/index.ts\" \"src/**/*.{ts,tsx}\"",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
|
||||
"lint": "eslint 'src/**/*.{js,ts,tsx}'",
|
||||
"benchmark": "node ./benchmark/benchmark.js",
|
||||
"start:demo": "webpack-dev-server --hot --config demo/webpack.config.ts --mode=development",
|
||||
"start:demo": "webpack serve --hot --config demo/webpack.config.ts --mode=development",
|
||||
"compile:cli": "tsc custom.d.ts cli/index.ts --target es6 --module commonjs --types yargs",
|
||||
"build:demo": "webpack --mode=production --config demo/webpack.config.ts",
|
||||
"deploy:demo": "aws s3 sync demo/dist s3://production-redoc-demo --acl=public-read",
|
||||
|
@ -54,10 +58,17 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.3",
|
||||
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
||||
"@babel/plugin-proposal-decorators": "^7.14.2",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.4",
|
||||
"@babel/plugin-syntax-decorators": "^7.12.13",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-syntax-jsx": "^7.10.4",
|
||||
"@babel/plugin-syntax-typescript": "^7.10.4",
|
||||
"@babel/plugin-transform-runtime": "^7.14.3",
|
||||
"@babel/preset-env": "^7.14.4",
|
||||
"@babel/preset-react": "^7.13.13",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@cypress/webpack-preprocessor": "^5.9.0",
|
||||
"@hot-loader/react-dom": "^17.0.1",
|
||||
"@types/chai": "^4.2.18",
|
||||
|
@ -77,18 +88,18 @@
|
|||
"@types/react-tabs": "^2.3.2",
|
||||
"@types/styled-components": "^5.1.1",
|
||||
"@types/tapable": "^2.2.2",
|
||||
"@types/webpack": "^4.41.21",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"@types/webpack-env": "^1.16.0",
|
||||
"@types/yargs": "^17.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.26.0",
|
||||
"@typescript-eslint/parser": "^4.26.0",
|
||||
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.1",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-styled-components": "^1.12.0",
|
||||
"beautify-benchmark": "^0.2.4",
|
||||
"bundlesize": "^0.18.1",
|
||||
"conventional-changelog-cli": "^2.0.34",
|
||||
"copy-webpack-plugin": "^6.0.3",
|
||||
"copy-webpack-plugin": "^9.0.0",
|
||||
"core-js": "^3.13.1",
|
||||
"coveralls": "^3.1.0",
|
||||
"css-loader": "^5.2.6",
|
||||
|
@ -99,7 +110,7 @@
|
|||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"fork-ts-checker-webpack-plugin": "^6.2.10",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"jest": "^27.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"license-checker": "^25.0.1",
|
||||
|
@ -112,21 +123,19 @@
|
|||
"react-hot-loader": "^4.13.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"shelljs": "^0.8.4",
|
||||
"source-map-loader": "^1.0.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"styled-components": "^5.3.0",
|
||||
"ts-jest": "^27.0.2",
|
||||
"ts-loader": "^8.0.1",
|
||||
"ts-node": "^10.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"typescript": "~4.1.0",
|
||||
"unfetch": "^4.2.0",
|
||||
"url-polyfill": "^1.1.12",
|
||||
"webpack": "^4.44.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack": "^5.38.1",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-node-externals": "^2.5.0",
|
||||
"workerize-loader": "^1.3.0"
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"workerize-loader": "github:redocly/workerize-loader#webpack-5-dist"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"core-js": "^3.1.4",
|
||||
|
@ -136,7 +145,8 @@
|
|||
"styled-components": "^4.1.1 || ^5.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@redocly/openapi-core": "^1.0.0-beta.48",
|
||||
"@babel/runtime": "^7.14.0",
|
||||
"@redocly/openapi-core": "^1.0.0-beta.50",
|
||||
"@redocly/react-dropdown-aria": "^2.0.11",
|
||||
"@types/node": "^15.6.1",
|
||||
"classnames": "^2.3.1",
|
||||
|
@ -150,21 +160,21 @@
|
|||
"memoize-one": "^5.2.1",
|
||||
"mobx-react": "^7.2.0",
|
||||
"openapi-sampler": "^1.0.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"perfect-scrollbar": "^1.5.1",
|
||||
"polished": "^4.1.3",
|
||||
"prismjs": "^1.23.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-tabs": "^3.2.2",
|
||||
"slugify": "^1.5.3",
|
||||
"slugify": "~1.4.7",
|
||||
"stickyfill": "^1.1.1",
|
||||
"swagger2openapi": "^7.0.6",
|
||||
"tslib": "^2.2.0",
|
||||
"url-template": "^2.0.8"
|
||||
},
|
||||
"bundlesize": [
|
||||
{
|
||||
"path": "./bundles/redoc.standalone.js",
|
||||
"maxSize": "300 kB"
|
||||
"maxSize": "350 kB"
|
||||
}
|
||||
],
|
||||
"jest": {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { StoreConsumer } from '../components/StoreBuilder';
|
||||
import { StoreContext } from '../components/StoreBuilder';
|
||||
import styled, { css } from '../styled-components';
|
||||
|
||||
import { HistoryService } from '../services';
|
||||
|
||||
// tslint:disable-next-line
|
||||
export const linkifyMixin = className => css`
|
||||
export const linkifyMixin = (className) => css`
|
||||
${className} {
|
||||
cursor: pointer;
|
||||
margin-left: -20px;
|
||||
|
@ -33,36 +33,41 @@ export const linkifyMixin = className => css`
|
|||
}
|
||||
`;
|
||||
|
||||
const isModifiedEvent = event =>
|
||||
const isModifiedEvent = (event) =>
|
||||
!!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
|
||||
|
||||
export class Link extends React.Component<{ to: string; className?: string; children?: any }> {
|
||||
navigate = (history: HistoryService, event) => {
|
||||
if (
|
||||
!event.defaultPrevented && // onClick prevented default
|
||||
event.button === 0 && // ignore everything but left clicks
|
||||
!isModifiedEvent(event) // ignore clicks with modifier keys
|
||||
) {
|
||||
event.preventDefault();
|
||||
history.replace(this.props.to);
|
||||
}
|
||||
};
|
||||
export function Link(props: { to: string; className?: string; children?: any }) {
|
||||
const store = React.useContext(StoreContext);
|
||||
const clickHandler = React.useCallback(
|
||||
(event) => {
|
||||
if (!store) return;
|
||||
navigate(store.menu.history, event);
|
||||
},
|
||||
[store],
|
||||
);
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StoreConsumer>
|
||||
{store => (
|
||||
<a
|
||||
className={this.props.className}
|
||||
href={store!.menu.history.linkForId(this.props.to)}
|
||||
onClick={this.navigate.bind(this, store!.menu.history)}
|
||||
aria-label={this.props.to}
|
||||
>
|
||||
{this.props.children}
|
||||
</a>
|
||||
)}
|
||||
</StoreConsumer>
|
||||
);
|
||||
if (!store) return null;
|
||||
|
||||
return (
|
||||
<a
|
||||
className={props.className}
|
||||
href={store!.menu.history.linkForId(props.to)}
|
||||
onClick={clickHandler}
|
||||
aria-label={props.to}
|
||||
>
|
||||
{props.children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function navigate(history: HistoryService, event) {
|
||||
if (
|
||||
!event.defaultPrevented && // onClick prevented default
|
||||
event.button === 0 && // ignore everything but left clicks
|
||||
!isModifiedEvent(event) // ignore clicks with modifier keys
|
||||
) {
|
||||
event.preventDefault();
|
||||
history.replace(this.props.to);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
|
||||
import { RedocNormalizedOptions, RedocRawOptions } from '../services/RedocNormalizedOptions';
|
||||
|
@ -14,47 +13,23 @@ export interface RedocStandaloneProps {
|
|||
onLoaded?: (e?: Error) => any;
|
||||
}
|
||||
|
||||
export class RedocStandalone extends React.PureComponent<RedocStandaloneProps> {
|
||||
static propTypes = {
|
||||
spec: (props, _, componentName) => {
|
||||
if (!props.spec && !props.specUrl) {
|
||||
return new Error(
|
||||
`One of props 'spec' or 'specUrl' was not specified in '${componentName}'.`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
export const RedocStandalone = function (props: RedocStandaloneProps) {
|
||||
const { spec, specUrl, options = {}, onLoaded } = props;
|
||||
const hideLoading = options.hideLoading !== undefined;
|
||||
|
||||
specUrl: (props, _, componentName) => {
|
||||
if (!props.spec && !props.specUrl) {
|
||||
return new Error(
|
||||
`One of props 'spec' or 'specUrl' was not specified in '${componentName}'.`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
options: PropTypes.any,
|
||||
onLoaded: PropTypes.any,
|
||||
};
|
||||
const normalizedOpts = new RedocNormalizedOptions(options);
|
||||
|
||||
render() {
|
||||
const { spec, specUrl, options = {}, onLoaded } = this.props;
|
||||
const hideLoading = options.hideLoading !== undefined;
|
||||
|
||||
const normalizedOpts = new RedocNormalizedOptions(options);
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<StoreBuilder spec={spec} specUrl={specUrl} options={options} onLoaded={onLoaded}>
|
||||
{({ loading, store }) =>
|
||||
!loading ? (
|
||||
<Redoc store={store!} />
|
||||
) : hideLoading ? null : (
|
||||
<Loading color={normalizedOpts.theme.colors.primary.main} />
|
||||
)
|
||||
}
|
||||
</StoreBuilder>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<StoreBuilder spec={spec} specUrl={specUrl} options={options} onLoaded={onLoaded}>
|
||||
{({ loading, store }) =>
|
||||
!loading ? (
|
||||
<Redoc store={store!} />
|
||||
) : hideLoading ? null : (
|
||||
<Loading color={normalizedOpts.theme.colors.primary.main} />
|
||||
)
|
||||
}
|
||||
</StoreBuilder>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as memoize from 'memoize-one/dist/memoize-one.cjs'; // fixme: https://github.com/alexreardon/memoize-one/issues/37
|
||||
import { Component, createContext } from 'react';
|
||||
import * as React from 'react';
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { AppStore } from '../services/';
|
||||
import { RedocRawOptions } from '../services/RedocNormalizedOptions';
|
||||
|
@ -14,7 +14,7 @@ export interface StoreBuilderProps {
|
|||
|
||||
onLoaded?: (e?: Error) => void;
|
||||
|
||||
children: (props: { loading: boolean; store?: AppStore }) => any;
|
||||
children: (props: { loading: boolean; store: AppStore | null }) => any;
|
||||
}
|
||||
|
||||
export interface StoreBuilderState {
|
||||
|
@ -25,79 +25,41 @@ export interface StoreBuilderState {
|
|||
prevSpecUrl?: string;
|
||||
}
|
||||
|
||||
const { Provider, Consumer } = createContext<AppStore | undefined>(undefined);
|
||||
export { Provider as StoreProvider, Consumer as StoreConsumer };
|
||||
const StoreContext = createContext<AppStore | undefined>(undefined);
|
||||
const { Provider, Consumer } = StoreContext;
|
||||
export { Provider as StoreProvider, Consumer as StoreConsumer, StoreContext };
|
||||
|
||||
export class StoreBuilder extends Component<StoreBuilderProps, StoreBuilderState> {
|
||||
static getDerivedStateFromProps(nextProps: StoreBuilderProps, prevState: StoreBuilderState) {
|
||||
if (nextProps.specUrl !== prevState.prevSpecUrl || nextProps.spec !== prevState.prevSpec) {
|
||||
return {
|
||||
loading: true,
|
||||
resolvedSpec: null,
|
||||
prevSpec: nextProps.spec,
|
||||
prevSpecUrl: nextProps.specUrl,
|
||||
};
|
||||
export function StoreBuilder(props: StoreBuilderProps) {
|
||||
const {spec, specUrl, options, onLoaded, children } = props;
|
||||
|
||||
const [resolvedSpec, setResolvedSpec] = React.useState<any>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
async function load() {
|
||||
if (!spec && !specUrl) {
|
||||
return undefined;
|
||||
}
|
||||
setResolvedSpec(null);
|
||||
const resolved = await loadAndBundleSpec(spec || specUrl!);
|
||||
setResolvedSpec(resolved);
|
||||
}
|
||||
load();
|
||||
}, [spec, specUrl])
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
state: StoreBuilderState = {
|
||||
loading: true,
|
||||
resolvedSpec: null,
|
||||
};
|
||||
|
||||
@memoize
|
||||
makeStore(spec, specUrl, options) {
|
||||
if (!spec) {
|
||||
return undefined;
|
||||
}
|
||||
const store = React.useMemo(() => {
|
||||
if (!resolvedSpec) return null;
|
||||
try {
|
||||
return new AppStore(spec, specUrl, options);
|
||||
return new AppStore(resolvedSpec, specUrl, options);
|
||||
} catch (e) {
|
||||
if (this.props.onLoaded) {
|
||||
this.props.onLoaded(e);
|
||||
if (onLoaded) {
|
||||
onLoaded(e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}, [resolvedSpec, specUrl, options]);
|
||||
|
||||
componentDidMount() {
|
||||
this.load();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.resolvedSpec === null) {
|
||||
this.load();
|
||||
} else if (!this.state.loading && this.props.onLoaded) {
|
||||
// may run multiple time
|
||||
this.props.onLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
async load() {
|
||||
const { specUrl, spec } = this.props;
|
||||
try {
|
||||
const resolvedSpec = await loadAndBundleSpec(spec || specUrl!);
|
||||
this.setState({ resolvedSpec, loading: false });
|
||||
} catch (e) {
|
||||
if (this.props.onLoaded) {
|
||||
this.props.onLoaded(e);
|
||||
}
|
||||
this.setState({ error: e });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
throw this.state.error;
|
||||
}
|
||||
|
||||
const { specUrl, options } = this.props;
|
||||
const { loading, resolvedSpec } = this.state;
|
||||
return this.props.children({
|
||||
loading,
|
||||
store: this.makeStore(resolvedSpec, specUrl, options),
|
||||
});
|
||||
}
|
||||
return children({
|
||||
loading: !store,
|
||||
store,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ export {
|
|||
Section,
|
||||
StyledDropdown,
|
||||
SimpleDropdown,
|
||||
DropdownOption,
|
||||
} from './common-elements/';
|
||||
export { OpenAPIEncoding } from './types';
|
||||
export type { DropdownOption } from './common-elements';
|
||||
export type { OpenAPIEncoding } from './types';
|
||||
export * from './services';
|
||||
export * from './utils';
|
||||
|
||||
|
|
|
@ -1,15 +1,2 @@
|
|||
import 'core-js/es/promise';
|
||||
|
||||
import 'core-js/es/array/find';
|
||||
import 'core-js/es/array/includes';
|
||||
import 'core-js/es/object/assign';
|
||||
import 'core-js/es/object/entries';
|
||||
import 'core-js/es/object/is';
|
||||
import 'core-js/es/string/ends-with';
|
||||
import 'core-js/es/string/starts-with';
|
||||
|
||||
import 'core-js/es/map';
|
||||
import 'core-js/es/symbol';
|
||||
|
||||
import 'unfetch/polyfill/index';
|
||||
import 'url-polyfill';
|
||||
import 'core-js/es/symbol';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as styledComponents from 'styled-components';
|
||||
|
||||
import { ResolvedThemeInterface } from './theme';
|
||||
import type { ResolvedThemeInterface } from './theme';
|
||||
|
||||
export { ResolvedThemeInterface };
|
||||
export type { ResolvedThemeInterface };
|
||||
|
||||
const {
|
||||
default: styled,
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { Source, Document, bundle, Config } from '@redocly/openapi-core';
|
||||
import type { Source, Document } from '@redocly/openapi-core';
|
||||
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
import { bundle } from '@redocly/openapi-core/lib/bundle';
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
import { Config } from '@redocly/openapi-core/lib/config/config';
|
||||
|
||||
/* tslint:disable-next-line:no-implicit-dependencies */
|
||||
import { convertObj } from 'swagger2openapi';
|
||||
import { OpenAPISpec } from '../types';
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
import * as webpack from 'webpack';
|
||||
import * as path from 'path';
|
||||
import { getBabelLoader, webpackIgnore } from './config/webpack-utils';
|
||||
|
||||
const nodeExternals = require('webpack-node-externals')({
|
||||
// bundle in modules that need transpiling + non-js (e.g. css)
|
||||
|
@ -31,7 +32,7 @@ const BANNER = `ReDoc - OpenAPI/Swagger-generated API Reference Documentation
|
|||
Version: ${VERSION}
|
||||
Repo: https://github.com/Redocly/redoc`;
|
||||
|
||||
export default (env: { standalone?: boolean } = {}, { mode }) => ({
|
||||
export default (env: { standalone?: boolean } = {}) => ({
|
||||
entry: env.standalone ? ['./src/polyfills.ts', './src/standalone.tsx'] : './src/index.ts',
|
||||
output: {
|
||||
filename: env.standalone ? 'redoc.standalone.js' : 'redoc.lib.js',
|
||||
|
@ -42,18 +43,20 @@ export default (env: { standalone?: boolean } = {}, { mode }) => ({
|
|||
},
|
||||
devtool: 'source-map',
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
||||
},
|
||||
node: {
|
||||
fs: 'empty',
|
||||
extensions: ['.ts', '.tsx', '.js', '.mjs', '.json'],
|
||||
fallback: {
|
||||
path: require.resolve('path-browserify'),
|
||||
http: false,
|
||||
fs: false,
|
||||
os: false,
|
||||
}
|
||||
},
|
||||
performance: false,
|
||||
optimization: {
|
||||
minimize: !!env.standalone,
|
||||
},
|
||||
// target: 'node',
|
||||
externalsPresets: env.standalone ? {} : { node: true },
|
||||
externals: env.standalone
|
||||
? {
|
||||
esprima: 'esprima',
|
||||
esprima: 'null',
|
||||
'node-fetch': 'null',
|
||||
'node-fetch-h2': 'null',
|
||||
yaml: 'null',
|
||||
|
@ -61,7 +64,7 @@ export default (env: { standalone?: boolean } = {}, { mode }) => ({
|
|||
}
|
||||
: (context, request, callback) => {
|
||||
// ignore node-fetch dep of swagger2openapi as it is not used
|
||||
if (/esprima|node-fetch|node-fetch-h2|yaml|safe-json-stringify$/i.test(request)) {
|
||||
if (/esprima|node-fetch|node-fetch-h2|\/yaml|safe-json-stringify$/i.test(request)) {
|
||||
return callback(null, 'var undefined');
|
||||
}
|
||||
return nodeExternals(context, request, callback);
|
||||
|
@ -70,51 +73,22 @@ export default (env: { standalone?: boolean } = {}, { mode }) => ({
|
|||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
compilerOptions: {
|
||||
module: 'es2015',
|
||||
declaration: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
generatorOpts: {
|
||||
decoratorsBeforeExport: true,
|
||||
},
|
||||
plugins: [
|
||||
['@babel/plugin-syntax-typescript', { isTSX: true }],
|
||||
['@babel/plugin-syntax-decorators', { legacy: true }],
|
||||
'@babel/plugin-syntax-jsx',
|
||||
[
|
||||
'babel-plugin-styled-components',
|
||||
{
|
||||
minify: true,
|
||||
displayName: mode !== 'production',
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: [/node_modules/],
|
||||
},
|
||||
{
|
||||
test: /node_modules\/(swagger2openapi|reftools|oas-resolver|oas-kit-common|oas-schema-walker)\/.*\.js$/,
|
||||
use: {
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
instance: 'ts2js-transpiler-only',
|
||||
transpileOnly: true,
|
||||
compilerOptions: {
|
||||
allowJs: true,
|
||||
declaration: false,
|
||||
},
|
||||
test: /\.(tsx?|[cm]?js)$/,
|
||||
use: [getBabelLoader({useBuiltIns: !!env.standalone})],
|
||||
exclude: {
|
||||
and: [/node_modules/],
|
||||
not: {
|
||||
or: [
|
||||
/swagger2openapi/,
|
||||
/reftools/,
|
||||
/openapi-sampler/,
|
||||
/mobx/,
|
||||
/oas-resolver/,
|
||||
/oas-kit-common/,
|
||||
/oas-schema-walker/,
|
||||
/\@redocly\/openapi-core/,
|
||||
/colorette/,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -127,22 +101,19 @@ export default (env: { standalone?: boolean } = {}, { mode }) => ({
|
|||
},
|
||||
},
|
||||
},
|
||||
{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' },
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
__REDOC_VERSION__: VERSION,
|
||||
__REDOC_REVISION__: REVISION,
|
||||
'process.env': '{}',
|
||||
'process.platform': '"browser"',
|
||||
'process.stdout': 'null',
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin({ logger: { infrastructure: 'silent', issues: 'console' } }),
|
||||
new webpack.BannerPlugin(BANNER),
|
||||
ignore(/js-yaml\/dumper\.js$/),
|
||||
ignore(/json-schema-ref-parser\/lib\/dereference\.js/),
|
||||
env.standalone ? ignore(/^\.\/SearchWorker\.worker$/) : ignore(/$non-existing^/),
|
||||
],
|
||||
webpackIgnore(/js-yaml\/dumper\.js$/),
|
||||
env.standalone ? webpackIgnore(/^\.\/SearchWorker\.worker$/) : undefined,
|
||||
].filter(Boolean),
|
||||
});
|
||||
|
||||
function ignore(regexp) {
|
||||
return new webpack.NormalModuleReplacementPlugin(regexp, require.resolve('lodash/noop.js'));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user