Compare commits

...

125 Commits
v2.0.0 ... main

Author SHA1 Message Date
Alex Varchuk
00bc6edfc4
chore: v2.5.0 (#2684) 2025-04-14 18:17:50 +03:00
Alex Varchuk
45476135ad
chore: fix moderate vulnerabilities (#2683) 2025-04-14 16:45:31 +03:00
dependabot[bot]
05a04c85ed
chore(deps): bump @babel/runtime from 7.23.2 to 7.27.0 (#2679)
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.23.2 to 7.27.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.27.0/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-version: 7.27.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-14 15:59:27 +03:00
Imamuzzaki Abu Salam
2db293bfb2
fix: enhance accessibility for menu items with keyboard support (#2655) 2025-04-14 15:54:15 +03:00
Imamuzzaki Abu Salam
1b4126fde4
feat: add keyboard navigation support to JsonViewer component (#2654) 2025-04-14 15:48:23 +03:00
dependabot[bot]
1fa13270a1
chore(deps): bump esbuild and esbuild-loader (#2661)
Bumps [esbuild](https://github.com/evanw/esbuild) to 0.25.0 and updates ancestor dependency [esbuild-loader](https://github.com/privatenumber/esbuild-loader). These dependencies need to be updated together.


Updates `esbuild` from 0.17.19 to 0.25.0
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2023.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.17.19...v0.25.0)

Updates `esbuild-loader` from 3.0.1 to 4.3.0
- [Release notes](https://github.com/privatenumber/esbuild-loader/releases)
- [Commits](https://github.com/privatenumber/esbuild-loader/compare/v3.0.1...v4.3.0)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-type: indirect
- dependency-name: esbuild-loader
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: kanoru <kanoru3101@gmail.com>
2025-04-08 15:47:37 +03:00
dependabot[bot]
7cedd59826
chore(deps): bump dompurify from 3.1.3 to 3.2.4 (#2667)
* chore(deps): bump dompurify from 3.1.3 to 3.2.4

Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.3 to 3.2.4.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.1.3...3.2.4)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): update dompurify

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: kanoru <kanoru3101@gmail.com>
2025-04-08 15:06:41 +03:00
dependabot[bot]
cab07bad3b
chore(deps): bump prismjs from 1.29.0 to 1.30.0 (#2672)
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.29.0 to 1.30.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.29.0...v1.30.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 10:59:04 +02:00
Ivan Kropyvnytskyi
1243095926
chore: v2.4.0 (#2658) 2025-02-07 14:30:00 +02:00
Alex Varchuk
6fa5a2a57a
fix: update version download/upload artifacts in cicd (#2656) 2025-02-07 13:27:21 +02:00
Alex Varchuk
3a748022be
feat: add supporting react 19 in package.json (#2652) 2025-02-05 18:13:55 +02:00
Alex Varchuk
53a6afc596
fix: unify redoc config (#2647)
---------

Co-authored-by: Ivan Kropyvnytskyi <130547411+ivankropyvnytskyi@users.noreply.github.com>
2025-01-30 14:23:07 +02:00
Alex Varchuk
ae1ae79901
docs: update options for future major release (#2646) 2025-01-30 10:26:09 +02:00
Lucas Akira Uehara
153ec7a0b7
fix: Prototype Pollution Vulnerability Affecting redoc <=2.2.0 (#2638)
https://github.com/Redocly/redoc/issues/2499

Co-authored-by: Lucas Akira Uehara <80917717@telefonicati.onmicrosoft.com>
2025-01-28 23:28:26 +02:00
Alex Varchuk
c765b34ef5
chore: v2.3.0 (#2649) 2025-01-16 13:33:22 +02:00
Alex Varchuk
0e2d595ef7
chore: fix vulnerabilities (#2648) 2025-01-16 13:01:29 +02:00
dependabot[bot]
8caddaf0eb
chore(deps-dev): bump micromatch from 4.0.4 to 4.0.8 (#2578)
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.4 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.4...4.0.8)

---
updated-dependencies:
- dependency-name: micromatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 12:50:06 +02:00
wadakatu
981e4a84fb
chore: move @cfaester/enzyme-adapter-react-18 to devDependencies (#2625) 2025-01-16 12:41:22 +02:00
Alex Varchuk
59ee73fefa
fix: displaying json example when showObjectSchemaExamples enabled (#2635) 2025-01-08 18:49:11 +02:00
Alex Varchuk
d614d2d022
fix: passing inline parameters after support react 18 for response title (#2640) 2025-01-06 13:40:07 +02:00
Alex Varchuk
85b622fc58
fix: displaying nested items with type string (#2634) 2024-12-31 13:09:48 +02:00
Alex Varchuk
639fd2c32c
chore: npm audit for previnting feature vulnerabilities (#2612) 2024-10-28 13:28:36 +02:00
Michael Huynh
aa0879ca02
feat: update pattern styling (#2196) (#2600)
Closes #2196
2024-10-28 13:25:32 +02:00
Dxuian
c3fce4e2b2
chore: updated webpack version to 5.94.0 (#2583) 2024-10-28 13:09:34 +02:00
Taylor Krusen
11912f5d91
docs(all): change admonition type to 'info' (#2608) 2024-10-18 07:47:56 -07:00
Alex Varchuk
1593d01936
fix: docker build (#2607) 2024-10-16 13:29:44 +03:00
Alex Varchuk
4736c54edd
chore: v2.2.0 (#2606) 2024-10-16 12:22:32 +03:00
Alex Varchuk
64f18779e5
feat: add support x-badges (#2605)
* feat: add support x-badges

Co-authored-by: Max Mueller <maxmueller@eaton.com>

* chore: try to fix e2e tests

* chore: try to fix e2e tests part 2

* Update docs/redoc-vendor-extensions.md

---------

Co-authored-by: Max Mueller <maxmueller@eaton.com>
Co-authored-by: Jacek Łękawa <164185257+JLekawa@users.noreply.github.com>
2024-10-16 11:48:21 +03:00
dependabot[bot]
1cceed4b47
chore(deps): bump dompurify from 3.0.6 to 3.1.3 (#2602)
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.0.6 to 3.1.3.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.0.6...3.1.3)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-15 18:24:19 +03:00
dependabot[bot]
c0c68206de
chore(deps): bump body-parser and express (#2603)
Bumps [body-parser](https://github.com/expressjs/body-parser) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `body-parser` from 1.20.2 to 1.20.3
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3)

Updates `express` from 4.19.2 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.1)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-15 17:59:12 +03:00
Lorna Jane Mitchell
d193dd2627
chore: Remove the sync job, we don't use it any more (#2591) 2024-09-19 16:10:09 +01:00
Lorna Jane Mitchell
c04b4c8fec
docs: Remove the old zero-dependency claim for Redoc docs (#2590) 2024-09-16 09:12:25 +01:00
Alex Varchuk
c0203be045
chore: upgrade node version for docker (#2589) 2024-09-13 11:17:02 +03:00
Lorna Jane Mitchell
c813eeac04
docs: fix http-server example from in-page feedback (#2580) 2024-09-02 11:48:55 +01:00
Alex Varchuk
60d131b0a9
fix: show siblings schema with oneOf (#2576) 2024-08-29 21:22:07 +03:00
Alex Varchuk
a7607eafdd
docs: update broken link of Openapi Object (#2577) 2024-08-29 19:18:05 +02:00
Roman Hotsiy
e0666776e8 chore: remove heavy bundlesize dev dependency 2024-08-01 15:56:39 +08:00
Roman Hotsiy
d0543bb116 chore: upgrade vulnerable dev dependencies 2024-08-01 14:37:12 +08:00
Alex Varchuk
3658b6def4
chore: v2.1.5 (#2550) 2024-06-10 16:21:57 +03:00
Alex Varchuk
c664dd0d56
fix: update react to 18 and react-tabs to 6 (#2547) 2024-06-06 17:03:18 +03:00
Alex Varchuk
72dd57d457
chore: move jest-environment-jsdom to dev dependencies (#2543) 2024-06-06 11:21:00 +03:00
Lorna Jane Mitchell
31d88a184b
docs: Remove outdated sync job for docs folder (#2465) 2024-04-26 12:43:35 +01:00
Alex Varchuk
50c7f60fb6
chore: fix docker publish action (#2531) 2024-04-25 19:46:13 +03:00
Alex Varchuk
a661320625
chore: v2.1.4 (#2530) 2024-04-25 17:19:58 +03:00
Kerem Nalbant
b0d03d0206
fix: add deprecated css to clickable property name (#2526)
Co-authored-by: Kerem Nalbant <k.nalbant@epilot.cloud>
2024-04-25 16:24:58 +03:00
Max Krumpe
2b72dc0e90
fix: use h2/h3 for headings instead of h1/h2 for better seo (#2514)
* fix: use h2/h3 for headings instead of h1/h2 for better seo

* fix: fixed e2e tests for changed headings

---------

Co-authored-by: Max Krumpe <max.krumpe@uniserv.com>
2024-04-25 12:46:12 +03:00
Alex Varchuk
ff91768879
chore: upgrade cypress to fix e2e tests and update-browserslist-db (#2529) 2024-04-25 11:21:26 +03:00
Alex Varchuk
20a923b485
chore: upgrade openapi-sampler (#2525) 2024-04-24 17:43:01 +03:00
Alex Varchuk
edac97236d
fix: publish script (#2524) 2024-04-24 16:30:51 +03:00
Alex Varchuk
9af774e443
chore: add check-version to publish script (#2446) 2024-04-24 16:07:21 +03:00
Alex Varchuk
1f11f597c4
chore: fix vulnerabilities and upgrade deps (#2445)
* chore: fix vulnerabilities and upgrade deps

* chore: use old version of cypress

* fix: additional vulnerabilities
2024-04-24 15:48:02 +03:00
Lorna Jane Mitchell
3f3f9551ee
docs: Update API examples list to include Museum API (#2506)
* feat: Update API examples list to include Museum API

* updates museum.yaml with logo and replaces petstore with museum api in playground for local dev and some minor edits to redoc name

* docs: update definition

---------

Co-authored-by: Heather Cloward <heathercloward@gmail.com>
Co-authored-by: Alex Varchuk <olexandr.varchuk@gmail.com>
2024-04-02 18:16:44 +03:00
Lorna Jane Mitchell
8c391497bf
docs: Fix a link that couldn't be checked as it reaches outside the Redoc project (#2490) 2024-02-12 14:44:00 +00:00
Lorna Jane Mitchell
4fd22f6d74
docs: Add docs tooling to align with publishing to main site (#2484)
* docs: add markdownlint and some link checks alongside vale

* docs: add link checker config and fix/update some links reported broken

* docs: update markdownlint action

* docs: fix markdown table formatting

* docs: Unpin Vale version and pick up the latest
2024-01-29 16:39:44 +00:00
Lorna Jane Mitchell
76cecf054c
chore: Update directory structure for Vale v3 (#2477)
* chore: Update directory structure for Vale v3

* chore: update Vale folder name
2024-01-17 18:33:40 +00:00
Javi Rubio
21b961dffa
Add Quaderno API to README's Showcase section (#2468) 2023-12-28 15:38:40 +00:00
Lorna Jane Mitchell
0db1e9872d
docs: Remove references to interactive docs in the open source project (#2460)
* docs: Remove references to interactive docs in the open source project

* Update README.md

Co-authored-by: Adam Altman <adam@redoc.ly>

---------

Co-authored-by: Adam Altman <adam@redoc.ly>
2023-12-01 16:00:50 +00:00
Alexei Maridashvili
e9f9799e89
Update README.md (#2422)
Fix link to deployment options
2023-11-13 11:48:58 +00:00
Adam Altman
8c04c02ab0
docs: fix admonition on config page (#2452) 2023-11-13 10:16:32 +00:00
redocly-bot
7b2931dc91 sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-11-09 15:56:30 +00:00
Alex Varchuk
b2d8e0f5b7
chore: v2.1.3 (#2439) 2023-10-25 11:43:48 +03:00
Alex Varchuk
8ddeb6dfda
fix: display string pattern in array items (#2438) 2023-10-24 13:12:51 +03:00
Alex Varchuk
bf960612a4
fix: hideRequestPayloadSample (#2436) 2023-10-23 18:36:53 +03:00
Alex Varchuk
b36a6e27bb
fix: default value as object in request body (#2437) 2023-10-23 18:36:30 +03:00
redocly-bot
ba7cd0a130 sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-10-23 12:07:23 +00:00
dependabot[bot]
88f813eb68
chore(deps-dev): bump postcss from 8.4.27 to 8.4.31 (#2427)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.27 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.27...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-22 12:49:59 +03:00
redocly-bot
f28a807dec sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-10-18 14:49:43 +00:00
redocly-bot
25394b7aba sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-10-09 19:12:25 +00:00
redocly-bot
75065a28fd sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-10-09 16:35:52 +00:00
redocly-bot
ff492b5eb2 sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-09-28 11:43:40 +00:00
redocly-bot
aadc32c1eb sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-09-21 14:20:06 +00:00
Lorna Jane Mitchell
b3503f2109
Config docs and README refresh (#2393)
* docs: Give Redoc a landing page with overview and tldr instructions

* docs: move config to dedicated page

* docs: modernise README, link to resources

* docs: more detailed format for theme configurations

* fix: README formatting

* fix: Fix future tense errors and add exceptions for config fields as headings

* Apply suggestions from code review

Co-authored-by: Heather Cloward <heathercloward@gmail.com>

* docs: minor updates from excellent pull request feedback

* docs: Remove the old quickstart, update HTML as the preferred onboarding method and improve docs/examples on that page

* Apply suggestions from code review

Co-authored-by: Heather Cloward <heathercloward@gmail.com>

---------

Co-authored-by: Heather Cloward <heathercloward@gmail.com>
2023-09-21 15:19:27 +01:00
Andrew Tatomyr
26674e70c6
fix: more cases for react18 and cli integration (#2416) 2023-09-15 13:28:35 +03:00
Alex Varchuk
0e38089204
chore: v2.1.2 (#2413) 2023-09-11 13:31:28 +03:00
ckszabi
1d6100111a
fix: style RefreshToken URL as <code> in the authorization section
Co-authored-by: szaszeke <Szabolcs.Szekely@t-systems.com>
2023-09-11 13:22:18 +03:00
dependabot[bot]
98813e687d
chore(deps): bump @cypress/request and cypress (#2410)
Bumps [@cypress/request](https://github.com/cypress-io/request) to 3.0.1 and updates ancestor dependency [cypress](https://github.com/cypress-io/cypress). These dependencies need to be updated together.


Updates `@cypress/request` from 2.88.11 to 3.0.1
- [Release notes](https://github.com/cypress-io/request/releases)
- [Changelog](https://github.com/cypress-io/request/blob/master/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/request/compare/v2.88.11...v3.0.1)

Updates `cypress` from 12.17.1 to 13.1.0
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/cypress/compare/v12.17.1...v13.1.0)

---
updated-dependencies:
- dependency-name: "@cypress/request"
  dependency-type: indirect
- dependency-name: cypress
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-08 11:08:57 +03:00
Oprysk Viacheslav
76edc15939
fix: react18 cli integration (#2404)
* fix: react18 cli integration

* fix: update unit tests snapshots
2023-09-08 10:51:39 +03:00
Alex Varchuk
2eff85a261
chore: add tests for cover field default crash (#2389) 2023-08-31 10:43:53 +03:00
Roman Hotsiy
c86fd7f597 chore: v2.1.1 2023-08-18 07:03:41 +10:00
Roman Hotsiy
9e14e1484c fix: hotfix, crash after 2.1 release 2023-08-18 07:03:41 +10:00
Alex Varchuk
ae74ef95c3
chore: v2.1.0 (#2382) 2023-08-17 16:33:15 +03:00
Lorna Mitchell
d6eac394cf docs: Remove Redoc CLI and a non-existent config option 2023-08-03 18:02:13 +03:00
Alex Varchuk
7529fd2492 chore: upgrade packages for fixing vulnerabilities 2023-07-27 13:09:38 +03:00
Alex Varchuk
6a52698da9 chore: upgrade openapi-core to 1.0.0-rc.2 2023-07-27 13:09:38 +03:00
Alex Varchuk
c7d07cdf18 chore: update cypress to 12.17.1 2023-07-27 13:09:38 +03:00
Roman Pidkostelnyi
054f604195
feat: add support of react 18 (#2369)
* feat: add support of react 18

* chore: add newest version of styled-components to peerDependencies

* chore: add supoort of styled components

* chore: downgrade types

* chore: update snapshots
2023-07-26 11:41:20 +03:00
Alex Varchuk
0bb21c8128
feat: add x-tags (#2355)
* feat: add x-tags

* chore: fix e2e tests and add new for x-tag

* chore: add x-tags to demo definition

* chore: update snapshots
2023-07-26 11:17:56 +03:00
Adam Altman
9b73dae685
docs: fix and update links in redoc-vendor-extensions (#2368)
Co-authored-by: Lorna Jane Mitchell <github@lornajane.net>
2023-07-21 11:40:20 -05:00
Roman Pidkostelnyi
d21af58414
feat: enable keyboard navigation (#2361) 2023-07-19 14:45:12 +03:00
dependabot[bot]
8fbc955f12
chore(deps-dev): bump word-wrap from 1.2.3 to 1.2.4 (#2359)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 10:59:23 +03:00
Oprysk Viacheslav
8907ff2ba0
chore: update packages dependecy (#2360)
* chore: update packages dependecy

* fix: remove redundant options

* fix: webpack config demo folder

* fix: replace cypress ts-loader

* chore: remove redundant dependency
2023-07-19 10:54:04 +03:00
Heather Cloward
c407726a66
docs: adds vale rules and workflow for running in CI (#2348)
* docs: adds vale rules and workflow for running in CI

* docs: updates product name from ReDoc to Redoc
2023-07-11 13:31:52 -04:00
Alex Varchuk
4386867d90
fix: schema oneOf title with const (#2350) 2023-07-11 15:33:36 +03:00
Ricardo Graça
7e052028d9
fix: renames 'FieldContstraints' to 'FieldConstraints' (#2352)
Co-authored-by: Ricagraca <ricardo.graca@freiheit.com>
2023-07-11 15:32:00 +03:00
Alex Varchuk
916639098f
chore: remove broken link from demo (#2338) 2023-06-14 07:17:48 +08:00
redocly-bot
44372d5702 sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-06-13 17:13:40 +00:00
Heather Cloward
7e4639e8cf
docs: updates the redocly cli command prefix from openapi to redocly in the redoc deployment guide intro page (#2326) 2023-05-26 11:11:14 -04:00
Alex Varchuk
d1c9155ae1
chore: remove redoc-cli (#2320) 2023-05-18 17:53:26 +03:00
dependabot[bot]
874b0d6f81
chore(deps): bump json5 from 1.0.1 to 1.0.2 (#2248)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-17 20:11:12 +03:00
redocly-bot
6a2f2c98e0 sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-05-10 18:51:48 +00:00
redocly-bot
c26e3473a4 sync: Synced local 'docs/' with remote 'docs/redoc/' 2023-03-31 17:40:37 +00:00
Alex Varchuk
d4cd6f7fbd
chore: update openapi-sampler (#2275) 2023-03-23 16:55:39 +02:00
Maryana Svitlyk
d3ad7925cf
feat: indicate whether request body is required or optional (#2175) 2023-03-06 20:41:41 +02:00
Danil Zagoskin
b4f71c6bbc
docs: add some success response codes to openapi 3.1 (#2251) 2023-03-06 20:13:18 +02:00
Michael Goberling
1a38b870ae
docs: fix typo in CLI readme (#2249) 2023-03-06 20:12:16 +02:00
Alex Varchuk
d3ac16f477
chore: cli-v0.13.21 (#2274) 2023-03-06 19:44:09 +02:00
Alex Varchuk
2ae7e08af4
feat: add deprecation label to redoc-cli (#2172)
---------

Co-authored-by: Adam Altman <adam@redoc.ly>
2023-03-06 14:36:53 +02:00
Jesper Hagström
53c83b4962
chore: bump http-cache-semantics to 4.1.1 (#2268) 2023-03-06 13:18:13 +02:00
Thomas Florelli
33be51a7a4
fix(types/open-api): import type (#2213) 2022-12-29 08:44:19 -06:00
ayame113
1597bae403
fix(demo): Get CORS proxy to work in Chrome on Windows (#2220) 2022-12-29 08:43:52 -06:00
Dag Frode Solberg
12be1bc5ff
fix: improve accessible label by using the property name (#2224) 2022-12-29 08:43:06 -06:00
Dag Frode Solberg
b8f7da6b00
fix: move role to list item to meet ARIA spec (#2228) 2022-12-29 08:39:48 -06:00
Tony Spataro
f6a70b11b0
chore: update developer setup with new dependency in contributing.md (#2239) 2022-12-29 08:38:32 -06:00
dependabot[bot]
ef99fb1f6b
chore(deps): bump qs from 6.5.2 to 6.5.3 (#2232)
Bumps [qs](https://github.com/ljharb/qs) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/ljharb/qs/releases)
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.5.2...v6.5.3)

---
updated-dependencies:
- dependency-name: qs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-29 08:37:45 -06:00
dependabot[bot]
f254e109b7
chore(deps): bump express from 4.17.1 to 4.18.2 (#2235)
Bumps [express](https://github.com/expressjs/express) from 4.17.1 to 4.18.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.1...4.18.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-29 08:37:38 -06:00
Mohamed El omary
630e63bf45
chore: remove isarray package (#2241) 2022-12-29 08:37:13 -06:00
Alex Varchuk
3d410b6002
fix: default value for array query parameter (#2186) 2022-10-31 20:46:00 +02:00
Alex Varchuk
0753bbea4b
fix: call onLoaded if specs are not found (#2182) 2022-10-21 17:15:22 +03:00
Alex Varchuk
187e555558
chore: update link to redocly.com and add security to definition (#2173) 2022-10-12 15:28:08 +03:00
Alex Varchuk
53c4f36fad
fix: error with immutable object spec (#2179) 2022-10-11 13:39:30 +03:00
Alex Varchuk
cc9818ca41
chore: return genericObject for cli (#2178) 2022-10-04 15:50:57 +03:00
Bill Collins
127ef260b9
fix: remove GenericObject shim (#2177)
This was declared in the local stubs file but not shipped, meaning that
consumers with typescript libchecking enabled would have to also add the
GenericObject definition to their local stubs file.

This commit inlines the definition where necessary, or replaces it with
object where appropriate.
2022-09-29 14:42:23 +03:00
André Stösel
168189b2fd
feat: add option to hide the example code when using the SchemaDefinition component (#2157) 2022-09-19 12:44:44 +03:00
Waldir Pimenta
1697d2ce78
chore: demo/index.tsx: update to use new Redoc logo (#2167) 2022-09-19 12:00:11 +03:00
Waldir Pimenta
a2a4cf9554
chore: update capitalization in README: ReDoc → Redoc (#2166)
Also add missing punctuation to warning, and change example CDN link to the now-released 2.0.0
2022-09-19 11:54:28 +03:00
149 changed files with 17482 additions and 22596 deletions

View File

@ -1,10 +1,12 @@
# ReDoc Contributing Guide
# Redoc Contributing Guide
Hi! We're really excited that you are interested in contributing to ReDoc. Before submitting your contribution though, please make sure to take a moment and read through the following guidelines.
Hi! We're really excited that you are interested in contributing to Redoc. Before submitting your contribution though, please make sure to take a moment and read through the following guidelines.
- [Redoc Contributing Guide](#redoc-contributing-guide)
- [Issue Reporting Guidelines](#issue-reporting-guidelines)
- [Pull Request Guidelines](#pull-request-guidelines)
- [Development Setup](#development-setup)
- [Commonly used NPM scripts](#commonly-used-npm-scripts)
- [Project Structure](#project-structure)
## Issue Reporting Guidelines
@ -22,7 +24,7 @@ Before submitting a pull request, please make sure the following is done:
## Development Setup
You will need [Node.js](http://nodejs.org) at `v12.0.0+`.
You need [Node.js](http://nodejs.org) at `v12.0.0+`.
After cloning the repo, run:
@ -88,7 +90,7 @@ There are some other scripts available in the `scripts` section of the `package.
- **`src/common-elements`**: contains common Styled elements or components used in multiple places
- **`src/components`**: contains main visual components
- **`src/services`**: contains different services used by ReDoc including MobX stores
- **`src/services`**: contains different services used by Redoc including MobX stores
- **`src/services/models`**: contains classes for OpenAPI entities (e.g. Response, Operations, etc)
- **`src/types`**: contains extra typescript typings including OpenAPI doc typings
- **`src/utils`**: utility functions

View File

@ -2,7 +2,7 @@
## Reference
## Testing
## Tests
## Screenshots (optional)

110
.github/styles/Rules/BritishEnglish.yml vendored Normal file
View File

@ -0,0 +1,110 @@
extends: substitution
message: 'Use the US spelling "%s" instead of British "%s".'
link: https://docs.microsoft.com/en-us/style-guide/word-choice/use-us-spelling-avoid-non-english-words
level: error
ignorecase: true
swap:
aeon: eon
aeroplane: airplane
ageing: aging
aluminium: aluminum
anaemia: anemia
anaesthesia: anesthesia
analyse: analyze
annexe: annex
apologise: apologize
behaviour: behavior
busses: buses
calibre: caliber
cancelled: canceled
cancellation: cancelation
catalogue: catalog
categorise: categorize
categorised: categorized
categorises: categorizes
categorising: categorizing
centre: center
cheque: check
civilisation: civilization
civilise: civilize
colour: color
cosy: cozy
cypher: cipher
dependant: dependent
defence: defense
distil: distill
draught: draft
encyclopaedia: encyclopedia
enquiry: inquiry
enrol: enroll
enrolment: enrollment
enthral: enthrall
expiry: expiration
favourite: favorite
fibre: fiber
fillet: filet
flavour: flavor
furore: furor
fulfil: fulfill
gaol: jail
grey: gray
humour: humor
honour: honor
initialled: initialed
initialling: initialing
instil: instill
jewellery: jewelry
labelling: labeling
labelled: labeled
labour: labor
libellous: libelous
licence: license
likeable: likable
liveable: livable
lustre: luster
manoeuvre: maneuver
marvellous: marvelous
matt: matte
meagre: meager
metre: meter
modelling: modeling
moustache: mustache
neighbour: neighbor
normalise: normalize
offence: offense
organise: organize
organisation: organization
orientated: oriented
paralyse: paralyze
plough: plow
pretence: pretense
programme: program
pyjamas: pajamas
rateable: ratable
realise: realize
recognise: recognize
reconnoitre: reconnoiter
rumour: rumor
sabre: saber
saleable: salable
saltpetre: saltpeter
sceptic: skeptic
sepulchre: sepulcher
signalling: signaling
sizeable: sizable
skilful: skillful
sombre: somber
smoulder: smolder
speciality: specialty
spectre: specter
splendour: splendor
standardise: standardize
standardised: standardized
sulphur: sulfur
theatre: theater
travelled: traveled
traveller: traveler
travelling: traveling
unshakeable: unshakable
wilful: willful
yoghurt: yogurt

10
.github/styles/Rules/FutureTense.yml vendored Normal file
View File

@ -0,0 +1,10 @@
extends: existence
message: 'Avoid using future tense: "%s". Use present tense instead.'
link: https://intranet.redoc.ly/contributing/documentation-style-guide/#tone-and-audience
ignorecase: true
level: error
raw:
- "(going to( |\n|[[:punct:]])[a-zA-Z]*|"
- "will( |\n|[[:punct:]])[a-zA-Z]*|"
- "won't( |\n|[[:punct:]])[a-zA-Z]*|"
- "[a-zA-Z]*'ll( |\n|[[:punct:]])[a-zA-Z]*)"

11
.github/styles/Rules/HeaderGerunds.yml vendored Normal file
View File

@ -0,0 +1,11 @@
extends: existence
message: 'Do not start headings with with a gerund (ing word). Use an imperative verb instead.'
link: https://intranet.redoc.ly/contributing/documentation-style-guide/#content-organization
level: error
scope: heading
tokens:
- '^\w*ing.*'
exceptions:
- expandSingleSchemaField
- hideLoading
- hideSingleRequestSampleTab

View File

@ -0,0 +1,16 @@
extends: substitution
message: 'Use inclusive language. Consider "%s" instead of "%s".'
link: https://intranet.redoc.ly/contributing/documentation-style-guide/#grammar-and-syntax
level: error
ignorecase: true
swap:
he: they
his: their
she: they
hers: their
blacklist(?:ed|ing|s)?: blocklist
whitelist(?:ed|ing|s)?: allowlist
master: primary, main
slave: replica
he/she: they
s/he: they

8
.github/styles/Rules/OxfordComma.yml vendored Normal file
View File

@ -0,0 +1,8 @@
extends: existence
message: "Use the Oxford comma in '%s'."
link: https://docs.microsoft.com/en-us/style-guide/punctuation/commas
scope: sentence
level: error
nonword: true
tokens:
- '(?:[^\s,]+,){1,} \w+ (?:and|or) \w+[.?!]'

View File

@ -0,0 +1,150 @@
[Aa]nsible
[Aa]utostart
[Bb]locklist
[Bb]locklists
[Bb]oolean
[Bb]reakpoint
[B]reakpoints
[Cc]ancelation
[Cc]lassloading
[Cc]hargeback
[Cc]hargebacks
[Cc]he
[Cc]rypto
[Cc]ryptocurrency
[Dd]evfile|[Dd]evfiles
[Dd]ownstream
[Dd]ownstreaming
[Ff]actories|[Ff]actory
[Gg]it
[Gg]rafana
[Hh]eatmap
[Hh]elm
[Hh]ostname
[Ii]tem
[Jj]etbrains
[Kk]eycloak
[Ll]iveness
[Ll]ombok
[Ll]oopback
[Mm]aven
[Mm]inikube
[Mm]inishift
[Mm]ixin|[Mm]ixins
[Mm]odularization
[Mm]ulticluster
[Mm]ultihost
[Mm]ultinode
[Mm]ultitenant
[Mm]ultiuser
[Mm]ultizone
[Nn]amespace|[Nn]amespaces
[Nn]etcoredebug[Oo]utput
[Nn]ginx
[Oo]nboarding
[Pp]podman
[Pp]reconfigured
[Rr]eadonly
[Rr]epresentment
[Rr]ollout|[Rr]ollouts
[Rr]untime|[Rr]untimes
[Ss]erializer
[Ss]erverless
[Ss]ubnetwork
[Ss]ubpath|[Ss]ubpaths
[Tt]heia
[Tt]olerations
[Tt]ruststore
[Uu]ninstallation
[Uu]nstaged
[Uu]ntrusted
[Ww]orkspace|[Ww]orkspaces
[Yy]eoman
\.NET
adoc
Antora
API
Apigee
AsciiDoc
AWS|aws
Azure
Bierner
Bitbucket
btn
Btrfs
CentOS
Ceph
Che-Theia
CLI
ConfigMap|ConfigMaps
Ctrl
DaemonSet
Dev Workspace
Developer Perspective
DNS
Docker
Dockerfile
Dotnet
Endevor
endif
GitHub|github
GitLab
Gluster
Gradle
Grafana
GUI
HTTPS|https
I/O
IDE|ide|IDEs
Intelephense
IntelliJ IDEA
Java
Java Lombok
JSON|json
JVM|jvm
kbd
Kubespray
Laravel
Let\'s Encrypt
Mattermost
mebibytes
Microsoft Azure
millicores
Mulesoft
MySQL
Netlify
Node.js
npm
NuGet
OAuth
ocp
OmniSharp
OpenShift
OpenTracing
Operator
OperatorHub
OpenAPI
osd
PHP
PostgreSQL
Quarkus
Rebilly
Redoc
Redocly
Redocly-cli
SCM
Sharding
SonarLint
Spring Boot
SVG
Uber
URI|URIs
URL|url|URLs
Velero
Vercel
Visual Studio Code
vsix
Webview|Webviews
Woopra
YAML|yaml
Zowe

View File

6
.github/sync.yml vendored
View File

@ -1,6 +0,0 @@
group:
- files:
- source: docs/
dest: docs/redoc
repos: |
Redocly/docs

37
.github/workflows/docs-tests.yaml vendored Normal file
View File

@ -0,0 +1,37 @@
name: Documentation tests
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
markdownlint:
name: markdownlint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DavidAnson/markdownlint-cli2-action@v15
with:
config: .markdownlint.yaml
globs: |
docs/**/*.md
README.md
vale:
name: vale action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: errata-ai/vale-action@reviewdog
with:
files: '["README.md", "docs"]'
filter_mode: file
linkcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Markup Link Checker (mlc)
uses: becheran/mlc@v0.16.1
with:
args: ./docs

View File

@ -7,6 +7,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci && npm ci --prefix cli
- run: npm ci
- run: npm run bundle
- run: npm run e2e

View File

@ -3,46 +3,6 @@ on:
release:
types: [published]
jobs:
# push_to_registry:
# name: Push Docker image to GitHub Packages
# runs-on: ubuntu-latest
# permissions:
# packages: write
# contents: read
# steps:
# - name: Check out the repo
# uses: actions/checkout@v3
# - name: Login to GitHub Container Registry
# uses: docker/login-action@v1
# with:
# registry: ghcr.io
# username: ${{ github.repository_owner }}
# password: ${{ secrets.GITHUB_TOKEN }}
# - name: Prepare
# id: prep
# run: |
# DOCKER_IMAGE=ghcr.io/redocly/redoc/cli
# VERSION=edge
# if [[ $GITHUB_REF == refs/tags/* ]]; then
# VERSION=${GITHUB_REF#refs/tags/}
# elif [[ $GITHUB_REF == refs/heads/* ]]; then
# VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g')
# elif [[ $GITHUB_REF == refs/pull/* ]]; then
# VERSION=pr-${{ github.event.number }}
# fi
# TAGS="${DOCKER_IMAGE}:${VERSION},${DOCKER_IMAGE}:latest"
# if [ "${{ github.event_name }}" = "push" ]; then
# TAGS="$TAGS,${DOCKER_IMAGE}:sha-${GITHUB_SHA::8}"
# fi
# echo ::set-output name=version::${VERSION}
# echo ::set-output name=tags::${TAGS}
# echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
# - name: Push to GitHub Packages
# uses: docker/build-push-action@v3
# with:
# context: ./cli
# push: ${{ github.event_name != 'pull_request' }}
# tags: ${{ steps.prep.outputs.tags }}
dockerhub:
name: Publish redoc image to DockerHub
runs-on: ubuntu-latest

View File

@ -1,120 +0,0 @@
name: Publish cli
on:
push:
branches:
- main
jobs:
bundle:
needs: [check-version-cli]
if: needs.check-version-cli.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS
key: npm-${{ hashFiles('package-lock.json') }}
restore-keys: |
npm-${{ hashFiles('package-lock.json') }}
npm-
- run: npm ci && npm ci --prefix cli
- run: npm run bundle
- name: Store bundle artifact
uses: actions/upload-artifact@v3
with:
name: bundles-cli
path: bundles
retention-days: 1
unit-tests:
needs: [check-version-cli]
if: needs.check-version-cli.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci && npm ci --prefix cli
- run: npm test
e2e-tests:
needs: [bundle]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci && npm ci --prefix cli
- name: Download bundled artifact
uses: actions/download-artifact@v3
with:
name: bundles-cli
path: bundles
- run: npm run e2e
bundle-cli:
needs: [check-version-cli]
if: needs.check-version-cli.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: npm-${{ hashFiles('package-lock.json') }}
restore-keys: |
npm-${{ hashFiles('package-lock.json') }}
npm-
- name: Install dependencies
run: npm ci && npm ci --prefix cli
- name: Bundle
run: npm run compile:cli
- name: Store bundle artifact
uses: actions/upload-artifact@v3
with:
name: cli
path: cli
retention-days: 1
check-version-cli:
name: Check Version
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.check.outputs.changed }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
- name: Check if version has been updated
id: check
uses: EndBug/version-check@v2.0.1
with:
file-name: ./cli/package.json
file-url: https://unpkg.com/redoc-cli/package.json
static-checking: localIsNew
publish-cli:
needs: [bundle-cli, unit-tests, e2e-tests]
if: needs.check-version-cli.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v3
with:
node-version: '14.x'
registry-url: 'https://registry.npmjs.org'
- uses: actions/checkout@v3
- name: Download cli bundled artifact
uses: actions/download-artifact@v3
with:
name: cli
path: cli
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS
key: npm-${{ hashFiles('package-lock.json') }}
restore-keys: |
npm-${{ hashFiles('package-lock.json') }}
npm-
- name: Publish to NPM
run: cd cli/ && npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -2,8 +2,7 @@ name: Publish
on:
push:
tags:
- v[0-9]*.[0-9]*.[0-9]*
branches: [main]
jobs:
bundle:
@ -19,10 +18,10 @@ jobs:
restore-keys: |
npm-${{ hashFiles('package-lock.json') }}
npm-
- run: npm ci && npm ci --prefix cli
- run: npm ci
- run: npm run bundle
- name: Store bundle artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: bundles
path: bundles
@ -31,23 +30,41 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci && npm ci --prefix cli
- run: npm ci
- run: npm test
e2e-tests:
needs: [bundle]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci && npm ci --prefix cli
- run: npm ci
- name: Download bundled artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: bundles
path: bundles
- run: npm run e2e
check-version:
name: Check Version
runs-on: ubuntu-latest
needs: [bundle, unit-tests, e2e-tests]
outputs:
changed: ${{ steps.check.outputs.changed }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
- name: Check if version has been updated
id: check
uses: EndBug/version-check@v2.0.1
with:
file-url: https://cdn.jsdelivr.net/npm/redoc/package.json
static-checking: localIsNew
publish:
name: Publish to NPM
needs: [bundle, unit-tests, e2e-tests]
needs: [check-version]
if: needs.check-version.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v3
@ -56,7 +73,7 @@ jobs:
registry-url: 'https://registry.npmjs.org'
- uses: actions/checkout@v3
- name: Download bundled artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: bundles
path: bundles
@ -77,7 +94,8 @@ jobs:
publish-cdn:
name: Publish to CDN
needs: [bundle, unit-tests, e2e-tests]
needs: [check-version]
if: needs.check-version.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
@ -89,14 +107,15 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Download all artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
- name: Publish to S3
run: npm run publish-cdn
invalidate-cache:
name: Clear cache
runs-on: ubuntu-latest
needs: [publish, publish-cdn]
needs: [check-version, publish, publish-cdn]
if: needs.check-version.outputs.changed == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@v3

View File

@ -1,18 +0,0 @@
name: Sync Files
on:
push:
branches:
- main
workflow_dispatch:
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Run GitHub File Sync
uses: Redocly/repo-file-sync-action@main
with:
GH_PAT: ${{ secrets.GH_PAT }}
COMMIT_PREFIX: 'sync:'
SKIP_PR: true

View File

@ -7,6 +7,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci && npm ci --prefix cli
- run: npm ci
- run: npm run bundle
- run: npm test

2
.gitignore vendored
View File

@ -27,8 +27,6 @@ cypress/
bundles/
typings/*
!typings/styled-patch.d.ts
cli/index.js
cli/__test__/*/**/*.html
/benchmark/revisions

54
.markdownlint.yaml Normal file
View File

@ -0,0 +1,54 @@
---
# Default rules: https://github.com/github/super-linter/blob/master/TEMPLATES/.markdown-lint.yml
# Rules by id
# Unordered list style
MD004: false
# Unordered list indentation
MD007:
indent: 2
MD013:
# TODO: Consider to decrease allowed line length
line_length: 800
tables: false
## Allow same headers in siblings
MD024:
siblings_only: true
# Multiple top level headings in the same document
MD025:
front_matter_title: ''
# Trailing punctuation in heading
MD026:
punctuation: '.,;:。,;:'
# Ordered list item prefix
MD029: false
# Unordered lists inside of ordered lists
MD030: false
# Inline HTML
MD033: false
# No bare urls
MD034: false
# Emphasis used instead of a heading
MD036: false
# Disable "First line in file should be a top level heading"
# We use uncommon format to add metadata.
# TODO: Consider to use "YAML front matter".
MD041: false
# Rules by tags
blank_lines: false
MD046: false
# code-block-style

4
.mlc.toml Normal file
View File

@ -0,0 +1,4 @@
# Ignore these links, we can't check them from this subproject
ignore-links=["../*", "/docs/*"]
# Path to the root folder used to resolve all relative paths
root-dir="./docs"

48
.vale.ini Normal file
View File

@ -0,0 +1,48 @@
# Vale configuration file.
# See: https://docs.errata.ai/vale/config
# The relative path to the folder containing linting rules (styles).
StylesPath = .github/styles
# Vocab define the exceptions to use in *all* `BasedOnStyles`.
# spelling-exceptions.txt triggers `Vale.Terms`
# reject.txt triggers `Vale.Avoid`
# See: https://docs.errata.ai/vale/vocab
Vocab = Rules
# Minimum alert level
# -------------------
# The minimum alert level in the output (suggestion, warning, or error).
# If integrated into CI, builds fail by default on error-level alerts, unless you run Vale with the --no-exit flag
MinAlertLevel = suggestion
# IgnoredScopes specifies inline-level HTML tags to ignore.
# These tags may occur in an active scope (unlike SkippedScopes, skipped entirely) but their content still won't raise any alerts.
# Default: ignore `code` and `tt`.
IgnoredScopes = code, tt, img, url, a, body.id
# SkippedScopes specifies block-level HTML tags to ignore. Ignore any content in these scopes.
# Default: ignore `script`, `style`, `pre`, and `figure`.
# For AsciiDoc: by default, listingblock, and literalblock.
SkippedScopes = script, style, pre, figure, code, tt, listingblock, literalblock
# Rules for matching file types. See: https://docs.errata.ai/vale/scoping
[formats]
properties = md
mdx = md
# Rules for .MD, .MDX
[*.{md,mdx}]
BasedOnStyles = Rules
# Ignore code surrounded by backticks or plus sign, parameters defaults, URLs.
TokenIgnores = (\x60[^\n\x60]+\x60), ([^\n]+=[^\n]*), (\+[^\n]+\+), (http[^\n]+\[)
Vale.Repetition = NO
Vale.SentenceSpacing = NO
Vale.Spelling = NO
# /End of rules for .MD, .MDX
# Process .ini files
[*.ini]

View File

@ -1,3 +1,141 @@
# [2.5.0](https://github.com/Redocly/redoc/compare/v2.4.0...v2.5.0) (2025-04-14)
### Bug Fixes
* enhance accessibility for menu items with keyboard support ([#2655](https://github.com/Redocly/redoc/issues/2655)) ([2db293b](https://github.com/Redocly/redoc/commit/2db293bfb2973497dd33f31dc99e97f5bb90bbe8))
### Features
* add keyboard navigation support to JsonViewer component ([#2654](https://github.com/Redocly/redoc/issues/2654)) ([1b4126f](https://github.com/Redocly/redoc/commit/1b4126fde4531387f49c90f52efbd0c0e5f7b6ea))
# [2.4.0](https://github.com/Redocly/redoc/compare/v2.3.0...v2.4.0) (2025-02-07)
### Bug Fixes
* Prototype Pollution Vulnerability Affecting redoc <=2.2.0 ([#2638](https://github.com/Redocly/redoc/issues/2638)) ([153ec7a](https://github.com/Redocly/redoc/commit/153ec7a0b7245639f404c0b038b612ae7377c7db))
* unify redoc config ([#2647](https://github.com/Redocly/redoc/issues/2647)) ([53a6afc](https://github.com/Redocly/redoc/commit/53a6afc59624fe4591b0a0f1f20f41c0fbb5f1cf))
### Features
* add supporting react 19 in package.json ([#2652](https://github.com/Redocly/redoc/issues/2652)) ([3a74802](https://github.com/Redocly/redoc/commit/3a748022be3a7dc7f98669e1645dd5cda72f1abc))
# [2.3.0](https://github.com/Redocly/redoc/compare/v2.2.0...v2.3.0) (2025-01-16)
### Bug Fixes
* displaying json example when showObjectSchemaExamples enabled ([#2635](https://github.com/Redocly/redoc/issues/2635)) ([59ee73f](https://github.com/Redocly/redoc/commit/59ee73fefa8e8edb398940076bdd721fc284caa3))
* displaying nested items with type string ([#2634](https://github.com/Redocly/redoc/issues/2634)) ([85b622f](https://github.com/Redocly/redoc/commit/85b622fc581eb96303aeb85056aef36c74ea9f9d))
* passing inline parameters after support react 18 for response title ([#2640](https://github.com/Redocly/redoc/issues/2640)) ([d614d2d](https://github.com/Redocly/redoc/commit/d614d2d022df8bd1989cb0eaf76d087b52120d36))
### Features
* update pattern styling ([#2196](https://github.com/Redocly/redoc/issues/2196)) ([#2600](https://github.com/Redocly/redoc/issues/2600)) ([aa0879c](https://github.com/Redocly/redoc/commit/aa0879ca0235112918428fdff8f4c48d2c6c4adf))
# [2.2.0](https://github.com/Redocly/redoc/compare/v2.1.5...v2.2.0) (2024-10-16)
### Bug Fixes
* show siblings schema with oneOf ([#2576](https://github.com/Redocly/redoc/issues/2576)) ([60d131b](https://github.com/Redocly/redoc/commit/60d131b0a9dab4710e900323c9ba81160cecf7d8))
### Features
* add support x-badges ([#2605](https://github.com/Redocly/redoc/issues/2605)) ([64f1877](https://github.com/Redocly/redoc/commit/64f18779e5fe7e03f25862463cbc5062e85c867c))
## [2.1.5](https://github.com/Redocly/redoc/compare/v2.1.4...v2.1.5) (2024-06-10)
### Bug Fixes
* update react to 18 and react-tabs to 6 ([#2547](https://github.com/Redocly/redoc/issues/2547)) ([c664dd0](https://github.com/Redocly/redoc/commit/c664dd0d56571ce799b8eadd081d86a6b2cdefae))
## [2.1.4](https://github.com/Redocly/redoc/compare/v2.1.3...v2.1.4) (2024-04-25)
### Bug Fixes
* add deprecated css to clickable property name ([#2526](https://github.com/Redocly/redoc/issues/2526)) ([b0d03d0](https://github.com/Redocly/redoc/commit/b0d03d02069c1508447ddebc2f8a3fffa9b03ce5))
* use h2/h3 for headings instead of h1/h2 for better seo ([#2514](https://github.com/Redocly/redoc/issues/2514)) ([2b72dc0](https://github.com/Redocly/redoc/commit/2b72dc0e90f759a8ee2e47691c844e7f05928a24))
* security vulnerability ([#2445](https://github.com/Redocly/redoc/pull/2445)) ([1f11f5](https://github.com/Redocly/redoc/commit/1f11f597c4f10ddd601db247f5034052b6ca689f))
## [2.1.3](https://github.com/Redocly/redoc/compare/v2.1.2...v2.1.3) (2023-10-24)
### Bug Fixes
* default value as object in request body ([#2437](https://github.com/Redocly/redoc/issues/2437)) ([b36a6e2](https://github.com/Redocly/redoc/commit/b36a6e27bb3e03d39ee74c3e71f18a504539d91b))
* display string pattern in array items ([#2438](https://github.com/Redocly/redoc/issues/2438)) ([8ddeb6d](https://github.com/Redocly/redoc/commit/8ddeb6dfda686ec8a6948eb2d96efb99bf422429))
* hideRequestPayloadSample ([#2436](https://github.com/Redocly/redoc/issues/2436)) ([bf96061](https://github.com/Redocly/redoc/commit/bf960612a47bfe10ff205b9d78f3040515a5467d))
* more cases for react18 and cli integration ([#2416](https://github.com/Redocly/redoc/issues/2416)) ([26674e7](https://github.com/Redocly/redoc/commit/26674e70c66b686d0f0baa569b186292c41e5726))
## [2.1.2](https://github.com/Redocly/redoc/compare/v2.1.1...v2.1.2) (2023-09-11)
### Bug Fixes
* react18 cli integration ([#2404](https://github.com/Redocly/redoc/issues/2404)) ([76edc15](https://github.com/Redocly/redoc/commit/76edc159399150778b384be87ee958a93e5c491c))
* style RefreshToken URL as <code> in the authorization section ([1d61001](https://github.com/Redocly/redoc/commit/1d6100111a0f3b609dadbd706354ce6125947df2))
## [2.1.1](https://github.com/Redocly/redoc/compare/v2.1.0...v2.1.1) (2023-08-17)
### Bug Fixes
* hotfix, crash after 2.1 release ([0ab3428](https://github.com/Redocly/redoc/commit/0ab3428664f857ea07381686a2b4beb4c22b17c3))
# [2.1.0](https://github.com/Redocly/redoc/compare/v2.0.0...v2.1.0) (2023-08-10)
### Bug Fixes
* call onLoaded if specs are not found ([#2182](https://github.com/Redocly/redoc/issues/2182)) ([0753bbe](https://github.com/Redocly/redoc/commit/0753bbea4b1425bdb09225fca45effae8003dce8))
* default value for array query parameter ([#2186](https://github.com/Redocly/redoc/issues/2186)) ([3d410b6](https://github.com/Redocly/redoc/commit/3d410b6002c656efa780254c9c45c6249f90bce1))
* **demo:** Get CORS proxy to work in Chrome on Windows ([#2220](https://github.com/Redocly/redoc/issues/2220)) ([1597bae](https://github.com/Redocly/redoc/commit/1597bae4032b65a94211e80aad51867e5af1ceb3))
* error with immutable object spec ([#2179](https://github.com/Redocly/redoc/issues/2179)) ([53c4f36](https://github.com/Redocly/redoc/commit/53c4f36fad3e4453a72c1d136e37929de47cd35e))
* improve accessible label by using the property name ([#2224](https://github.com/Redocly/redoc/issues/2224)) ([12be1bc](https://github.com/Redocly/redoc/commit/12be1bc5ffa11f9092c2faacd69d787f4e899960))
* move role to list item to meet ARIA spec ([#2228](https://github.com/Redocly/redoc/issues/2228)) ([b8f7da6](https://github.com/Redocly/redoc/commit/b8f7da6b003ca12c1e2f0f4d42f3dd6d6f86ccac))
* remove GenericObject shim ([#2177](https://github.com/Redocly/redoc/issues/2177)) ([127ef26](https://github.com/Redocly/redoc/commit/127ef260b961e07c5f82a7494b51dd3f04294e87))
* renames 'FieldContstraints' to 'FieldConstraints' ([#2352](https://github.com/Redocly/redoc/issues/2352)) ([7e05202](https://github.com/Redocly/redoc/commit/7e052028d965624feb72d5f4b74fdb3c2d5df21f))
* schema oneOf title with const ([#2350](https://github.com/Redocly/redoc/issues/2350)) ([4386867](https://github.com/Redocly/redoc/commit/4386867d908eae2aed2b9fd86e9f5476aadce52b))
* **types/open-api:** import type ([#2213](https://github.com/Redocly/redoc/issues/2213)) ([33be51a](https://github.com/Redocly/redoc/commit/33be51a7a4068f44fd914314002c058a204ba0c2))
### Features
* add deprecation label to redoc-cli ([#2172](https://github.com/Redocly/redoc/issues/2172)) ([2ae7e08](https://github.com/Redocly/redoc/commit/2ae7e08af49321cea9bf2078f309b48bacf76ad6))
* add option to hide the example code when using the `SchemaDefinition` component ([#2157](https://github.com/Redocly/redoc/issues/2157)) ([168189b](https://github.com/Redocly/redoc/commit/168189b2fdcf3667422ce3940ace3eedd0bdf284))
* add support of react 18 ([#2369](https://github.com/Redocly/redoc/issues/2369)) ([054f604](https://github.com/Redocly/redoc/commit/054f604195629197aa8bd0fc46e91383ca5a05af))
* add x-tags ([#2355](https://github.com/Redocly/redoc/issues/2355)) ([0bb21c8](https://github.com/Redocly/redoc/commit/0bb21c812840999d2dd2d96da42124746440b035))
* enable keyboard navigation ([#2361](https://github.com/Redocly/redoc/issues/2361)) ([d21af58](https://github.com/Redocly/redoc/commit/d21af5841455901f0572ab475b7dc661acb86a71))
* indicate whether request body is required or optional ([#2175](https://github.com/Redocly/redoc/issues/2175)) ([d3ad792](https://github.com/Redocly/redoc/commit/d3ad7925cfbd90b59b502b5ef53228fcd34b8a1e))
# [2.0.0](https://github.com/Redocly/redoc/compare/v2.0.0-rc.77...v2.0.0) (2022-09-12)
@ -498,7 +636,7 @@ closes: [#1506](https://github.com/Redocly/redoc/issues/1506), [#1478](https://g
### Bug Fixes
* invalid discriminator dropdown behaviour with enum ([be07197](https://github.com/Redocly/redoc/commit/be07197e6d1e85a3fd3e61189a36b288751c077d))
* invalid discriminator dropdown behavior with enum ([be07197](https://github.com/Redocly/redoc/commit/be07197e6d1e85a3fd3e61189a36b288751c077d))
@ -716,7 +854,7 @@ Same as rc.31 by mistake
### Bug Fixes
* empty servers behaviour per OAS spec ([ed1db0c](https://github.com/Redocly/redoc/commit/ed1db0c9027087ae0ae923e390e3e1d638a647ae)), closes [#1151](https://github.com/Redocly/redoc/issues/1151)
* empty servers behavior per OAS spec ([ed1db0c](https://github.com/Redocly/redoc/commit/ed1db0c9027087ae0ae923e390e3e1d638a647ae)), closes [#1151](https://github.com/Redocly/redoc/issues/1151)
* fix duplicated content in tags when using md headings ([a260c84](https://github.com/Redocly/redoc/commit/a260c8414c34a259a70a20ebcd20ecbb06c3d250)), closes [#1150](https://github.com/Redocly/redoc/issues/1150) [#1152](https://github.com/Redocly/redoc/issues/1152)
* use mobile menu background color value from theme ([#1144](https://github.com/Redocly/redoc/issues/1144)) ([41a9b3c](https://github.com/Redocly/redoc/commit/41a9b3c18228d236d182d3c15c9abc35ae72a0d5))
@ -1694,7 +1832,7 @@ Complete rewrite also means that this rewrite may introduce issues, but they sho
- no more GitHub pages-based CDN. Use [unpkg.com](https://unpkg.com/) to access ReDoc releases
### Known Regression (will be resolved before leaving alpha stage)
### Known Regression (resolved before leaving alpha stage)
- `lazyLoading` option not implemented yet
- Copying to clipboard of samples not implemented yet
- Search not implemented yet

349
README.md
View File

@ -1,19 +1,17 @@
<div align="center">
<img alt="Redoc logo" src="https://raw.githubusercontent.com/Redocly/redoc/main//docs/images/redoc.png" width="400px" />
# Generate interactive API documentation from OpenAPI definitions
# Generate beautiful API documentation from OpenAPI
[![Coverage Status](https://coveralls.io/repos/Redocly/redoc/badge.svg?branch=main&service=github)](https://coveralls.io/github/Redocly/redoc?branch=main) [![npm](http://img.shields.io/npm/v/redoc.svg)](https://www.npmjs.com/package/redoc) [![License](https://img.shields.io/npm/l/redoc.svg)](https://github.com/Redocly/redoc/blob/main/LICENSE)
[![npm](http://img.shields.io/npm/v/redoc.svg)](https://www.npmjs.com/package/redoc) [![License](https://img.shields.io/npm/l/redoc.svg)](https://github.com/Redocly/redoc/blob/main/LICENSE)
[![bundle size](http://img.badgesize.io/https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js?compression=gzip&max=300000)](https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js) [![npm](https://img.shields.io/npm/dm/redoc.svg)](https://www.npmjs.com/package/redoc) [![](https://data.jsdelivr.com/v1/package/npm/redoc/badge)](https://www.jsdelivr.com/package/npm/redoc) [![Docker Build Status](https://img.shields.io/docker/build/redocly/redoc.svg)](https://hub.docker.com/r/redocly/redoc/)
[![bundle size](http://img.badgesize.io/https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js?compression=gzip&max=300000)](https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js) [![npm](https://img.shields.io/npm/dm/redoc.svg)](https://www.npmjs.com/package/redoc) [![jsDelivr status](https://data.jsdelivr.com/v1/package/npm/redoc/badge)](https://www.jsdelivr.com/package/npm/redoc)
</div>
**This is the README for the `2.x` version of Redoc (React-based).**
**The README for the `1.x` version is on the [v1.x](https://github.com/Redocly/redoc/tree/v1.x) branch**
## About Redoc
Redoc is an open-source tool for generating documentation from OpenAPI (fka Swagger) definitions.
Redoc is an open source tool for generating documentation from OpenAPI (formerly Swagger) definitions.
By default Redoc offers a three-panel, responsive layout:
@ -25,102 +23,78 @@ By default Redoc offers a three-panel, responsive layout:
## Live demo
If you want to see how Redoc will render your OpenAPI definition,
If you want to see how Redoc renders 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 **TRY IT**.
## Redoc vs. Reference vs. Portals
## Redoc features
- Responsive three-panel design with menu/scrolling synchronization
- Support for OpenAPI 3.1, OpenAPI 3.0, and Swagger 2.0
- Ability to integrate your API introduction into the side menu
- High-level grouping in side menu with the [`x-tagGroups`](https://redocly.com/docs/api-reference-docs/specification-extensions/x-tag-groups/) specification extension
- [Simple integration with `create-react-app`](https://redocly.com/docs/redoc/quickstart/react/)
- Code samples support (with vendor extension) <br>
![code samples in action](docs/images/code-samples-demo.gif)
## Usage
Redoc is provided as a CLI tool (also distributed as a Docker image), HTML tag, and React component.
### Generate documentation from the CLI
If you have Node installed, quickly generate documentation using `npx`:
```bash
npx @redocly/cli build-docs openapi.yaml
```
The tool outputs by default to a file named `redoc-static.html` that you can open in your browser.
> [Redocly CLI](https://github.com/Redocly/redocly-cli/) does more than docs; check it out and add linting, bundling, and more to your API workflow.
### Add an HTML element to the page
Create an HTML page, or edit an existing one, and add the following within the body tags:
```html
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
```
Open the HTML file in your browser, and your API documentation is shown on the page.
Add your own `spec-url` to the `<redoc>` tag; this attribute can also be a local file. The JavaScript library can also be installed locally using `npm` and served from your own server, see the [HTML deployment documentation](https://redocly.com/docs/redoc/deployment/html/) for more details.
### More usage options
Check out the [deployment documentation](./docs/deployment/intro.md) for more options, and detailed documentation for each.
## Redoc vs. Redocly API Reference
Redoc is Redocly's community-edition product. Looking for something more?
Checkout the following feature comparison of Redocly's premium products versus Redoc:
We also offer [hosted API reference documentation](https://redocly.com/docs/api-registry/guides/api-registry-quickstart/)
with additional features including:
| Features | Redoc | Reference | Portals |
|------------------------------|:---------:|:---------:|:-----------:|
| **Specs** | | | |
| Swagger 2.0 | √ | √ | √ |
| OpenAPI 3.0 | √ | √ | √ |
| OpenAPI 3.1 | √ (basic) | √ | √ |
| | | | |
| **Theming** | | | |
| Fonts/colors | √ | √ | √ |
| Extra theme options | | √ | √ |
| | | | |
| **Performance** | | | |
| Pagination | | √ | √ |
| Search (enhanced) | | √ | √ |
| Search (server-side) | | | √ |
| | | | |
| **Multiple APIs** | | | |
| Multiple versions | | √ | √ |
| Multiple APIs | | | √ |
| API catalog | | | √ |
| | | | |
| **Additional features** | | | |
| Try-it console | | √ | √ |
| Automated code samples | | √ | √ |
| Deep links | | √ | √ |
| More SEO control | | | √ |
| Contextual docs | | | √ |
| Landing pages | | | √ |
| React hooks for more control | | | √ |
| Personalization | | | √ |
| Analytics integrations | | | √ |
| Feedback | | | Coming Soon |
* Try-it console
* Automated code samples
* Pagination
* Extra theme options
Refer to the Redocly's documentation for more information on these products:
### Documentation and resources
- [Portals](https://redoc.ly/docs/developer-portal/introduction/)
- [Reference](https://redoc.ly/docs/api-reference-docs/getting-started/)
- [Redoc](https://redoc.ly/docs/redoc/quickstart/intro/)
## Features
- Responsive three-panel design with menu/scrolling synchronization
- [Multiple deployment options](https://redoc.ly/docs/redoc/quickstart/intro/)
- [Server-side rendering (SSR) ready](https://redoc.ly/docs/redoc/quickstart/cli/#redoc-cli-commands)
- Ability to integrate your API introduction into the side menu
- [Simple integration with `create-react-app`](https://redoc.ly/docs/redoc/quickstart/react/)
[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/)
- Neat **interactive** documentation for nested objects <br>
![](docs/images/nested-demo.gif)
## Customization options
[<img alt="Customization services" src="http://i.imgur.com/c4sUF7M.png" height="60px">](https://redoc.ly/#services)
- High-level grouping in side-menu with the [`x-tagGroups`](https://redoc.ly/docs/api-reference-docs/specification-extensions/x-tag-groups/) specification extension
- Branding/customizations using the [`theme` option](https://redoc.ly/docs/api-reference-docs/configuration/theming/)
## Support
- OpenAPI v3.0 support
- Basic OpenAPI v3.1 support
- Broad OpenAPI v2.0 feature support (yes, it supports even `discriminator`) <br>
![](docs/images/discriminator-demo.gif)
- Code samples support (via vendor extension) <br>
![](docs/images/code-samples-demo.gif)
## Releases
**Important:** all the 2.x releases are deployed to npm and can be used with Redocly-cdn:
- particular release, for example, `v2.0.0-rc.70`: https://cdn.redoc.ly/redoc/v2.0.0-rc.70/bundles/redoc.standalone.js
- `latest` release: https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js
Additionally, all the 1.x releases are hosted on our GitHub Pages-based CDN **(deprecated)**:
- particular release, for example `v1.2.0`: https://rebilly.github.io/ReDoc/releases/v1.2.0/redoc.min.js
- `v1.x.x` release: https://rebilly.github.io/ReDoc/releases/v1.x.x/redoc.min.js
- `latest` release: https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js - it will point to latest 1.x.x release since 2.x releases are not hosted on this CDN but on unpkg.
## Version Guidance
| Redoc Release | OpenAPI Specification |
|:--------------|:----------------------|
| 2.0.0-alpha.54| 3.1, 3.0.x, 2.0 |
| 2.0.0-alpha.x | 3.0, 2.0 |
| 1.19.x | 2.0 |
| 1.18.x | 2.0 |
| 1.17.x | 2.0 |
- [Reference docs](https://redocly.com/docs/api-reference-docs/getting-started/) - we take care of the hosting
- [Redoc](https://redocly.com/docs/redoc/) - detailed documentation for this open source project (also in the `docs/` folder)
- [Command-line interface to bundle your docs into a web-ready HTML file](https://redocly.com/docs/cli/commands/build-docs/)
- API linting, bundling, and much more with open source [Redocly CLI](https://redocly.com/docs/cli)
## Showcase
A sample of the organizations using Redocly tools in the wild:
- [Rebilly](https://api-reference.rebilly.com/)
- [Docker Engine](https://docs.docker.com/engine/api/v1.25/)
- [Zuora](https://www.zuora.com/developer/api-reference/)
@ -128,202 +102,43 @@ Additionally, all the 1.x releases are hosted on our GitHub Pages-based CDN **(d
- [Commbox](https://www.commbox.io/api/)
- [APIs.guru](https://apis.guru/api-doc/)
- [BoxKnight](https://www.docs.boxknight.com/)
- [Quaderno API](https://developers.quaderno.io/api)
## Lint OpenAPI definitions
Redocly's CLI is an [open source command-line tool](https://github.com/Redocly/redocly-cli) that you can use to lint
your OpenAPI definition. Linting helps you to catch errors and inconsistencies in your
OpenAPI definition before publishing.
Refer to [Redocly configuration](https://redocly.com/docs/cli/configuration/) in the OpenAPI documentation for more information.
## Deployment
### TL;DR final code example
To render your OpenAPI definition using Redoc, use the following HTML code sample and
replace the `spec-url` attribute with the url or local file address to your definition.
```html
<!DOCTYPE html>
<html>
<head>
<title>Redoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<!--
Redoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json'></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
</body>
</html>
```
For step-by-step instructions for how to get started using Redoc
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 CLI
For more information on Redoc's commmand-line interface, refer to
[**Using the Redoc CLI**](https://redocly.com/docs/redoc/deployment/cli/).
_Pull requests to add your own API page to the list are welcome_
## Configuration
### Security Definition location
You can inject the Security Definitions widget into any place in your definition `description`.
For more information, refer to [Security definitions injection](docs/security-definitions-injection.md).
Redoc is highly configurable, see the [configuration documentation](docs/config.md) for details.
### OpenAPI specification extensions
Redoc uses the following [specification extensions](https://redocly.com/docs/api-reference-docs/spec-extensions/):
* [`x-logo`](docs/redoc-vendor-extensions.md#x-logo) - is used to specify API logo
* [`x-traitTag`](docs/redoc-vendor-extensions.md#x-traitTag) - useful for handling out common things like Pagination, Rate-Limits, etc
* [`x-traitTag`](docs/redoc-vendor-extensions.md#x-traitTag) - useful for tags that refer to non-navigation properties like Pagination, Rate-Limits, etc
* [`x-codeSamples`](docs/redoc-vendor-extensions.md#x-codeSamples) - specify operation code samples
* [`x-badges`](docs/redoc-vendor-extensions.md#x-badges) - specify operation badges
* [`x-examples`](docs/redoc-vendor-extensions.md#x-examples) - specify JSON example for requests
* [`x-nullable`](docs/redoc-vendor-extensions.md#x-nullable) - mark schema param as a nullable
* [`x-displayName`](docs/redoc-vendor-extensions.md#x-displayname) - specify human-friendly names for the menu categories
* [`x-tagGroups`](docs/redoc-vendor-extensions.md#x-tagGroups) - group tags by categories in the side menu
* [`x-servers`](docs/redoc-vendor-extensions.md#x-servers) - ability to specify different servers for API (backported from OpenAPI 3.0)
* [`x-ignoredHeaderParameters`](docs/redoc-vendor-extensions.md#x-ignoredHeaderParameters) - ability to specify header parameter names to ignore
* [`x-additionalPropertiesName`](docs/redoc-vendor-extensions.md#x-additionalPropertiesName) - ability to supply a descriptive name for the additional property keys
* [`x-summary`](docs/redoc-vendor-extensions.md#x-summary) - For Response object, use as the response button text, with description rendered under the button
* [`x-extendedDiscriminator`](docs/redoc-vendor-extensions.md#x-extendedDiscriminator) - In Schemas, uses this to solve name-clash issues with the standard discriminator
* [`x-explicitMappingOnly`](docs/redoc-vendor-extensions.md#x-explicitMappingOnly) - In Schemas, display a more descriptive property name in objects with additionalProperties when viewing the property list with an object
* [`x-summary`](docs/redoc-vendor-extensions.md#x-summary) - for Response object, use as the response button text, with description rendered under the button
* [`x-explicitMappingOnly`](docs/redoc-vendor-extensions.md#x-explicitMappingOnly) - in Schemas, display a more descriptive property name in objects with additionalProperties when viewing the property list with an object
### `<redoc>` options object
You can use all of the following options with the standalone version of the <redoc> tag by kebab-casing them. For example, `scrollYOffset` becomes `scroll-y-offset`, and `expandResponses` becomes `expand-responses`.
## Releases
* `disableSearch` - disable search indexing and search box.
* `minCharacterLengthToInitSearch` - set minimal characters length to init search, default `3`, minimal `1`.
* `expandDefaultServerVariables` - enable expanding default server variables, default `false`.
* `expandResponses` - specify which responses to expand by default by response codes. Values should be passed as comma-separated list without spaces e.g. `expandResponses="200,201"`. Special value `"all"` expands all responses by default. Be careful: this option can slow-down documentation rendering time.
* `generatedPayloadSamplesMaxDepth` - set the maximum render depth for JSON payload samples (responses and request body). The default value is `10`.
* `maxDisplayedEnumValues` - display only specified number of enum values. hide rest values under spoiler.
* `hideDownloadButton` - do not show "Download" spec button. **THIS DOESN'T MAKE YOUR SPEC PRIVATE**, it just hides the button.
* `downloadFileName` - set a custom file name for the downloaded API definition file.
* `downloadDefinitionUrl` - If the 'Download' button is visible in the API reference documentation (hideDownloadButton=false), the URL configured here will open when that button is selected. Provide it as an absolute URL with the full URI scheme.
* `hideHostname` - if set, the protocol and hostname is not shown in the operation definition.
* `hideLoading` - do not show loading animation. Useful for small docs.
* `hideFab` - do not show FAB in mobile view. Useful for implementing a custom floating action button.
* `hideSchemaPattern` - if set, the pattern is not shown in the schema.
* `hideSingleRequestSampleTab` - do not show the request sample tab for requests with only one sample.
* `showObjectSchemaExamples` - show object schema example in the properties, default `false`.
* `expandSingleSchemaField` - automatically expand single field in a schema
* `schemaExpansionLevel` - specifies whether to automatically expand schemas. Special value `"all"` expands all levels. The default value is `0`.
* `jsonSampleExpandLevel` - set the default expand level for JSON payload samples (responses and request body). Special value `"all"` expands all levels. The default value is `2`.
* `hideSchemaTitles` - do not display schema `title` next to to the type
* `simpleOneOfTypeLabel` - show only unique oneOf types in the label without titles
* `sortEnumValuesAlphabetically` - set to true, sorts all enum values in all schemas alphabetically
* `sortOperationsAlphabetically` - set to true, sorts operations in the navigation sidebar and in the middle panel alphabetically
* `sortTagsAlphabetically` - set to true, sorts tags in the navigation sidebar and in the middle panel alphabetically
* `lazyRendering` - _Not implemented yet_ ~~if set, enables lazy rendering mode in ReDoc. This mode is useful for APIs with big number of operations (e.g. > 50). In this mode ReDoc shows initial screen ASAP and then renders the rest operations asynchronously while showing progress bar on the top. Check out the [demo](\\redocly.github.io/redoc) for the example.~~
* `menuToggle` - if true clicking second time on expanded menu item will collapse it, default `true`.
* `nativeScrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs).
* `onlyRequiredInSamples` - shows only required fields in request samples.
* `pathInMiddlePanel` - show path link and HTTP verb in the middle panel instead of the right one.
* `requiredPropsFirst` - show required properties first ordered in the same order as in `required` array.
* `scrollYOffset` - If set, specifies a vertical scroll-offset. This is often useful when there are fixed positioned elements at the top of the page, such as navbars, headers etc;
`scrollYOffset` can be specified in various ways:
* **number**: A fixed number of pixels to be used as offset.
* **selector**: selector of the element to be used for specifying the offset. The distance from the top of the page to the element's bottom will be used as offset.
* **function**: A getter function. Must return a number representing the offset (in pixels).
* `showExtensions` - show vendor extensions ("x-" fields). Extensions used by ReDoc are ignored. Can be boolean or an array of `string` with names of extensions to display.
* `sortPropsAlphabetically` - sort properties alphabetically.
* `payloadSampleIdx` - if set, payload sample will be inserted at this index or last. Indexes start from 0.
* `theme` - ReDoc theme. For details check [theme docs](#redoc-theme-object).
* `untrustedSpec` - if set, the spec is considered untrusted and all HTML/markdown is sanitized to prevent XSS. **Disabled by default** for performance reasons. **Enable this option if you work with untrusted user data!**
* `nonce` - if set, the provided value will be injected in every injected HTML element in the `nonce` attribute. Useful when using CSP, see https://webpack.js.org/guides/csp/.
* `sideNavStyle` - can be specified in various ways:
* **summary-only**: displays a summary in the sidebar navigation item. (**default**)
* **path-only**: displays a path in the sidebar navigation item.
* **id-only**: displays the operation id with a fallback to the path in the sidebar navigation item.
* `showWebhookVerb` - when set to `true`, shows the HTTP request method for webhooks in operations and in the sidebar.
**The README for the `1.x` version is on the [v1.x](https://github.com/Redocly/redoc/tree/v1.x) branch.**
All the 2.x releases are deployed to npm and can be used with Redocly-cdn:
- particular release, for example, `v2.0.0`: https://cdn.redoc.ly/redoc/v2.0.0/bundles/redoc.standalone.js
- `latest` release: https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js
Additionally, all the 1.x releases are hosted on our GitHub Pages-based CDN **(deprecated)**:
- particular release, for example `v1.2.0`: https://rebilly.github.io/ReDoc/releases/v1.2.0/redoc.min.js
- `v1.x.x` release: https://rebilly.github.io/ReDoc/releases/v1.x.x/redoc.min.js
- `latest` release: https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js - points to latest 1.x.x release since 2.x releases are not hosted on this CDN but on unpkg.
### `<redoc>` theme object
* `spacing`
* `unit`: 5 # main spacing unit used in autocomputed theme values later
* `sectionHorizontal`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `sectionVertical`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `breakpoints` # breakpoints for switching three/two and mobile view layouts
* `small`: '50rem'
* `medium`: '85rem'
* `large`: '105rem'
* `colors`
* `tonalOffset`: 0.3 # default tonal offset used in computations
* `typography`
* `fontSize`: '14px'
* `lineHeight`: '1.5em'
* `fontWeightRegular`: '400'
* `fontWeightBold`: '600'
* `fontWeightLight`: '300'
* `fontFamily`: 'Roboto, sans-serif'
* `smoothing`: 'antialiased'
* `optimizeSpeed`: true
* `headings`
* `fontFamily`: 'Montserrat, sans-serif'
* `fontWeight`: '400'
* `lineHeight`: '1.6em'
* `code` # inline code styling
* `fontSize`: '13px'
* `fontFamily`: 'Courier, monospace'
* `lineHeight`: # COMPUTED: typography.lineHeight
* `fontWeight`: # COMPUTED: typography.fontWeightRegular
* `color`: '#e53935'
* `backgroundColor`: 'rgba(38, 50, 56, 0.05)'
* `wrap`: false # whether to break word for inline blocks (otherwise they can overflow)
* `links`
* `color`: # COMPUTED: colors.primary.main
* `visited`: # COMPUTED: typography.links.color
* `hover`: # COMPUTED: lighten(0.2 typography.links.color)
* `textDecoration`: 'auto'
* `hoverTextDecoration`: 'auto'
* `sidebar`
* `width`: '260px'
* `backgroundColor`: '#fafafa'
* `textColor`: '#333333'
* `activeTextColor`: # COMPUTED: theme.sidebar.textColor (if set by user) or theme.colors.primary.main
* `groupItems` # Group headings
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'uppercase'
* `level1Items` # Level 1 items like tags or section 1st level items
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'none'
* `arrow` # sidebar arrow
* `size`: '1.5em'
* `color`: # COMPUTED: theme.sidebar.textColor
* `logo`
* `maxHeight`: # COMPUTED: sidebar.width
* `maxWidth`: # COMPUTED: sidebar.width
* `gutter`: '2px' # logo image padding
* `rightPanel`
* `backgroundColor`: '#263238'
* `width`: '40%'
* `textColor`: '#ffffff'
* `servers`
* `overlay`
* `backgroundColor`: '#fafafa'
* `textColor`: '#263238'
* `url`
* `backgroundColor`: '#fff'
* `fab`
* `backgroundColor`: '#263238'
* `color`: '#ffffff'
-----------
## Development
see [CONTRIBUTING.md](.github/CONTRIBUTING.md)

View File

@ -1,4 +0,0 @@
*/
!index.js
!package.json
!README.md

View File

@ -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 []

View File

@ -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`.

View File

@ -1,2 +0,0 @@
features.openapi:
disableSearch: true

View File

@ -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');
});
});

View File

@ -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"}');
}
});
});

View File

@ -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');
});
});

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

View File

@ -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>

View File

@ -5,7 +5,7 @@
# npm i -g http-server
# http-server -p 8000 --cors
FROM node:12-alpine
FROM node:18-alpine
RUN apk update && apk add --no-cache git
@ -13,6 +13,7 @@ RUN apk update && apk add --no-cache git
WORKDIR /build
COPY package.json package-lock.json /build/
RUN npm ci --no-optional --ignore-scripts
RUN npm explore esbuild -- npm run postinstall
# copy only required for the build files
COPY src /build/src

20
cypress.config.ts Normal file
View File

@ -0,0 +1,20 @@
import { defineConfig } from 'cypress';
export default defineConfig({
fixturesFolder: false,
fileServerFolder: '.',
video: true,
projectId: 'z6eb6h',
viewportWidth: 1440,
viewportHeight: 720,
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./e2e/plugins/index.js')(on, config);
},
excludeSpecPattern: '*.js.map',
specPattern: 'e2e/integration/**/*.{js,jsx,ts,tsx}',
supportFile: false,
},
});

View File

@ -1,12 +0,0 @@
{
"ignoreTestFiles": "*.js.map",
"integrationFolder": "e2e/integration",
"pluginsFile": "e2e/plugins/index.js",
"fixturesFolder": false,
"supportFile": false,
"fileServerFolder": ".",
"video": true,
"projectId": "z6eb6h",
"viewportWidth": 1440,
"viewportHeight": 720
}

View File

@ -6,8 +6,8 @@
import * as React from 'react';
import styled from '../src/styled-components';
const DropDownItem = styled.li<{ active?: boolean }>`
${(props: any) => (props.active ? 'background-color: #eee' : '')};
const DropDownItem = styled.li<{ $active?: boolean }>`
${(props: any) => (props.$active ? 'background-color: #eee' : '')};
padding: 13px 16px;
&:hover {
background-color: #eee;
@ -183,7 +183,7 @@ export default class ComboBox extends React.Component<ComboBoxProps, ComboBoxSta
renderOption = (option: { value: string; label: string }, idx: number) => {
return (
<DropDownItem
active={idx === this.state.activeItemIdx}
$active={idx === this.state.activeItemIdx}
key={option.value}
// tslint:disable-next-line
onMouseDown={() => {

View File

@ -1,16 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>ReDoc Interactive Demo</title>
<meta name="description" content="ReDoc Interactive Demo. OpenAPI/Swagger-generated API Reference Documentation" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Redoc Interactive Demo</title>
<meta
name="description"
content="Redoc Interactive Demo. OpenAPI-generated API Reference Documentation"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:title" content="ReDoc Interactive Demo">
<meta property="og:description" content="ReDoc Interactive Demo. OpenAPI/Swagger-generated API Reference Documentation">
<meta property="og:image" content="https://user-images.githubusercontent.com/3975738/37729752-8a9ea38a-2d46-11e8-8438-42ed26bf1751.png">
<meta name="twitter:card" content="summary_large_image">
<meta property="og:title" content="Redoc Interactive Demo" />
<meta
property="og:description"
content="Redoc Interactive Demo. OpenAPI-generated API Reference Documentation"
/>
<meta
property="og:image"
content="https://user-images.githubusercontent.com/3975738/37729752-8a9ea38a-2d46-11e8-8438-42ed26bf1751.png"
/>
<meta name="twitter:card" content="summary_large_image" />
<style>
body {
@ -22,7 +30,10 @@
display: block;
}
</style>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
</head>
<body>
@ -30,10 +41,17 @@
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
i['GoogleAnalyticsObject'] = r;
(i[r] =
i[r] ||
function () {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
if (window.location.host === 'rebilly.github.io') {
@ -42,5 +60,4 @@
}
</script>
</body>
</html>

View File

@ -1,15 +1,16 @@
import * as React from 'react';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import styled from 'styled-components';
import { RedocStandalone } from '../src';
import ComboBox from './ComboBox';
import FileInput from './components/FileInput';
const DEFAULT_SPEC = 'openapi.yaml';
const NEW_VERSION_SPEC = 'openapi-3-1.yaml';
const DEFAULT_SPEC = 'museum.yaml';
const NEW_VERSION_PETSTORE = 'openapi-3-1.yaml';
const demos = [
{ value: NEW_VERSION_SPEC, label: 'Petstore OpenAPI 3.1' },
{ value: DEFAULT_SPEC, label: 'Museum API' },
{ value: NEW_VERSION_PETSTORE, label: 'Petstore OpenAPI 3.1' },
{ value: 'https://api.apis.guru/v2/specs/instagram.com/1.0.0/swagger.yaml', label: 'Instagram' },
{
value: 'https://api.apis.guru/v2/specs/googleapis.com/calendar/v3/openapi.yaml',
@ -17,7 +18,6 @@ const demos = [
},
{ value: 'https://api.apis.guru/v2/specs/slack.com/1.7.0/openapi.yaml', label: 'Slack' },
{ value: 'https://api.apis.guru/v2/specs/zoom.us/2.0.0/openapi.yaml', label: 'Zoom.us' },
{ value: 'https://docs.graphhopper.com/openapi.json', label: 'GraphHopper' },
];
class DemoApp extends React.Component<
@ -55,7 +55,7 @@ class DemoApp extends React.Component<
};
handleChange = (url: string) => {
if (url === NEW_VERSION_SPEC) {
if (url === NEW_VERSION_PETSTORE) {
this.setState({ cors: false });
0;
}
@ -86,7 +86,7 @@ class DemoApp extends React.Component<
let proxiedUrl = specUrl;
if (specUrl !== DEFAULT_SPEC) {
proxiedUrl = cors
? '\\\\cors.redoc.ly/' + new URL(specUrl, window.location.href).href
? 'https://cors.redoc.ly/' + new URL(specUrl, window.location.href).href
: specUrl;
}
return (
@ -94,7 +94,7 @@ class DemoApp extends React.Component<
<Heading>
<a href=".">
<Logo
src="https://github.com/Redocly/redoc/raw/main/docs/images/redoc-logo.png"
src="https://github.com/Redocly/redoc/raw/main/docs/images/redoc.png"
alt="Redoc logo"
/>
</a>
@ -122,7 +122,7 @@ class DemoApp extends React.Component<
<RedocStandalone
spec={this.state.spec}
specUrl={proxiedUrl}
options={{ scrollYOffset: 'nav', untrustedSpec: true }}
options={{ scrollYOffset: 'nav', sanitize: true }}
/>
</>
);
@ -179,7 +179,9 @@ const Logo = styled.img`
}
`;
render(<DemoApp />, document.getElementById('container'));
const container = document.getElementById('container');
const root = createRoot(container!);
root.render(<DemoApp />);
/* ====== Helpers ====== */
function updateQueryStringParameter(uri, key, value) {

BIN
demo/museum-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

787
demo/museum.yaml Normal file
View File

@ -0,0 +1,787 @@
openapi: 3.1.0
info:
title: Redocly Museum API
description: An imaginary, but delightful Museum API for interacting with museum services and information. Built with love by Redocly.
version: 1.0.0
contact:
email: team@redocly.com
url: 'https://redocly.com/docs/cli/'
x-logo:
url: 'https://redocly.github.io/redoc/museum-logo.png'
altText: Museum logo
license:
name: MIT
url: 'https://opensource.org/license/mit/ '
servers:
- url: 'https://api.fake-museum-example.com/v1'
paths:
/museum-hours:
get:
summary: Get museum hours
description: Get upcoming museum operating hours
operationId: getMuseumHours
tags:
- Operations
x-badges:
- name: 'Beta'
position: before
color: purple
parameters:
- $ref: '#/components/parameters/StartDate'
- $ref: '#/components/parameters/PaginationPage'
- $ref: '#/components/parameters/PaginationLimit'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/GetMuseumHoursResponse'
examples:
default:
summary: Museum opening hours
value:
- date: '2023-09-11'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-12'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-13'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-17'
timeOpen: '09:00'
timeClose: '18:00'
closed:
summary: The museum is closed
value: []
'400':
description: Bad request
'404':
description: Not found
/special-events:
post:
security: []
operationId: CreateSpecialEvent
summary: Create special event
tags:
- Events
x-badges:
- name: 'Alpha'
color: purple
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSpecialEventRequest'
examples:
default_example:
$ref: '#/components/examples/CreateSpecialEventRequestExample'
responses:
'200':
description: success
content:
application/json:
schema:
$ref: '#/components/schemas/SpecialEventResponse'
examples:
default_example:
$ref: '#/components/examples/CreateSpecialEventResponseExample'
'400':
description: Bad request
'404':
description: Not found
get:
summary: List special events
description: Return a list of upcoming special events at the museum.
security: []
operationId: listSpecialEvents
x-badges:
- name: 'Gamma'
tags:
- Events
parameters:
- name: startDate
in: query
description: The starting date to retrieve future operating hours from. Defaults to today's date.
schema:
type: string
format: date
example: 2023-02-23
- name: endDate
in: query
description: The end of a date range to retrieve special events for. Defaults to 7 days after `startDate`.
schema:
type: string
format: date
example: 2023-04-18
- name: page
in: query
description: The page number to retrieve.
schema:
type: integer
default: 1
example: 2
- name: limit
in: query
description: The number of days per page.
schema:
type: integer
default: 10
maximum: 30
example: 15
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/ListSpecialEventsResponse'
examples:
default_example:
$ref: '#/components/examples/ListSpecialEventsResponseExample'
'400':
description: Bad request
'404':
description: Not found
/special-events/{eventId}:
get:
summary: Get special event
description: Get details about a special event.
operationId: getSpecialEvent
tags:
- Events
parameters:
- $ref: '#/components/parameters/EventId'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/SpecialEventResponse'
examples:
default_example:
$ref: '#/components/examples/GetSpecialEventResponseExample'
'400':
description: Bad request
'404':
description: Not found
patch:
summary: Update special event
description: Update the details of a special event
operationId: updateSpecialEvent
tags:
- Events
parameters:
- $ref: '#/components/parameters/EventId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateSpecialEventRequest'
examples:
default_example:
$ref: '#/components/examples/UpdateSpecialEventRequestExample'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/SpecialEventResponse'
examples:
default_example:
$ref: '#/components/examples/UpdateSpecialEventResponseExample'
'400':
description: Bad request
'404':
description: Not found
delete:
summary: Delete special event
description: Delete a special event from the collection. Allows museum to cancel planned events.
operationId: deleteSpecialEvent
tags:
- Events
parameters:
- $ref: '#/components/parameters/EventId'
responses:
'204':
description: Success - no content
'400':
description: Bad request
'401':
description: Unauthorized
'404':
description: Not found
/tickets:
post:
summary: Buy museum tickets
description: Purchase museum tickets for general entry or special events.
operationId: buyMuseumTickets
tags:
- Tickets
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BuyMuseumTicketsRequest'
examples:
general_entry:
$ref: '#/components/examples/BuyGeneralTicketsRequestExample'
event_entry:
$ref: '#/components/examples/BuyEventTicketsRequestExample'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/BuyMuseumTicketsResponse'
examples:
general_entry:
$ref: '#/components/examples/BuyGeneralTicketsResponseExample'
event_entry:
$ref: '#/components/examples/BuyEventTicketsResponseExample'
'400':
description: Bad request
'404':
description: Not found
/tickets/{ticketId}/qr:
get:
summary: Get ticket QR code
description: Return an image of your ticket with scannable QR code. Used for event entry.
operationId: getTicketCode
tags:
- Tickets
parameters:
- $ref: '#/components/parameters/TicketId'
responses:
'200':
description: Scannable event ticket in image format
content:
image/png:
schema:
$ref: '#/components/schemas/GetTicketCodeResponse'
'400':
description: Bad request
'404':
description: Not found
components:
schemas:
SpecialEvent:
description: Request payload for creating new special events at the museum.
properties:
name:
description: Name of the special event
type: string
example: Fossil lecture
location:
description: Location where the special event is held
type: string
example: Lecture theatre
eventDescription:
description: Description of the special event
type: string
example: Our panel of experts will share their favorite fossils and explain why they are so great.
dates:
description: List of planned dates for the special event
type: array
items:
type: string
format: date
example: 2024-03-29
price:
description: Price of a ticket for the special event
type: number
format: float
example: 12.50
TicketType:
description: Type of ticket being purchased. Use `general` for regular museum entry and `event` for tickets to special events.
type: string
enum:
- event
- general
x-enumDescriptions:
event: Special event ticket
general: General museum entry ticket
example: event
Date:
type: string
format: date
example: 2023-10-29
Email:
description: Email address for ticket purchaser.
type: string
format: email
example: museum-lover@example.com
Phone:
description: Phone number for the ticket purchaser (optional).
type: string
example: +1(234)-567-8910
BuyMuseumTicketsRequest:
description: Request payload used for purchasing museum tickets.
type: object
properties:
ticketType:
$ref: '#/components/schemas/TicketType'
eventId:
description: Unique identifier for a special event. Required if purchasing tickets for the museum's special events.
$ref: '#/components/schemas/EventId'
ticketDate:
description: Date that the ticket is valid for.
$ref: '#/components/schemas/Date'
email:
$ref: '#/components/schemas/Email'
phone:
$ref: '#/components/schemas/Phone'
required:
- ticketType
- ticketDate
- email
TicketMessage:
description: Confirmation message after a ticket purchase.
type: string
example: Museum general entry ticket purchased
TicketId:
description: Unique identifier for museum ticket. Generated when purchased.
type: string
format: uuid
example: a54a57ca-36f8-421b-a6b4-2e8f26858a4c
TicketConfirmation:
description: Unique confirmation code used to verify ticket purchase.
type: string
example: ticket-event-a98c8f-7eb12
BuyMuseumTicketsResponse:
description: Details for a museum ticket after a successful purchase.
type: object
properties:
message:
$ref: '#/components/schemas/TicketMessage'
eventName:
$ref: '#/components/schemas/EventName'
ticketId:
$ref: '#/components/schemas/TicketId'
ticketType:
$ref: '#/components/schemas/TicketType'
ticketDate:
description: Date the ticket is valid for.
$ref: '#/components/schemas/Date'
confirmationCode:
$ref: '#/components/schemas/TicketConfirmation'
required:
- message
- ticketId
- ticketType
- ticketDate
- confirmationCode
GetTicketCodeResponse:
description: An image of a ticket with a QR code used for museum or event entry.
type: string
format: binary
GetMuseumHoursResponse:
description: List of museum operating hours for consecutive days.
type: array
items:
$ref: '#/components/schemas/MuseumDailyHours'
MuseumDailyHours:
description: Daily operating hours for the museum.
type: object
properties:
date:
description: Date the operating hours apply to.
$ref: '#/components/schemas/Date'
example: 2024-12-31
timeOpen:
type: string
pattern: '^([01]\d|2[0-3]):?([0-5]\d)$'
description: Time the museum opens on a specific date. Uses 24 hour time format (`HH:mm`).
example: 09:00
timeClose:
description: Time the museum closes on a specific date. Uses 24 hour time format (`HH:mm`).
type: string
pattern: '^([01]\d|2[0-3]):?([0-5]\d)$'
example: 18:00
required:
- date
- timeOpen
- timeClose
EventId:
description: Identifier for a special event.
type: string
format: uuid
example: 3be6453c-03eb-4357-ae5a-984a0e574a54
EventName:
type: string
description: Name of the special event
example: Pirate Coding Workshop
EventLocation:
type: string
description: Location where the special event is held
example: Computer Room
EventDescription:
type: string
description: Description of the special event
example: Captain Blackbeard shares his love of the C...language. And possibly Arrrrr (R lang).
EventDates:
type: array
items:
$ref: '#/components/schemas/Date'
description: List of planned dates for the special event
EventPrice:
description: Price of a ticket for the special event
type: number
format: float
example: 25
CreateSpecialEventRequest:
description: Request payload for creating new special events at the museum.
properties:
name:
$ref: '#/components/schemas/EventName'
location:
$ref: '#/components/schemas/EventLocation'
eventDescription:
$ref: '#/components/schemas/EventDescription'
dates:
$ref: '#/components/schemas/EventDates'
price:
$ref: '#/components/schemas/EventPrice'
required:
- name
- location
- eventDescription
- dates
- price
UpdateSpecialEventRequest:
description: Request payload for updating an existing special event. Only included fields are updated in the event.
properties:
name:
$ref: '#/components/schemas/EventName'
location:
$ref: '#/components/schemas/EventLocation'
eventDescription:
$ref: '#/components/schemas/EventDescription'
dates:
$ref: '#/components/schemas/EventDates'
price:
$ref: '#/components/schemas/EventPrice'
ListSpecialEventsResponse:
description: A list of upcoming special events
type: array
items:
$ref: '#/components/schemas/SpecialEventResponse'
SpecialEventResponse:
description: Information about a special event.
properties:
eventId:
$ref: '#/components/schemas/EventId'
name:
$ref: '#/components/schemas/EventName'
location:
$ref: '#/components/schemas/EventLocation'
eventDescription:
$ref: '#/components/schemas/EventDescription'
dates:
$ref: '#/components/schemas/EventDates'
price:
$ref: '#/components/schemas/EventPrice'
required:
- eventId
- name
- location
- eventDescription
- dates
- price
securitySchemes:
MuseumPlaceholderAuth:
type: http
scheme: basic
examples:
BuyGeneralTicketsRequestExample:
summary: General entry ticket
value:
ticketType: general
ticketDate: 2023-09-07
email: todd@example.com
BuyEventTicketsRequestExample:
summary: Special event ticket
value:
ticketType: general
eventId: dad4bce8-f5cb-4078-a211-995864315e39
ticketDate: 2023-09-05
email: todd@example.com
BuyGeneralTicketsResponseExample:
summary: General entry ticket
value:
message: Museum general entry ticket purchased
ticketId: 382c0820-0530-4f4b-99af-13811ad0f17a
ticketType: general
ticketDate: 2023-09-07
confirmationCode: ticket-general-e5e5c6-dce78
BuyEventTicketsResponseExample:
summary: Special event ticket
value:
message: Museum special event ticket purchased
ticketId: b811f723-17b2-44f7-8952-24b03e43d8a9
eventName: Mermaid Treasure Identification and Analysis
ticketType: event
ticketDate: 2023-09-05
confirmationCode: ticket-event-9c55eg-8v82a
CreateSpecialEventRequestExample:
summary: Create special event
value:
name: Mermaid Treasure Identification and Analysis
location: Under the seaaa 🦀 🎶 🌊.
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
price: 0
CreateSpecialEventResponseExample:
summary: Special event created
value:
eventId: dad4bce8-f5cb-4078-a211-995864315e39
name: Mermaid Treasure Identification and Analysis
location: Under the seaaa 🦀 🎶 🌊.
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
price: 30
GetSpecialEventResponseExample:
summary: Get special event
value:
eventId: 6744a0da-4121-49cd-8479-f8cc20526495
name: Time Traveler Tea Party
location: Temporal Tearoom
eventDescription: Sip tea with important historical figures.
dates:
- 2023-11-18
- 2023-11-25
- 2023-12-02
price: 60
ListSpecialEventsResponseExample:
summary: List of special events
value:
- eventId: f3e0e76e-e4a8-466e-ab9c-ae36c15b8e97
name: Sasquatch Ballet
location: Seattle... probably
eventDescription: They're big, they're hairy, but they're also graceful. Come learn how the biggest feet can have the lightest touch.
dates:
- 2023-12-15
- 2023-12-22
price: 40
- eventId: 2f14374a-9c65-4ee5-94b7-fba66d893483
name: Solar Telescope Demonstration
location: Far from the sun.
eventDescription: Look at the sun without going blind!
dates:
- 2023-09-07
- 2023-09-14
price: 50
- eventId: 6aaa61ba-b2aa-4868-b803-603dbbf7bfdb
name: Cook like a Caveman
location: Fire Pit on East side
eventDescription: Learn to cook on an open flame.
dates:
- 2023-11-10
- 2023-11-17
- 2023-11-24
price: 5
- eventId: 602b75e1-5696-4ab8-8c7a-f9e13580f910
name: Underwater Basket Weaving
location: Rec Center Pool next door.
eventDescription: Learn to weave baskets underwater.
dates:
- 2023-09-12
- 2023-09-15
price: 15
- eventId: dad4bce8-f5cb-4078-a211-995864315e39
name: Mermaid Treasure Identification and Analysis
location: Room Sea-12
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits — kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
price: 30
- eventId: 6744a0da-4121-49cd-8479-f8cc20526495
name: Time Traveler Tea Party
location: Temporal Tearoom
eventDescription: Sip tea with important historical figures.
dates:
- 2023-11-18
- 2023-11-25
- 2023-12-02
price: 60
- eventId: 3be6453c-03eb-4357-ae5a-984a0e574a54
name: Pirate Coding Workshop
location: Computer Room
eventDescription: Captain Blackbeard shares his love of the C...language. And possibly Arrrrr (R lang).
dates:
- 2023-10-29
- 2023-10-30
- 2023-10-31
price: 45
- eventId: 9d90d29a-2af5-4206-97d9-9ea9ceadcb78
name: Llama Street Art Through the Ages
location: Auditorium
eventDescription: Llama street art?! Alpaca my bags -- let's go!
dates:
- 2023-10-29
- 2023-10-30
- 2023-10-31
price: 45
- eventId: a3c7b2c4-b5fb-4ef7-9322-00a919864957
name: The Great Parrot Debate
location: Outdoor Amphitheatre
eventDescription: See leading parrot minds discuss important geopolitical issues.
dates:
- 2023-11-03
- 2023-11-10
price: 35
- eventId: b92d46b7-4c5d-422b-87a5-287767e26f29
name: Eat a Bunch of Corn
location: Cafeteria
eventDescription: We accidentally bought too much corn. Please come eat it.
dates:
- 2023-11-10
- 2023-11-17
- 2023-11-24
price: 5
UpdateSpecialEventRequestExample:
summary: Update special event request
value:
location: On the beach.
price: 15
UpdateSpecialEventResponseExample:
summary: Update special event
value:
eventId: dad4bce8-f5cb-4078-a211-995864315e39
name: Mermaid Treasure Identification and Analysis
location: On the beach.
eventDescription: Join us as we review and classify a rare collection of 20 thingamabobs, gadgets, gizmos, whoosits, and whatsits, kindly donated by Ariel.
dates:
- 2023-09-05
- 2023-09-08
price: 15
GetMuseumHours:
summary: Museum opening hours
value:
- date: '2023-09-11'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-12'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-13'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-14'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-15'
timeOpen: '10:00'
timeClose: '16:00'
- date: '2023-09-18'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-19'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-20'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-21'
timeOpen: '09:00'
timeClose: '18:00'
- date: '2023-09-22'
timeOpen: '10:00'
timeClose: '16:00'
ClosedMuseumHours:
summary: The museum is closed
value: []
parameters:
PaginationPage:
name: page
in: query
description: The page number to retrieve.
schema:
type: integer
default: 1
example: 2
PaginationLimit:
name: limit
in: query
description: The number of days per page.
schema:
type: integer
default: 10
maximum: 30
example: 15
EventId:
name: eventId
in: path
description: An identifier for a special event.
required: true
schema:
type: string
format: uuid
example: dad4bce8-f5cb-4078-a211-995864315e39
StartDate:
name: startDate
in: query
description: The starting date to retrieve future operating hours from. Defaults to today's date.
schema:
type: string
format: date
example: 2023-02-23
EndDate:
name: endDate
in: query
description: The end of a date range to retrieve special events for. Defaults to 7 days after `startDate`.
schema:
type: string
format: date
example: 2023-04-18
TicketId:
name: ticketId
in: path
description: An identifier for a ticket to a museum event. Used to generate ticket image.
required: true
schema:
type: string
format: uuid
example: a54a57ca-36f8-421b-a6b4-2e8f26858a4c
tags:
- name: Operations
x-displayName: About the museum
description: Operational information about the museum.
- name: Events
x-displayName: Upcoming events
description: Special events hosted by the Museum.
- name: Tickets
x-displayName: Buy tickets
description: Museum tickets for general entrance or special events.
x-tagGroups:
- name: Plan your visit
tags:
- Operations
- Events
- name: Purchases
tags:
- Tickets
- name: Entities
tags:
- Schemas
security:
- MuseumPlaceholderAuth: []

View File

@ -88,6 +88,8 @@ x-tagGroups:
tags:
- pet_model
- store_model
security:
- {}
paths:
/pet:
parameters:
@ -803,11 +805,17 @@ paths:
parameters:
- name: username
in: path
description: name that need to be deleted
description: name that need to be updated
required: true
schema:
type: string
responses:
'200':
description: User is updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Invalid user supplied
'404':
@ -833,6 +841,8 @@ paths:
schema:
type: string
responses:
'204':
description: User is deleted
'400':
description: Invalid username supplied
'404':
@ -1129,6 +1139,7 @@ components:
type: [string, integer, 'null']
minItems: 1
maxItems: 10
default: []
xml:
name: photoUrl
wrapped: true

View File

@ -83,6 +83,8 @@ x-tagGroups:
tags:
- pet_model
- store_model
security:
- {}
paths:
/pet:
parameters:
@ -104,6 +106,10 @@ paths:
post:
tags:
- pet
x-badges:
- name: 'Beta'
position: before
color: purple
summary: Add a new pet to the store
description: Add new pet to the store inventory.
operationId: addPet
@ -148,6 +154,9 @@ paths:
put:
tags:
- pet
x-badges:
- name: 'Alpha'
color: purple
summary: Update an existing pet
description: ''
operationId: updatePet
@ -181,6 +190,8 @@ paths:
get:
tags:
- pet
x-badges:
- name: 'Gamma'
summary: Find pet by ID
description: Returns a single pet
operationId: getPetById
@ -908,6 +919,7 @@ components:
message:
type: string
Cat:
'x-tags': ['pet']
description: A representation of a cat
allOf:
- $ref: '#/components/schemas/Pet'
@ -1044,6 +1056,7 @@ components:
photoUrls:
description: The list of URL to a cute photos featuring pet
type: array
default: []
maxItems: 20
xml:
name: photoUrl
@ -1070,6 +1083,10 @@ components:
- available
- pending
- sold
x-enumDescriptions:
available: Available status
pending: Pending status
sold: Sold status
petType:
description: Type of a pet
type: string
@ -1173,6 +1190,7 @@ components:
name:
type: string
description: hooray
default: []
description: Pet object that needs to be added to the store
required: true
UserArray:

View File

@ -1,7 +1,7 @@
import * as React from 'react';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import type { RedocRawOptions } from '../../src/services/RedocNormalizedOptions';
import RedocStandalone from './hot';
import { RedocStandalone } from '../../src';
const big = window.location.search.indexOf('big') > -1;
const swagger = window.location.search.indexOf('swagger') > -1;
@ -9,8 +9,14 @@ const swagger = window.location.search.indexOf('swagger') > -1;
const userUrl = window.location.search.match(/url=(.*)$/);
const specUrl =
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
(userUrl && userUrl[1]) || (swagger ? 'museum.yaml' : big ? 'big-openapi.json' : 'museum.yaml');
const options: RedocRawOptions = { nativeScrollbars: false, maxDisplayedEnumValues: 3 };
const options: RedocRawOptions = {
nativeScrollbars: false,
maxDisplayedEnumValues: 3,
schemaDefinitionsTagName: 'schemas',
};
render(<RedocStandalone specUrl={specUrl} options={options} />, document.getElementById('example'));
const container = document.getElementById('example');
const root = createRoot(container!);
root.render(<RedocStandalone specUrl={specUrl} options={options} />);

View File

@ -1,10 +0,0 @@
import * as React from 'react';
// eslint-disable-next-line import/no-internal-modules
import { hot } from 'react-hot-loader/root';
import { RedocStandalone as RedocStandaloneOrig, RedocStandaloneProps } from '../../src';
const RedocStandalone = function (props: RedocStandaloneProps) {
return <RedocStandaloneOrig {...props} />;
}
export default hot(RedocStandalone);

View File

@ -1,10 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ReDoc</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Redoc</title>
<style>
body {
margin: 0;
@ -15,11 +14,13 @@
display: block;
}
</style>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
</head>
<body>
<redoc id="example"></redoc>
</body>
</html>

View File

@ -780,6 +780,7 @@ definitions:
photoUrls:
description: The list of URL to a cute photos featuring pet
type: array
default: []
xml:
name: photoUrl
wrapped: true

View File

@ -14,7 +14,7 @@ function root(filename) {
return resolve(__dirname + '/' + filename);
}
export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) => ({
export default (env: { playground?: boolean; bench?: boolean } = {}) => ({
entry: [
root('../src/polyfills.ts'),
root(
@ -51,12 +51,6 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
fs: false,
os: false,
},
alias:
mode !== 'production'
? {
'react-dom': '@hot-loader/react-dom',
}
: {},
},
performance: false,
@ -76,7 +70,6 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
test: /\.(tsx?|[cm]?js)$/,
loader: 'esbuild-loader',
options: {
loader: 'tsx',
target: 'es2015',
tsconfigRaw: require('../tsconfig.json'),
},
@ -90,7 +83,6 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
{
loader: 'esbuild-loader',
options: {
loader: 'css',
minify: true,
},
},
@ -123,7 +115,7 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
webpackIgnore(/json-schema-ref-parser\/lib\/dereference\.js/),
webpackIgnore(/^\.\/SearchWorker\.worker$/),
new CopyWebpackPlugin({
patterns: ['demo/openapi.yaml'],
patterns: ['demo/museum.yaml'],
}),
],
});

311
docs/config.md Normal file
View File

@ -0,0 +1,311 @@
# Configure Redoc
Getting your documentation just right is important, and Redoc comes with many configuration options to help you succeed in that mission.
Each deployment type has documentation on how to configure options for that type of Redoc project. This page lists all the options you can use with Redoc.
**Versions: 2.x**
{% admonition type="success" name="Client-side configuration" %}
Using Redoc as a standalone (HTML or React) tool, these options must be presented in [kebab case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case).
For example, `scrollYOffset` becomes `scroll-y-offset`, and `expandResponses` becomes `expand-responses`.
{% /admonition %}
## Functional settings
### disableSearch
Disables search indexing and hides the search box from the API documentation page.
### minCharacterLengthToInitSearch
Sets the minimum amount of characters that need to be typed into the search dialog to initiate the search.
_Default: 3_
### hideDownloadButtons
Hides the 'Download' button for saving the API definition source file. **This setting does not make the API definition private**; it just hides the button.
### hideLoading
Hides the loading animation. Does not apply to CLI or Workflows-rendered docs.
### hideSchemaTitles
Hides the schema title next to to the type.
### jsonSamplesExpandLevel
Sets the default expand level for JSON payload samples (response and request body). The default value is 2, and the maximum supported value is '+Infinity'. It can also be configured as a string with the special value `all` that expands all levels.
_Default: 2_
### maxDisplayedEnumValues
Displays only the specified number of enum values. The remaining values are hidden in an expandable area. If not set, all values are displayed.
### onlyRequiredInSamples
Shows only required fields in request samples.
### sortRequiredPropsFirst
Shows required properties in schemas first, ordered in the same order as in the required array.
### schemasExpansionLevel
Specifies whether to automatically expand schemas in Reference docs. Set it to `all` to expand all schemas regardless of their level, or set it to a number to expand schemas up to the specified level. For example, `schemasExpansionLevel: 3` expands schemas up to three levels deep. The default value is `0`, meaning no schemas are expanded automatically.
### scrollYOffset
Specifies a vertical scroll-offset.
This setting is useful when there are fixed positioned elements at the top of the page, such as navbars, headers, etc.
Note that you can specify the `scrollYOffset` value in any of the following ways:
- as a number - a fixed number of pixels to be used as the offset.
- as a CSS selector - the selector of the element to be used for specifying the offset. The distance from the top of the page to the element's bottom is used as the offset.
- a function (advanced) - a getter function. Must return a number representing the offset (in pixels).
### showExtensions
Shows specification extensions ('x-' fields). Extensions used by Redoc are ignored. The value can be boolean or an array of strings with names of extensions to display. When used as boolean and set to `true`, all specification extensions are shown.
### sanitize
If set to `true`, the API definition is considered untrusted and all HTML/Markdown is sanitized to prevent XSS.
### downloadUrls
Set the URLs used to download the OpenAPI description or other documentation related files from the API documentation page.
### schemaDefinitionsTagName
If a value is set, all of the schemas are rendered with the designated tag name. The schemas then render and display in the sidebar navigation (with that associated tag name).
### generatedSamplesMaxDepth
The generatedSamplesMaxDepth option controls how many schema levels automatically generated for payload samples. The default is 8 which works well for most APIs, but you can adjust it if necessary for your use case.
### hidePropertiesPrefix
In complex data structures or object schemas where properties are nested within parent objects the hidePropertiesPrefix option enables the hiding of parent names for nested properties within the documentation.
_Default: true_
## Deprecated Functional settings
### hideDownloadButton
Hides the 'Download' button for saving the API definition source file. **This setting does not make the API definition private**; it just hides the button.
### downloadFileName
Sets the filename for the downloaded API definition source file.
### downloadDefinitionUrl
Sets the URL for the downloaded API definition source file.
### requiredPropsFirst
Shows required properties in schemas first, ordered in the same order as in the required array.
### jsonSampleExpandLevel
Sets the default expand level for JSON payload samples (response and request body). The default value is 2, and the maximum supported value is '+Infinity'. It can also be configured as a string with the special value `all` that expands all levels.
_Default: 2_
### schemaExpansionLevel
Specifies whether to automatically expand schemas in Reference docs. Set it to `all` to expand all schemas regardless of their level, or set it to a number to expand schemas up to the specified level. For example, `schemaExpansionLevel: 3` expands schemas up to three levels deep. The default value is `0`, meaning no schemas are expanded automatically.
### expandDefaultServerVariables
Enables or disables expanding default server variables.
### expandResponses
Controls which responses to expand by default. Specify one or more responses by providing their response codes as a comma-separated list without spaces, for example `expandResponses='200,201'`. Special value 'all' expands all responses by default. Be careful: this option can slow down documentation rendering time.
### expandSingleSchemaField
Automatically expands the single field in a schema.
### hideHostname
If set to `true`, the protocol and hostname are not shown in the operation definition.
### hideRequestPayloadSample
Hides request payload examples.
### hideOneOfDescription
If set to `true`, the description for `oneOf`/`anyOf` object is not shown in the schema.
### hideSchemaPattern
If set to `true`, the pattern is not shown in the schema.
### hideSecuritySection
Hides the Security panel section.
### hideSingleRequestSampleTab
Hides the request sample tab for requests with only one sample.
### menuToggle
If set to `true`, selecting an expanded item in the sidebar twice collapses it.
_Default: true_
### nativeScrollbars
If set to `true`, the sidebar uses the native scrollbar instead of perfect-scroll. This setting is a scrolling performance optimization for big API definitions.
### pathInMiddlePanel
Shows the path link and HTTP verb in the middle panel instead of the right panel.
### payloadSampleIdx
If set, the payload sample is inserted at the specified index. If there are `N` payload samples and the value configured here is bigger than `N`, the payload sample is inserted last. Indexes start from 0.
### showObjectSchemaExamples
Shows object schema example in the properties; default `false`.
### showWebhookVerb
When set to `true`, shows the HTTP request method for webhooks in operations and in the sidebar.
### simpleOneOfTypeLabel
Shows only unique `oneOf` types in the label without titles.
### sortEnumValuesAlphabetically
When set to `true`, sorts all enum values in all schemas alphabetically.
### sortOperationsAlphabetically
When set to `true`, sorts operations in the navigation sidebar and in the middle panel alphabetically.
### sortPropsAlphabetically
When set to `true`, sorts properties in all schemas alphabetically.
### sortTagsAlphabetically
When set to true, sorts tags in the navigation sidebar and in the middle panel alphabetically. Note that only tags are sorted alphabetically in the middle panel, not the operations associated with each tag. To sort operations alphabetically as well, you must set the `sortOperationsAlphabetically` setting to `true`.
_Default: false_
### untrustedSpec
If set to `true`, the API definition is considered untrusted and all HTML/Markdown is sanitized to prevent XSS.
## Theme settings
Change styles for the API documentation page. **Supported in Redoc CE 2.x**.
* `spacing`
* `unit`: 5 # main spacing unit used in autocomputed theme values later
* `sectionHorizontal`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `sectionVertical`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `breakpoints` # breakpoints for switching three/two and mobile view layouts
* `small`: '50rem'
* `medium`: '85rem'
* `large`: '105rem'
* `colors`
* `tonalOffset`: 0.3 # default tonal offset used in computations
* `typography`
* `fontSize`: '14px'
* `lineHeight`: '1.5em'
* `fontWeightRegular`: '400'
* `fontWeightBold`: '600'
* `fontWeightLight`: '300'
* `fontFamily`: 'Roboto, sans-serif'
* `smoothing`: 'antialiased'
* `optimizeSpeed`: true
* `headings`
* `fontFamily`: 'Montserrat, sans-serif'
* `fontWeight`: '400'
* `lineHeight`: '1.6em'
* `code` # inline code styling
* `fontSize`: '13px'
* `fontFamily`: 'Courier, monospace'
* `lineHeight`: # COMPUTED: typography.lineHeight
* `fontWeight`: # COMPUTED: typography.fontWeightRegular
* `color`: '#e53935'
* `backgroundColor`: 'rgba(38, 50, 56, 0.05)'
* `wrap`: false # whether to break word for inline blocks (otherwise they can overflow)
* `links`
* `color`: # COMPUTED: colors.primary.main
* `visited`: # COMPUTED: typography.links.color
* `hover`: # COMPUTED: lighten(0.2 typography.links.color)
* `textDecoration`: 'auto'
* `hoverTextDecoration`: 'auto'
* `sidebar`
* `width`: '260px'
* `backgroundColor`: '#fafafa'
* `textColor`: '#333333'
* `activeTextColor`: # COMPUTED: theme.sidebar.textColor (if set by user) or theme.colors.primary.main
* `groupItems` # Group headings
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'uppercase'
* `level1Items` # Level 1 items like tags or section 1st level items
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'none'
* `arrow` # sidebar arrow
* `size`: '1.5em'
* `color`: # COMPUTED: theme.sidebar.textColor
* `logo`
* `maxHeight`: # COMPUTED: sidebar.width
* `maxWidth`: # COMPUTED: sidebar.width
* `gutter`: '2px' # logo image padding
* `rightPanel`
* `backgroundColor`: '#263238'
* `width`: '40%'
* `textColor`: '#ffffff'
* `servers`
* `overlay`
* `backgroundColor`: '#fafafa'
* `textColor`: '#263238'
* `url`
* `backgroundColor`: '#fff'
* `fab`
* `backgroundColor`: '#263238'
* `color`: '#ffffff'
## Additional customization
### Security Definition location
You can inject the Security Definitions widget into any place in your definition `description`.
For more information, refer to [Security definitions injection](./security-definitions-injection.md).
### OpenAPI specification extensions
Redoc uses the following [specification extensions](https://redocly.com/docs-legacy/api-reference-docs/spec-extensions/):
* [`x-logo`](./redoc-vendor-extensions.md#x-logo) - is used to specify API logo
* [`x-traitTag`](./redoc-vendor-extensions.md#x-traittag) - useful for handling out common things like Pagination, Rate-Limits, etc
* [`x-codeSamples`](./redoc-vendor-extensions.md#x-codesamples) - specify operation code samples
* [`x-examples`](./redoc-vendor-extensions.md#x-examples) - specify JSON example for requests
* [`x-nullable`](./redoc-vendor-extensions.md#x-nullable) - mark schema param as a nullable
* [`x-displayName`](./redoc-vendor-extensions.md#x-displayname) - specify human-friendly names for the menu categories
* [`x-tagGroups`](./redoc-vendor-extensions.md#x-taggroups) - group tags by categories in the side menu
* [`x-servers`](./redoc-vendor-extensions.md#x-servers) - ability to specify different servers for API (backported from OpenAPI 3.0)
* [`x-additionalPropertiesName`](./redoc-vendor-extensions.md#x-additionalpropertiesname) - ability to supply a descriptive name for the additional property keys
* [`x-summary`](./redoc-vendor-extensions.md#x-summary) - For Response object, use as the response button text, with description rendered under the button
* [`x-explicitMappingOnly`](./redoc-vendor-extensions.md#x-explicitmappingonly) - In Schemas, display a more descriptive property name in objects with additionalProperties when viewing the property list with an object

View File

@ -1,114 +1,35 @@
---
seo:
title: Use the Redoc CLI
redirectFrom:
- /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
(made with Redoc) into a zero-dependency HTML file and locally render your
OpenAPI definition with Redoc.
With Redocly CLI, you can bundle your OpenAPI definition and API documentation
(made with Redoc) into an HTML file and render it locally.
## 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)
- [yarn](https://classic.yarnpkg.com/en/docs/getting-started)
You can install it [globally](../../cli/installation.md#install-globally) using npm or Yarn.
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](../../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 an HTML file.
To build an HTML file using Redocly CLI, enter the following command,
replacing `apis/openapi.yaml` with your API definition file's name and path:
```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:
```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 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
```
Also, check out [Redocly CLI commands](../../cli/commands/index.md), for more
information on the different things you can do with Redocly CLI including
linting, splitting, and bundling your API definition file.

View File

@ -1,7 +1,6 @@
---
seo:
title: Use the Redoc Docker image
redirectFrom:
- /docs/redoc/quickstart/docker/
---
# How to use the Redoc Docker image

View File

@ -1,123 +1,140 @@
---
seo:
title: Use the Redoc HTML element
redirectFrom:
- /docs/redoc/quickstart/html/
---
# How to use the Redoc HTML element
# Use Redoc in HTML
## Step 1 - Install Redoc
To render API documentation in an HTML page, start with the template below and
replace the `spec-url` value with the local file path or URL of your API
description.
You can install Redoc using one of the following package managers:
```html
<!DOCTYPE html>
<html>
<head>
<title>Redoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
- [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
<!--
Redoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json'></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
</body>
</html>
```
### Install Redoc with npm
{% admonition type="success" name="URL or local file" %}
Set `spec-url` to a relative path if the file is local, e.g. `spec-url=my-api.yaml`. Use a full URL like the example above if it's hosted elsewhere.
{% /admonition %}
After navigating to your project directory in your terminal, use the following command:
Open the HTML file in your browser to see the HTML documentation rendering. You may want to read the next section and add some configuration to make your documentation your own.
```bash
npm i redoc
## Configure Redoc
Redoc is highly configurable, find a [full list of configuration options](../config.md) on the dedicated page.
To configure Redoc in HTML, add the property names to the HTML tag. Here's an example that makes all the required properties display first in the list:
```html
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json' required-props-first=true></redoc>
```
## Step 2 - Reference the Redoc script
Any of the individual properties can be added to the tag, as many as you need to get your API docs set up as you like them.
### Theme configuration
The `theme` configuration setting is more complex since it represents many nested options, you can supply these as a JSON string to the `theme` attribute. For example, to change the sidebar color you would use a tag like this:
```html
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json'
required-props-first=true
theme='{
"sidebar": {
"backgroundColor": "lightblue"
}
}'
></redoc>
```
Check out the [list of options for theme configuration](../config.md#theme-settings) and build up the configuration that suits your API needs.
## Advanced options
### The Redoc object
As an alternative to the HTML tag, you can also initialise Redoc in a web page using the Redoc object and invoking it from JavaScript. This is useful for situations where you want to create dynamic content in a page, and also provides a simple way to attach the Redoc element to an existing container.
The Redoc object offers an `init` function:
```js
Redoc.init(specOrSpecUrl, options, element, callback)
```
- `specOrSpecUrl`: Either a JSON object with the OpenAPI definition or a file name/URL to the
definition in JSON or YAML format.
- `options`: See the [configuration reference](../config.md).
- `element`: DOM element Redoc is 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.
Call `Redoc.init()` from the JavaScript on a web page to add the element to the named container. Below is an example of an HTML page with a `<div>` tag, and the JavaScript to add the Redoc object to it.
```html
<!DOCTYPE html>
<html>
<head />
<body>
<H1>Redoc in action</H1>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
<div id="redoc-container"></div>
<script>
Redoc.init('http://petstore.swagger.io/v2/swagger.json', {
"expandResponses": "200,400"
}, document.getElementById('redoc-container'))
</script>
</body>
</html>
```
This example also sets the configuration for `expandResponses` so all 200 and 400 status responses are shown unfolded and with their details visible when the page loads.
### Self-host dependencies
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.
or install to your `node-modules` folder. Using the CDN is the simplest option, but
if you need to host in a closed environment or have requirements around external
dependencies, it may be useful to self-host.
### CDN link
To reference the Redoc script with a CDN link:
The main example shows using the CDN:
```html
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
```
### Node modules link
If you would instead prefer to host the depdencies yourself, first install `redoc` using `npm`:
To reference the Redoc script with a node modules link:
```sh
npm install redoc
```
_(Yarn users can install the `redoc` package with `yarn`)_.
You can then reference the Redoc script with a node modules link:
```html
<script src="node_modules/redoc/bundles/redoc.standalone.js"> </script>
```
## Step 3 - Add the <redoc> element
You can add the <redoc> 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.
### The `spec-url` attribute
To add the <redoc> element with the `spec-url` attribute:
```html
<redoc spec-url="url/to/your/spec"></redoc>
```
#### Examples
```html
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
```
You can also use a local file (JSON or YAML) in your project, for instance:
```html
<redoc spec-url="dist.json"></redoc>
```
### The Redoc object
To add the <redoc> 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 [features.openapi object](/docs/api-reference-docs/configuration/functionality.mdx) 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
<script>
Redoc.init('http://petstore.swagger.io/v2/swagger.json', {
scrollYOffset: 50
}, document.getElementById('redoc-container'))
</script>
```
You can also use a local file (JSON or YAML) in your project, for instance:
```html
<script>
Redoc.init('dist.yaml', {
scrollYOffset: 50
}, document.getElementById('redoc-container'))
</script>
```

View File

@ -1,7 +1,6 @@
---
seo:
title: Redoc deployment guide
redirectFrom:
- /docs/redoc/quickstart/intro/
---
# Redoc deployment guide
@ -12,7 +11,7 @@ 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.
The live demo offers a fast way to see how your OpenAPI renders with 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 **TRY IT**.
- **[HTML element](./html.md):**
@ -21,26 +20,26 @@ The following options are supported:
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.
- **[Redocly CLI](./cli.md):**
Using the Redocly CLI is an option for users who prefer to use a command-line interface.
## Before you start
### OpenAPI definition
You will need an OpenAPI definition. For testing purposes, you can use one of the following sample OpenAPI definitions:
You 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)
- [Museum Example API](https://github.com/Redocly/museum-openapi-example/blob/main/openapi.yaml)
- [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)
:::info OpenAPI specification
{% admonition type="info" name="OpenAPI specification" %}
For more information on the OpenAPI specification, refer to the [Learning OpenAPI 3](https://redocly.com/docs/resources/learning-openapi/)
section in the documentation.
:::
{% /admonition %}
### How to run Redoc locally
@ -55,7 +54,7 @@ If you have [Redocly CLI](https://redocly.com/docs/cli/#installation-and-usage)
project directory and run the following command:
```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.
@ -66,7 +65,7 @@ To exit the preview, use `control+C`.
You can alter the port if you are using 8080 already, for example:
```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.

View File

@ -1,7 +1,9 @@
---
seo:
title: Use the Redoc React component
redirectFrom:
- /docs/redoc/quickstart/react/
redirects:
'/docs/redoc/quickstart/react/':
to: '/docs/redoc/deployment/react/'
---
# How to use the Redoc React component
@ -71,7 +73,7 @@ is fully rendered or when an error occurs (with an error as the first argument).
```js
<RedocStandalone
specUrl="http://petstore.swagger.io/v2/swagger.json"
onLoaded={error => {
onLoaded={(error) => {
if (!error) {
console.log('Yay!');
}

97
docs/index.md Normal file
View File

@ -0,0 +1,97 @@
---
seo:
title: Redoc
---
# Redoc: Open source API documentation tool
Redoc is a clean and easy way to produce web-ready documentation from an OpenAPI description (Swagger is also still supported). With one command, create your documentation, and customize it to meet the needs of your users.
Redoc is based around a three panel layout, with clear sections for navigation, detailed documentation, and request/response examples.
## Headline features
* Modern layout with extensive customization options.
* Support for OpenAPI 3.1, 3.0 and older 2.0 and Swagger formats.
* Embed or build standalone HTML documentation.
* CLI tool for easy automation and local development.
## Demo
[Try the live demo](https://redocly.github.io/redoc/) and upload your own API specification there to try.
## Usage
Redoc is provided as a CLI tool (also distributed as a Docker image), HTML tag, and React component.
### Generate documentation from the CLI
If you have Node installed, quickly generate documentation using `npx`:
```sh
npx @redocly/cli build-docs openapi.yaml
```
The tool outputs by default to a file named `redoc-static.html` that you can open in your browser.
> [Redocly CLI](https://github.com/Redocly/redocly-cli/) does more than docs, check it out and add linting, bundling and more to your API workflow.
### Add an HTML element to the page
Create an HTML page, or edit an existing one, and add the following:
```html
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
```
Open the HTML file in your browser, and your API documentation is shown on the page.
Add your own `spec-url` to the `<redoc>` tag; this attribute can also be a local file. The JavaScript library can also be installed locally using `npm` and served from your own server, see the [HTML deployment documentation](https://redocly.com/docs/redoc/deployment/html/) for more details.
### More usage options
Check out the [deployment documentation](./deployment/intro.md) for more options, and detailed documentation for each.
## Configure Redoc
Redoc is highly configurable. Each deployment option accepts configuration in a way that's appropriate to that platform, but the options are the same for each. For example:
* Using [Redocly CLI](../cli/index.md), configuration goes in the `redocly.yaml` file, or can be supplied as command line parameters, such as `--theme.openapi.disableSearch`.
* Using HTML or React, configure by setting `option` in the tag.
Here's a sample `redocly.yaml` configuration file, showing a few common settings and tweaking some of the visual theme settings:
```yaml
theme:
openapi:
disableSearch: true
expandResponses: 200,202
jsonSamplesExpandLevel: 1
theme:
sidebar:
backgroundColor: '#eae0cc'
textColor: '#3d005b'
colors:
primary:
main: '#660099'
typography:
fontSize: 14pt
headings:
fontWeight: bold
```
Redocly CLI detects a file named `redocly.yaml` in the same directory as you run the command and uses it. See the documentation with a command like this:
```sh
redocly preview-docs openapi.yaml
```
There are many, many more options available. Visit the [configuration reference](./config.md) for a complete list.
## Next steps
* If you are new to OpenAPI, try the [OpenAPI starter project](../cli/openapi-starter.md) for a great introduction.
* Ready to build documentation from an existing OpenAPI file? Go to the [Redoc quickstart](./quickstart.md) and get started.
* Learn more about the project by visiting [Redoc on GitHub](https://github.com/Redocly/redoc).

View File

@ -1,4 +1,5 @@
---
seo:
title: Redoc quickstart guide
---
@ -43,12 +44,10 @@ replace the `spec-url` attribute with the URL or local file address to your defi
</html>
```
:::attention Redoc requires an HTTP server to run locally
{% admonition type="info" name="Redoc requires an HTTP server to run locally" %}
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. Refer to [Running Redoc locally](./deployment/intro.md#how-to-run-redoc-locally) for more information.
:::
{% /admonition %}
For a more detailed explanation with step-by-step instructions and additional options for using Redoc, refer to the [Redoc deployment guide](./deployment/intro.md).

View File

@ -1,56 +1,78 @@
# Redoc vendor extensions
You can use the following [vendor extensions](https://swagger.io/specification/#specificationExtensions) with Redoc.
You can use the following [vendor extensions](https://redocly.com/docs/openapi-visual-reference/specification-extensions/) with Redoc.
- [Redoc vendor extensions](#redoc-vendor-extensions)
- [Swagger Object](#swagger-object)
- [x-servers](#x-servers)
- [x-tagGroups](#x-taggroups)
- [Tag Group Object](#a-nametaggroupobjectatag-group-object)
- [x-ignoredHeaderParameters](#x-ignoredheaderparameters)
- [How to use with Redoc](#how-to-use-with-redoc)
- [Tag Group Object](#tag-group-object)
- [Fixed fields](#fixed-fields)
- [x-tagGroups example](#x-taggroups-example)
- [Info Object](#info-object)
- [x-logo](#x-logo)
- [Logo Object](#a-namelogoobjectalogo-object)
- [How to use with Redoc](#how-to-use-with-redoc-2)
- [Logo Object](#logo-object)
- [Fixed fields](#fixed-fields-1)
- [x-logo example](#x-logo-example)
- [Tag Object](#tag-object)
- [x-traitTag](#x-traittag)
- [How to use with Redoc](#how-to-use-with-redoc-3)
- [x-traitTag example](#x-traittag-example)
- [x-displayName](#x-displayname)
- [Operation Object](#operation-object-vendor-extensions)
- [Operation Object vendor extensions](#operation-object-vendor-extensions)
- [x-codeSamples](#x-codesamples)
- [Code Sample Object](#a-namecodesampleobjectacode-sample-object)
- [How to use with Redoc](#how-to-use-with-redoc-4)
- [Code Sample Object](#code-sample-object)
- [Fixed fields](#fixed-fields-2)
- [Code Sample Object example](#code-sample-object-example)
- [Parameter Object](#parameter-object)
- [x-examples](#x-examples)
- [How to use with Redoc](#how-to-use-with-redoc-5)
- [Response Object vendor extensions](#response-object-vendor-extensions)
- [x-summary](#x-summary)
- [How to use with Redoc](#how-to-use-with-redoc-6)
- [Schema Object](#schema-object)
- [x-nullable](#x-nullable)
- [x-extendedDiscriminator](#x-extendeddiscriminator)
- [How to use with Redoc](#how-to-use-with-redoc-7)
- [x-additionalPropertiesName](#x-additionalpropertiesname)
- [How to use with Redoc](#how-to-use-with-redoc-9)
- [x-additionalPropertiesName example](#x-additionalpropertiesname-example)
- [x-explicitMappingOnly](#x-explicitmappingonly)
- [How to use with Redoc](#how-to-use-with-redoc-10)
- [x-explicitMappingOnly example](#x-explicitmappingonly-example)
- [x-enumDescriptions](#x-enumdescriptions)
- [How to use with Redoc](#how-to-use-with-redoc-11)
- [x-enumDescriptions example](#x-enumdescriptions-example)
### Swagger Object
Extends the OpenAPI root [OpenAPI Object](https://swagger.io/specification/#oasObject)
## Swagger Object
Extends the OpenAPI root [OpenAPI Object](https://redocly.com/docs/openapi-visual-reference/openapi)
#### x-servers
Backported from OpenAPI 3.0 [`servers`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#serverObject). Currently doesn't support templates.
### x-servers
Backported from OpenAPI 3.0 [`servers`](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#server-object). Currently doesn't support templates.
#### x-tagGroups
### x-tagGroups
| Field Name | Type | Description |
| :------------- | :-----------: | :---------- |
| x-tagGroups | [ [Tag Group Object](#tagGroupObject) ] | A list of tag groups |
| x-tagGroups | [ [Tag Group Object](#tag-group-object) ] | A list of tag groups |
###### How to use with Redoc
#### How to use with Redoc
`x-tagGroups` is used to group tags in the side menu.
Before you use `x-tagGroups`, make sure you **add all tags to a group**, since a tag that is not in a group, **will not be displayed** at all!
Before you use `x-tagGroups`, make sure you **add all tags to a group**, since a tag that is not in a group, **is not displayed** at all!
#### <a name="tagGroupObject"></a>Tag Group Object
<a name="tagGroupObject"></a>
#### Tag Group Object
Information about tags group
###### Fixed fields
##### Fixed fields
| Field Name | Type | Description |
| :---------- | :--------: | :---------- |
| name | string | The group name |
| tags | [ string ] | List of tags to include in this group
| tags | [ string ] | List of tags to include in this group |
###### x-tagGroups example
#### x-tagGroups example
json
```json
{
@ -80,53 +102,33 @@ x-tagGroups:
- Secondary Stats
```
#### x-ignoredHeaderParameters
## Info Object
Extends the OpenAPI [Info Object](https://redocly.com/docs/openapi-visual-reference/info/)
| Field Name | Type | Description |
| :-------------------------- | :-----------: | :---------- |
| x-ignoredHeaderParameters | [ string ] | A list of ignored headers |
###### How to use with Redoc
Use `x-ignoredHeaderParameters` to specify header parameter names which are ignored by ReDoc.
###### x-ignoredHeaderParameters example
```yaml
swagger: '2.0'
info:
...
tags: [...]
x-ignoredHeaderParameters:
- Accept
- User-Agent
- X-Test-Header
```
### Info Object
Extends the OpenAPI [Info Object](http://swagger.io/specification/#infoObject)
#### x-logo
### x-logo
| Field Name | Type | Description |
| :------------- | :-----------: | :---------- |
| x-logo | [Logo Object](#logoObject) | The information about API logo |
| x-logo | [Logo Object](#logo-object) | The information about API logo |
###### How to use with Redoc
#### How to use with Redoc
`x-logo` is used to specify API logo. The corresponding image is displayed just above the side-menu.
#### <a name="logoObject"></a>Logo Object
<a name="logoObject"></a>
#### Logo Object
The information about API logo
###### Fixed fields
#### Fixed fields
| Field Name | Type | Description |
| :-------------- | :------: | :---------- |
| url | string | The URL pointing to the spec logo. MUST be in the format of a URL. It SHOULD be an absolute URL so your API definition is usable from any location
| backgroundColor | string | background color to be used. MUST be RGB color in [hexadecimal format] (https://en.wikipedia.org/wiki/Web_colors#Hex_triplet)
| altText | string | Text to use for alt tag on the logo. Defaults to 'logo' if nothing is provided.
| href | string | The URL pointing to the contact page. Default to 'info.contact.url' field of the OAS.
| url | string | The URL pointing to the spec logo. MUST be in the format of a URL. It SHOULD be an absolute URL so your API definition is usable from any location |
| backgroundColor | string | background color to be used. MUST be RGB color in [hexadecimal format] (https://en.wikipedia.org/wiki/Web_colors#Hex_triplet) |
| altText | string | Text to use for alt tag on the logo. Defaults to 'logo' if nothing is provided. |
| href | string | The URL pointing to the contact page. Default to 'info.contact.url' field of the OAS. |
###### x-logo example
#### x-logo example
json
```json
{
@ -152,19 +154,19 @@ info:
altText: "Petstore logo"
```
### Tag Object
Extends the OpenAPI [Tag Object](http://swagger.io/specification/#tagObject)
## Tag Object
Extends the OpenAPI [Tag Object](https://redocly.com/docs/openapi-visual-reference/tags/)
#### x-traitTag
### x-traitTag
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-traitTag | boolean | In Swagger two operations can have multiple tags. This property distinguishes between tags that are used to group operations (default) from tags that are used to mark operation with certain trait (`true` value) |
###### How to use with Redoc
#### How to use with Redoc
Tags that have `x-traitTag` set to `true` are listed in the side-menu but don't have any subitems (operations). It also renders the `description` tag.
This is useful for handling out common things like Pagination, Rate-Limits, etc.
###### x-traitTag example
#### x-traitTag example
json
```json
{
@ -180,35 +182,37 @@ description: Pagination description (can use markdown syntax)
x-traitTag: true
```
#### x-displayName
### x-displayName
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-displayName | string | Defines the text that is used for this tag in the menu and in section headings |
### Operation Object vendor extensions
Extends the OpenAPI [Operation Object](http://swagger.io/specification/#operationObject)
## Operation Object vendor extensions
Extends the OpenAPI [Operation Object](https://redocly.com/docs/openapi-visual-reference/operation/)
#### x-codeSamples
### x-codeSamples
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-codeSamples | [ [Code Sample Object](#codeSampleObject) ] | A list of code samples associated with operation |
| x-codeSamples | [ [Code Sample Object](#code-sample-object) ] | A list of code samples associated with operation |
###### How to use with Redoc
#### How to use with Redoc
`x-codeSamples` are rendered on the right panel in Redoc.
#### <a name="codeSampleObject"></a>Code Sample Object
<a name="codeSampleObject"></a>
### Code Sample Object
Operation code sample
###### Fixed fields
#### Fixed fields
| Field Name | Type | Description |
| :---------- | :------: | :----------- |
| lang | string | Code sample language. Value should be one of the following [list](https://github.com/github/linguist/blob/master/lib/linguist/popular.yml) |
| label | string? | Code sample label e.g. `Node` or `Python2.7`, _optional_, `lang` will be used by default |
| label | string? | Code sample label, for example `Node` or `Python2.7`, _optional_, `lang` is used by default |
| source | string | Code sample source code |
###### Code Sample Object example
#### Code Sample Object example
json
```json
{
@ -222,94 +226,46 @@ lang: JavaScript
source: console.log('Hello World');
```
### Parameter Object
Extends the OpenAPI [Parameter Object](http://swagger.io/specification/#parameterObject)
#### x-examples
### x-badges
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-examples | [Example Object](http://swagger.io/specification/#exampleObject) | Object that contains examples for the request. Applies when `in` is `body` and mime-type is `application/json` |
| x-badges | [[Badge Object](https://redocly.com/docs/realm/author/reference/openapi-extensions/x-badges#badge-object)] | A list of badges associated with the operation |
###### How to use with Redoc
## Parameter Object
Extends the OpenAPI [Parameter Object](https://redocly.com/docs/openapi-visual-reference/parameter/)
### x-examples
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-examples | [Example Object](https://redocly.com/docs/openapi-visual-reference/example/) | Object that contains examples for the request. Applies when `in` is `body` and mime-type is `application/json` |
#### How to use with Redoc
`x-examples` are rendered in the JSON tab on the right panel in Redoc.
### Response Object vendor extensions
Extends the OpenAPI [Response Object](https://swagger.io/specification/#responseObject)
## Response Object vendor extensions
Extends the OpenAPI [Response Object](https://redocly.com/docs/openapi-visual-reference/response/).
#### x-summary
### x-summary
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-summary | string | a short summary of the response |
###### How to use with Redoc
#### How to use with Redoc
If specified, you can use `x-summary` as the response button text, with description rendered under the button.
### Schema Object
Extends the OpenAPI [Schema Object](http://swagger.io/specification/#schemaObject)
## Schema Object
Extends the OpenAPI [Schema Object](https://redocly.com/docs/openapi-visual-reference/schemas/)
#### x-nullable
### x-nullable
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-nullable | boolean | marks schema as a nullable |
###### How to use with Redoc
Schemas marked as `x-nullable` are marked in Redoc with the label Nullable
#### How to use with Redoc
Schemas marked as `x-nullable` are marked in Redoc with the label Nullable.
#### x-extendedDiscriminator
**ATTENTION**: This is a Redoc-specific vendor extension, and is not supported by other tools.
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-extendedDiscriminator | string | specifies extended discriminator |
###### How to use with Redoc
Redoc uses this vendor extension to solve name-clash issues with the standard `discriminator`.
Value of this field specifies the field which will be used as a extended discriminator.
Redoc displays definition with selectpicker using which user can select value of the `x-extendedDiscriminator`-marked field.
Redoc displays the definition derived from the current (using `allOf`) and has `enum` with only one value which is the same as the selected value of the field specified as `x-extendedDiscriminator`.
###### x-extendedDiscriminator example
```yaml
Payment:
x-extendedDiscriminator: type
type: object
required:
- type
properties:
type:
type: string
name:
type: string
CashPayment:
allOf:
- $ref: "#/definitions/Payment"
- properties:
type:
type: string
enum:
- cash
currency:
type: string
PayPalPayment:
allOf:
- $ref: "#/definitions/Payment"
- properties:
type:
type: string
enum:
- paypal
userEmail:
type: string
```
In the example above, the names of definitions (`PayPalPayment`) are named differently than names in the payload (`paypal`) which is not supported by default `discriminator`.
#### x-additionalPropertiesName
**ATTENTION**: This is a Redoc-specific vendor extension, and is not supported by other tools.
### x-additionalPropertiesName
**Attention**: This is a Redoc-specific vendor extension, and is not supported by other tools.
Extends the `additionalProperties` property of the schema object.
@ -317,10 +273,10 @@ Extends the `additionalProperties` property of the schema object.
| :------------- | :------: | :---------- |
| x-additionalPropertiesName | string | descriptive name of additional properties keys |
###### How to use with Redoc
#### How to use with Redoc
Redoc uses this extension to display a more descriptive property name in objects with `additionalProperties` when viewing the property list with an `object`.
###### x-additionalPropertiesName example
#### x-additionalPropertiesName example
```yaml
Player:
@ -336,8 +292,8 @@ Player:
type: string
```
#### x-explicitMappingOnly
**ATTENTION**: This is Redoc-specific vendor extension, and is not supported by other tools.
### x-explicitMappingOnly
**Attention**: This is Redoc-specific vendor extension, and is not supported by other tools.
Extends the `discriminator` property of the schema object.
@ -345,11 +301,11 @@ Extends the `discriminator` property of the schema object.
| :------------- | :------: | :---------- |
| x-explicitMappingOnly | boolean | limit the discriminator selectpicker to the explicit mappings only |
###### How to use with Redoc
#### How to use with Redoc
Redoc uses this extension to filter the `discriminator` mappings shown in the selectpicker.
When set to `true`, the selectpicker will only list the the explicitly defined mappings. When `false`, the default behavior is kept, i.e. explicit and implicit mappings will be shown.
When set to `true`, the selectpicker lists only the explicitly defined mappings. When `false`, the default behavior is kept, in other words, explicit and implicit mappings are shown.
###### x-explicitMappingOnly example
#### x-explicitMappingOnly example
```yaml
@ -366,4 +322,32 @@ Pet:
bee: "#/components/schemas/HoneyBee"
```
Will show in the selectpicker only the items `cat` and `bee`, even though the `Dog` class inherits from the `Pet` class.
Shows in the selectpicker only the items `cat` and `bee`, even though the `Dog` class inherits from the `Pet` class.
### x-enumDescriptions
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-enumDescriptions | [[Enum Description Object](https://redocly.com/docs/realm/author/reference/openapi-extensions/x-enum-descriptions#enum-description-object)] | A list of the enum values and descriptions to include in the documentation. |
#### How to use with Redoc
The enum (short for "enumeration") fields in OpenAPI allow you to restrict the value of a field to a list of allowed values. These values need to be short and machine-readable, but that can make them harder for humans to parse and work with.
Add x-enumDescriptions to your OpenAPI description to show a helpful table of enum options and an explanation of what each one means. This field supports Markdown.
#### x-enumDescriptions example
The following example shows a schema with two short-named options, and the x-enumDescriptions entry to list all enum entries and give additional context for each:
```yaml
components:
schemas:
TicketType:
description: Type of ticket being purchased. Use `general` for regular museum entry and `event` for tickets to special events.
type: string
enum:
- event
- general
x-enumDescriptions:
event: Event Tickets _(timed entry)_
general: General Admission
example: event
```

View File

@ -1,19 +1,23 @@
# Injection security definitions
You can inject Security Definitions widget into any place of your specification `description`:
You can inject the Security Definitions widget anywhere in your specification `description`:
```markdown
...
# Authorization
## Authorization
Some description
<!-- ReDoc-Inject: <security-definitions> -->
<!-- Redoc-Inject: <security-definitions> -->
...
```
Inject instruction is wrapped into HTML comment so it is **visible only in ReDoc**. It won't be visible e.g. in SwaggerUI.
The inject instruction is wrapped in an HTML comment,
so it is **visible only in Redoc** and not visible, for instance, in the SwaggerUI.
# Default behavior
If injection tag is not found in the description it will be appended to the end
of description under `Authentication` header.
## Default behavior
If `Authentication` header is already present in the description, Security Definitions won't be inserted and rendered at all.
If the injection tag is not found in the description, it is appended to the end
of description under the `Authentication` header.
If the `Authentication` header is already present in the description,
Security Definitions are not inserted or rendered.

View File

@ -1,22 +1,22 @@
describe('Menu', () => {
describe('3.0 spec', () => {
beforeEach(() => {
cy.visit('e2e/standalone.html');
});
it('should have valid items count', () => {
cy.get('.menu-content').find('li').should('have.length', 34);
cy.get('.menu-content').find('li').should('have.length', 35);
});
it('should sync active menu items while scroll', () => {
cy.contains('h1', 'Introduction')
cy.contains('h2', 'Introduction')
.scrollIntoView()
.get('[role=menuitem].active')
.get('[role=menuitem] > label.active')
.should('have.text', 'Introduction');
cy.contains('h2', 'Add a new pet to the store')
.scrollIntoView()
.wait(100)
.get('[role=menuitem].active')
.get('[role=menuitem] > label.active')
.children()
.last()
.should('have.text', 'Add a new pet to the store')
@ -27,7 +27,7 @@ describe('Menu', () => {
cy.contains('h2', 'Add a new pet to the store')
.scrollIntoView()
.wait(100)
.get('[role=menuitem].active')
.get('[role=menuitem] > label.active')
.children()
.last()
.should('have.text', 'Add a new pet to the store')
@ -35,17 +35,50 @@ describe('Menu', () => {
cy.contains('h1', 'Swagger Petstore').scrollIntoView().wait(100);
cy.contains('h1', 'Introduction')
cy.contains('h2', 'Introduction')
.scrollIntoView()
.wait(100)
.get('[role=menuitem].active')
.get('[role=menuitem] > label.active')
.should('have.text', 'Introduction');
cy.url().should('include', '#section/Introduction');
});
it('should update URL hash when clicking on menu items', () => {
cy.contains('[role=menuitem].-depth1', 'pet').click({ force: true });
cy.contains('[role=menuitem] > label.-depth1', 'pet').click({ force: true });
cy.get('li[data-item-id="schema/Cat"]')
.should('have.text', 'schemaCat')
.click({ force: true });
cy.location('hash').should('equal', '#schema/Cat');
});
it('should contains badge schema from x-badges', () => {
cy.contains('h2', 'Add a new pet to the store').scrollIntoView();
cy.contains('h2 > span', 'Beta')
.scrollIntoView()
.wait(100)
.get('[role=menuitem] > label.active')
.children('span[type="badge"]')
.should('have.text', 'Beta');
cy.contains('h2 > span', 'Alpha')
.scrollIntoView()
.wait(100)
.get('[role=menuitem] > label.active')
.children('span[type="badge"]')
.should('have.text', 'Alpha');
cy.contains('h2 > span', 'Gamma')
.scrollIntoView()
.wait(100)
.get('[role=menuitem] > label.active')
.children('span[type="badge"]')
.should('have.text', 'Gamma');
});
it('should contains Cat schema in Pet using x-tags', () => {
cy.contains('[role=menuitem] > label.-depth1', 'pet').click({ force: true });
cy.location('hash').should('equal', '#tag/pet');
cy.contains('[role=menuitem]', 'Find pet by ID').click({ force: true });
@ -53,10 +86,10 @@ describe('Menu', () => {
});
it('should deactivate tag when other is activated', () => {
const petItem = () => cy.contains('[role=menuitem].-depth1', 'pet');
const petItem = () => cy.contains('[role=menuitem] > label.-depth1', 'pet');
petItem().click({ force: true }).should('have.class', 'active');
cy.contains('[role=menuitem].-depth1', 'store').click({ force: true });
cy.contains('[role=menuitem] > label.-depth1', 'store').click({ force: true });
petItem().should('not.have.class', 'active');
});
@ -76,6 +109,7 @@ describe('Menu', () => {
.then($h5 => $h5[0].firstChild!.nodeValue!.trim())
.should('eq', 'Response Schema:');
});
});
it('should be able to open the operation details when the operation IDs have quotes', () => {
cy.visit('e2e/standalone-3-1.html');
@ -85,7 +119,7 @@ describe('Menu', () => {
cy.url().should('include', 'deletePetBy%22Id');
});
it.only('should encode URL when the operation IDs have backslashes', () => {
it('should encode URL when the operation IDs have backslashes', () => {
cy.visit('e2e/standalone-3-1.html');
cy.get('label span[title="pet"]').click({ multiple: true, force: true });
cy.get('li').contains('OperationId with backslash').click({ multiple: true, force: true });

View File

@ -1,7 +1,7 @@
describe('Search', () => {
const getSearchInput = () => cy.get('[role="search"] input');
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(() => {
cy.visit('e2e/standalone.html');
@ -45,7 +45,7 @@ describe('Search', () => {
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', () => {

View File

@ -1,7 +1,7 @@
describe('Standalone bundle test', () => {
function baseCheck(name: string, url: string) {
describe(name, () => {
before(() => {
beforeEach(() => {
cy.visit(url);
});

View File

@ -12,9 +12,9 @@ const webpackOptions = {
exclude: [/node_modules/],
use: [
{
loader: 'ts-loader',
loader: 'esbuild-loader',
options: {
configFile: 'e2e/tsconfig.json',
tsconfigRaw: require('../tsconfig.json'),
},
},
],

View File

@ -1,58 +0,0 @@
module.exports = function(config) {
const testWebpackConfig = require('./build/webpack.test.js');
const travis = process.env.TRAVIS;
config.set({
frameworks: ['jasmine', 'sinon', 'should'],
preprocessors: {
'./tests/spec-bundle.js': ['coverage', 'webpack', 'sourcemap'],
},
coverageReporter: {
type: 'in-memory',
},
remapCoverageReporter: {
'text-summary': null,
'text-lcov': './coverage/lcov.info',
html: './coverage/html',
},
webpack: testWebpackConfig,
webpackMiddleware: {
stats: 'errors-only',
state: true,
},
client: {
chai: {
truncateThreshold: 0,
},
},
files: [
{ pattern: './tests/spec-bundle.js', watched: false },
{ pattern: 'tests/schemas/**/*.json', included: false },
{ pattern: 'tests/schemas/**/*.yml', included: false },
{ pattern: 'lib/**/*.html', included: false },
],
proxies: {
'/tests/schemas': '/base/tests/schemas',
'/lib/': '/base/lib/',
'/node_modules/': '/base/node_modules/',
},
colors: true,
singleRun: true,
reporters: travis
? ['mocha', 'coverage', 'remap-coverage', 'coveralls']
: ['mocha', 'coverage', 'remap-coverage'],
browsers: ['ChromeHeadlessNoSandbox'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
},
browserNoActivityTimeout: 60000,
});
};

22379
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "redoc",
"version": "2.0.0",
"version": "2.5.0",
"description": "ReDoc",
"repository": {
"type": "git",
@ -44,32 +44,31 @@
"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 && 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/",
"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",
"lint": "eslint --fix 'src/**/*.{js,ts,tsx}' --cache",
"benchmark": "node ./benchmark/benchmark.js",
"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",
"publish-cdn": "scripts/publish-cdn.sh",
"deploy:demo": "aws s3 sync demo/dist s3://production-redoc-demo --acl=public-read",
"license-check": "license-checker --production --onlyAllow 'MIT;ISC;Apache-2.0;BSD;BSD-2-Clause;BSD-3-Clause;CC-BY-4.0;Python-2.0' --summary",
"license-check": "license-checker --production --onlyAllow 'MIT;ISC;Apache-2.0;BSD;BSD-2-Clause;BSD-3-Clause;CC-BY-4.0;CC0-1.0;Python-2.0 ' --summary",
"docker:build": "docker build -f config/docker/Dockerfile -t redoc .",
"prepare": "husky install",
"pre-commit": "pretty-quick --staged && npm run lint"
},
"devDependencies": {
"@cypress/webpack-preprocessor": "^5.12.0",
"@hot-loader/react-dom": "^17.0.2",
"@size-limit/preset-app": "^7.0.4",
"@cfaester/enzyme-adapter-react-18": "^0.8.0",
"@cypress/webpack-preprocessor": "^5.17.1",
"@size-limit/file": "^11.1.4",
"@types/chai": "^4.2.18",
"@types/dompurify": "^2.2.2",
"@types/enzyme": "^3.10.5",
"@types/enzyme-to-json": "^1.5.3",
"@types/jest": "^26.0.23",
"@types/jest": "^29.5.6",
"@types/json-pointer": "^1.0.30",
"@types/lunr": "^2.3.3",
"@types/mark.js": "^8.11.5",
@ -77,91 +76,88 @@
"@types/node": "^15.6.1",
"@types/prismjs": "^1.16.5",
"@types/prop-types": "^15.7.3",
"@types/react": "^17.0.8",
"@types/react-dom": "^17.0.5",
"@types/react-tabs": "^2.3.2",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/styled-components": "^5.1.1",
"@types/tapable": "^2.2.2",
"@types/webpack": "^5.28.0",
"@types/webpack-env": "^1.16.0",
"@types/webpack-env": "^1.18.0",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.1",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"beautify-benchmark": "^0.2.4",
"conventional-changelog-cli": "^2.0.34",
"conventional-changelog-cli": "^3.0.0",
"copy-webpack-plugin": "^9.0.0",
"core-js": "^3.13.1",
"coveralls": "^3.1.0",
"css-loader": "^5.2.6",
"cypress": "^7.4.0",
"cypress": "^13.8.1",
"enzyme": "^3.11.0",
"enzyme-to-json": "^3.6.2",
"esbuild-loader": "^2.18.0",
"esbuild-loader": "^4.3.0",
"eslint": "^7.27.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-react": "^7.25.1",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"fork-ts-checker-webpack-plugin": "^6.2.10",
"html-webpack-plugin": "^5.3.1",
"husky": "^7.0.0",
"jest": "^27.0.3",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"js-yaml": "^4.1.0",
"license-checker": "^25.0.1",
"lodash.noop": "^3.0.1",
"mobx": "^6.3.2",
"mobx": "^6.10.2",
"outdent": "^0.8.0",
"prettier": "^2.3.2",
"pretty-quick": "^3.0.0",
"raf": "^3.4.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-hot-loader": "^4.13.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"rimraf": "^3.0.2",
"shelljs": "^0.8.4",
"size-limit": "^7.0.4",
"size-limit": "^11.1.4",
"style-loader": "^3.3.1",
"styled-components": "^5.3.0",
"ts-jest": "^27.0.2",
"ts-loader": "^9.2.6",
"ts-node": "^10.0.0",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"tslib": "^2.4.0",
"typescript": "~4.1.0",
"typescript": "^4.9.0",
"unfetch": "^4.2.0",
"webpack": "^5.50.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^4.6.0",
"url": "^0.11.1",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-node-externals": "^3.0.0",
"workerize-loader": "github:redocly/workerize-loader#webpack-5-dist"
},
"peerDependencies": {
"core-js": "^3.1.4",
"mobx": "^6.0.4",
"react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0",
"styled-components": "^4.1.1 || ^5.1.1"
"react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"styled-components": "^4.1.1 || ^5.1.1 || ^6.0.5"
},
"dependencies": {
"@redocly/openapi-core": "^1.0.0-beta.104",
"classnames": "^2.3.1",
"@redocly/openapi-core": "^1.4.0",
"classnames": "^2.3.2",
"decko": "^1.2.0",
"dompurify": "^2.2.8",
"eventemitter3": "^4.0.7",
"dompurify": "^3.2.4",
"eventemitter3": "^5.0.1",
"json-pointer": "^0.6.2",
"lunr": "^2.3.9",
"mark.js": "^8.11.1",
"marked": "^4.0.15",
"mobx-react": "^7.2.0",
"openapi-sampler": "^1.3.0",
"marked": "^4.3.0",
"mobx-react": "^9.1.1",
"openapi-sampler": "^1.5.0",
"path-browserify": "^1.0.1",
"perfect-scrollbar": "^1.5.5",
"polished": "^4.1.3",
"prismjs": "^1.27.0",
"prop-types": "^15.7.2",
"react-tabs": "^3.2.2",
"polished": "^4.2.2",
"prismjs": "^1.29.0",
"prop-types": "^15.8.1",
"react-tabs": "^6.0.2",
"slugify": "~1.4.7",
"stickyfill": "^1.1.1",
"style-loader": "^3.3.1",
"swagger2openapi": "^7.0.6",
"swagger2openapi": "^7.0.8",
"url-template": "^2.0.8"
},
"size-limit": [

View File

@ -49,7 +49,7 @@ const Gap = styled.div`
bottom: -20px;
`;
export interface TooltipProps {
export interface TooltipProps extends React.PropsWithChildren<any> {
open: boolean;
title: string;
}

View File

@ -1,10 +1,17 @@
import { transparentize } from 'polished';
import styled, { extensionsHook, css } from '../styled-components';
import styled, { css, extensionsHook } from '../styled-components';
import { PropertyNameCell } from './fields-layout';
import { deprecatedCss } from './mixins';
import { ShelfIcon } from './shelfs';
export const ClickablePropertyNameCell = styled(PropertyNameCell)`
&.deprecated {
span.property-name {
${deprecatedCss}
}
}
button {
background-color: transparent;
border: 0;
@ -69,7 +76,9 @@ export const TypeTitle = styled(FieldLabel)`
export const TypeFormat = TypeName;
export const RequiredLabel = styled(FieldLabel.withComponent('div'))`
export const RequiredLabel = styled(FieldLabel).attrs({
as: 'div',
})`
color: ${props => props.theme.schema.requireLabelColor};
font-size: ${props => props.theme.schema.labelsTextSize};
font-weight: normal;
@ -88,9 +97,11 @@ export const RecursiveLabel = styled(FieldLabel)`
export const PatternLabel = styled(FieldLabel)`
color: #0e7c86;
font-family: ${props => props.theme.typography.code.fontFamily};
font-size: 12px;
&::before,
&::after {
font-weight: bold;
content: ' ';
}
`;

View File

@ -1,14 +1,14 @@
import { SECTION_ATTR } from '../services/MenuStore';
import styled, { media } from '../styled-components';
export const MiddlePanel = styled.div<{ compact?: boolean }>`
export const MiddlePanel = styled.div<{ $compact?: boolean }>`
width: calc(100% - ${props => props.theme.rightPanel.width});
padding: 0 ${props => props.theme.spacing.sectionHorizontal}px;
${({ compact, theme }) =>
${({ $compact, theme }) =>
media.lessThan('medium', true)`
width: 100%;
padding: ${`${compact ? 0 : theme.spacing.sectionVertical}px ${
padding: ${`${$compact ? 0 : theme.spacing.sectionVertical}px ${
theme.spacing.sectionHorizontal
}px`};
`};
@ -16,7 +16,7 @@ export const MiddlePanel = styled.div<{ compact?: boolean }>`
export const Section = styled.div.attrs(props => ({
[SECTION_ATTR]: props.id,
}))<{ underlined?: boolean }>`
}))<{ $underlined?: boolean }>`
padding: ${props => props.theme.spacing.sectionVertical}px 0;
&:last-child {
@ -30,8 +30,8 @@ export const Section = styled.div.attrs(props => ({
${media.lessThan('medium', true)`
padding: 0;
`}
${(props: any) =>
(props.underlined &&
${({ $underlined }) =>
($underlined &&
`
position: relative;

View File

@ -33,7 +33,9 @@ export interface PerfectScrollbarProps {
updateFn?: (fn) => void;
}
export class PerfectScrollbar extends React.Component<PerfectScrollbarProps> {
export class PerfectScrollbar extends React.Component<
React.PropsWithChildren<PerfectScrollbarProps>
> {
private _container: HTMLElement;
private inst: PerfectScrollbarType;

View File

@ -32,7 +32,9 @@ export const SampleControlsWrap = styled.div`
}
`;
export const StyledPre = styled(PrismDiv.withComponent('pre'))`
export const StyledPre = styled(PrismDiv).attrs({
as: 'pre',
})`
font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize};
overflow-x: auto;

View File

@ -15,7 +15,7 @@ export const OneOfLabel = styled.span`
}
`;
export const OneOfButton = styled.button<{ active: boolean; deprecated: boolean }>`
export const OneOfButton = styled.button<{ $active: boolean; $deprecated: boolean }>`
display: inline-block;
margin-right: 10px;
margin-bottom: 5px;
@ -29,10 +29,10 @@ export const OneOfButton = styled.button<{ active: boolean; deprecated: boolean
box-shadow: 0 0 0 1px ${props => props.theme.colors.primary.main};
}
${({ deprecated }) => (deprecated && deprecatedCss) || ''};
${({ $deprecated }) => ($deprecated && deprecatedCss) || ''};
${props => {
if (props.active) {
if (props.$active) {
return `
color: white;
background-color: ${props.theme.colors.primary.main};

View File

@ -47,11 +47,11 @@ export const ShelfIcon = styled(IntShelfIcon)`
}
`;
export const Badge = styled.span<{ type: string }>`
export const Badge = styled.span<{ type: string; color?: string }>`
display: inline-block;
padding: 2px 8px;
margin: 0;
background-color: ${props => props.theme.colors[props.type].main};
background-color: ${props => props.color || props.theme.colors[props.type].main};
color: ${props => props.theme.colors[props.type].contrastText};
font-size: ${props => props.theme.typography.code.fontSize};
vertical-align: middle;

View File

@ -22,20 +22,13 @@ export interface ApiInfoProps {
@observer
export class ApiInfo extends React.Component<ApiInfoProps> {
handleDownloadClick = e => {
if (!e.target.href) {
e.target.href = this.props.store.spec.info.downloadLink;
}
};
render() {
const { store } = this.props;
const { info, externalDocs } = store.spec;
const hideDownloadButton = store.options.hideDownloadButton;
const downloadFilename = info.downloadFileName;
const downloadLink = info.downloadLink;
const hideDownloadButtons = store.options.hideDownloadButtons;
const downloadUrls = info.downloadUrls;
const downloadFileName = info.downloadFileName;
const license =
(info.license && (
<InfoSpan>
@ -83,17 +76,22 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
<ApiHeader>
{info.title} {version}
</ApiHeader>
{!hideDownloadButton && (
{!hideDownloadButtons && (
<p>
{l('downloadSpecification')}:
{downloadUrls?.map(({ title, url }) => {
return (
<DownloadButton
download={downloadFilename || true}
download={downloadFileName || true}
target="_blank"
href={downloadLink}
onClick={this.handleDownloadClick}
href={url}
rel="noreferrer"
key={url}
>
{l('download')}
{title}
</DownloadButton>
);
})}
</p>
)}
<StyledMarkdownBlock>

View File

@ -24,7 +24,7 @@ export const CallbackTitle = (props: CallbackTitleProps) => {
<CallbackTitleWrapper className={className} onClick={onClick || undefined}>
<OperationBadgeStyled type={httpVerb}>{shortenHTTPVerb(httpVerb)}</OperationBadgeStyled>
<ShelfIcon size={'1.5em'} direction={opened ? 'down' : 'right'} float={'left'} />
<CallbackName deprecated={deprecated}>{name}</CallbackName>
<CallbackName $deprecated={deprecated}>{name}</CallbackName>
{deprecated ? <Badge type="warning"> {l('deprecated')} </Badge> : null}
</CallbackTitleWrapper>
);
@ -45,8 +45,8 @@ const CallbackTitleWrapper = styled.button`
}
`;
const CallbackName = styled.span<{ deprecated?: boolean }>`
text-decoration: ${props => (props.deprecated ? 'line-through' : 'none')};
const CallbackName = styled.span<{ $deprecated?: boolean }>`
text-decoration: ${props => (props.$deprecated ? 'line-through' : 'none')};
margin-right: 8px;
`;

View File

@ -3,7 +3,7 @@ import * as React from 'react';
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
import { AdvancedMarkdown } from '../Markdown/AdvancedMarkdown';
import { H1, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
import { H2, H3, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
import type { ContentItemModel } from '../../services';
import type { GroupModel, OperationModel } from '../../services/models';
import { Operation } from '../Operation/Operation';
@ -51,7 +51,7 @@ export class ContentItem extends React.Component<ContentItemProps> {
return (
<>
{content && (
<Section id={item.id} underlined={item.type === 'operation'}>
<Section id={item.id} $underlined={item.type === 'operation'}>
{content}
</Section>
)}
@ -61,18 +61,18 @@ export class ContentItem extends React.Component<ContentItemProps> {
}
}
const middlePanelWrap = component => <MiddlePanel compact={true}>{component}</MiddlePanel>;
const middlePanelWrap = component => <MiddlePanel $compact={true}>{component}</MiddlePanel>;
@observer
export class SectionItem extends React.Component<ContentItemProps> {
render() {
const { name, description, externalDocs, level } = this.props.item as GroupModel;
const Header = level === 2 ? H2 : H1;
const Header = level === 2 ? H3 : H2;
return (
<>
<Row>
<MiddlePanel compact={false}>
<MiddlePanel $compact={false}>
<Header>
<ShareLink to={this.props.item.id} />
{name}

View File

@ -4,7 +4,7 @@ import { StyledComponent } from 'styled-components';
import { DropdownProps, MimeLabel, SimpleDropdown } from '../../common-elements/Dropdown';
export interface DropdownOrLabelProps extends DropdownProps {
Label?: StyledComponent<any, any, GenericObject, never>;
Label?: StyledComponent<any, any, Record<string, any>, never>;
Dropdown?: StyledComponent<
React.NamedExoticComponent<DropdownProps>,
any,

View File

@ -49,8 +49,8 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
<OptionsContext.Consumer>
{options => (
<OperationEndpointWrap>
<EndpointInfo onClick={this.toggle} expanded={expanded} inverted={inverted}>
<HttpVerb type={operation.httpVerb} compact={this.props.compact}>
<EndpointInfo onClick={this.toggle} $expanded={expanded} $inverted={inverted}>
<HttpVerb type={operation.httpVerb} $compact={this.props.compact}>
{operation.httpVerb}
</HttpVerb>
<ServerRelativeURL>{operation.path}</ServerRelativeURL>
@ -62,7 +62,7 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
style={{ marginRight: '-25px' }}
/>
</EndpointInfo>
<ServersOverlay expanded={expanded} aria-hidden={!expanded}>
<ServersOverlay $expanded={expanded} aria-hidden={!expanded}>
{operation.servers.map(server => {
const normalizedUrl = options.expandDefaultServerVariables
? expandDefaultServerVariables(server.url, server.variables)

View File

@ -14,61 +14,62 @@ export const ServerRelativeURL = styled.span`
text-overflow: ellipsis;
`;
export const EndpointInfo = styled.button<{ expanded?: boolean; inverted?: boolean }>`
export const EndpointInfo = styled.button<{ $expanded?: boolean; $inverted?: boolean }>`
outline: 0;
color: inherit;
width: 100%;
text-align: left;
cursor: pointer;
padding: 10px 30px 10px ${props => (props.inverted ? '10px' : '20px')};
border-radius: ${props => (props.inverted ? '0' : '4px 4px 0 0')};
padding: 10px 30px 10px ${props => (props.$inverted ? '10px' : '20px')};
border-radius: ${props => (props.$inverted ? '0' : '4px 4px 0 0')};
background-color: ${props =>
props.inverted ? 'transparent' : props.theme.codeBlock.backgroundColor};
props.$inverted ? 'transparent' : props.theme.codeBlock.backgroundColor};
display: flex;
white-space: nowrap;
align-items: center;
border: ${props => (props.inverted ? '0' : '1px solid transparent')};
border-bottom: ${props => (props.inverted ? '1px solid #ccc' : '0')};
border: ${props => (props.$inverted ? '0' : '1px solid transparent')};
border-bottom: ${props => (props.$inverted ? '1px solid #ccc' : '0')};
transition: border-color 0.25s ease;
${props =>
(props.expanded && !props.inverted && `border-color: ${props.theme.colors.border.dark};`) || ''}
(props.$expanded && !props.$inverted && `border-color: ${props.theme.colors.border.dark};`) ||
''}
.${ServerRelativeURL} {
color: ${props => (props.inverted ? props.theme.colors.text.primary : '#ffffff')};
color: ${props => (props.$inverted ? props.theme.colors.text.primary : '#ffffff')};
}
&:focus {
box-shadow: inset 0 2px 2px rgba(0, 0, 0, 0.45), 0 2px 0 rgba(128, 128, 128, 0.25);
}
`;
export const HttpVerb = styled.span.attrs((props: { type: string; compact?: boolean }) => ({
export const HttpVerb = styled.span.attrs((props: { type: string; $compact?: boolean }) => ({
className: `http-verb ${props.type}`,
}))<{ type: string; compact?: boolean }>`
font-size: ${props => (props.compact ? '0.8em' : '0.929em')};
line-height: ${props => (props.compact ? '18px' : '20px')};
}))<{ type: string; $compact?: boolean }>`
font-size: ${props => (props.$compact ? '0.8em' : '0.929em')};
line-height: ${props => (props.$compact ? '18px' : '20px')};
background-color: ${props => props.theme.colors.http[props.type] || '#999999'};
color: #ffffff;
padding: ${props => (props.compact ? '2px 8px' : '3px 10px')};
padding: ${props => (props.$compact ? '2px 8px' : '3px 10px')};
text-transform: uppercase;
font-family: ${props => props.theme.typography.headings.fontFamily};
margin: 0;
`;
export const ServersOverlay = styled.div<{ expanded: boolean }>`
export const ServersOverlay = styled.div<{ $expanded: boolean }>`
position: absolute;
width: 100%;
z-index: 100;
background: ${props => props.theme.rightPanel.servers.overlay.backgroundColor};
color: ${props => props.theme.rightPanel.servers.overlay.textColor};
box-sizing: border-box;
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.33);
box-shadow: 0 0 6px rgba(0, 0, 0, 0.33);
overflow: hidden;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
transition: all 0.25s ease;
visibility: hidden;
${props => (props.expanded ? 'visibility: visible;' : 'transform: translateY(-50%) scaleY(0);')}
${props => (props.$expanded ? 'visibility: visible;' : 'transform: translateY(-50%) scaleY(0);')}
`;
export const ServerItem = styled.div`

View File

@ -4,9 +4,9 @@ import styled from '../../styled-components';
import { OpenAPIExternalDocumentation } from '../../types';
import { linksCss } from '../Markdown/styled.elements';
const LinkWrap = styled.div<{ compact?: boolean }>`
const LinkWrap = styled.div<{ $compact?: boolean }>`
${linksCss};
${({ compact }) => (!compact ? 'margin: 1em 0' : '')}
${({ $compact }) => (!$compact ? 'margin: 1em 0' : '')}
`;
@observer
@ -21,7 +21,7 @@ export class ExternalDocumentation extends React.Component<{
}
return (
<LinkWrap compact={this.props.compact}>
<LinkWrap $compact={this.props.compact}>
<a href={externalDocs.url}>{externalDocs.description || externalDocs.url}</a>
</LinkWrap>
);

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import { TypeFormat, TypePrefix } from '../../common-elements/fields';
import { ConstraintsView } from './FieldContstraints';
import { ConstraintsView } from './FieldConstraints';
import { Pattern } from './Pattern';
import { SchemaModel } from '../../services';
import styled from '../../styled-components';
@ -10,11 +10,10 @@ export function ArrayItemDetails({ schema }: { schema: SchemaModel }) {
const { hideSchemaPattern } = React.useContext(OptionsContext);
if (
!schema ||
(schema.type === 'string' && !schema.constraints.length) ||
((!schema?.pattern || hideSchemaPattern) &&
!schema.items &&
!schema.displayFormat &&
!schema.constraints.length) // return null for cases where all constraints are empty
!schema.constraints?.length) // return null for cases where all constraints are empty
) {
return null;
}

View File

@ -5,17 +5,29 @@ import { l } from '../../services/Labels';
import { OptionsContext } from '../OptionsProvider';
import styled from '../../styled-components';
import { RedocRawOptions } from '../../services/RedocNormalizedOptions';
import { StyledMarkdownBlock } from '../Markdown/styled.elements';
import { Markdown } from '../Markdown/Markdown';
export interface EnumValuesProps {
values: string[];
isArrayType: boolean;
values?: string[] | { [name: string]: string };
type: string | string[];
}
export interface EnumValuesState {
collapsed: boolean;
}
const DescriptionEnumsBlock = styled(StyledMarkdownBlock)`
table {
margin-bottom: 0.2em;
}
`;
export class EnumValues extends React.PureComponent<EnumValuesProps, EnumValuesState> {
constructor(props: EnumValuesProps) {
super(props);
this.toggle = this.toggle.bind(this);
}
state: EnumValuesState = {
collapsed: true,
};
@ -27,35 +39,79 @@ export class EnumValues extends React.PureComponent<EnumValuesProps, EnumValuesS
}
render() {
const { values, isArrayType } = this.props;
const { values, type } = this.props;
const { collapsed } = this.state;
const isDescriptionEnum = !Array.isArray(values);
const enums =
(Array.isArray(values) && values) ||
Object.entries(values || {}).map(([value, description]) => ({
value,
description,
}));
// TODO: provide context interface in more elegant way
const { enumSkipQuotes, maxDisplayedEnumValues } = this.context as RedocRawOptions;
if (!values.length) {
if (!enums.length) {
return null;
}
const displayedItems =
this.state.collapsed && maxDisplayedEnumValues
? values.slice(0, maxDisplayedEnumValues)
: values;
? enums.slice(0, maxDisplayedEnumValues)
: enums;
const showToggleButton = maxDisplayedEnumValues
? values.length > maxDisplayedEnumValues
: false;
const showToggleButton = maxDisplayedEnumValues ? enums.length > maxDisplayedEnumValues : false;
const toggleButtonText = maxDisplayedEnumValues
? collapsed
? `${values.length - maxDisplayedEnumValues} more`
? `${enums.length - maxDisplayedEnumValues} more`
: 'Hide'
: '';
return (
<div>
{isDescriptionEnum ? (
<>
<DescriptionEnumsBlock>
<table>
<thead>
<tr>
<th>
<FieldLabel>
{isArrayType ? l('enumArray') : ''}{' '}
{type === 'array' ? l('enumArray') : ''}{' '}
{enums.length === 1 ? l('enumSingleValue') : l('enum')}
</FieldLabel>{' '}
</th>
<th>
<strong>Description</strong>
</th>
</tr>
</thead>
<tbody>
{(displayedItems as { value: string; description: string }[]).map(
({ description, value }) => {
return (
<tr key={value}>
<td>{value}</td>
<td>
<Markdown source={description} compact inline />
</td>
</tr>
);
},
)}
</tbody>
</table>
</DescriptionEnumsBlock>
{showToggleButton ? (
<ToggleButton onClick={this.toggle}>{toggleButtonText}</ToggleButton>
) : null}
</>
) : (
<>
<FieldLabel>
{type === 'array' ? l('enumArray') : ''}{' '}
{values.length === 1 ? l('enumSingleValue') : l('enum')}:
</FieldLabel>{' '}
{displayedItems.map((value, idx) => {
@ -67,14 +123,10 @@ export class EnumValues extends React.PureComponent<EnumValuesProps, EnumValuesS
);
})}
{showToggleButton ? (
<ToggleButton
onClick={() => {
this.toggle();
}}
>
{toggleButtonText}
</ToggleButton>
<ToggleButton onClick={this.toggle}>{toggleButtonText}</ToggleButton>
) : null}
</>
)}
</div>
);
}

View File

@ -19,6 +19,8 @@ import { Schema } from '../Schema/Schema';
import type { SchemaOptions } from '../Schema/Schema';
import type { FieldModel } from '../../services/models';
import { OptionsContext } from '../OptionsProvider';
import { RedocNormalizedOptions } from '../../services/RedocNormalizedOptions';
export interface FieldProps extends SchemaOptions {
className?: string;
@ -27,12 +29,15 @@ export interface FieldProps extends SchemaOptions {
field: FieldModel;
expandByDefault?: boolean;
fieldParentsName?: string[];
renderDiscriminatorSwitch?: (opts: FieldProps) => JSX.Element;
}
@observer
export class Field extends React.Component<FieldProps> {
static contextType = OptionsContext;
context: RedocNormalizedOptions;
toggle = () => {
if (this.props.field.expanded === undefined && this.props.expandByDefault) {
this.props.field.collapse();
@ -49,12 +54,12 @@ export class Field extends React.Component<FieldProps> {
};
render() {
const { className = '', field, isLast, expandByDefault } = this.props;
const { hidePropertiesPrefix } = this.context;
const { className = '', field, isLast, expandByDefault, fieldParentsName = [] } = this.props;
const { name, deprecated, required, kind } = field;
const withSubSchema = !field.schema.isPrimitive && !field.schema.isCircular;
const expanded = field.expanded === undefined ? expandByDefault : field.expanded;
const labels = (
<>
{kind === 'additionalProperties' && <PropertyLabel>additional property</PropertyLabel>}
@ -73,8 +78,12 @@ export class Field extends React.Component<FieldProps> {
<button
onClick={this.toggle}
onKeyPress={this.handleKeyPress}
aria-label="expand properties"
aria-label={`expand ${name}`}
>
{!hidePropertiesPrefix &&
fieldParentsName.map(
name => name + '.\u200B', // zero-width space, a special character is used for correct line breaking
)}
<span className="property-name">{name}</span>
<ShelfIcon direction={expanded ? 'down' : 'right'} />
</button>
@ -83,6 +92,10 @@ export class Field extends React.Component<FieldProps> {
) : (
<PropertyNameCell className={deprecated ? 'deprecated' : undefined} kind={kind} title={name}>
<PropertyBullet />
{!hidePropertiesPrefix &&
fieldParentsName.map(
name => name + '.\u200B', // zero-width space, a special character is used for correct line breaking
)}
<span className="property-name">{name}</span>
{labels}
</PropertyNameCell>
@ -102,6 +115,7 @@ export class Field extends React.Component<FieldProps> {
<InnerPropertiesWrap>
<Schema
schema={field.schema}
fieldParentsName={[...(fieldParentsName || []), field.name]}
skipReadOnly={this.props.skipReadOnly}
skipWriteOnly={this.props.skipWriteOnly}
showTitle={this.props.showTitle}

View File

@ -8,14 +8,14 @@ import {
TypePrefix,
TypeTitle,
} from '../../common-elements/fields';
import { getSerializedValue } from '../../utils';
import { getSerializedValue, isArray, isObject } from '../../utils';
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
import { Markdown } from '../Markdown/Markdown';
import { EnumValues } from './EnumValues';
import { Extensions } from './Extensions';
import { FieldProps } from './Field';
import { Examples } from './Examples';
import { ConstraintsView } from './FieldContstraints';
import { ConstraintsView } from './FieldConstraints';
import { FieldDetail } from './FieldDetail';
import { Badge } from '../../common-elements/';
@ -30,7 +30,8 @@ export const FieldDetailsComponent = observer((props: FieldProps) => {
const { showExamples, field, renderDiscriminatorSwitch } = props;
const { schema, description, deprecated, extensions, in: _in, const: _const } = field;
const isArrayType = schema.type === 'array';
const isArrayType =
schema.type === 'array' || (isArray(schema.type) && schema.type.includes('array'));
const rawDefault = enumSkipQuotes || _in === 'header'; // having quotes around header field default values is confusing and inappropriate
@ -51,6 +52,10 @@ export const FieldDetailsComponent = observer((props: FieldProps) => {
return null;
}, [field, showExamples]);
const defaultValue =
isObject(schema.default) && field.in
? getSerializedValue(field, schema.default).replace(`${field.name}=`, '')
: schema.default;
return (
<div>
@ -92,9 +97,9 @@ export const FieldDetailsComponent = observer((props: FieldProps) => {
<Badge type="warning"> {l('deprecated')} </Badge>
</div>
)}
<FieldDetail raw={rawDefault} label={l('default') + ':'} value={schema.default} />
<FieldDetail raw={rawDefault} label={l('default') + ':'} value={defaultValue} />
{!renderDiscriminatorSwitch && (
<EnumValues isArrayType={isArrayType} values={schema.enum} />
<EnumValues type={schema.type} values={schema['x-enumDescriptions'] || schema.enum} />
)}{' '}
{renderedExamples}
<Extensions extensions={{ ...extensions, ...schema.extensions }} />

View File

@ -41,11 +41,12 @@ const Json = (props: JsonProps) => {
<OptionsContext.Consumer>
{options => (
<PrismDiv
tabIndex={0}
className={props.className}
// tslint:disable-next-line
ref={node => setNode(node!)}
dangerouslySetInnerHTML={{
__html: jsonToHTML(props.data, options.jsonSampleExpandLevel),
__html: jsonToHTML(props.data, options.jsonSamplesExpandLevel),
}}
/>
)}

View File

@ -4,26 +4,36 @@ import * as React from 'react';
import { OptionsConsumer } from '../OptionsProvider';
import { StylingMarkdownProps } from './Markdown';
import { StyledMarkdownBlock } from './styled.elements';
import styled from 'styled-components';
const StyledMarkdownSpan = StyledMarkdownBlock.withComponent('span');
// Workaround for DOMPurify type issues (https://github.com/cure53/DOMPurify/issues/1034)
const dompurify = DOMPurify['default'] as DOMPurify.DOMPurify;
const sanitize = (untrustedSpec, html) => (untrustedSpec ? DOMPurify.sanitize(html) : html);
const StyledMarkdownSpan = styled(StyledMarkdownBlock)`
display: inline;
`;
export function SanitizedMarkdownHTML(
props: StylingMarkdownProps & { html: string; className?: string; 'data-role'?: string },
) {
const Wrap = props.inline ? StyledMarkdownSpan : StyledMarkdownBlock;
const sanitize = (sanitize, html) => (sanitize ? dompurify.sanitize(html) : html);
export function SanitizedMarkdownHTML({
inline,
compact,
...rest
}: StylingMarkdownProps & { html: string; className?: string; 'data-role'?: string }) {
const Wrap = inline ? StyledMarkdownSpan : StyledMarkdownBlock;
return (
<OptionsConsumer>
{options => (
<Wrap
className={'redoc-markdown ' + (props.className || '')}
className={'redoc-markdown ' + (rest.className || '')}
dangerouslySetInnerHTML={{
__html: sanitize(options.untrustedSpec, props.html),
__html: sanitize(options.sanitize, rest.html),
}}
data-role={props['data-role']}
{...props}
data-role={rest['data-role']}
{...rest}
$inline={inline}
$compact={compact}
/>
)}
</OptionsConsumer>

View File

@ -24,7 +24,7 @@ export const StyledMarkdownBlock = styled(
PrismDiv as StyledComponent<
'div',
ResolvedThemeInterface,
{ compact?: boolean; inline?: boolean }
{ $compact?: boolean; $inline?: boolean }
>,
)`
font-family: ${props => props.theme.typography.fontFamily};
@ -37,8 +37,8 @@ export const StyledMarkdownBlock = styled(
}
}
${({ compact }) =>
compact &&
${({ $compact }) =>
$compact &&
`
p:first-child {
margin-top: 0;
@ -48,8 +48,8 @@ export const StyledMarkdownBlock = styled(
}
`}
${({ inline }) =>
inline &&
${({ $inline }) =>
$inline &&
` p {
display: inline-block;
}`}
@ -87,7 +87,7 @@ export const StyledMarkdownBlock = styled(
padding: ${props => props.theme.spacing.unit * 4}px;
overflow-x: auto;
line-height: normal;
border-radius: 0px;
border-radius: 0;
border: 1px solid rgba(38, 50, 56, 0.1);
code {

View File

@ -28,9 +28,20 @@ export interface OperationProps {
}
export const Operation = observer(({ operation }: OperationProps): JSX.Element => {
const { name: summary, description, deprecated, externalDocs, isWebhook, httpVerb } = operation;
const {
name: summary,
description,
deprecated,
externalDocs,
isWebhook,
httpVerb,
badges,
} = operation;
const hasDescription = !!(description || externalDocs);
const { showWebhookVerb } = React.useContext(OptionsContext);
const badgesBefore = badges.filter(({ position }) => position === 'before');
const badgesAfter = badges.filter(({ position }) => position === 'after');
return (
<OptionsContext.Consumer>
{options => (
@ -38,6 +49,11 @@ export const Operation = observer(({ operation }: OperationProps): JSX.Element =
<MiddlePanel>
<H2>
<ShareLink to={operation.id} />
{badgesBefore.map(({ name, color }) => (
<Badge type="primary" key={name} color={color}>
{name}
</Badge>
))}
{summary} {deprecated && <Badge type="warning"> Deprecated </Badge>}
{isWebhook && (
<Badge type="primary">
@ -45,6 +61,11 @@ export const Operation = observer(({ operation }: OperationProps): JSX.Element =
Webhook {showWebhookVerb && httpVerb && '| ' + httpVerb.toUpperCase()}
</Badge>
)}
{badgesAfter.map(({ name, color }) => (
<Badge type="primary" key={name} color={color}>
{name}
</Badge>
))}
</H2>
{options.pathInMiddlePanel && !isWebhook && (
<Endpoint operation={operation} inverted={true} />

View File

@ -1,5 +1,5 @@
import * as React from 'react';
import { DropdownOrLabel } from '../DropdownOrLabel/DropdownOrLabel';
import { DropdownOrLabel, DropdownOrLabelProps } from '../DropdownOrLabel/DropdownOrLabel';
import { ParametersGroup } from './ParametersGroup';
import { UnderlinedHeader } from '../../common-elements';
@ -10,7 +10,9 @@ import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
import { Schema } from '../Schema';
import { Markdown } from '../Markdown/Markdown';
import { ConstraintsView } from '../Fields/FieldContstraints';
import { ConstraintsView } from '../Fields/FieldConstraints';
import { RequiredLabel } from '../../common-elements/fields';
import styled from '../../styled-components';
function safePush(obj, prop, item) {
if (!obj[prop]) {
@ -49,21 +51,37 @@ export class Parameters extends React.PureComponent<ParametersProps> {
const bodyDescription = body && body.description;
const bodyRequired = body && body.required;
return (
<>
{paramsPlaces.map(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 (
<UnderlinedHeader key="header">
Request Body schema: <DropdownOrLabel {...props} />
{isRequired && <RequiredBody>required</RequiredBody>}
{isOptional && <OptionalBody>optional</OptionalBody>}
</UnderlinedHeader>
);
}
@ -71,11 +89,15 @@ function DropdownWithinHeader(props) {
export function BodyContent(props: {
content: MediaContentModel;
description?: string;
bodyRequired?: boolean;
}): JSX.Element {
const { content, description } = props;
const { content, description, bodyRequired } = props;
const { isRequestType } = content;
return (
<MediaTypesSwitch content={content} renderDropdown={DropdownWithinHeader}>
<MediaTypesSwitch
content={content}
renderDropdown={props => <DropdownWithinHeader bodyRequired={bodyRequired} {...props} />}
>
{({ schema }) => {
return (
<>
@ -95,3 +117,19 @@ export function BodyContent(props: {
</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};
`;

View File

@ -34,7 +34,12 @@ export const RedocStandalone = function (props: RedocStandaloneProps) {
return (
<ErrorBoundary>
<StoreBuilder spec={spec} specUrl={specUrl} options={options} onLoaded={onLoaded}>
<StoreBuilder
spec={spec ? { ...spec } : undefined}
specUrl={specUrl}
options={options}
onLoaded={onLoaded}
>
{({ loading, store }) =>
!loading ? (
<Redoc store={store!} />

View File

@ -10,7 +10,7 @@ import { Schema } from '../Schema';
import { Extensions } from '../Fields/Extensions';
import { Markdown } from '../Markdown/Markdown';
import { ResponseHeaders } from './ResponseHeaders';
import { ConstraintsView } from '../Fields/FieldContstraints';
import { ConstraintsView } from '../Fields/FieldConstraints';
export class ResponseDetails extends React.PureComponent<{ response: ResponseModel }> {
render() {

View File

@ -41,7 +41,9 @@ export const ResponseDetailsWrap = styled.div`
padding: 10px;
`;
export const HeadersCaption = styled(UnderlinedHeader.withComponent('caption'))`
export const HeadersCaption = styled(UnderlinedHeader).attrs({
as: 'caption',
})`
text-align: left;
margin-top: 1em;
caption-side: top;

View File

@ -16,14 +16,24 @@ export class ArraySchema extends React.PureComponent<SchemaProps> {
render() {
const schema = this.props.schema;
const itemsSchema = schema.items;
const fieldParentsName = this.props.fieldParentsName;
const minMaxItems =
schema.minItems === undefined && schema.maxItems === undefined
? ''
: `(${humanizeConstraints(schema)})`;
const updatedParentsArray = fieldParentsName
? [...fieldParentsName.slice(0, -1), fieldParentsName[fieldParentsName.length - 1] + '[]']
: fieldParentsName;
if (schema.fields) {
return <ObjectSchema {...(this.props as any)} level={this.props.level} />;
return (
<ObjectSchema
{...(this.props as any)}
level={this.props.level}
fieldParentsName={updatedParentsArray}
/>
);
}
if (schema.displayType && !itemsSchema && !minMaxItems.length) {
return (
@ -37,7 +47,7 @@ export class ArraySchema extends React.PureComponent<SchemaProps> {
<div>
<ArrayOpenningLabel> Array {minMaxItems}</ArrayOpenningLabel>
<PaddedSchema>
<Schema {...this.props} schema={itemsSchema} />
<Schema {...this.props} schema={itemsSchema} fieldParentsName={updatedParentsArray} />
</PaddedSchema>
<ArrayClosingLabel />
</div>

View File

@ -16,6 +16,7 @@ export interface ObjectSchemaProps extends SchemaProps {
fieldName: string;
parentSchema: SchemaModel;
};
fieldParentsName?: string[];
}
export const ObjectSchema = observer(
@ -26,8 +27,9 @@ export const ObjectSchema = observer(
skipReadOnly,
skipWriteOnly,
level,
fieldParentsName,
}: ObjectSchemaProps) => {
const { expandSingleSchemaField, showObjectSchemaExamples, schemaExpansionLevel } =
const { expandSingleSchemaField, showObjectSchemaExamples, schemasExpansionLevel } =
React.useContext(OptionsContext);
const filteredFields = React.useMemo(
@ -45,7 +47,7 @@ export const ObjectSchema = observer(
);
const expandByDefault =
(expandSingleSchemaField && filteredFields.length === 1) || schemaExpansionLevel >= level!;
(expandSingleSchemaField && filteredFields.length === 1) || schemasExpansionLevel >= level!;
return (
<PropertiesTable>
@ -58,6 +60,7 @@ export const ObjectSchema = observer(
isLast={isLast}
field={field}
expandByDefault={expandByDefault}
fieldParentsName={Number(level) > 1 ? fieldParentsName : []}
renderDiscriminatorSwitch={
discriminator?.fieldName === field.name
? () => (

View File

@ -8,7 +8,7 @@ import {
} from '../../common-elements/schema';
import { Badge } from '../../common-elements/shelfs';
import { SchemaModel } from '../../services/models';
import { ConstraintsView } from '../Fields/FieldContstraints';
import { ConstraintsView } from '../Fields/FieldConstraints';
import { Schema, SchemaProps } from './Schema';
export interface OneOfButtonProps {
@ -23,8 +23,8 @@ export class OneOfButton extends React.Component<OneOfButtonProps> {
const { idx, schema, subSchema } = this.props;
return (
<StyledOneOfButton
deprecated={subSchema.deprecated}
active={idx === schema.activeOneOf}
$deprecated={subSchema.deprecated}
$active={idx === schema.activeOneOf}
onClick={this.activateOneOf}
>
{subSchema.title || subSchema.typePrefix + subSchema.displayType}

View File

@ -21,6 +21,7 @@ export interface SchemaOptions {
export interface SchemaProps extends SchemaOptions {
schema: SchemaModel;
fieldParentsName?: string[];
}
@observer

View File

@ -14,6 +14,7 @@ export interface ObjectDescriptionProps {
exampleRef?: string;
showReadOnly?: boolean;
showWriteOnly?: boolean;
showExample?: boolean;
parser: OpenAPIParser;
options: RedocNormalizedOptions;
}
@ -53,7 +54,7 @@ export class SchemaDefinition extends React.PureComponent<ObjectDescriptionProps
}
render() {
const { showReadOnly = true, showWriteOnly = false } = this.props;
const { showReadOnly = true, showWriteOnly = false, showExample = true } = this.props;
return (
<Section>
<Row>
@ -64,11 +65,16 @@ export class SchemaDefinition extends React.PureComponent<ObjectDescriptionProps
schema={this.mediaModel.schema}
/>
</MiddlePanel>
{showExample && (
<DarkRightPanel>
<MediaSamplesWrap>
<MediaTypeSamples renderDropdown={this.renderDropdown} mediaType={this.mediaModel} />
<MediaTypeSamples
renderDropdown={this.renderDropdown}
mediaType={this.mediaModel}
/>
</MediaSamplesWrap>
</DarkRightPanel>
)}
</Row>
</Section>
);

View File

@ -37,6 +37,7 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
activeItemRef: MenuItem | null = null;
static contextType = OptionsContext;
declare context: React.ContextType<typeof OptionsContext>;
constructor(props) {
super(props);

View File

@ -39,7 +39,7 @@ export function OAuthFlowComponent(props: OAuthFlowProps) {
{flow!.refreshUrl && (
<SecurityRow>
<strong> Refresh URL: </strong>
{flow!.refreshUrl}
<code>{flow!.refreshUrl}</code>
</SecurityRow>
)}
{!!scopesNames.length && (

Some files were not shown because too many files have changed in this diff Show More