mirror of
https://github.com/Redocly/redoc.git
synced 2025-07-10 16:22:27 +03:00
commit
8011affd00
8
.github/workflows/e2e-tests.yml
vendored
8
.github/workflows/e2e-tests.yml
vendored
|
@ -1,12 +1,16 @@
|
||||||
name: E2E Tests
|
name: E2E Tests
|
||||||
|
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-e2e:
|
build-and-e2e:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: npm ci && npm ci --prefix cli
|
- run: npm ci
|
||||||
- run: npm run bundle
|
- run: npm run bundle
|
||||||
- run: npm run e2e
|
- run: npm run e2e
|
||||||
|
|
22
.github/workflows/publish.yml
vendored
22
.github/workflows/publish.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
||||||
npm-
|
npm-
|
||||||
|
|
||||||
- name: Clean Install
|
- name: Clean Install
|
||||||
run: npm ci && npm ci --prefix cli
|
run: npm ci
|
||||||
|
|
||||||
- name: Bundle
|
- name: Bundle
|
||||||
run: npm run bundle
|
run: npm run bundle
|
||||||
|
@ -37,7 +37,7 @@ jobs:
|
||||||
name: bundles
|
name: bundles
|
||||||
path: bundles
|
path: bundles
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
unit-tests:
|
unit-tests:
|
||||||
name: Unit Tests
|
name: Unit Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -46,11 +46,11 @@ jobs:
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Clean Install
|
- name: Clean Install
|
||||||
run: npm ci && npm ci --prefix cli
|
run: npm ci
|
||||||
|
|
||||||
- name: Unit Test
|
- name: Unit Test
|
||||||
run: npm test
|
run: npm test
|
||||||
|
|
||||||
e2e-tests:
|
e2e-tests:
|
||||||
name: E2E Tests
|
name: E2E Tests
|
||||||
needs: [bundle]
|
needs: [bundle]
|
||||||
|
@ -60,7 +60,7 @@ jobs:
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Clean Install
|
- name: Clean Install
|
||||||
run: npm ci && npm ci --prefix cli
|
run: npm ci
|
||||||
|
|
||||||
- name: Download bundled artifact
|
- name: Download bundled artifact
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
|
@ -70,7 +70,7 @@ jobs:
|
||||||
|
|
||||||
- name: E2E Test
|
- name: E2E Test
|
||||||
run: npm run e2e
|
run: npm run e2e
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
name: Publish
|
name: Publish
|
||||||
needs: [unit-tests, e2e-tests]
|
needs: [unit-tests, e2e-tests]
|
||||||
|
@ -109,11 +109,11 @@ jobs:
|
||||||
|
|
||||||
- name: Publish npm Package
|
- name: Publish npm Package
|
||||||
run: |
|
run: |
|
||||||
npm version $RELEASE_VERSION --no-git-tag-version
|
npm version $RELEASE_VERSION --no-git-tag-version
|
||||||
npm publish --access public
|
npm publish --access public
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
|
||||||
|
|
||||||
publish-beta:
|
publish-beta:
|
||||||
name: Publish Beta to NPM
|
name: Publish Beta to NPM
|
||||||
needs: [unit-tests, e2e-tests]
|
needs: [unit-tests, e2e-tests]
|
||||||
|
@ -172,7 +172,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish npm Package
|
- name: Publish npm Package
|
||||||
run: |
|
run: |
|
||||||
npm version $RELEASE_VERSION --no-git-tag-version
|
npm version $RELEASE_VERSION --no-git-tag-version
|
||||||
npm publish --access public --tag beta
|
npm publish --access public --tag beta
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
|
||||||
|
|
8
.github/workflows/unit-tests.yml
vendored
8
.github/workflows/unit-tests.yml
vendored
|
@ -1,12 +1,16 @@
|
||||||
name: Unit Tests
|
name: Unit Tests
|
||||||
|
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-unit:
|
build-and-unit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: npm ci && npm ci --prefix cli
|
- run: npm ci
|
||||||
- run: npm run bundle
|
- run: npm run bundle
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -27,8 +27,6 @@ cypress/
|
||||||
bundles/
|
bundles/
|
||||||
typings/*
|
typings/*
|
||||||
!typings/styled-patch.d.ts
|
!typings/styled-patch.d.ts
|
||||||
cli/index.js
|
|
||||||
cli/__test__/*/**/*.html
|
|
||||||
|
|
||||||
/benchmark/revisions
|
/benchmark/revisions
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ Refer to the Redocly's documentation for more information on these products:
|
||||||
- [Simple integration with `create-react-app`](https://redocly.com/docs/redoc/quickstart/react/)
|
- [Simple integration with `create-react-app`](https://redocly.com/docs/redoc/quickstart/react/)
|
||||||
|
|
||||||
[Example repo](https://github.com/APIs-guru/create-react-app-redoc)
|
[Example repo](https://github.com/APIs-guru/create-react-app-redoc)
|
||||||
- [Command-line interface to bundle your docs into a **zero-dependency** HTML file](https://redoc.ly/docs/redoc/quickstart/cli/)
|
- [Command-line interface to bundle your docs into a **zero-dependency** HTML file](https://redocly.com/docs/cli/commands/build-docs/)
|
||||||
- Neat **interactive** documentation for nested objects <br>
|
- Neat **interactive** documentation for nested objects <br>
|
||||||

|

|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ to render your OpenAPI definition, refer to the
|
||||||
[**Redoc quickstart guide**](https://redocly.com/docs/redoc/quickstart/) and [**How to use the HTML element**](https://redocly.com/docs/redoc/deployment/html/).
|
[**Redoc quickstart guide**](https://redocly.com/docs/redoc/quickstart/) and [**How to use the HTML element**](https://redocly.com/docs/redoc/deployment/html/).
|
||||||
|
|
||||||
## Redoc CLI
|
## Redoc CLI
|
||||||
For more information on Redoc's commmand-line interface, refer to
|
For more information on Redoc's command-line interface, refer to
|
||||||
[**Using the Redoc CLI**](https://redocly.com/docs/redoc/deployment/cli/).
|
[**Using the Redoc CLI**](https://redocly.com/docs/redoc/deployment/cli/).
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
*/
|
|
||||||
!index.js
|
|
||||||
!package.json
|
|
||||||
!README.md
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Package the 'redoc-cli' as a docker image.
|
|
||||||
#
|
|
||||||
# To build:
|
|
||||||
# $ cd <Redoc project directory>
|
|
||||||
# $ docker build -t redoc-cli -f cli/Dockerfile .
|
|
||||||
#
|
|
||||||
# To run:
|
|
||||||
# To display the command line options:
|
|
||||||
# $ docker run --rm -it redoc-cli --help
|
|
||||||
# .. will display the command line help
|
|
||||||
#
|
|
||||||
# To turn `swagger.yml` file in the current directory, to html documentation 'redoc-static.html'
|
|
||||||
# $ docker run --rm -it -v $PWD:/data redoc-cli bundle swagger.yml
|
|
||||||
|
|
||||||
FROM node:alpine
|
|
||||||
|
|
||||||
RUN npm install -g redoc-cli
|
|
||||||
|
|
||||||
WORKDIR /data
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
ENTRYPOINT ["redoc-cli"]
|
|
||||||
CMD []
|
|
|
@ -1,40 +0,0 @@
|
||||||
# redoc-cli
|
|
||||||
|
|
||||||
**[ReDoc](https://github.com/Redocly/redoc)'s Command Line Interface**
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
You can use `redoc-cli` by installing [the package](https://www.npmjs.com/package/redoc-cli) globally,
|
|
||||||
or using [npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b).
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
The two following commands are available:
|
|
||||||
|
|
||||||
- `redoc-cli serve [spec]` - starts the server with `spec` rendered with ReDoc.
|
|
||||||
Supports a server-side rendering mode (`--ssr`)
|
|
||||||
and can watch the spec (`--watch`) to automatically reload the page whenever it changes.\
|
|
||||||
Deprecated. Use `npx @redocly/cli preview-docs [spec]`
|
|
||||||
- `redoc-cli bundle [spec]` - bundles `spec` and Redoc into a **zero-dependency** HTML file.\
|
|
||||||
Deprecated. Use Use "build" command instead.
|
|
||||||
- `redoc-cli build [spec]` - build `spec` and Redoc into a **zero-dependency** HTML file.
|
|
||||||
|
|
||||||
Some examples:
|
|
||||||
|
|
||||||
- Bundle with the main color changed to `orange`:<br/>
|
|
||||||
`$ redoc-cli build [spec] --options.theme.colors.primary.main=orange`
|
|
||||||
- Serve with the `nativeScrollbars` option set to true:<br/>
|
|
||||||
`$ redoc-cli serve [spec] --options.nativeScrollbars`
|
|
||||||
- Bundle using a custom [Handlebars](https://handlebarsjs.com/) template
|
|
||||||
(check the [default template](https://github.com/Redocly/redoc/blob/main/cli/template.hbs) for an example):<br/>
|
|
||||||
`$ redoc-cli build [spec] -t custom.hbs`
|
|
||||||
- Bundle using a custom template and add custom `templateOptions`:<br/>
|
|
||||||
`$ redoc-cli build [spec] -t custom.hbs --templateOptions.metaDescription "Page meta description"`
|
|
||||||
|
|
||||||
#### With a Redocly configuration file ([more info](https://redocly.com/docs/cli/configuration/#redocly-configuration-file)):
|
|
||||||
|
|
||||||
1. Go to folder with your Redocly configuration file (`.redocly.yaml` or `redocly.yaml`) and your OpenAPI definition file.
|
|
||||||
2. Build the site using the `build` command (options from the Redocly configuration file will be automatically fetched):
|
|
||||||
`redoc build openapi.yaml`
|
|
||||||
|
|
||||||
For more details, run `redoc-cli --help`.
|
|
|
@ -1,2 +0,0 @@
|
||||||
features.openapi:
|
|
||||||
disableSearch: true
|
|
|
@ -1,30 +0,0 @@
|
||||||
import { spawnSync } from 'child_process';
|
|
||||||
import { readFileSync } from 'fs';
|
|
||||||
|
|
||||||
describe('build', () => {
|
|
||||||
it('should use .redocly.yaml', () => {
|
|
||||||
const r = spawnSync(
|
|
||||||
'ts-node',
|
|
||||||
['../../../index.ts', 'build', ' ../../../../demo/openapi.yaml', '--output=redoc-test.html'],
|
|
||||||
{
|
|
||||||
cwd: __dirname,
|
|
||||||
shell: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const out = r.stdout.toString('utf-8');
|
|
||||||
const err = r.stderr.toString('utf-8');
|
|
||||||
const result = `${out}\n${err}`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const redocStaticFile = readFileSync(`${__dirname}/redoc-test.html`, 'utf8');
|
|
||||||
expect(redocStaticFile).toContain('"options":{"disableSearch":true}');
|
|
||||||
expect(redocStaticFile).not.toContain('role="search"');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.toString()).toContain('{"options":{"disableSearch":"true"}');
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(result).toContain('Found .redocly.yaml and using features.openapi options');
|
|
||||||
expect(result).toContain('bundled successfully');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { spawnSync } from 'child_process';
|
|
||||||
import { readFileSync } from 'fs';
|
|
||||||
|
|
||||||
describe('build with inline options', () => {
|
|
||||||
it('should use inline options and ignore .redocly.yaml', () => {
|
|
||||||
const r = spawnSync(
|
|
||||||
'ts-node',
|
|
||||||
[
|
|
||||||
'../../../index.ts',
|
|
||||||
'build',
|
|
||||||
' ../../../../demo/openapi.yaml',
|
|
||||||
'--options.disableSearch="false" ',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
cwd: __dirname,
|
|
||||||
shell: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const out = r.stdout.toString('utf-8');
|
|
||||||
const err = r.stderr.toString('utf-8');
|
|
||||||
const result = `${out}\n${err}`;
|
|
||||||
expect(result).not.toContain('Found .redocly.yaml and using features.openapi options');
|
|
||||||
expect(result).toContain('bundled successfully');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const redocStaticFile = readFileSync(`${__dirname}/redoc-static.html`, 'utf8');
|
|
||||||
expect(redocStaticFile).toContain('"options":{"disableSearch":"false"}');
|
|
||||||
expect(redocStaticFile).toContain('role="search"');
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.toString()).toContain('"options":{"disableSearch":"false"}');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { spawnSync } from 'child_process';
|
|
||||||
|
|
||||||
describe('build with url', () => {
|
|
||||||
it('should not fail on resolving url', () => {
|
|
||||||
const r = spawnSync(
|
|
||||||
'ts-node',
|
|
||||||
[
|
|
||||||
'../../../index.ts',
|
|
||||||
'build',
|
|
||||||
'http://petstore.swagger.io/v2/swagger.json',
|
|
||||||
'--output=url-test.html',
|
|
||||||
],
|
|
||||||
{
|
|
||||||
cwd: __dirname,
|
|
||||||
shell: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const out = r.stdout.toString('utf-8');
|
|
||||||
const err = r.stderr.toString('utf-8');
|
|
||||||
const result = `${out}\n${err}`;
|
|
||||||
expect(result).toContain('bundled successfully');
|
|
||||||
});
|
|
||||||
});
|
|
486
cli/index.ts
486
cli/index.ts
|
@ -1,486 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
/* tslint:disable:no-implicit-dependencies */
|
|
||||||
import * as React from 'react';
|
|
||||||
import * as updateNotifier from 'update-notifier';
|
|
||||||
import { renderToString } from 'react-dom/server';
|
|
||||||
import { ServerStyleSheet } from 'styled-components';
|
|
||||||
|
|
||||||
import { compile } from 'handlebars';
|
|
||||||
import { createServer, IncomingMessage, ServerResponse } from 'http';
|
|
||||||
import { dirname, join, resolve, extname as getExtName } from 'path';
|
|
||||||
|
|
||||||
import * as zlib from 'zlib';
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import { createStore, loadAndBundleSpec, Redoc } from 'redoc';
|
|
||||||
|
|
||||||
import { watch } from 'chokidar';
|
|
||||||
import {
|
|
||||||
createReadStream,
|
|
||||||
existsSync,
|
|
||||||
lstatSync,
|
|
||||||
readFileSync,
|
|
||||||
ReadStream,
|
|
||||||
writeFileSync,
|
|
||||||
} from 'fs';
|
|
||||||
import * as mkdirp from 'mkdirp';
|
|
||||||
|
|
||||||
import * as YargsParser from 'yargs';
|
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
||||||
import { findConfig } from '@redocly/openapi-core';
|
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
||||||
import { parseYaml } from '@redocly/openapi-core';
|
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
||||||
import { Config } from '@redocly/openapi-core';
|
|
||||||
|
|
||||||
interface Options {
|
|
||||||
ssr?: boolean;
|
|
||||||
watch?: boolean;
|
|
||||||
cdn?: boolean;
|
|
||||||
output?: string;
|
|
||||||
title?: string;
|
|
||||||
disableGoogleFont?: boolean;
|
|
||||||
port?: number;
|
|
||||||
templateFileName?: string;
|
|
||||||
templateOptions?: any;
|
|
||||||
redocOptions?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const mimeTypes = {
|
|
||||||
'.html': 'text/html',
|
|
||||||
'.js': 'text/javascript',
|
|
||||||
'.css': 'text/css',
|
|
||||||
'.json': 'application/json',
|
|
||||||
'.png': 'image/png',
|
|
||||||
'.jpg': 'image/jpg',
|
|
||||||
'.gif': 'image/gif',
|
|
||||||
'.svg': 'image/svg+xml',
|
|
||||||
'.wav': 'audio/wav',
|
|
||||||
'.mp4': 'video/mp4',
|
|
||||||
'.woff': 'application/font-woff',
|
|
||||||
'.ttf': 'application/font-ttf',
|
|
||||||
'.eot': 'application/vnd.ms-fontobject',
|
|
||||||
'.otf': 'application/font-otf',
|
|
||||||
'.wasm': 'application/wasm',
|
|
||||||
};
|
|
||||||
|
|
||||||
const BUNDLES_DIR = dirname(require.resolve('redoc'));
|
|
||||||
|
|
||||||
const builderForBuildCommand = yargs => {
|
|
||||||
yargs.positional('spec', {
|
|
||||||
describe: 'path or URL to your spec',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.option('o', {
|
|
||||||
describe: 'Output file',
|
|
||||||
alias: 'output',
|
|
||||||
type: 'string',
|
|
||||||
default: 'redoc-static.html',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.options('title', {
|
|
||||||
describe: 'Page Title',
|
|
||||||
type: 'string',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.options('disableGoogleFont', {
|
|
||||||
describe: 'Disable Google Font',
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.option('cdn', {
|
|
||||||
describe: 'Do not include ReDoc source code into html page, use link to CDN instead',
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.demandOption('spec');
|
|
||||||
return yargs;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlerForBuildCommand = async (argv: any) => {
|
|
||||||
const config = {
|
|
||||||
ssr: true,
|
|
||||||
output: argv.o as string,
|
|
||||||
cdn: argv.cdn as boolean,
|
|
||||||
title: argv.title as string,
|
|
||||||
disableGoogleFont: argv.disableGoogleFont as boolean,
|
|
||||||
templateFileName: argv.template as string,
|
|
||||||
templateOptions: argv.templateOptions || {},
|
|
||||||
redocOptions: getObjectOrJSON(argv.options),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
notifyUpdateCliVersion();
|
|
||||||
await bundle(argv.spec, config);
|
|
||||||
} catch (e) {
|
|
||||||
handleError(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
YargsParser.command(
|
|
||||||
'serve <spec>',
|
|
||||||
'start the server',
|
|
||||||
yargs => {
|
|
||||||
yargs.positional('spec', {
|
|
||||||
describe: 'path or URL to your spec',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.options('title', {
|
|
||||||
describe: 'Page Title',
|
|
||||||
type: 'string',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.option('s', {
|
|
||||||
alias: 'ssr',
|
|
||||||
describe: 'Enable server-side rendering',
|
|
||||||
type: 'boolean',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.option('h', {
|
|
||||||
alias: 'host',
|
|
||||||
type: 'string',
|
|
||||||
default: '127.0.0.1',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.option('p', {
|
|
||||||
alias: 'port',
|
|
||||||
type: 'number',
|
|
||||||
default: 8080,
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.option('w', {
|
|
||||||
alias: 'watch',
|
|
||||||
type: 'boolean',
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.options('disable-google-font', {
|
|
||||||
describe: 'Disable Google Font',
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
yargs.demandOption('spec');
|
|
||||||
return yargs;
|
|
||||||
},
|
|
||||||
async argv => {
|
|
||||||
const config: Options = {
|
|
||||||
ssr: argv.ssr as boolean,
|
|
||||||
title: argv.title as string,
|
|
||||||
watch: argv.watch as boolean,
|
|
||||||
disableGoogleFont: argv.disableGoogleFont as boolean,
|
|
||||||
templateFileName: argv.template as string,
|
|
||||||
templateOptions: argv.templateOptions || {},
|
|
||||||
redocOptions: getObjectOrJSON(argv.options),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
notifyUpdateCliVersion();
|
|
||||||
await serve(argv.host as string, argv.port as number, argv.spec as string, config);
|
|
||||||
} catch (e) {
|
|
||||||
handleError(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
res => {
|
|
||||||
console.log(
|
|
||||||
`\n⚠️ This command is deprecated. Use "npx @redocly/cli preview-docs petstore.yaml"\n`,
|
|
||||||
);
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.command(
|
|
||||||
'build <spec>',
|
|
||||||
'build definition into zero-dependency HTML-file',
|
|
||||||
builderForBuildCommand,
|
|
||||||
handlerForBuildCommand,
|
|
||||||
)
|
|
||||||
.command(
|
|
||||||
'bundle <spec>',
|
|
||||||
'bundle spec into zero-dependency HTML-file [deprecated]',
|
|
||||||
builderForBuildCommand,
|
|
||||||
handlerForBuildCommand,
|
|
||||||
[
|
|
||||||
res => {
|
|
||||||
console.log(`\n⚠️ This command is deprecated. Use "build" command instead.\n`);
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.demandCommand()
|
|
||||||
.options('t', {
|
|
||||||
alias: 'template',
|
|
||||||
describe: 'Path to handlebars page template, see https://git.io/vh8fP for the example ',
|
|
||||||
type: 'string',
|
|
||||||
})
|
|
||||||
.options('templateOptions', {
|
|
||||||
describe:
|
|
||||||
'Additional options that you want pass to template. Use dot notation, e.g. templateOptions.metaDescription',
|
|
||||||
})
|
|
||||||
.options('options', {
|
|
||||||
describe: 'ReDoc options, use dot notation, e.g. options.nativeScrollbars',
|
|
||||||
}).argv;
|
|
||||||
|
|
||||||
async function serve(host: string, port: number, pathToSpec: string, options: Options = {}) {
|
|
||||||
let spec = await loadAndBundleSpec(isURL(pathToSpec) ? pathToSpec : resolve(pathToSpec));
|
|
||||||
let pageHTML = await getPageHTML(spec, pathToSpec, options);
|
|
||||||
const server = createServer((request, response) => {
|
|
||||||
console.time('GET ' + request.url);
|
|
||||||
if (request.url === '/redoc.standalone.js') {
|
|
||||||
respondWithGzip(
|
|
||||||
createReadStream(join(BUNDLES_DIR, 'redoc.standalone.js'), 'utf8'),
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
{
|
|
||||||
'Content-Type': 'application/javascript',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else if (request.url === '/') {
|
|
||||||
respondWithGzip(pageHTML, request, response, {
|
|
||||||
'Content-Type': 'text/html',
|
|
||||||
});
|
|
||||||
} else if (request.url === '/spec.json') {
|
|
||||||
const specStr = JSON.stringify(spec, null, 2);
|
|
||||||
respondWithGzip(specStr, request, response, {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const filePath = join(dirname(pathToSpec), request.url || '');
|
|
||||||
const extname = String(getExtName(filePath)).toLowerCase() as keyof typeof mimeTypes;
|
|
||||||
|
|
||||||
const contentType = mimeTypes[extname] || 'application/octet-stream';
|
|
||||||
respondWithGzip(createReadStream(filePath), request, response, {
|
|
||||||
'Content-Type': contentType,
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
response.writeHead(404);
|
|
||||||
response.write('Not found');
|
|
||||||
response.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.timeEnd('GET ' + request.url);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
server.listen(port, host, () => console.log(`Server started: http://${host}:${port}`));
|
|
||||||
|
|
||||||
if (options.watch && existsSync(pathToSpec)) {
|
|
||||||
const pathToSpecDirectory = resolve(dirname(pathToSpec));
|
|
||||||
const watchOptions = {
|
|
||||||
ignored: [/(^|[\/\\])\../, /___jb_[a-z]+___$/],
|
|
||||||
ignoreInitial: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const watcher = watch(pathToSpecDirectory, watchOptions);
|
|
||||||
const log = console.log.bind(console);
|
|
||||||
|
|
||||||
const handlePath = async _path => {
|
|
||||||
try {
|
|
||||||
spec = await loadAndBundleSpec(resolve(pathToSpec));
|
|
||||||
pageHTML = await getPageHTML(spec, pathToSpec, options);
|
|
||||||
log('Updated successfully');
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error while updating: ', e.message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
watcher
|
|
||||||
.on('change', async path => {
|
|
||||||
log(`${path} changed, updating docs`);
|
|
||||||
handlePath(path);
|
|
||||||
})
|
|
||||||
.on('add', async path => {
|
|
||||||
log(`File ${path} added, updating docs`);
|
|
||||||
handlePath(path);
|
|
||||||
})
|
|
||||||
.on('addDir', path => {
|
|
||||||
log(`↗ Directory ${path} added. Files in here will trigger reload.`);
|
|
||||||
})
|
|
||||||
.on('error', error => console.error(`Watcher error: ${error}`))
|
|
||||||
.on('ready', () => log(`👀 Watching ${pathToSpecDirectory} for changes...`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function bundle(pathToSpec, options: Options = {}) {
|
|
||||||
const start = Date.now();
|
|
||||||
const spec = await loadAndBundleSpec(isURL(pathToSpec) ? pathToSpec : resolve(pathToSpec));
|
|
||||||
const pageHTML = await getPageHTML(spec, pathToSpec, { ...options, ssr: true });
|
|
||||||
|
|
||||||
mkdirp.sync(dirname(options.output!));
|
|
||||||
writeFileSync(options.output!, pageHTML);
|
|
||||||
const sizeInKiB = Math.ceil(Buffer.byteLength(pageHTML) / 1024);
|
|
||||||
const time = Date.now() - start;
|
|
||||||
console.log(
|
|
||||||
`\n🎉 bundled successfully in: ${options.output!} (${sizeInKiB} KiB) [⏱ ${time / 1000}s]`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getPageHTML(
|
|
||||||
spec: any,
|
|
||||||
pathToSpec: string,
|
|
||||||
{
|
|
||||||
ssr,
|
|
||||||
cdn,
|
|
||||||
title,
|
|
||||||
disableGoogleFont,
|
|
||||||
templateFileName,
|
|
||||||
templateOptions,
|
|
||||||
redocOptions = {},
|
|
||||||
}: Options,
|
|
||||||
) {
|
|
||||||
let html;
|
|
||||||
let css;
|
|
||||||
let state;
|
|
||||||
let redocStandaloneSrc;
|
|
||||||
if (ssr) {
|
|
||||||
console.log('Prerendering docs');
|
|
||||||
|
|
||||||
const specUrl = redocOptions.specUrl || (isURL(pathToSpec) ? pathToSpec : undefined);
|
|
||||||
const store = await createStore(spec, specUrl, redocOptions);
|
|
||||||
const sheet = new ServerStyleSheet();
|
|
||||||
// @ts-ignore
|
|
||||||
html = renderToString(sheet.collectStyles(React.createElement(Redoc, { store })));
|
|
||||||
css = sheet.getStyleTags();
|
|
||||||
state = await store.toJS();
|
|
||||||
|
|
||||||
if (!cdn) {
|
|
||||||
redocStandaloneSrc = readFileSync(join(BUNDLES_DIR, 'redoc.standalone.js'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
templateFileName = templateFileName ? templateFileName : join(__dirname, './template.hbs');
|
|
||||||
const template = compile(readFileSync(templateFileName).toString());
|
|
||||||
return template({
|
|
||||||
redocHTML: `
|
|
||||||
<div id="redoc">${(ssr && html) || ''}</div>
|
|
||||||
<script>
|
|
||||||
${(ssr && `const __redoc_state = ${sanitizeJSONString(JSON.stringify(state))};`) || ''}
|
|
||||||
|
|
||||||
var container = document.getElementById('redoc');
|
|
||||||
Redoc.${
|
|
||||||
ssr
|
|
||||||
? 'hydrate(__redoc_state, container)'
|
|
||||||
: `init("spec.json", ${JSON.stringify(redocOptions)}, container)`
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>`,
|
|
||||||
redocHead: ssr
|
|
||||||
? (cdn
|
|
||||||
? '<script src="https://unpkg.com/redoc@latest/bundles/redoc.standalone.js"></script>'
|
|
||||||
: `<script>${redocStandaloneSrc}</script>`) + css
|
|
||||||
: '<script src="redoc.standalone.js"></script>',
|
|
||||||
title: title || spec.info.title || 'ReDoc documentation',
|
|
||||||
disableGoogleFont,
|
|
||||||
templateOptions,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// credits: https://stackoverflow.com/a/9238214/1749888
|
|
||||||
function respondWithGzip(
|
|
||||||
contents: string | ReadStream,
|
|
||||||
request: IncomingMessage,
|
|
||||||
response: ServerResponse,
|
|
||||||
headers = {},
|
|
||||||
) {
|
|
||||||
let compressedStream;
|
|
||||||
const acceptEncoding = (request.headers['accept-encoding'] as string) || '';
|
|
||||||
if (acceptEncoding.match(/\bdeflate\b/)) {
|
|
||||||
response.writeHead(200, { ...headers, 'content-encoding': 'deflate' });
|
|
||||||
compressedStream = zlib.createDeflate();
|
|
||||||
} else if (acceptEncoding.match(/\bgzip\b/)) {
|
|
||||||
response.writeHead(200, { ...headers, 'content-encoding': 'gzip' });
|
|
||||||
compressedStream = zlib.createGzip();
|
|
||||||
} else {
|
|
||||||
response.writeHead(200, headers);
|
|
||||||
if (typeof contents === 'string') {
|
|
||||||
response.write(contents);
|
|
||||||
response.end();
|
|
||||||
} else {
|
|
||||||
contents.pipe(response);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof contents === 'string') {
|
|
||||||
compressedStream.write(contents);
|
|
||||||
compressedStream.pipe(response);
|
|
||||||
compressedStream.end();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
contents.pipe(compressedStream).pipe(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isURL(str: string): boolean {
|
|
||||||
return /^(https?:)\/\//m.test(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sanitizeJSONString(str: string) {
|
|
||||||
return escapeClosingScriptTag(escapeUnicode(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
// see http://www.thespanner.co.uk/2011/07/25/the-json-specification-is-now-wrong/
|
|
||||||
function escapeClosingScriptTag(str) {
|
|
||||||
return str.replace(/<\/script>/g, '<\\/script>');
|
|
||||||
}
|
|
||||||
|
|
||||||
// see http://www.thespanner.co.uk/2011/07/25/the-json-specification-is-now-wrong/
|
|
||||||
function escapeUnicode(str) {
|
|
||||||
return str.replace(/\u2028|\u2029/g, m => '\\u202' + (m === '\u2028' ? '8' : '9'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleError(error: Error) {
|
|
||||||
console.error(error.stack);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getObjectOrJSON(options) {
|
|
||||||
switch (typeof options) {
|
|
||||||
case 'object':
|
|
||||||
return options;
|
|
||||||
case 'string':
|
|
||||||
try {
|
|
||||||
if (existsSync(options) && lstatSync(options).isFile()) {
|
|
||||||
return JSON.parse(readFileSync(options, 'utf-8'));
|
|
||||||
} else {
|
|
||||||
return JSON.parse(options);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(
|
|
||||||
`Encountered error:\n\n${options}\n\nis neither a file with a valid JSON object neither a stringified JSON object.`,
|
|
||||||
);
|
|
||||||
handleError(e);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
const configFile = findConfig();
|
|
||||||
if (configFile) {
|
|
||||||
console.log(`Found ${configFile} and using features.openapi options`);
|
|
||||||
try {
|
|
||||||
const config = parseYaml(readFileSync(configFile, 'utf-8')) as Config;
|
|
||||||
|
|
||||||
return config['features.openapi'];
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(`Found ${configFile} but failed to parse: ${e.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function notifyUpdateCliVersion() {
|
|
||||||
const pkg = require('./package.json');
|
|
||||||
const notifier = updateNotifier({
|
|
||||||
pkg,
|
|
||||||
updateCheckInterval: 0,
|
|
||||||
shouldNotifyInNpmScript: true,
|
|
||||||
});
|
|
||||||
notifier.notify({
|
|
||||||
message:
|
|
||||||
'Run `{updateCommand}` to update.\nChangelog: https://github.com/Redocly/redoc/releases/tag/{latestVersion}',
|
|
||||||
});
|
|
||||||
}
|
|
6912
cli/npm-shrinkwrap.json
generated
6912
cli/npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"name": "redoc-cli",
|
|
||||||
"version": "0.13.20",
|
|
||||||
"description": "ReDoc's Command Line Interface",
|
|
||||||
"main": "index.js",
|
|
||||||
"bin": "index.js",
|
|
||||||
"repository": "https://github.com/Redocly/redoc",
|
|
||||||
"author": "Roman Hotsiy <gotsijroman@gmail.com>",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"chokidar": "^3.5.1",
|
|
||||||
"handlebars": "^4.7.7",
|
|
||||||
"isarray": "^2.0.5",
|
|
||||||
"mkdirp": "^1.0.4",
|
|
||||||
"mobx": "^6.3.2",
|
|
||||||
"node-libs-browser": "^2.2.1",
|
|
||||||
"react": "^17.0.1",
|
|
||||||
"react-dom": "^17.0.1",
|
|
||||||
"redoc": "2.0.0-rc.77",
|
|
||||||
"styled-components": "^5.3.0",
|
|
||||||
"update-notifier": "^5.0.1",
|
|
||||||
"yargs": "^17.3.1"
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/mkdirp": "^1.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf8" />
|
|
||||||
<title>{{title}}</title>
|
|
||||||
<!-- needed for adaptive design -->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{{{redocHead}}}
|
|
||||||
{{#unless disableGoogleFont}}<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">{{/unless}}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
{{{redocHTML}}}
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
|
@ -86,7 +86,7 @@ class DemoApp extends React.Component<
|
||||||
let proxiedUrl = specUrl;
|
let proxiedUrl = specUrl;
|
||||||
if (specUrl !== DEFAULT_SPEC) {
|
if (specUrl !== DEFAULT_SPEC) {
|
||||||
proxiedUrl = cors
|
proxiedUrl = cors
|
||||||
? '\\\\cors.redoc.ly/' + new URL(specUrl, window.location.href).href
|
? 'https://cors.redoc.ly/' + new URL(specUrl, window.location.href).href
|
||||||
: specUrl;
|
: specUrl;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -805,11 +805,17 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- name: username
|
- name: username
|
||||||
in: path
|
in: path
|
||||||
description: name that need to be deleted
|
description: name that need to be updated
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
responses:
|
responses:
|
||||||
|
'200':
|
||||||
|
description: User is updated successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
'400':
|
'400':
|
||||||
description: Invalid user supplied
|
description: Invalid user supplied
|
||||||
'404':
|
'404':
|
||||||
|
@ -835,6 +841,8 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
responses:
|
responses:
|
||||||
|
'204':
|
||||||
|
description: User is deleted
|
||||||
'400':
|
'400':
|
||||||
description: Invalid username supplied
|
description: Invalid username supplied
|
||||||
'404':
|
'404':
|
||||||
|
|
|
@ -4,111 +4,33 @@ redirectFrom:
|
||||||
- /docs/redoc/quickstart/cli/
|
- /docs/redoc/quickstart/cli/
|
||||||
---
|
---
|
||||||
|
|
||||||
# How to use the Redoc CLI
|
# How to use the Redocly CLI
|
||||||
|
|
||||||
With Redoc's command-line interface you can bundle your OpenAPI definition and API documentation
|
With Redocly CLI, you can bundle your OpenAPI definition and API documentation
|
||||||
(made with Redoc) into a zero-dependency HTML file and locally render your
|
(made with Redoc) into a zero-dependency HTML file and render it locally.
|
||||||
OpenAPI definition with Redoc.
|
|
||||||
|
|
||||||
## Step 1 - Install Redoc CLI
|
## Step 1 - Install Redocly CLI
|
||||||
|
|
||||||
You can install the `redoc-cli` package globally using one of the following package managers:
|
First, you need to install the `@redocly/cli` package.
|
||||||
|
|
||||||
- [npm](https://docs.npmjs.com/about-npm)
|
You can install it [globally](/docs/cli/installation.md#install-globally) using npm or Yarn.
|
||||||
- [yarn](https://classic.yarnpkg.com/en/docs/getting-started)
|
|
||||||
|
|
||||||
Or you can install `redoc-cli` using [npx](https://www.freecodecamp.org/news/npm-vs-npx-whats-the-difference/).
|
Or you can install it during [runtime](/docs/cli/installation.md#use-npx-at-runtime) using npx or Docker.
|
||||||
|
|
||||||
### Install Redoc CLI with yarn
|
## Step 2 - Build the HTML file
|
||||||
|
|
||||||
To install the `redoc-cli` package globally with yarn:
|
The Redocly CLI `build-docs` command builds Redoc into a zero-dependency HTML file.
|
||||||
|
|
||||||
|
To build a zero-dependency HTML file using Redocly CLI, enter the following command,
|
||||||
|
replacing `apis/openapi.yaml` with your API definition file's name and path:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn global add redoc-cli
|
redocly build-docs apis/openapi.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install Redoc with npm
|
See the [build-docs](../../cli/commands/build-docs.md) documentation for more information
|
||||||
|
on the different options and ways you can use the command.
|
||||||
|
|
||||||
To install the `redoc-cli` package globally with npm:
|
Also, check out [Redocly CLI commands](../../cli/commands/index.md), for more
|
||||||
|
information on the different things you can do with Redocly CLI including
|
||||||
```bash
|
linting, splitting, and bundling your API definition file.
|
||||||
npm i -g redoc-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install with `npx`
|
|
||||||
|
|
||||||
To install the `redoc-cli` package locally with `npx`, navigate to your project
|
|
||||||
directory in your terminal, then use the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npx redoc-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
## Step 2 - Use the CLI
|
|
||||||
|
|
||||||
### Redoc CLI commands
|
|
||||||
|
|
||||||
The CLI includes the following commands:
|
|
||||||
|
|
||||||
- **`redoc-cli serve [spec]`:** Starts a local server with Redoc. You must include the required parameter, spec, which is
|
|
||||||
a reference to an OpenAPI definition. Options include:
|
|
||||||
- `--ssr`: Implements a server-side rendering model.
|
|
||||||
- `--watch`: Automatically reloads the server while you edit your OpenAPI definition.
|
|
||||||
- `--options`: Customizes your output using [Redoc functionality options](https://redocly.com/docs/api-reference-docs/configuration/functionality) or [Redoc theming options](https://redocly.com/docs/api-reference-docs/configuration/theming).
|
|
||||||
To add nested options, use dot notation.
|
|
||||||
- **`redoc-cli build [spec]`:** Builds `spec` and Redoc into a zero-dependency HTML file. Options include:
|
|
||||||
- `-t` or `--template`: Uses custom [Handlebars](https://handlebarsjs.com/) templates to render your OpenAPI definition.
|
|
||||||
- `--templateOptions`: Adds template options you want to pass to your
|
|
||||||
custom Handlebars template. To add options, use dot notation.
|
|
||||||
- **`--help`:** Prints help text for the Redoc CLI commands and options.
|
|
||||||
- **`--version`:** Prints the version of the `redoc-cli` package you have installed.
|
|
||||||
|
|
||||||
### Redoc CLI examples
|
|
||||||
|
|
||||||
#### Bundle
|
|
||||||
|
|
||||||
Bundle with the main color changed to `orange`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
redoc-cli build openapi.yaml --options.theme.colors.primary.main=orange
|
|
||||||
```
|
|
||||||
|
|
||||||
Bundle using a custom Handlebars template and add custom `templateOptions`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
redoc-cli build http://petstore.swagger.io/v2/swagger.json -t custom.hbs --templateOptions.metaDescription "Page meta description"
|
|
||||||
```
|
|
||||||
|
|
||||||
Sample Handlebars template:
|
|
||||||
|
|
||||||
```handlebars
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf8" />
|
|
||||||
<title>{{title}}</title>
|
|
||||||
<!-- needed for adaptive design -->
|
|
||||||
<meta description="{{{templateOptions.metaDescription}}}">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{{{redocHead}}}
|
|
||||||
{{#unless disableGoogleFont}}<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">{{/unless}}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{{{redocHTML}}}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Serve
|
|
||||||
|
|
||||||
Serve with the `nativeScrollbars` option set to `true`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
redoc-cli serve openapi/dist.yaml --options.nativeScrollbars
|
|
||||||
```
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ The following options are supported:
|
||||||
Using the React component is an option for users with a React-based application.
|
Using the React component is an option for users with a React-based application.
|
||||||
- **[Docker image](./docker.md):**
|
- **[Docker image](./docker.md):**
|
||||||
Using the Docker image works in a container-based deployment.
|
Using the Docker image works in a container-based deployment.
|
||||||
- **[CLI](./cli.md):**
|
- **[Redocly CLI](./cli.md):**
|
||||||
Using the CLI is an option for users who prefer to use a command-line interface.
|
Using the Redocly CLI is an option for users who prefer to use a command-line interface.
|
||||||
|
|
||||||
## Before you start
|
## Before you start
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ If you have [Redocly CLI](https://redocly.com/docs/cli/#installation-and-usage)
|
||||||
project directory and run the following command:
|
project directory and run the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
openapi preview-docs openapi.yaml
|
redocly preview-docs openapi.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `openapi.yaml` in the example command with the file path to your OpenAPI definition.
|
Replace `openapi.yaml` in the example command with the file path to your OpenAPI definition.
|
||||||
|
@ -66,7 +66,7 @@ To exit the preview, use `control+C`.
|
||||||
You can alter the port if you are using 8080 already, for example:
|
You can alter the port if you are using 8080 already, for example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
openapi preview-docs -p 8888 openapi.yaml
|
redocly preview-docs -p 8888 openapi.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `openapi.yaml` in the example command with the file path to your OpenAPI definition.
|
Replace `openapi.yaml` in the example command with the file path to your OpenAPI definition.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
describe('Search', () => {
|
describe('Search', () => {
|
||||||
const getSearchInput = () => cy.get('[role="search"] input');
|
const getSearchInput = () => cy.get('[role="search"] input');
|
||||||
const getSearchResults = () => cy.get('[data-role="search:results"]');
|
const getSearchResults = () => cy.get('[data-role="search:results"]');
|
||||||
const getResult = i => cy.get('[role=search] [role=menuitem]').eq(i);
|
const getResult = i => cy.get('[role=search] label').eq(i);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.visit('e2e/standalone.html');
|
cy.visit('e2e/standalone.html');
|
||||||
|
@ -45,7 +45,7 @@ describe('Search', () => {
|
||||||
|
|
||||||
getSearchInput().type('{enter}', { force: true });
|
getSearchInput().type('{enter}', { force: true });
|
||||||
|
|
||||||
cy.contains('[role=menu] [role=menuitem]', 'Introduction').should('have.class', 'active');
|
cy.contains('[role=menu] label', 'Introduction').should('have.class', 'active');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mark search results', () => {
|
it('should mark search results', () => {
|
||||||
|
|
753
package-lock.json
generated
753
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -44,15 +44,14 @@
|
||||||
"bundle:standalone": "webpack --env production --env standalone --mode=production",
|
"bundle:standalone": "webpack --env production --env standalone --mode=production",
|
||||||
"bundle:lib": "webpack --mode=production && npm run declarations",
|
"bundle:lib": "webpack --mode=production && npm run declarations",
|
||||||
"bundle:browser": "webpack --env production --env browser --mode=production",
|
"bundle:browser": "webpack --env production --env browser --mode=production",
|
||||||
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:browser && npm run bundle:standalone && npm run compile:cli",
|
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:browser && npm run bundle:standalone",
|
||||||
"declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/",
|
"declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/",
|
||||||
"stats": "webpack --env production --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}\"",
|
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
|
||||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
|
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
|
||||||
"lint": "eslint --fix 'src/**/*.{js,ts,tsx}' --cache",
|
"lint": "eslint --fix 'src/**/*.{js,ts,tsx}' --cache",
|
||||||
"benchmark": "node ./benchmark/benchmark.js",
|
"benchmark": "node ./benchmark/benchmark.js",
|
||||||
"start:demo": "webpack serve --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",
|
"build:demo": "webpack --mode=production --config demo/webpack.config.ts",
|
||||||
"publish-cdn": "scripts/publish-cdn.sh",
|
"publish-cdn": "scripts/publish-cdn.sh",
|
||||||
"deploy:demo": "aws s3 sync demo/dist s3://production-redoc-demo --acl=public-read",
|
"deploy:demo": "aws s3 sync demo/dist s3://production-redoc-demo --acl=public-read",
|
||||||
|
@ -151,7 +150,7 @@
|
||||||
"mark.js": "^8.11.1",
|
"mark.js": "^8.11.1",
|
||||||
"marked": "^4.0.15",
|
"marked": "^4.0.15",
|
||||||
"mobx-react": "^7.2.0",
|
"mobx-react": "^7.2.0",
|
||||||
"openapi-sampler": "^1.3.0",
|
"openapi-sampler": "^1.3.1",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"perfect-scrollbar": "^1.5.5",
|
"perfect-scrollbar": "^1.5.5",
|
||||||
"polished": "^4.1.3",
|
"polished": "^4.1.3",
|
||||||
|
|
|
@ -73,7 +73,7 @@ export class Field extends React.Component<FieldProps> {
|
||||||
<button
|
<button
|
||||||
onClick={this.toggle}
|
onClick={this.toggle}
|
||||||
onKeyPress={this.handleKeyPress}
|
onKeyPress={this.handleKeyPress}
|
||||||
aria-label="expand properties"
|
aria-label={`expand ${name}`}
|
||||||
>
|
>
|
||||||
<span className="property-name">{name}</span>
|
<span className="property-name">{name}</span>
|
||||||
<ShelfIcon direction={expanded ? 'down' : 'right'} />
|
<ShelfIcon direction={expanded ? 'down' : 'right'} />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { DropdownOrLabel } from '../DropdownOrLabel/DropdownOrLabel';
|
import { DropdownOrLabel, DropdownOrLabelProps } from '../DropdownOrLabel/DropdownOrLabel';
|
||||||
import { ParametersGroup } from './ParametersGroup';
|
import { ParametersGroup } from './ParametersGroup';
|
||||||
|
|
||||||
import { UnderlinedHeader } from '../../common-elements';
|
import { UnderlinedHeader } from '../../common-elements';
|
||||||
|
@ -11,6 +11,8 @@ import { Schema } from '../Schema';
|
||||||
|
|
||||||
import { Markdown } from '../Markdown/Markdown';
|
import { Markdown } from '../Markdown/Markdown';
|
||||||
import { ConstraintsView } from '../Fields/FieldContstraints';
|
import { ConstraintsView } from '../Fields/FieldContstraints';
|
||||||
|
import { RequiredLabel } from '../../common-elements/fields';
|
||||||
|
import styled from '../../styled-components';
|
||||||
|
|
||||||
function safePush(obj, prop, item) {
|
function safePush(obj, prop, item) {
|
||||||
if (!obj[prop]) {
|
if (!obj[prop]) {
|
||||||
|
@ -49,21 +51,37 @@ export class Parameters extends React.PureComponent<ParametersProps> {
|
||||||
|
|
||||||
const bodyDescription = body && body.description;
|
const bodyDescription = body && body.description;
|
||||||
|
|
||||||
|
const bodyRequired = body && body.required;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{paramsPlaces.map(place => (
|
{paramsPlaces.map(place => (
|
||||||
<ParametersGroup key={place} place={place} parameters={paramsMap[place]} />
|
<ParametersGroup key={place} place={place} parameters={paramsMap[place]} />
|
||||||
))}
|
))}
|
||||||
{bodyContent && <BodyContent content={bodyContent} description={bodyDescription} />}
|
{bodyContent && (
|
||||||
|
<BodyContent
|
||||||
|
content={bodyContent}
|
||||||
|
description={bodyDescription}
|
||||||
|
bodyRequired={bodyRequired}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownWithinHeader(props) {
|
function DropdownWithinHeader({
|
||||||
|
bodyRequired,
|
||||||
|
...props
|
||||||
|
}: DropdownOrLabelProps & { bodyRequired?: boolean }) {
|
||||||
|
const isRequired = typeof bodyRequired === 'boolean' && !!bodyRequired;
|
||||||
|
const isOptional = typeof bodyRequired === 'boolean' && !bodyRequired;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UnderlinedHeader key="header">
|
<UnderlinedHeader key="header">
|
||||||
Request Body schema: <DropdownOrLabel {...props} />
|
Request Body schema: <DropdownOrLabel {...props} />
|
||||||
|
{isRequired && <RequiredBody>required</RequiredBody>}
|
||||||
|
{isOptional && <OptionalBody>optional</OptionalBody>}
|
||||||
</UnderlinedHeader>
|
</UnderlinedHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -71,11 +89,15 @@ function DropdownWithinHeader(props) {
|
||||||
export function BodyContent(props: {
|
export function BodyContent(props: {
|
||||||
content: MediaContentModel;
|
content: MediaContentModel;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
bodyRequired?: boolean;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { content, description } = props;
|
const { content, description, bodyRequired } = props;
|
||||||
const { isRequestType } = content;
|
const { isRequestType } = content;
|
||||||
return (
|
return (
|
||||||
<MediaTypesSwitch content={content} renderDropdown={DropdownWithinHeader}>
|
<MediaTypesSwitch
|
||||||
|
content={content}
|
||||||
|
renderDropdown={props => <DropdownWithinHeader bodyRequired={bodyRequired} {...props} />}
|
||||||
|
>
|
||||||
{({ schema }) => {
|
{({ schema }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -97,3 +119,19 @@ export function BodyContent(props: {
|
||||||
</MediaTypesSwitch>
|
</MediaTypesSwitch>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const commonStyles = `
|
||||||
|
text-transform: lowercase;
|
||||||
|
margin-left: 0;
|
||||||
|
line-height: 1.5em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RequiredBody = styled(RequiredLabel)`
|
||||||
|
${commonStyles}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const OptionalBody = styled('div')`
|
||||||
|
${commonStyles}
|
||||||
|
color: ${({ theme }) => theme.colors.text.secondary};
|
||||||
|
font-size: ${props => props.theme.schema.labelsTextSize};
|
||||||
|
`;
|
||||||
|
|
|
@ -44,7 +44,7 @@ export class MenuItem extends React.Component<MenuItemProps> {
|
||||||
render() {
|
render() {
|
||||||
const { item, withoutChildren } = this.props;
|
const { item, withoutChildren } = this.props;
|
||||||
return (
|
return (
|
||||||
<MenuItemLi onClick={this.activate} depth={item.depth} data-item-id={item.id}>
|
<MenuItemLi onClick={this.activate} depth={item.depth} data-item-id={item.id} role="menuitem">
|
||||||
{item.type === 'operation' ? (
|
{item.type === 'operation' ? (
|
||||||
<OperationMenuItemContent {...this.props} item={item as OperationModel} />
|
<OperationMenuItemContent {...this.props} item={item as OperationModel} />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -125,7 +125,6 @@ export interface MenuItemLabelType {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
|
export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
|
||||||
role: 'menuitem',
|
|
||||||
className: classnames('-depth' + props.depth, {
|
className: classnames('-depth' + props.depth, {
|
||||||
active: props.active,
|
active: props.active,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -3,21 +3,21 @@
|
||||||
exports[`SecurityRequirement should render SecurityDefs 1`] = `
|
exports[`SecurityRequirement should render SecurityDefs 1`] = `
|
||||||
"<div id=\\"section/Authentication/petstore_auth\\" data-section-id=\\"section/Authentication/petstore_auth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">petstore_auth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
|
"<div id=\\"section/Authentication/petstore_auth\\" data-section-id=\\"section/Authentication/petstore_auth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">petstore_auth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
|
||||||
OAuth2 is also a safer and more secure way to give you access.</p>
|
OAuth2 is also a safer and more secure way to give you access.</p>
|
||||||
</div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>OAuth2</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-fXgAZx gZCyoW\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div class=\\"sc-fXgAZx gZCyoW\\"><b> Scopes: </b></div><div class=\\"sc-jXcxbT blWOKY container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
|
</div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>OAuth2</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-jXcxbT gllWlr\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div class=\\"sc-jXcxbT gllWlr\\"><b> Scopes: </b></div><div class=\\"sc-fmdNqN eKoRDV container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
|
||||||
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
|
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
|
||||||
</span></li></ul></div><div class=\\"sc-eEVmNe gbLbHj\\"></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_PersonalAccessToken\\" data-section-id=\\"section/Authentication/GitLab_PersonalAccessToken\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_PersonalAccessToken</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
|
</span></li></ul></div><div class=\\"sc-ljsmAU blhEdv\\"></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_PersonalAccessToken\\" data-section-id=\\"section/Authentication/GitLab_PersonalAccessToken\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_PersonalAccessToken</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
|
||||||
</div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>API Key</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_OpenIdConnect\\" data-section-id=\\"section/Authentication/GitLab_OpenIdConnect\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_OpenIdConnect</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
|
</div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>API Key</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_OpenIdConnect\\" data-section-id=\\"section/Authentication/GitLab_OpenIdConnect\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_OpenIdConnect</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
|
||||||
</div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>OpenID Connect</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div></div></div></div><div id=\\"section/Authentication/basicAuth\\" data-section-id=\\"section/Authentication/basicAuth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">basicAuth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>HTTP</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-fXgAZx gZCyoW\\"></div></div></div></div></div></div>"
|
</div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>OpenID Connect</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div></div></div></div><div id=\\"section/Authentication/basicAuth\\" data-section-id=\\"section/Authentication/basicAuth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">basicAuth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>HTTP</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-jXcxbT gllWlr\\"></div></div></div></div></div></div>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SecurityRequirement should render authDefinition 1`] = `"<div class=\\"sc-bQCEYZ eDdCgW operation-security\\"><div class=\\"sc-xGAEC femyTb\\"><h5 class=\\"sc-iqAclL sc-jHcXXw eONCmm keQLTh\\">Authorizations:</h5><svg class=\\"sc-dIsUp iPqByX\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-dWBRfb kJFNCL\\"><span class=\\"sc-kYPZxB irJeRy\\">(<span class=\\"sc-hzUIXc gcouO\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-hzUIXc gcouO\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-hzUIXc gcouO\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kYPZxB irJeRy\\"><span class=\\"sc-hzUIXc gcouO\\">OAuth2: <i>petstore_auth</i></span></span></div></div>,"`;
|
exports[`SecurityRequirement should render authDefinition 1`] = `"<div class=\\"sc-EZqKI eriJMk operation-security\\"><div class=\\"sc-jHcXXw kurgNF\\"><h5 class=\\"sc-iqAclL sc-fXgAZx eONCmm xiVXt\\">Authorizations:</h5><svg class=\\"sc-dIsUp iPqByX\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-bQCEYZ cCwYjG\\"><span class=\\"sc-dWBRfb hoKBYz\\">(<span class=\\"sc-xGAEC bCFTJj\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-xGAEC bCFTJj\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-xGAEC bCFTJj\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-dWBRfb hoKBYz\\"><span class=\\"sc-xGAEC bCFTJj\\">OAuth2: <i>petstore_auth</i></span></span></div></div>,"`;
|
||||||
|
|
||||||
exports[`SecurityRequirement should render authDefinition 2`] = `
|
exports[`SecurityRequirement should render authDefinition 2`] = `
|
||||||
"<div class=\\"sc-bQCEYZ dSwEDq operation-security\\"><div class=\\"sc-xGAEC femyTb\\"><h5 class=\\"sc-iqAclL sc-jHcXXw eONCmm keQLTh\\">Authorizations:</h5><svg class=\\"sc-dIsUp fVWtGJ\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-dWBRfb ekRdav\\"><span class=\\"sc-kYPZxB fhGdrc\\">(<span class=\\"sc-hzUIXc gcouO\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-hzUIXc gcouO\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-hzUIXc gcouO\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kYPZxB fhGdrc\\"><span class=\\"sc-hzUIXc gcouO\\">OAuth2: <i>petstore_auth</i> (<code class=\\"sc-eHEENL fwFTyL\\">write:pets</code><code class=\\"sc-eHEENL fwFTyL\\">read:pets</code>) </span></span></div></div><div class=\\"sc-EZqKI aOkZE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OAuth2: petstore_auth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
|
"<div class=\\"sc-EZqKI hSmRqE operation-security\\"><div class=\\"sc-jHcXXw kurgNF\\"><h5 class=\\"sc-iqAclL sc-fXgAZx eONCmm xiVXt\\">Authorizations:</h5><svg class=\\"sc-dIsUp fVWtGJ\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-bQCEYZ gvMhNy\\"><span class=\\"sc-dWBRfb eLEzSd\\">(<span class=\\"sc-xGAEC bCFTJj\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-xGAEC bCFTJj\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-xGAEC bCFTJj\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-dWBRfb eLEzSd\\"><span class=\\"sc-xGAEC bCFTJj\\">OAuth2: <i>petstore_auth</i> (<code class=\\"sc-kYPZxB beMTTe\\">write:pets</code><code class=\\"sc-kYPZxB beMTTe\\">read:pets</code>) </span></span></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OAuth2: petstore_auth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
|
||||||
OAuth2 is also a safer and more secure way to give you access.</p>
|
OAuth2 is also a safer and more secure way to give you access.</p>
|
||||||
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-fXgAZx gZCyoW\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div><b>Required scopes: </b><code>write:pets</code> <code>read:pets</code> </div><div class=\\"sc-fXgAZx gZCyoW\\"><b> Scopes: </b></div><div class=\\"sc-jXcxbT blWOKY container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
|
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-jXcxbT gllWlr\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div><b>Required scopes: </b><code>write:pets</code> <code>read:pets</code> </div><div class=\\"sc-jXcxbT gllWlr\\"><b> Scopes: </b></div><div class=\\"sc-fmdNqN eKoRDV container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
|
||||||
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
|
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
|
||||||
</span></li></ul></div><div class=\\"sc-eEVmNe gbLbHj\\"></div></div></div><div class=\\"sc-EZqKI aOkZE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> API Key: GitLab_PersonalAccessToken</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
|
</span></li></ul></div><div class=\\"sc-ljsmAU blhEdv\\"></div></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> API Key: GitLab_PersonalAccessToken</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
|
||||||
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div><div class=\\"sc-EZqKI aOkZE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OpenID Connect: GitLab_OpenIdConnect</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
|
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OpenID Connect: GitLab_OpenIdConnect</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
|
||||||
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div><div class=\\"sc-EZqKI aOkZE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> HTTP: basicAuth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-fXgAZx gZCyoW\\"></div></div></div>,"
|
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> HTTP: basicAuth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-jXcxbT gllWlr\\"></div></div></div>,"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -23,6 +23,14 @@ describe('Models', () => {
|
||||||
const consoleError = jest.spyOn(global.console, 'error');
|
const consoleError = jest.spyOn(global.console, 'error');
|
||||||
const req = new RequestBodyModel(props);
|
const req = new RequestBodyModel(props);
|
||||||
expect(consoleError).not.toHaveBeenCalled();
|
expect(consoleError).not.toHaveBeenCalled();
|
||||||
|
expect(req).toEqual({ description: '', required: undefined });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should work with set required', () => {
|
||||||
|
const consoleError = jest.spyOn(global.console, 'error');
|
||||||
|
props.infoOrRef.required = false;
|
||||||
|
const req = new RequestBodyModel(props);
|
||||||
|
expect(consoleError).not.toHaveBeenCalled();
|
||||||
expect(req).toEqual({ description: '', required: false });
|
expect(req).toEqual({ description: '', required: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,14 @@ type RequestBodyProps = {
|
||||||
|
|
||||||
export class RequestBodyModel {
|
export class RequestBodyModel {
|
||||||
description: string;
|
description: string;
|
||||||
required: boolean;
|
required?: boolean;
|
||||||
content?: MediaContentModel;
|
content?: MediaContentModel;
|
||||||
|
|
||||||
constructor({ parser, infoOrRef, options, isEvent }: RequestBodyProps) {
|
constructor({ parser, infoOrRef, options, isEvent }: RequestBodyProps) {
|
||||||
const isRequest = !isEvent;
|
const isRequest = !isEvent;
|
||||||
const { resolved: info } = parser.deref(infoOrRef);
|
const { resolved: info } = parser.deref(infoOrRef);
|
||||||
this.description = info.description || '';
|
this.description = info.description || '';
|
||||||
this.required = !!info.required;
|
this.required = info.required;
|
||||||
|
|
||||||
const mediaContent = getContentWithLegacyExamples(info);
|
const mediaContent = getContentWithLegacyExamples(info);
|
||||||
if (mediaContent !== undefined) {
|
if (mediaContent !== undefined) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Omit } from './index';
|
import type { Omit } from './index';
|
||||||
|
|
||||||
export interface OpenAPISpec {
|
export interface OpenAPISpec {
|
||||||
openapi: string;
|
openapi: string;
|
||||||
|
|
|
@ -4211,6 +4211,9 @@ culpa qui officia deserunt mollit anim id est laborum.
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"responses": Object {
|
"responses": Object {
|
||||||
|
"204": Object {
|
||||||
|
"description": "User is deleted",
|
||||||
|
},
|
||||||
"400": Object {
|
"400": Object {
|
||||||
"description": "Invalid username supplied",
|
"description": "Invalid username supplied",
|
||||||
},
|
},
|
||||||
|
@ -4270,7 +4273,7 @@ culpa qui officia deserunt mollit anim id est laborum.
|
||||||
"operationId": "updateUser",
|
"operationId": "updateUser",
|
||||||
"parameters": Array [
|
"parameters": Array [
|
||||||
Object {
|
Object {
|
||||||
"description": "name that need to be deleted",
|
"description": "name that need to be updated",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"name": "username",
|
"name": "username",
|
||||||
"required": true,
|
"required": true,
|
||||||
|
@ -4291,6 +4294,16 @@ culpa qui officia deserunt mollit anim id est laborum.
|
||||||
"required": true,
|
"required": true,
|
||||||
},
|
},
|
||||||
"responses": Object {
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/User",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "User is updated successfully",
|
||||||
|
},
|
||||||
"400": Object {
|
"400": Object {
|
||||||
"description": "Invalid user supplied",
|
"description": "Invalid user supplied",
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
"compileOnSave": false,
|
"compileOnSave": false,
|
||||||
"exclude": ["node_modules", ".tmp", "lib", "e2e/**"],
|
"exclude": ["node_modules", ".tmp", "lib", "e2e/**"],
|
||||||
"include": [
|
"include": [
|
||||||
"cli/index.ts",
|
|
||||||
"./custom.d.ts",
|
"./custom.d.ts",
|
||||||
"./demo/playground/hmr-playground.tsx",
|
"./demo/playground/hmr-playground.tsx",
|
||||||
"./src/**/*.ts?",
|
"./src/**/*.ts?",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user