diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42afcc4c..ab74307f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,3 +43,37 @@ jobs: context: ./cli push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.prep.outputs.tags }} + dockerhub: + name: Publish redoc image to DockerHub + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Docker meta + id: docker_meta + uses: crazy-max/ghaction-docker-meta@v1 + with: + images: redocly/redoc + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./config/docker/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml index 91d3daf4..635eae5e 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish-cli.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - run: npm ci + - run: npm ci && npm ci --prefix cli - run: npm test e2e-tests: needs: [bundle] diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8beb2e59..5146cb04 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - run: npm ci + - run: npm ci && npm ci --prefix cli - run: npm test e2e-tests: needs: [bundle] @@ -98,37 +98,3 @@ jobs: run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - dockerhub: - needs: [publish] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Docker meta - id: docker_meta - uses: crazy-max/ghaction-docker-meta@v1 - with: - images: redocly/redoc - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - file: ./config/docker/Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.docker_meta.outputs.tags }} - labels: ${{ steps.docker_meta.outputs.labels }} diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index a0a0bbd1..3df1b925 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -6,7 +6,7 @@ jobs: build-and-unit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - run: npm ci - - run: npm run bundle - - run: npm test \ No newline at end of file + - uses: actions/checkout@v1 + - run: npm ci && npm ci --prefix cli + - run: npm run bundle + - run: npm test diff --git a/.gitignore b/.gitignore index 84e2c76f..0ba02826 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ bundles/ typings/* !typings/styled-patch.d.ts cli/index.js +cli/__test__/*/**/*.html /benchmark/revisions diff --git a/CHANGELOG.md b/CHANGELOG.md index d43ea681..c4825105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +# [2.0.0-rc.69](https://github.com/Redocly/redoc/compare/v2.0.0-rc.68.1...v2.0.0-rc.69) (2022-05-12) + + +### Bug Fixes + +* wrong base url format causing error when constructing new URL ([#1996](https://github.com/Redocly/redoc/issues/1996)) ([d2cdaa1](https://github.com/Redocly/redoc/commit/d2cdaa1221b6a5e7b5da2418414bce1586069deb)) + + +### Features + +* add download file option ([#1699](https://github.com/Redocly/redoc/issues/1699)) ([b601c9a](https://github.com/Redocly/redoc/commit/b601c9ae9e3288286f28e06854bd93cb3507706e)) +* add option to display verb in webhooks ([#1994](https://github.com/Redocly/redoc/issues/1994)) ([311d2ce](https://github.com/Redocly/redoc/commit/311d2ce64dcf1e68c2563a276b34dda0e08b709c)) +* support .redocly.yaml for options for redoc-cli ([#1981](https://github.com/Redocly/redoc/issues/1981)) ([1f417d6](https://github.com/Redocly/redoc/commit/1f417d67c6b2e0b49e41c713958c100d8e1ad19d)) + + + # [2.0.0-rc.68](https://github.com/Redocly/redoc/compare/v2.0.0-rc.67...v2.0.0-rc.68) (2022-05-10) diff --git a/README.md b/README.md index 625931ee..ddc7411d 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,8 @@ You can use all of the following options with the standalone version of the ` theme object * `spacing` diff --git a/cli/README.md b/cli/README.md index 1d6537b6..885561f1 100644 --- a/cli/README.md +++ b/cli/README.md @@ -31,4 +31,10 @@ Some examples: - Bundle using a custom template and add custom `templateOptions`:
`$ 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`. diff --git a/cli/__test__/build/configRedoc/.redocly.yaml b/cli/__test__/build/configRedoc/.redocly.yaml new file mode 100644 index 00000000..d0c49e68 --- /dev/null +++ b/cli/__test__/build/configRedoc/.redocly.yaml @@ -0,0 +1,2 @@ +features.openapi: + disableSearch: true diff --git a/cli/__test__/build/configRedoc/index.test.ts b/cli/__test__/build/configRedoc/index.test.ts new file mode 100644 index 00000000..91296f35 --- /dev/null +++ b/cli/__test__/build/configRedoc/index.test.ts @@ -0,0 +1,30 @@ +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'); + }); +}); diff --git a/cli/__test__/build/configRedoc/inline-options.test.ts b/cli/__test__/build/configRedoc/inline-options.test.ts new file mode 100644 index 00000000..9ed0cfad --- /dev/null +++ b/cli/__test__/build/configRedoc/inline-options.test.ts @@ -0,0 +1,34 @@ +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"}'); + } + }); +}); diff --git a/cli/__test__/build/configRedoc/url.test.ts b/cli/__test__/build/configRedoc/url.test.ts new file mode 100644 index 00000000..0acc8aa3 --- /dev/null +++ b/cli/__test__/build/configRedoc/url.test.ts @@ -0,0 +1,25 @@ +import { spawnSync } from 'child_process'; + +describe('build with url', () => { + // FIXME: remove skip after release + it.skip('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'); + }); +}); diff --git a/cli/index.ts b/cli/index.ts index 9f6d764d..ebdb425f 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -25,6 +25,12 @@ import { 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; @@ -447,6 +453,17 @@ function getObjectOrJSON(options) { 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 {}; } } diff --git a/cli/npm-shrinkwrap.json b/cli/npm-shrinkwrap.json index 9d6258bc..9ac75b6d 100644 --- a/cli/npm-shrinkwrap.json +++ b/cli/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "redoc-cli", - "version": "0.13.11", + "version": "0.13.12", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "redoc-cli", - "version": "0.13.11", + "version": "0.13.12", "license": "MIT", "dependencies": { "chokidar": "^3.5.1", @@ -17,7 +17,7 @@ "node-libs-browser": "^2.2.1", "react": "^17.0.1", "react-dom": "^17.0.1", - "redoc": "2.0.0-rc.67", + "redoc": "2.0.0-rc.68", "styled-components": "^5.3.0", "yargs": "^17.3.1" }, @@ -216,9 +216,9 @@ } }, "node_modules/@redocly/openapi-core": { - "version": "1.0.0-beta.91", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.91.tgz", - "integrity": "sha512-8RhZGn5jSoy3oZE0sAdXxhPPHrqKgy2JVJzLqjgX9LDjNf7cXOTYOXkXIkjv1tfZHFBV/H7c08rRLEdxnzn0dg==", + "version": "1.0.0-beta.96", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.96.tgz", + "integrity": "sha512-tcy0q+9PRWV4rcnVx5uHII/9Cq9qpUzWNppupAaVgutxjQRPWH45e24NLinn6lA8Q4por6HuMYkk/0QAJE8d3A==", "dependencies": { "@redocly/ajv": "^8.6.4", "@types/node": "^14.11.8", @@ -236,19 +236,9 @@ } }, "node_modules/@redocly/openapi-core/node_modules/@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" - }, - "node_modules/@redocly/react-dropdown-aria": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@redocly/react-dropdown-aria/-/react-dropdown-aria-2.0.12.tgz", - "integrity": "sha512-feQEZlyBvQsbT/fvpJ4jJ5OLGaUPpnskHYDsY8DGpPymN+HUeDQrqkBEbbKRwMKidFTI2cxk2kJNNTnvdS9jyw==", - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0", - "styled-components": "^5.1.1" - } + "version": "14.18.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.16.tgz", + "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" }, "node_modules/@types/chokidar": { "version": "2.1.3", @@ -1621,9 +1611,9 @@ "integrity": "sha1-GA8fnr74sOY45BZq1S24eb6y/8U=" }, "node_modules/marked": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz", - "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==", + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.15.tgz", + "integrity": "sha512-esX5lPdTfG4p8LDkv+obbRCyOKzB+820ZZyMOXJZygZBHrH9b3xXR64X4kT3sPe9Nx8qQXbmcz6kFSMt4Nfk6Q==", "bin": { "marked": "bin/marked.js" }, @@ -2217,12 +2207,11 @@ } }, "node_modules/redoc": { - "version": "2.0.0-rc.67", - "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.67.tgz", - "integrity": "sha512-u6rEKB0LylSisN+mFa3flj7zf+prXDB+G02foqC9BOlcXkUYXHFDZM4L3BTBL/DstyGTgjhe2dA9csAjIVti/g==", + "version": "2.0.0-rc.68", + "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.68.tgz", + "integrity": "sha512-sCz52OEhLDu2cIBimy4f6CaVoDxUzD16x63oZx4kpDQOTXYtk0hEOlph1s5VrgNg9pg+rJ9LCCfnwCuzx3Be8w==", "dependencies": { - "@redocly/openapi-core": "^1.0.0-beta.88", - "@redocly/react-dropdown-aria": "^2.0.11", + "@redocly/openapi-core": "^1.0.0-beta.95", "classnames": "^2.3.1", "decko": "^1.2.0", "dompurify": "^2.2.8", @@ -2230,7 +2219,7 @@ "json-pointer": "^0.6.2", "lunr": "^2.3.9", "mark.js": "^8.11.1", - "marked": "^4.0.10", + "marked": "^4.0.15", "mobx-react": "^7.2.0", "openapi-sampler": "^1.2.1", "path-browserify": "^1.0.1", @@ -3146,9 +3135,9 @@ } }, "@redocly/openapi-core": { - "version": "1.0.0-beta.91", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.91.tgz", - "integrity": "sha512-8RhZGn5jSoy3oZE0sAdXxhPPHrqKgy2JVJzLqjgX9LDjNf7cXOTYOXkXIkjv1tfZHFBV/H7c08rRLEdxnzn0dg==", + "version": "1.0.0-beta.96", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.96.tgz", + "integrity": "sha512-tcy0q+9PRWV4rcnVx5uHII/9Cq9qpUzWNppupAaVgutxjQRPWH45e24NLinn6lA8Q4por6HuMYkk/0QAJE8d3A==", "requires": { "@redocly/ajv": "^8.6.4", "@types/node": "^14.11.8", @@ -3163,18 +3152,12 @@ }, "dependencies": { "@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" + "version": "14.18.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.16.tgz", + "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" } } }, - "@redocly/react-dropdown-aria": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@redocly/react-dropdown-aria/-/react-dropdown-aria-2.0.12.tgz", - "integrity": "sha512-feQEZlyBvQsbT/fvpJ4jJ5OLGaUPpnskHYDsY8DGpPymN+HUeDQrqkBEbbKRwMKidFTI2cxk2kJNNTnvdS9jyw==", - "requires": {} - }, "@types/chokidar": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@types/chokidar/-/chokidar-2.1.3.tgz", @@ -4351,9 +4334,9 @@ "integrity": "sha1-GA8fnr74sOY45BZq1S24eb6y/8U=" }, "marked": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz", - "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==" + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.15.tgz", + "integrity": "sha512-esX5lPdTfG4p8LDkv+obbRCyOKzB+820ZZyMOXJZygZBHrH9b3xXR64X4kT3sPe9Nx8qQXbmcz6kFSMt4Nfk6Q==" }, "md5.js": { "version": "1.3.5", @@ -4822,12 +4805,11 @@ } }, "redoc": { - "version": "2.0.0-rc.67", - "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.67.tgz", - "integrity": "sha512-u6rEKB0LylSisN+mFa3flj7zf+prXDB+G02foqC9BOlcXkUYXHFDZM4L3BTBL/DstyGTgjhe2dA9csAjIVti/g==", + "version": "2.0.0-rc.68", + "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.68.tgz", + "integrity": "sha512-sCz52OEhLDu2cIBimy4f6CaVoDxUzD16x63oZx4kpDQOTXYtk0hEOlph1s5VrgNg9pg+rJ9LCCfnwCuzx3Be8w==", "requires": { - "@redocly/openapi-core": "^1.0.0-beta.88", - "@redocly/react-dropdown-aria": "^2.0.11", + "@redocly/openapi-core": "^1.0.0-beta.95", "classnames": "^2.3.1", "decko": "^1.2.0", "dompurify": "^2.2.8", @@ -4835,7 +4817,7 @@ "json-pointer": "^0.6.2", "lunr": "^2.3.9", "mark.js": "^8.11.1", - "marked": "^4.0.10", + "marked": "^4.0.15", "mobx-react": "^7.2.0", "openapi-sampler": "^1.2.1", "path-browserify": "^1.0.1", diff --git a/cli/package.json b/cli/package.json index bfd76e32..9e1857e4 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "redoc-cli", - "version": "0.13.11", + "version": "0.13.12", "description": "ReDoc's Command Line Interface", "main": "index.js", "bin": "index.js", @@ -19,7 +19,7 @@ "node-libs-browser": "^2.2.1", "react": "^17.0.1", "react-dom": "^17.0.1", - "redoc": "2.0.0-rc.67", + "redoc": "2.0.0-rc.68", "styled-components": "^5.3.0", "yargs": "^17.3.1" }, diff --git a/config/docker/Dockerfile b/config/docker/Dockerfile index 55e5d0a9..bc54ee35 100644 --- a/config/docker/Dockerfile +++ b/config/docker/Dockerfile @@ -12,7 +12,7 @@ RUN apk update && apk add --no-cache git # Install dependencies WORKDIR /build COPY package.json package-lock.json /build/ -RUN npm ci --no-optional --ignore-scripts +RUN npm ci --no-optional --ignore-scripts --force # copy only required for the build files COPY src /build/src diff --git a/docs/deployment/cli.md b/docs/deployment/cli.md index cd9afbe7..acaf86b4 100644 --- a/docs/deployment/cli.md +++ b/docs/deployment/cli.md @@ -1,7 +1,7 @@ --- title: Use the Redoc CLI redirectFrom: - - /docs/quickstart/cli/ + - /docs/redoc/quickstart/cli/ --- # How to use the Redoc CLI @@ -56,7 +56,7 @@ The CLI includes the following commands: - `--watch`: Automatically reloads the server while you edit your OpenAPI definition. - `--options`: Customizes your output using [Redoc options](https://redocly.com/docs/api-reference-docs/configuration/). To add nested options, use dot notation. -- **`redoc-cli bundle [spec]`:** Bundles `spec` and Redoc into a zero-dependency HTML file. Options include: +- **`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. @@ -70,13 +70,13 @@ The CLI includes the following commands: Bundle with the main color changed to `orange`: ```bash -redoc-cli bundle openapi.yaml --options.theme.colors.primary.main=orange +redoc-cli build openapi.yaml --options.theme.colors.primary.main=orange ``` Bundle using a custom Handlebars template and add custom `templateOptions`: ```bash -redoc-cli bundle http://petstore.swagger.io/v2/swagger.json -t custom.hbs --templateOptions.metaDescription "Page meta description" +redoc-cli build http://petstore.swagger.io/v2/swagger.json -t custom.hbs --templateOptions.metaDescription "Page meta description" ``` Sample Handlebars template: diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index 4ec791c0..5f11804f 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -1,7 +1,7 @@ --- title: Use the Redoc Docker image redirectFrom: - - /docs/quickstart/docker/ + - /docs/redoc/quickstart/docker/ --- # How to use the Redoc Docker image diff --git a/docs/deployment/html.md b/docs/deployment/html.md index 920b2510..604f7ce2 100644 --- a/docs/deployment/html.md +++ b/docs/deployment/html.md @@ -1,7 +1,7 @@ --- title: Use the Redoc HTML element redirectFrom: - - /docs/quickstart/html/ + - /docs/redoc/quickstart/html/ --- # How to use the Redoc HTML element diff --git a/docs/deployment/intro.md b/docs/deployment/intro.md index 0b0f6494..b88b18b7 100644 --- a/docs/deployment/intro.md +++ b/docs/deployment/intro.md @@ -1,7 +1,7 @@ --- title: Redoc deployment guide redirectFrom: - - /docs/quickstart/intro/ + - /docs/redoc/quickstart/intro/ --- # Redoc deployment guide diff --git a/docs/deployment/react.md b/docs/deployment/react.md index a22a7f9e..3a923d4a 100644 --- a/docs/deployment/react.md +++ b/docs/deployment/react.md @@ -1,7 +1,7 @@ --- title: Use the Redoc React component redirectFrom: - - /docs/quickstart/react/ + - /docs/redoc/quickstart/react/ --- # How to use the Redoc React component diff --git a/docs/quickstart/cli.md b/docs/quickstart/cli.md deleted file mode 100644 index 0a93dbbc..00000000 --- a/docs/quickstart/cli.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Using the Redoc CLI ---- - -# Using the Redoc CLI - -With Redoc's command-line interface you can bundle your OpenAPI definition and API documentation -(made with Redoc) into a zero-dependency HTML file and locally render your -OpenAPI definition with Redoc. - -## Step 1 - Install Redoc CLI - -You can install the `redoc-cli` package globally using one of the following package managers: - -- [npm](https://docs.npmjs.com/about-npm) -- [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/). - -### Install Redoc CLI with yarn - -To install the `redoc-cli` package globally with yarn: - -```bash -yarn global add redoc-cli -``` - -### Install Redoc with npm - -To install the `redoc-cli` package globally with npm: - -```bash -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 options](https://redocly.com/docs/api-reference-docs/configuration/). - To add nested options, use dot notation. -- **`redoc-cli bundle [spec]`:** Bundles `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 bundle openapi.yaml --options.theme.colors.primary.main=orange -``` - -Bundle using a custom Handlebars template and add custom `templateOptions`: - -```bash -redoc-cli bundle http://petstore.swagger.io/v2/swagger.json -t custom.hbs --templateOptions.metaDescription "Page meta description" -``` - -Sample Handlebars template: - -```handlebars - - - - - {{title}} - - - - - {{{redocHead}}} - {{#unless disableGoogleFont}}{{/unless}} - - - {{{redocHTML}}} - - -``` - -#### Serve - -Serve with the `nativeScrollbars` option set to `true`: - -```bash -redoc-cli serve openapi/dist.yaml --options.nativeScrollbars -``` diff --git a/docs/quickstart/docker.md b/docs/quickstart/docker.md deleted file mode 100644 index 31539fdb..00000000 --- a/docs/quickstart/docker.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Using the Redoc Docker image ---- - -# Using the Redoc Docker image - -Redoc is available as a pre-built Docker image in [Docker Hub](https://hub.docker.com/r/redocly/redoc/). - -If you have [Docker](https://docs.docker.com/get-docker/) installed, pull the image with the following command: - -```docker -docker pull redocly/redoc -``` - -Then run the image with the following command: - -```docker -docker run -p 8080:80 redocly/redoc -``` - -The preview starts on port 8080, based on the port used in the command, -and can be accessed at `http://localhost:8080`. -To exit the preview, use `control+C`. - -By default Redoc starts with a demo Swagger Petstore OpenAPI definition located at -http://petstore.swagger.io/v2/swagger.json. You can update this URL using -the environment variable `SPEC_URL`. - -For example: - -```bash -docker run -p 8080:80 -e SPEC_URL=https://api.example.com/openapi.json redocly/redoc -``` - -## Using a Dockerfile - -You can also create a Dockerfile with some predefined environment variables. Check out -a sample [Dockerfile](https://github.com/Redocly/redoc/blob/master/config/docker/Dockerfile) -in our code repo. \ No newline at end of file diff --git a/docs/quickstart/html.md b/docs/quickstart/html.md deleted file mode 100644 index 19d7f996..00000000 --- a/docs/quickstart/html.md +++ /dev/null @@ -1,214 +0,0 @@ ---- -title: Using the Redoc HTML element ---- - -# Using the Redoc HTML element - -## TL;DR final code example - -```html - - - - Redoc - - - - - - - - - - - - - - -``` - -:::attention Running Redoc locally requires an HTTP server -Loading local OpenAPI definitions is impossible without running a web server because of issues with -[same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) and -other security reasons. -::: - -### Running Redoc locally - -If you want to view your Redoc output locally, you can simulate an HTTP server. - -#### Using Redocly CLI - -Redocly CLI is an open source command-line tool that includes a command -for simulating an HTTP server to provide a preview of your OpenAPI definition locally. - -If you have [Redocly CLI](https://redocly.com/docs/cli/#installation-and-usage) installed, `cd` into your -project directory and run the following command: - -```bash -openapi preview-docs openapi.yaml -``` - -By default, without providing a port, the preview starts on port 8080, and can be accessed at `http://localhost:8080`. -To exit the preview, use `control+C`. - -#### Using Python - -If you have [Python 3](https://www.python.org/downloads/) installed, `cd` into your -project directory and run the following command: - -```python -python3 -m http.server -``` - -If you have [Python 2](https://www.python.org/downloads/) installed, `cd` into your -project directory and run the following command: - -```python -python -m SimpleHTTPServer 8000 -``` - -The output after entering the command provides the local URL where the preview can be accessed. -To exit the preview, use `control-C`. - -#### Using Node.js - -If you have [Node.js](https://nodejs.org/en/download/) installed, install `http-server` -using the following npm command: - -```bash -npm install -g http-server -``` - -Then, `cd` into your project directory and run the following command: - -```node -http-server -``` - -The output after entering the command provides the local URL where the preview can be accessed. -To exit the preview, use `control-C`. - -## Step 1 - Install Redoc - -You can install Redoc using one of the following package managers: - -- [npm](https://docs.npmjs.com/about-npm) -- [yarn](https://classic.yarnpkg.com/en/docs/getting-started) - -:::attention Initialize your package manager -If you do not have a `package.json` file in your project directory, -you need to add one by initializing npm or yarn in your project. Use the command `npm init` for npm, -or `yarn init` for yarn. These initialization commands will lead you through the process -of creating a `package.json` file in your project. - -For more information, see -[Creating a package.json file](https://docs.npmjs.com/creating-a-package-json-file) -in the npm documentation or [Yarn init](https://classic.yarnpkg.com/en/docs/cli/init/) -in the yarn documentation. - -::: - -### Install Redoc with yarn - -After navigating to your project directory in your terminal, use the following command: - -```bash -yarn add redoc -``` - -### Install Redoc with npm - -After navigating to your project directory in your terminal, use the following command: - -```bash -npm i redoc -``` - -## Step 2 - Reference the Redoc script - -You can reference the Redoc script using either a link to the files hosted on a CDN -or the files located in your `node modules` folder. - -### CDN link - -To reference the Redoc script with a CDN link: - -```html - -``` - -### Node modules link - -To reference the Redoc script with a node modules link: - -```html - -``` - -## Step 3 - Add the element - -You can add the element to your HTML page and reference your OpenAPI -definition using the `spec-url` attribute, or you can initialize Redoc using -a globally exposed Redoc object. - -### Using the `spec-url` attribute - -To add the element with the `spec-url` attribute: - -```html - -``` - -#### Examples - -```html - -``` - -You can also use a local file (JSON or YAML) in your project, for instance: - -```html - -``` - -### Using a Redoc object - -To add the element with a globally exposed Redoc object: - -```js -Redoc.init(specOrSpecUrl, options, element, callback) -``` -- `specOrSpecUrl`: Either a JSON object with the OpenAPI definition or a URL to the - definition in JSON or YAML format. -- `options`: See [options object](https://redocly.com/docs/api-reference-docs/configuration/) reference. -- `element`: DOM element Redoc will be inserted into. -- `callback`(optional): Callback to be called after Redoc has been fully rendered. - It is also called on errors with `error` as the first argument. - -#### Examples - -```html - -``` - -You can also use a local file (JSON or YAML) in your project, for instance: - -```html - -``` diff --git a/docs/quickstart/intro.md b/docs/quickstart/intro.md deleted file mode 100644 index b5c26b8c..00000000 --- a/docs/quickstart/intro.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Redoc quickstart guide ---- - -# Redoc quickstart guide - -This guide includes step-by-step instructions for how to get started using -Redoc to render your OpenAPI definition. - -Redoc offers multiple options for rendering your OpenAPI definition. -You should select the option that best fits your needs. - -The following options are supported: - -- **[Live demo](https://redocly.github.io/redoc/):** - The live demo offers a fast way to see how your OpenAPI will render with Redoc. -- **[HTML element](./html.md):** - Using the HTML element works well for typical website deployments. -- **[React component](./react.md):** - Using the React component is an option for users with a React-based application. -- **[Docker image](./docker.md):** - Using the Docker image works in a container-based deployment. -- **[CLI](./cli.md):** - Using the CLI is an option for users who prefer to use a command-line interface. - -## Before you start - -You will need an OpenAPI definition. For testing purposes, you can use one of the following sample OpenAPI definitions: -- OpenAPI 3.0 - - [Rebilly Users OpenAPI Definition](https://raw.githubusercontent.com/Rebilly/api-definitions/main/openapi/users.yaml) - - [Swagger Petstore Sample OpenAPI Definition](https://petstore3.swagger.io/api/v3/openapi.json) -- OpenAPI 2.0 - - [Thingful OpenAPI Definition](https://raw.githubusercontent.com/thingful/openapi-spec/master/spec/swagger.yaml) - - [Fitbit Plus OpenAPI Definition](https://raw.githubusercontent.com/TwineHealth/TwineDeveloperDocs/master/spec/swagger.yaml) - -For more information on the OpenAPI specification, refer to the [Learning OpenAPI 3](https://redocly.com/docs/resources/learning-openapi/) -section in the documentation. - -## Live demo online - -If you want to see how ReDoc will render your OpenAPI definition, you can try it out online at https://redocly.github.io/redoc/. - -A version of the Swagger Petstore API is displayed by default. To test it with your own OpenAPI definition, enter the URL for your -definition and select the **TRY IT** button. diff --git a/docs/quickstart/react.md b/docs/quickstart/react.md deleted file mode 100644 index 221dfc6b..00000000 --- a/docs/quickstart/react.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Using the Redoc React component ---- - -# Using the Redoc React component - -## Before you start - -Install the following dependencies required by Redoc if you do not already have them installed: - -- `react` -- `react-dom` -- `mobx` -- `styled-components` -- `core-js` - -If you have npm installed, you can install these dependencies using the following command: - -```js -npm i react react-dom mobx styled-components core-js -``` - -## Step 1 - Import the `RedocStandalone` component - -```js -import { RedocStandalone } from 'redoc'; -``` - -## Step 2 - Use the component - -You can either link to your OpenAPI definition with a URL, using the following format: - -```react - -``` - -Or you can pass your OpenAPI definition as an object, using the following format: - -```js - -``` - -## Optional - Pass options - -Options can be passed into the RedocStandalone component to alter how it renders. - -For example: - -```js - -``` - -For more information on configuration options, refer to the -[Configuration options for Reference docs](https://redocly.com/docs/api-reference-docs/configuration/) -section of the documentation. Options available for Redoc are noted, -"Supported in Redoc CE". - -## Optional - Specify `onLoaded` callback - -You can also specify the `onLoaded` callback, which is called each time Redoc -is fully rendered or when an error occurs (with an error as the first argument). - -```js - { - if (!error) { - console.log('Yay!'); - } - }} -/> -``` diff --git a/package-lock.json b/package-lock.json index 8fb562ef..bfd4e16a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "redoc", - "version": "2.0.0-rc.68", + "version": "2.0.0-rc.69", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "redoc", - "version": "2.0.0-rc.68", + "version": "2.0.0-rc.69", "license": "MIT", "dependencies": { - "@redocly/openapi-core": "^1.0.0-beta.95", + "@redocly/openapi-core": "^1.0.0-beta.97", "classnames": "^2.3.1", "decko": "^1.2.0", "dompurify": "^2.2.8", @@ -19,7 +19,7 @@ "mark.js": "^8.11.1", "marked": "^4.0.15", "mobx-react": "^7.2.0", - "openapi-sampler": "^1.2.1", + "openapi-sampler": "^1.2.3", "path-browserify": "^1.0.1", "perfect-scrollbar": "^1.5.1", "polished": "^4.1.3", @@ -2590,9 +2590,9 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/@redocly/openapi-core": { - "version": "1.0.0-beta.95", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.95.tgz", - "integrity": "sha512-7Nnc4Obp/1lbrjNjD33oOnZCuoJa8awhBCEyyayPWGQFp1SkhjpZJnfnKkFuYbQzMjTIAvEeSp9DOQK/E0fgEA==", + "version": "1.0.0-beta.97", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.97.tgz", + "integrity": "sha512-3WW9/6flosJuRtU3GI0Vw39OYFZqqXMDCp5TLa3EjXOb7Nm6AZTWRb3Y+I/+UdNJ/NTszVJkQczoa1t476ekiQ==", "dependencies": { "@redocly/ajv": "^8.6.4", "@types/node": "^14.11.8", @@ -2600,7 +2600,7 @@ "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "lodash.isequal": "^4.5.0", - "minimatch": "^3.0.4", + "minimatch": "^5.0.1", "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" @@ -2614,6 +2614,25 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz", "integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw==" }, + "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -4521,6 +4540,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5124,7 +5144,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "node_modules/connect-history-api-fallback": { "version": "1.6.0", @@ -13482,6 +13503,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -14195,9 +14217,9 @@ } }, "node_modules/openapi-sampler": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.2.1.tgz", - "integrity": "sha512-mHrYmyvcLD0qrfqPkPRBAL2z16hGT2rW0d0B7nklfoTcc3pmkJLkSZlKSeFgerUM41E5c7jlxf0Y19xrM7mWQQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.2.3.tgz", + "integrity": "sha512-dH2QYXqakorV5dxkP/f1BV3Ku4yNn21YmBsqJunnyrHLw7mnCNZZldftgrEpv/66b1m5oaUAmiJoJN+FqBEkJg==", "dependencies": { "@types/json-schema": "^7.0.7", "json-pointer": "0.6.2" @@ -20971,9 +20993,9 @@ } }, "@redocly/openapi-core": { - "version": "1.0.0-beta.95", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.95.tgz", - "integrity": "sha512-7Nnc4Obp/1lbrjNjD33oOnZCuoJa8awhBCEyyayPWGQFp1SkhjpZJnfnKkFuYbQzMjTIAvEeSp9DOQK/E0fgEA==", + "version": "1.0.0-beta.97", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.97.tgz", + "integrity": "sha512-3WW9/6flosJuRtU3GI0Vw39OYFZqqXMDCp5TLa3EjXOb7Nm6AZTWRb3Y+I/+UdNJ/NTszVJkQczoa1t476ekiQ==", "requires": { "@redocly/ajv": "^8.6.4", "@types/node": "^14.11.8", @@ -20981,7 +21003,7 @@ "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "lodash.isequal": "^4.5.0", - "minimatch": "^3.0.4", + "minimatch": "^5.0.1", "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" @@ -20991,6 +21013,22 @@ "version": "14.17.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz", "integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw==" + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "requires": { + "brace-expansion": "^2.0.1" + } } } }, @@ -22567,6 +22605,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -23038,7 +23077,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "connect-history-api-fallback": { "version": "1.6.0", @@ -29310,6 +29350,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -29831,9 +29872,9 @@ } }, "openapi-sampler": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.2.1.tgz", - "integrity": "sha512-mHrYmyvcLD0qrfqPkPRBAL2z16hGT2rW0d0B7nklfoTcc3pmkJLkSZlKSeFgerUM41E5c7jlxf0Y19xrM7mWQQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.2.3.tgz", + "integrity": "sha512-dH2QYXqakorV5dxkP/f1BV3Ku4yNn21YmBsqJunnyrHLw7mnCNZZldftgrEpv/66b1m5oaUAmiJoJN+FqBEkJg==", "requires": { "@types/json-schema": "^7.0.7", "json-pointer": "0.6.2" diff --git a/package.json b/package.json index f6e2e113..3296cacb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redoc", - "version": "2.0.0-rc.68", + "version": "2.0.0-rc.69", "description": "ReDoc", "repository": { "type": "git", @@ -43,7 +43,7 @@ "bundle:standalone": "webpack --env production --env standalone --mode=production", "bundle:lib": "webpack --mode=production && npm run declarations", "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", + "bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:browser && npm run bundle:standalone && npm run compile:cli", "declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/", "stats": "webpack --env production --env standalone --json --profile --mode=production > stats.json", "prettier": "prettier --write \"cli/index.ts\" \"src/**/*.{ts,tsx}\"", @@ -138,7 +138,7 @@ "styled-components": "^4.1.1 || ^5.1.1" }, "dependencies": { - "@redocly/openapi-core": "^1.0.0-beta.95", + "@redocly/openapi-core": "^1.0.0-beta.97", "classnames": "^2.3.1", "decko": "^1.2.0", "dompurify": "^2.2.8", @@ -148,7 +148,7 @@ "mark.js": "^8.11.1", "marked": "^4.0.15", "mobx-react": "^7.2.0", - "openapi-sampler": "^1.2.1", + "openapi-sampler": "^1.2.3", "path-browserify": "^1.0.1", "perfect-scrollbar": "^1.5.1", "polished": "^4.1.3", diff --git a/src/components/Operation/Operation.tsx b/src/components/Operation/Operation.tsx index 8170351e..b6904f62 100644 --- a/src/components/Operation/Operation.tsx +++ b/src/components/Operation/Operation.tsx @@ -27,48 +27,48 @@ export interface OperationProps { operation: OperationModel; } -@observer -export class Operation extends React.Component { - render() { - const { operation } = this.props; - - const { name: summary, description, deprecated, externalDocs, isWebhook } = operation; - const hasDescription = !!(description || externalDocs); - - return ( - - {options => ( - - -

- - {summary} {deprecated && Deprecated } - {isWebhook && Webhook } -

- {options.pathInMiddlePanel && !isWebhook && ( - +export const Operation = observer(({ operation }: OperationProps): JSX.Element => { + const { name: summary, description, deprecated, externalDocs, isWebhook, httpVerb } = operation; + const hasDescription = !!(description || externalDocs); + const { showWebhookVerb } = React.useContext(OptionsContext); + return ( + + {options => ( + + +

+ + {summary} {deprecated && Deprecated } + {isWebhook && ( + + {' '} + Webhook {showWebhookVerb && httpVerb && '| ' + httpVerb.toUpperCase()} + )} - {hasDescription && ( - - {description !== undefined && } - {externalDocs && } - - )} - - - - - - - - {!options.pathInMiddlePanel && !isWebhook && } - - - - - - )} - - ); - } -} +

+ {options.pathInMiddlePanel && !isWebhook && ( + + )} + {hasDescription && ( + + {description !== undefined && } + {externalDocs && } + + )} + + + + + +
+ + {!options.pathInMiddlePanel && !isWebhook && } + + + + +
+ )} +
+ ); +}); diff --git a/src/components/SideMenu/MenuItem.tsx b/src/components/SideMenu/MenuItem.tsx index 5c5d58ea..2f0f6cc9 100644 --- a/src/components/SideMenu/MenuItem.tsx +++ b/src/components/SideMenu/MenuItem.tsx @@ -8,11 +8,13 @@ import { MenuItems } from './MenuItems'; import { MenuItemLabel, MenuItemLi, MenuItemTitle, OperationBadge } from './styled.elements'; import { l } from '../../services/Labels'; import { scrollIntoViewIfNeeded } from '../../utils'; +import { OptionsContext } from '../OptionsProvider'; export interface MenuItemProps { item: IMenuItem; onActivate?: (item: IMenuItem) => void; withoutChildren?: boolean; + children?: React.ReactChild; } @observer @@ -75,37 +77,33 @@ export class MenuItem extends React.Component { export interface OperationMenuItemContentProps { item: OperationModel; + children?: React.ReactChild; } -@observer -export class OperationMenuItemContent extends React.Component { - ref = React.createRef(); +export const OperationMenuItemContent = observer((props: OperationMenuItemContentProps) => { + const { item } = props; + const ref = React.createRef(); + const { showWebhookVerb } = React.useContext(OptionsContext); - componentDidUpdate() { - if (this.props.item.active && this.ref.current) { - scrollIntoViewIfNeeded(this.ref.current); + React.useEffect(() => { + if (props.item.active && ref.current) { + scrollIntoViewIfNeeded(ref.current); } - } + }, [props.item.active, ref]); - render() { - const { item } = this.props; - return ( - - {item.isWebhook ? ( - {l('webhook')} - ) : ( - {shortenHTTPVerb(item.httpVerb)} - )} - - {item.sidebarLabel} - {this.props.children} - - - ); - } -} + return ( + + {item.isWebhook ? ( + + {showWebhookVerb ? item.httpVerb : l('webhook')} + + ) : ( + {shortenHTTPVerb(item.httpVerb)} + )} + + {item.sidebarLabel} + {props.children} + + + ); +}); diff --git a/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap b/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap index 73ef4b8f..75f0ac05 100644 --- a/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap @@ -77,6 +77,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -105,6 +107,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -330,6 +333,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -358,6 +363,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -558,6 +564,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -586,6 +594,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -853,6 +862,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -881,6 +892,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -1106,6 +1118,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -1134,6 +1148,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -1334,6 +1349,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -1362,6 +1379,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -1585,6 +1603,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -1613,6 +1633,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -1877,6 +1898,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -1905,6 +1928,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -2130,6 +2154,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -2158,6 +2184,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, @@ -2358,6 +2385,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "options": RedocNormalizedOptions { "allowedMdComponents": Object {}, "disableSearch": false, + "downloadDefinitionUrl": undefined, + "downloadFileName": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": Object {}, @@ -2386,6 +2415,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sectionsAtTheEnd": Array [], "showExtensions": false, "showObjectSchemaExamples": false, + "showWebhookVerb": false, "sideNavStyle": "summary-only", "simpleOneOfTypeLabel": false, "sortEnumValuesAlphabetically": false, diff --git a/src/services/OpenAPIParser.ts b/src/services/OpenAPIParser.ts index b9883ff9..66536997 100644 --- a/src/services/OpenAPIParser.ts +++ b/src/services/OpenAPIParser.ts @@ -58,7 +58,7 @@ export class OpenAPIParser { this.spec = spec; this.allowMergeRefs = spec.openapi.startsWith('3.1'); - const href = IS_BROWSER ? window.location.href : ''; + const href = IS_BROWSER ? window.location.href : undefined; if (typeof specUrl === 'string') { this.specUrl = new URL(specUrl, href).href; } diff --git a/src/services/RedocNormalizedOptions.ts b/src/services/RedocNormalizedOptions.ts index b11ad2b3..9ad5b559 100644 --- a/src/services/RedocNormalizedOptions.ts +++ b/src/services/RedocNormalizedOptions.ts @@ -27,6 +27,8 @@ export interface RedocRawOptions { untrustedSpec?: boolean | string; hideLoading?: boolean | string; hideDownloadButton?: boolean | string; + downloadFileName?: string; + downloadDefinitionUrl?: string; disableSearch?: boolean | string; onlyRequiredInSamples?: boolean | string; showExtensions?: boolean | string | string[]; @@ -58,6 +60,7 @@ export interface RedocRawOptions { nonce?: string; hideFab?: boolean; minCharacterLengthToInitSearch?: number; + showWebhookVerb?: boolean; } export function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean { @@ -235,6 +238,8 @@ export class RedocNormalizedOptions { pathInMiddlePanel: boolean; untrustedSpec: boolean; hideDownloadButton: boolean; + downloadFileName?: string; + downloadDefinitionUrl?: string; disableSearch: boolean; onlyRequiredInSamples: boolean; showExtensions: boolean | string[]; @@ -263,6 +268,7 @@ export class RedocNormalizedOptions { generatedPayloadSamplesMaxDepth: number; hideFab: boolean; minCharacterLengthToInitSearch: number; + showWebhookVerb: boolean; nonce?: string; @@ -303,6 +309,8 @@ export class RedocNormalizedOptions { this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel); this.untrustedSpec = argValueToBoolean(raw.untrustedSpec); this.hideDownloadButton = argValueToBoolean(raw.hideDownloadButton); + this.downloadFileName = raw.downloadFileName; + this.downloadDefinitionUrl = raw.downloadDefinitionUrl; this.disableSearch = argValueToBoolean(raw.disableSearch); this.onlyRequiredInSamples = argValueToBoolean(raw.onlyRequiredInSamples); this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions); @@ -339,5 +347,6 @@ export class RedocNormalizedOptions { this.nonce = raw.nonce; this.hideFab = argValueToBoolean(raw.hideFab); this.minCharacterLengthToInitSearch = argValueToNumber(raw.minCharacterLengthToInitSearch) || 3; + this.showWebhookVerb = argValueToBoolean(raw.showWebhookVerb); } } diff --git a/src/services/SpecStore.ts b/src/services/SpecStore.ts index 783e1b59..20023ce0 100644 --- a/src/services/SpecStore.ts +++ b/src/services/SpecStore.ts @@ -24,7 +24,7 @@ export class SpecStore { private options: RedocNormalizedOptions, ) { this.parser = new OpenAPIParser(spec, specUrl, options); - this.info = new ApiInfoModel(this.parser); + this.info = new ApiInfoModel(this.parser, this.options); this.externalDocs = this.parser.spec.externalDocs; this.contentItems = MenuBuilder.buildStructure(this.parser, this.options); this.securitySchemes = new SecuritySchemesModel(this.parser); diff --git a/src/services/__tests__/models/ApiInfo.test.ts b/src/services/__tests__/models/ApiInfo.test.ts index 0bf148a1..4a67139e 100644 --- a/src/services/__tests__/models/ApiInfo.test.ts +++ b/src/services/__tests__/models/ApiInfo.test.ts @@ -62,5 +62,80 @@ describe('Models', () => { const { license = { identifier: null } } = new ApiInfoModel(parser); expect(license.identifier).toEqual('MIT'); }); + + test('should correctly populate default download file name', () => { + parser.spec = { + openapi: '3.0.0', + info: { + description: 'Test description', + }, + } as any; + + const info = new ApiInfoModel(parser); + expect(info.downloadFileName).toEqual('openapi.json'); + }); + + test('should correctly populate default download file is undefined when using specUrl', () => { + parser = new OpenAPIParser( + { + openapi: '3.0.0', + info: { + description: 'Test description', + }, + } as any, + '/demo/openapi.yaml', + opts, + ); + + const info = new ApiInfoModel(parser); + expect(info.downloadFileName).toEqual(undefined); + }); + + test('should correctly populate download file name', () => { + parser.spec = { + info: { + description: 'Test description', + }, + } as any; + + const opts = new RedocNormalizedOptions({ + downloadFileName: 'test.yaml', + }); + + const info = new ApiInfoModel(parser, opts); + expect(info.downloadFileName).toEqual('test.yaml'); + }); + + test('should correctly populate download link', () => { + parser.spec = { + openapi: '3.0.0', + info: { + description: 'Test description', + }, + } as any; + + const opts = new RedocNormalizedOptions({ + downloadDefinitionUrl: 'https:test.com/filename.yaml', + }); + const info = new ApiInfoModel(parser, opts); + expect(info.downloadLink).toEqual('https:test.com/filename.yaml'); + }); + + test('should correctly populate download link and download file name', () => { + parser.spec = { + openapi: '3.0.0', + info: { + description: 'Test description', + }, + } as any; + + const opts = new RedocNormalizedOptions({ + downloadDefinitionUrl: 'https:test.com/filename.yaml', + downloadFileName: 'test.yaml', + }); + const info = new ApiInfoModel(parser, opts); + expect(info.downloadLink).toEqual('https:test.com/filename.yaml'); + expect(info.downloadFileName).toEqual('test.yaml'); + }); }); }); diff --git a/src/services/models/ApiInfo.ts b/src/services/models/ApiInfo.ts index 517538db..0c4d91eb 100644 --- a/src/services/models/ApiInfo.ts +++ b/src/services/models/ApiInfo.ts @@ -1,6 +1,7 @@ import { OpenAPIContact, OpenAPIInfo, OpenAPILicense } from '../../types'; import { IS_BROWSER } from '../../utils/'; import { OpenAPIParser } from '../OpenAPIParser'; +import { RedocNormalizedOptions } from '../RedocNormalizedOptions'; export class ApiInfoModel implements OpenAPIInfo { title: string; @@ -15,7 +16,10 @@ export class ApiInfoModel implements OpenAPIInfo { downloadLink?: string; downloadFileName?: string; - constructor(private parser: OpenAPIParser) { + constructor( + private parser: OpenAPIParser, + private options: RedocNormalizedOptions = new RedocNormalizedOptions({}), + ) { Object.assign(this, parser.spec.info); this.description = parser.spec.info.description || ''; this.summary = parser.spec.info.summary || ''; @@ -30,6 +34,10 @@ export class ApiInfoModel implements OpenAPIInfo { } private getDownloadLink(): string | undefined { + if (this.options.downloadDefinitionUrl) { + return this.options.downloadDefinitionUrl; + } + if (this.parser.specUrl) { return this.parser.specUrl; } @@ -43,9 +51,9 @@ export class ApiInfoModel implements OpenAPIInfo { } private getDownloadFileName(): string | undefined { - if (!this.parser.specUrl) { - return 'swagger.json'; + if (!this.parser.specUrl && !this.options.downloadDefinitionUrl) { + return this.options.downloadFileName || 'openapi.json'; } - return undefined; + return this.options.downloadFileName; } } diff --git a/src/services/models/Example.ts b/src/services/models/Example.ts index 016e5caa..1eb81847 100644 --- a/src/services/models/Example.ts +++ b/src/services/models/Example.ts @@ -21,7 +21,7 @@ export class ExampleModel { this.summary = example.summary; this.description = example.description; if (example.externalValue) { - this.externalValueUrl = new URL(example.externalValue, parser.specUrl || '').href; + this.externalValueUrl = new URL(example.externalValue, parser.specUrl).href; } parser.exitRef(infoOrRef);