mirror of
				https://github.com/Redocly/redoc.git
				synced 2025-10-31 15:57:30 +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 | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.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 | ||||||
|  | @ -46,7 +46,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: Unit Test |       - name: Unit Test | ||||||
|         run: npm test |         run: npm test | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
							
								
								
									
										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