Merge remote-tracking branch 'main/master'

# Conflicts:
#	README.md
#	package.json
#	src/services/RedocNormalizedOptions.ts
#	tslint.json
#	yarn.lock
This commit is contained in:
Arian Rahimi 2020-02-17 14:54:39 +03:30
commit 4cc3706585
57 changed files with 3029 additions and 2345 deletions

View File

@ -36,7 +36,7 @@ $ yarn install # or npm
# dev-server, watch and auto reload playground
$ yarn start
# start playground app in production environement
# start playground app in production environment
$ yarn start:prod
# runt tslint
@ -84,11 +84,11 @@ There are some other scripts available in the `scripts` section of the `package.
- **`src`**: contains the source code. The codebase is written in Typescript. CSS styles are managed with [Styled components](https://www.styled-components.com/). State is managed by [MobX](https://github.com/mobxjs/mobx)
- **`src/common-elements`**: containts common Styled elements or components used in multiple places
- **`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/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
- **`src/styled-components.ts`**: - reexprots styled-components with proper typescript annotations using theme
- **`src/styled-components.ts`**: - reexports styled-components with proper typescript annotations using theme
- **`src/theme.ts`**: - default theme (colors, fonts, etc) used by all the components

View File

@ -4,8 +4,7 @@ node_js:
cache:
yarn: true
directories:
# we also need to cache folder with Cypress binary
- ~/.cache
- "~/.cache"
env:
global:
- GH_REF: github.com/Redocly/redoc.git
@ -15,12 +14,12 @@ env:
- secure: apiavCfCQngL9Een1m7MIXMf3bqO3rY4YY59TMBl/yFKi80CEsHPHhgVUkl6hC+aM5PeBt/vgjh37rHMX31j/pcSZ4Z8SO/4Bwr36iHfhSxSEuAQog8P07qWqH7wYYWGIVmF682stgl0fYF+GN92sx/6edFVzsWVECf2G7imtICKSTbhKGm3Dhn2JwGnhD7eyfgZ33omgiaswumdu0xABoXDfqSZR+16fC4Ap5rhv3fXO9ndvRNy1STn376nT+my6e86UrQL4aS/S+HNHgIe1BUs+5cOp6Jgw6t0ie7phY0EAiECsRxy9K4e3Dctv9m6+Wma4+vy65MS0zGyrqey6oyV4l827sCOjrD1qcqc9bX6FlMSouVoNfE4ZjINNAbgigTaiLSoDSPcf5I5smkkM2ezzFOMSZwZxNdaNL2LKb97vc8m/ZUkv0sKZyT7oqVL7aJweEivsSHj5l2KR8Z7XrVB1y2eI6GvyTSa/d+CL4dSRzjh8+IRN047YBrdTKD5IkdT0upfoBu14WPUfFmLKxX+iMCslXRWb6kwojhrWNYmZvL65KRAzJ6+eIPDG/W5QUOpYyYT77bLlBQjVo6NmVvl9v3HMECq9CHH0ivKFBGPiKMOx7cJkTax3FuyznOW2WCXB9kTb5Zk9toaiNlSp9L6ll/h2Eyxa6n6sWUgmmM=
- secure: vVRg9BKGBwF2MbXQnEccFL+XW0/7RaBmge9k7jbGYScBwkP3XjnQ/Xaj0cvTz2CM2EqXsbpwfvr4Jo+enW/E3MGy5RiEzv5hUe/jIFRR0gfAFbZxSTvg5xiFhTDffqQk0fncO4jXu+wPO5lZ2CMRWzyXz3i1MZhjMcAgoDr1+TRss/EGXLNHxr2RM88tpUW0fV2prIRoyGqhCgnYZtrm7hmr41Ej+itg1MqZLml/Rjkt3KsNgI+z0O5Qn3QSAO8GtPZqeftQxAjevOmxZGcssxY8EJvqbjAujr4y51WncXpEmCRPSY2J9R5+fkgZurqwnJapbQpjwKYemok3ps7EHg2gWkAlmPdQO4LKpbffGkM/o5b+8+HdIuQZugsSWQD9hUSftTAFLcfA1isi7V2lHE1m8bX/vk9zIyDdcPSwIaFe9y+w3PexwFmTjPLq+nia/UY2kARFZMEIFAJby6gkA70DcAJ50QOM86InJu5DSzGbIssgTGAXCn0TPPyGveaurVLw8x61j3yh8LDF46gUHey3rqv6WjpCM9h/vg7X/gq5ve/5Q2KHscUKfs/sA53Mt7qPeqRZY1QCaaRjzqJO/ZraHqWWeKmPKaWhPGR0kYEnkvB+K9GZ+HNSWCltjCO4SJ1xeEl7CRqQxAwdiMATF5SKqyiC+bn5oc35mFgbRF8=
- secure: ela1tn4wkJQZ8O4iv+4pIZi5cebxeCStVF1tEUe6qa6WWgJYVXmS2tEv3QQ36NUBFrP58Y6yl10XguPnvj/2BCqcZI4FUBHh3BfiBoUtXxDCVKI5LtlniNiOFGUwfzEeYka8T51zFlcUXSCCaxHkRZbmBsIzeJ39UwTi5fy0qwLv9GgL0czhwm8I8sZ8gyWdGmqpXNFEsb9JP4ZA3mw2qpWkGpGAqQPD9XSCkU3LmX1/ltwsBMAgGYKLLo7vU8d5KV2c8L1Gnxfl6BvfmqUD/dsas/1rnk08rU2nez5ekuQa2tJRkDLOv8bqvrGRLjHSUa3yPuisC6SsDGSU7/3DcozZyYsz7WQ6WI8tYabyjqqeJTF1N8a5T3IbZaZNV1J4JHOO9Cb/y7gIg4edANg6tbe7MzZpdEPRBnw6OkdTdirpNsWQ/jnfpY1hn6mraQZz/q8yaz3W21NjbBJhVnvfh5gWLKQ3YAAziCBhmmrThFhUu0czz+G920MuFo477TBcxvlrE7CaNJ0Q6yYkDehEPOv3jvEs1QVHPwuRrlaLTbBhrlTICKZ58gdX30O8N4i0Xgp/v6qrC03bplnMQc8E/uC61wcVLJixnlZVp8FODpUvPjsxVFkpuNSOIAaiqcERmoiPXx05Epzmr78hjU5rYCx/1MmVoeB4gs9YO+4guD4=
- secure: SEqTg6WoGPPpcWzJ03ZfcSBb3nZ2Mdhug0ec2PszuzYO3libCb9usiqi+jils9z6qyXsL6ecz8HYazDGOUepnubhIpI5otLgfn9XiapjMT06Bj//AjbKpH7eu3TJSpJMzoRHZrKIE1y9ZKIBqKwl9Xs7ko+1oa+MLhrLuxXkoi0JqRB5UzkQtJRDoxVNjysnLQn+hsfnm+yuqPHZd2+Loy++q//WHuf9bwJrlkXn2ICYQIX5oQGlxNO6ui+OZklb0YknvyO5GdQeoKaHYru3MMKKCIS6I7AG9wLmPs5Ou3T0Ia0Xx4/7xazs0rH4NCVpIceSYc3v6evR37pp8MsFTC3BzjL1V3slTnmitC1KSNM8ndGRUg1nsCBkJysnR3HpX6SHuCH+UzOuMxEjwiPdSRnzJPEbTHa1HqMfTkTJMbm4zhp7W4/ozX4TtjUB0ql6NoQE2n0Z3aYgR2C78TmzaPQun8EgredWnCID1FedyexaNcw4HyZ2rXlcvG3rBzSwLHH5PePT9skyqy6KtIaL0MlAP556ilgUeyCZfCNdTmzCvPDZuqaeLRezWDdsKnRfTkxIW80QWlmZ6sW0hynJV5JN2Oghk9Tr+QzgV4ZF68FHwoU9YXCTyX4w5iTYq/GjvfTBqB3VSGPOz3PwU7r47tmaYzPj+I44zqktgxyuxDo=
- secure: Pc86j2/rgCPAEWcjzPbbVFkL2SwNt4CpeXP69zedMi9RomQblMJa9R0wbAT6H5VCnPky2cpmxkzjFWOc91N9crzceg6aOoWkPr6pTTnTv+EL70i6+XSrAFpkgRjszprxnU1Bz+GcYEjP/zR8479fx8ooSl7MwHOaP7XiQyaBQAbY1CPlmpT+b4Ut7Fm5QnD90/NgPjbKkngl0kVUfNFdFOSfJ3QWLyFCUUSQ4DlxccJOTIaOH/n8u9Nz4NTuuHE3XeRuEsuj2SJutJnFBUYwsvugrdPvKWiubkewJfylp6EwABzByENsg6XxW9SIq80lMc3Oi7ld9L2lAgpj+8/42olnbMzH0F0rw/p1ccPAdVwQVV6YFaqCzivK5A5aX5LmGKwJ6SR9k1PgcWP6sKKMIsIEObbyM88Tke3QkreEz+cLg/3jjko7Vpb0tbqh8BtbpWV+exL4rX3r2C5Mb1Es1W597hN5LSczWYFgw0ZETpfbVZg6Ri1iZks0wpsT/E+c0q2scUaBVrdTZseHxUPB7mPDlXL1l9/i4sOxPyBHZtJRAzeTT/fOXfj4vuD+ihspXzoRRLaQbizlb8FpyPA47XdmBDpXi3OBiaIFLwvybEn7qM7rqvWxdz6vvCZv0t/AN3t3Qvh2vHKCshHecaa8NoJQHWrdFMHeecYHyeoujZ8=
addons:
chrome: stable
apt:
packages:
- libgconf-2-4 # for cypress
- libgconf-2-4
before_script: npm run bundle
script: npm test && ([ "${TRAVIS_PULL_REQUEST}" = "false" ] && npm run e2e-ci || npm
run e2e)

View File

@ -1,3 +1,99 @@
# [2.0.0-rc.23](https://github.com/Redocly/redoc/compare/v2.0.0-rc.22...v2.0.0-rc.23) (2020-02-09)
### Bug Fixes
* fix broken sticky sidebar in Chrome 80 ([1a2a7dd](https://github.com/Redocly/redoc/commit/1a2a7dd8331cedd6ced4c18accf0b417549b3ff3)), closes [#1167](https://github.com/Redocly/redoc/issues/1167)
# [2.0.0-rc.22](https://github.com/Redocly/redoc/compare/v2.0.0-rc.21...v2.0.0-rc.22) (2020-01-15)
### Bug Fixes
* do not process oneOf if inherited from parent with discriminator ([5248415](https://github.com/Redocly/redoc/commit/52484157912d908daea8255d0b7d684b33258d7a))
### Features
* add HTTP syntax highlighting ([#1157](https://github.com/Redocly/redoc/issues/1157)) ([27a4af7](https://github.com/Redocly/redoc/commit/27a4af707686d56280753473b4294ee4af096534))
# [2.0.0-rc.21](https://github.com/Redocly/redoc/compare/v2.0.0-rc.20...v2.0.0-rc.21) (2020-01-10)
### 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)
* 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))
# [2.0.0-rc.20](https://github.com/Redocly/redoc/compare/v2.0.0-rc.19...v2.0.0-rc.20) (2019-12-13)
### Bug Fixes
* fix missing parameters ([942d782](https://github.com/Redocly/redoc/commit/942d782b5a8d08767a7538741b75587cf1e67f44)), closes [#1142](https://github.com/Redocly/redoc/issues/1142)
# [2.0.0-rc.19](https://github.com/Redocly/redoc/compare/v2.0.0-rc.18...v2.0.0-rc.19) (2019-12-13)
### Bug Fixes
* change the title of "Security Scheme Type" to match "HTTP Authorization Scheme" ([#1126](https://github.com/Redocly/redoc/issues/1126)) ([289c8e6](https://github.com/Redocly/redoc/commit/289c8e6ae1ff00371f86d3f2646607c64bc30050))
* do not URI-encode parameter values for better readability ([6aeb0bf](https://github.com/Redocly/redoc/commit/6aeb0bf68df3f03f2ca1317f8b5787545bd363f1)), closes [#1138](https://github.com/Redocly/redoc/issues/1138)
* fix sortByRequired (stabilise sort) ([#1136](https://github.com/Redocly/redoc/issues/1136)) ([d92434d](https://github.com/Redocly/redoc/commit/d92434d11b08e8b0f6be5453ec69aa1d0e0df79f)), closes [#1104](https://github.com/Redocly/redoc/issues/1104) [#1121](https://github.com/Redocly/redoc/issues/1121) [#1061](https://github.com/Redocly/redoc/issues/1061)
* h2 padding on mobile ([7ed1a7e](https://github.com/Redocly/redoc/commit/7ed1a7ef0e7978a0dfb40afcc72c3362466f9624)), closes [#1118](https://github.com/Redocly/redoc/issues/1118)
* python comment stripped in headings ([4a25aae](https://github.com/Redocly/redoc/commit/4a25aaef69fad814836392ea7e41eb32c182a261)), closes [#1116](https://github.com/Redocly/redoc/issues/1116)
* remove hardcoded fontFamily for oneOf labels ([094ce91](https://github.com/Redocly/redoc/commit/094ce914e3f9cfe567b39db4ea88208014d8b686)), closes [#1120](https://github.com/Redocly/redoc/issues/1120)
* search-box use theme ([1bf490c](https://github.com/Redocly/redoc/commit/1bf490c05b343d262f8819bf1ddc433e070be1b9))
* support discriminator mapping 1-n ([6e390f9](https://github.com/Redocly/redoc/commit/6e390f9c7909da0b5d1d6fc571ab4ad92e715d6e)), closes [#1111](https://github.com/Redocly/redoc/issues/1111)
* wrap json examples in code tag ([#1064](https://github.com/Redocly/redoc/issues/1064)) ([dc5430e](https://github.com/Redocly/redoc/commit/dc5430e53def780a81612d269cc3aea3f8785eea))
### Features
* display `multipleOf` constrains ([#1065](https://github.com/Redocly/redoc/issues/1065)) ([3e90133](https://github.com/Redocly/redoc/commit/3e901336643b988ae45ae86c485005b8865e6e04))
* enable menuToggle by default ([5d81abe](https://github.com/Redocly/redoc/commit/5d81abeb28c1e4f2826e41424c10163834c37e45))
* new option hideSchemaTitles ([11cc4c4](https://github.com/Redocly/redoc/commit/11cc4c4c3e04a7e5bf3a9ebba20d10fa882a49e5))
* new option payloadSampleIdx ([eaaa99d](https://github.com/Redocly/redoc/commit/eaaa99d68e2392273e8d9c0173db3b546e035d5f))
* **cli:** Fallback on the spec's title before falling back on… ([#1073](https://github.com/Redocly/redoc/issues/1073)) ([e01eea4](https://github.com/Redocly/redoc/commit/e01eea445c93d74b66533c860d76bb3aff4d6df2))
# [2.0.0-rc.18](https://github.com/Redocly/redoc/compare/v2.0.0-rc.17...v2.0.0-rc.18) (2019-10-16)
### Bug Fixes
* add oneOf buttons vertical space when wrapped to new line ([cd9fd61](https://github.com/Redocly/redoc/commit/cd9fd61))
* improve mime-type dropdown font ([ce885f8](https://github.com/Redocly/redoc/commit/ce885f8))
# [2.0.0-rc.17](https://github.com/Redocly/redoc/compare/v2.0.0-rc.16...v2.0.0-rc.17) (2019-10-16)
### Bug Fixes
* active menu item scroll into view ([0a01e9a](https://github.com/Redocly/redoc/commit/0a01e9a))
* changed several components style font-family to monospace ([#1063](https://github.com/Redocly/redoc/issues/1063)) ([0c20e64](https://github.com/Redocly/redoc/commit/0c20e64)), closes [#909](https://github.com/Redocly/redoc/issues/909)
* no quotes for default values in header fields. ([#1059](https://github.com/Redocly/redoc/issues/1059)) ([b5af71d](https://github.com/Redocly/redoc/commit/b5af71d))
* types over-pluralization ([#1057](https://github.com/Redocly/redoc/issues/1057)) ([4494f80](https://github.com/Redocly/redoc/commit/4494f80)), closes [#1053](https://github.com/Redocly/redoc/issues/1053)
### Features
* added support for file paths as --options cli argument ([#1049](https://github.com/Redocly/redoc/issues/1049)) ([4adb927](https://github.com/Redocly/redoc/commit/4adb927))
# [2.0.0-rc.16](https://github.com/Redocly/redoc/compare/v2.0.0-rc.15...v2.0.0-rc.16) (2019-09-30)
@ -17,7 +113,7 @@
* do not crash on empty scopes ([e787d9e](https://github.com/Redocly/redoc/commit/e787d9e)), closes [#1044](https://github.com/Redocly/redoc/issues/1044)
* false-positive recursive detection with allOf at the same level ([faa74d6](https://github.com/Redocly/redoc/commit/faa74d6))
* fix scrollYOffset when SSR ([21258a5](https://github.com/Redocly/redoc/commit/21258a5))
* left menu item before group is not highligted ([67e2a8f](https://github.com/Redocly/redoc/commit/67e2a8f)), closes [#1033](https://github.com/Redocly/redoc/issues/1033)
* left menu item before group is not highlighted ([67e2a8f](https://github.com/Redocly/redoc/commit/67e2a8f)), closes [#1033](https://github.com/Redocly/redoc/issues/1033)
* remove excessive whitespace between md sections on small screens ([e318fb3](https://github.com/Redocly/redoc/commit/e318fb3)), closes [#874](https://github.com/Redocly/redoc/issues/874)
* use url-template dependency ([#1008](https://github.com/Redocly/redoc/issues/1008)) ([32a464a](https://github.com/Redocly/redoc/commit/32a464a)), closes [#1007](https://github.com/Redocly/redoc/issues/1007)
@ -70,7 +166,7 @@
* do not add extra slashes to pattern ([70d1ee9](https://github.com/Redocly/redoc/commit/70d1ee9)), closes [#983](https://github.com/Redocly/redoc/issues/983)
* dropdown fixes related to object description ([0504ad4](https://github.com/Redocly/redoc/commit/0504ad4))
* incorrect serialization of parameter sample with hypen ([f7dd658](https://github.com/Redocly/redoc/commit/f7dd658))
* incorrect serialization of parameter sample with hyphen ([f7dd658](https://github.com/Redocly/redoc/commit/f7dd658))
* redoc-cli: Add missing content type header on compressed responses of `/` path
@ -144,7 +240,7 @@
### Bug Fixes
* broken schema talbes with long enums ([3a74b74](https://github.com/Rebilly/ReDoc/commit/3a74b74))
* broken schema tables with long enums ([3a74b74](https://github.com/Rebilly/ReDoc/commit/3a74b74))
* deep linking sometimes not working when sent over messengers ([2491d97](https://github.com/Rebilly/ReDoc/commit/2491d97))
@ -162,7 +258,7 @@
* IE11 add missing fetch and URL polyfills ([d2ce1bd](https://github.com/Rebilly/ReDoc/commit/d2ce1bd)), closes [#875](https://github.com/Rebilly/ReDoc/issues/875)
* ignore empty x-tagGroups array ([#869](https://github.com/Rebilly/ReDoc/issues/869)) ([4366a0d](https://github.com/Rebilly/ReDoc/commit/4366a0d))
* incorrect detected schema title for deeply inherited schemas ([7d7b4e3](https://github.com/Rebilly/ReDoc/commit/7d7b4e3))
* pluralize arrray of types ([fdcac30](https://github.com/Rebilly/ReDoc/commit/fdcac30))
* pluralize array of types ([fdcac30](https://github.com/Rebilly/ReDoc/commit/fdcac30))
* remove huge space after Authentication section ([548fae3](https://github.com/Rebilly/ReDoc/commit/548fae3)), closes [#872](https://github.com/Rebilly/ReDoc/issues/872)
* remove query string from server URL ([#895](https://github.com/Rebilly/ReDoc/issues/895)) ([64453ff](https://github.com/Rebilly/ReDoc/commit/64453ff))
* remove tabs top margin ([5c187f3](https://github.com/Rebilly/ReDoc/commit/5c187f3))
@ -246,7 +342,7 @@
* improve scrolling performance in Chrome with non-wrapped json examples ([a69c402](https://github.com/Rebilly/ReDoc/commit/a69c402))
* nested oneOf button spacing ([3673720](https://github.com/Rebilly/ReDoc/commit/3673720)), closes [#719](https://github.com/Rebilly/ReDoc/issues/719)
* onLoaded callback not run on spec error ([e77df0c](https://github.com/Rebilly/ReDoc/commit/e77df0c)), closes [#690](https://github.com/Rebilly/ReDoc/issues/690)
* theme improvments by [@stasiukanya](https://github.com/stasiukanya) ([e2d0cd5](https://github.com/Rebilly/ReDoc/commit/e2d0cd5))
* theme improvements by [@stasiukanya](https://github.com/stasiukanya) ([e2d0cd5](https://github.com/Rebilly/ReDoc/commit/e2d0cd5))
* **cli:** old peer dependency issue with styled-components ([#699](https://github.com/Rebilly/ReDoc/issues/699)) ([9e2853c](https://github.com/Rebilly/ReDoc/commit/9e2853c))
@ -318,7 +414,7 @@
### Bug Fixes
* addd indent to array schema internals ([865f3ce](https://github.com/Rebilly/ReDoc/commit/865f3ce))
* add indent to array schema internals ([865f3ce](https://github.com/Rebilly/ReDoc/commit/865f3ce))
* fix oneOf/anyOf titles ([39b930d](https://github.com/Rebilly/ReDoc/commit/39b930d)), closes [#618](https://github.com/Rebilly/ReDoc/issues/618) [#621](https://github.com/Rebilly/ReDoc/issues/621)
@ -364,7 +460,7 @@
### Bug Fixes
* add some spacing between operation description and parameters ([597688e](https://github.com/Rebilly/ReDoc/commit/597688e))
* description is not rendered if doesn't containt markdown headings ([90ed717](https://github.com/Rebilly/ReDoc/commit/90ed717)), closes [#591](https://github.com/Rebilly/ReDoc/issues/591)
* description is not rendered if doesn't contain markdown headings ([90ed717](https://github.com/Rebilly/ReDoc/commit/90ed717)), closes [#591](https://github.com/Rebilly/ReDoc/issues/591)
* download button downloads index.html instead of spec with CLI ([334f904](https://github.com/Rebilly/ReDoc/commit/334f904)), closes [#594](https://github.com/Rebilly/ReDoc/issues/594)
* fix Authentication section is not rendered ([2ecc8bc](https://github.com/Rebilly/ReDoc/commit/2ecc8bc)), closes [#590](https://github.com/Rebilly/ReDoc/issues/590)
* fix linebreaks in multiparagraph field descriptions ([8fb9cd6](https://github.com/Rebilly/ReDoc/commit/8fb9cd6))
@ -675,7 +771,7 @@
### Bug Fixes
* Path parameters are not correctly overriden ([c406dc5](https://github.com/Rebilly/ReDoc/commit/c406dc5)), closes [#400](https://github.com/Rebilly/ReDoc/issues/400)
* Path parameters are not correctly overridden ([c406dc5](https://github.com/Rebilly/ReDoc/commit/c406dc5)), closes [#400](https://github.com/Rebilly/ReDoc/issues/400)
* Use parentNode instead of parentElement to fix IE11 crash ([e8adb60](https://github.com/Rebilly/ReDoc/commit/e8adb60)), closes [#406](https://github.com/Rebilly/ReDoc/issues/406)
@ -837,7 +933,7 @@
* do not ignore path level parameters ([14f8408](https://github.com/Rebilly/Redoc/commit/14f8408))
* improve rendering of types ([17da7b7](https://github.com/Rebilly/Redoc/commit/17da7b7))
* move title propagation to the correct place ([0b0bc99](https://github.com/Rebilly/Redoc/commit/0b0bc99))
* owerwrite text-align to left ([bfee3ed](https://github.com/Rebilly/Redoc/commit/bfee3ed))
* overwrite text-align to left ([bfee3ed](https://github.com/Rebilly/Redoc/commit/bfee3ed))
### Features
@ -899,7 +995,7 @@ Complete rewrite also means that this rewrite may introduce issues, but they sho
### Deprecations
- Fonts are not loaded by ReDoc so you should load them. Default fonts can be loaded as bellow:
- Fonts are not loaded by ReDoc so you should load them. Default fonts can be loaded as below:
```html
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
@ -1268,7 +1364,7 @@ closes [#321](https://github.com/Rebilly/ReDoc/issues/321)
### Bug fixes
* Update webpack to the latest beta ([#143](https://github.com/Rebilly/ReDoc/issues/143))
* Fix read-only fields appear in request samples ([#142](https://github.com/Rebilly/ReDoc/issues/142))
* A few more minor UI improvemnts
* A few more minor UI improvements
### Features/Improvements
* Major performance optimization with new option `lazy-rendering`

View File

@ -214,7 +214,7 @@ ReDoc makes use of the following [vendor extensions](https://swagger.io/specific
* [`x-traitTag`](docs/redoc-vendor-extensions.md#x-traitTag) - useful for handling out common things like Pagination, Rate-Limits, etc
* [`x-code-samples`](docs/redoc-vendor-extensions.md#x-code-samples) - specify operation code samples
* [`x-examples`](docs/redoc-vendor-extensions.md#x-examples) - specify JSON example for requests
* [`x-nullable`](docs/redoc-vendor-extensions.md#nullable) - mark schema param as a nullable
* [`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)
@ -224,31 +224,33 @@ ReDoc makes use of the following [vendor extensions](https://swagger.io/specific
### `<redoc>` options object
You can use all of the following options with standalone version on <redoc> tag by kebab-casing them, e.g. `scrollYOffset` becomes `scroll-y-offset` and `expandResponses` becomes `expand-responses`.
* `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!**
* `disableSearch` - disable search indexing and search box.
* `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.
* `enableConsole` - you should set true if you want to use the built-in console, default `false`
* `hideDownloadButton` - do not show "Download" spec button. **THIS DOESN'T MAKE YOUR SPEC PRIVATE**, it just hides the button.
* `hideHostname` - if set, the protocol and hostname is not shown in the operation definition.
* `hideLoading` - do not show loading animation. Useful for small docs.
* `hideSingleRequestSampleTab` - do not show the request sample tab for requests with only one sample.
* `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`.
* `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 `false`.
* `nativeScrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs).
* `noAutoAuth` - do not inject Authentication section automatically.
* `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);
* **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.
* `suppressWarnings` - if set, warnings are not rendered at the top of documentation (they still are logged to the console).
* `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.~~
* `hideHostname` - if set, the protocol and hostname is not shown in the operation definition.
* `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.
* `requiredPropsFirst` - show required properties first ordered in the same order as in `required` array.
* `sortPropsAlphabetically` - sort properties alphabetically
* `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
* `noAutoAuth` - do not inject Authentication section automatically
* `pathInMiddlePanel` - show path link and HTTP verb in the middle panel instead of the right one
* `hideLoading` - do not show loading animation. Useful for small docs
* `nativeScrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs)
* `hideDownloadButton` - do not show "Download" spec button. **THIS DOESN'T MAKE YOUR SPEC PRIVATE**, it just hides the button.
* `disableSearch` - disable search indexing and search box
* `onlyRequiredInSamples` - shows only required fields in request samples.
* `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`.
* `menuToggle` - if true clicking second time on expanded menu item will collapse it, default `false`
* `enableConsole` - you should set true if you want to use the built-in console, default `false`
* `expandDefaultServerVariables` - enable expanding default server variables, default `false`
* `theme` - ReDoc theme. Not documented yet. For details check source code: [theme.ts](https://github.com/Redocly/redoc/blob/master/src/theme.ts)
* `payloadSampleIdx` - if set, payload sample will be inserted at this index or last. Indexes start from 0.
* `theme` - ReDoc theme. Not documented yet. For details check source code: [theme.ts](https://github.com/Redocly/redoc/blob/master/src/theme.ts).
* `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!**
## Advanced usage of standalone version
Instead of adding `spec-url` attribute to the `<redoc>` element you can initialize ReDoc via globally exposed `Redoc` object:

View File

@ -32,7 +32,7 @@ const configDir = './benchmark/revisions/config.js';
console.log(`Writing config "${configDir}"`);
fs.writeFileSync(configDir, configFile);
console.log('Starging benchmark server');
console.log('Starting benchmark server');
const proc = spawn('npm', ['run', 'start:benchmark']);
proc.stdout.on('data', data => {

View File

@ -7,7 +7,7 @@
# To run:
# To display the command line options:
# $ docker run --rm -it redoc-cli --help
# .. will display the comand line 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

View File

@ -14,7 +14,14 @@ import * as zlib from 'zlib';
import { createStore, loadAndBundleSpec, Redoc } from 'redoc';
import { watch } from 'chokidar';
import { createReadStream, existsSync, readFileSync, ReadStream, writeFileSync } from 'fs';
import {
createReadStream,
existsSync,
lstatSync,
readFileSync,
ReadStream,
writeFileSync,
} from 'fs';
import * as mkdirp from 'mkdirp';
import * as YargsParser from 'yargs';
@ -99,7 +106,6 @@ YargsParser.command(
yargs.options('title', {
describe: 'Page Title',
type: 'string',
default: 'ReDoc documentation',
});
yargs.options('disableGoogleFont', {
@ -197,7 +203,7 @@ async function serve(port: number, pathToSpec: string, options: Options = {}) {
const watcher = watch(pathToSpecDirectory, watchOptions);
const log = console.log.bind(console);
const handlePath = async path => {
const handlePath = async _path => {
try {
spec = await loadAndBundleSpec(pathToSpec);
pageHTML = await getPageHTML(spec, pathToSpec, options);
@ -291,7 +297,7 @@ async function getPageHTML(
? '<script src="https://unpkg.com/redoc@next/bundles/redoc.standalone.js"></script>'
: `<script>${redocStandaloneSrc}</script>`) + css
: '<script src="redoc.standalone.js"></script>',
title,
title: title || spec.info.title || 'ReDoc documentation',
disableGoogleFont,
templateOptions,
});
@ -357,13 +363,23 @@ function handleError(error: Error) {
}
function getObjectOrJSON(options) {
switch (typeof options) {
case 'object':
return options;
case 'string':
try {
return options && typeof options === 'string'
? JSON.parse(options) : options
? options
: {};
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${options}\nis not a valid JSON.`);
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:
return {};
}
}

View File

@ -1,6 +1,6 @@
{
"name": "redoc-cli",
"version": "0.9.2",
"version": "0.9.6",
"description": "ReDoc's Command Line Interface",
"main": "index.js",
"bin": "index.js",
@ -19,7 +19,7 @@
"node-libs-browser": "^2.2.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"redoc": "2.0.0-rc.16",
"redoc": "2.0.0-rc.23",
"styled-components": "^4.3.2",
"tslib": "^1.10.0",
"yargs": "^13.3.0"

View File

@ -78,6 +78,13 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.6.3":
version "7.7.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f"
integrity sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/template@^7.1.0":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
@ -264,11 +271,6 @@ better-ajv-errors@^0.6.1:
jsonpointer "^4.0.1"
leven "^2.1.0"
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
binary-extensions@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
@ -475,10 +477,10 @@ color-name@1.1.3:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
console-browserify@^1.1.0:
version "1.1.0"
@ -619,20 +621,15 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
dom-walk@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
dompurify@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.3.tgz#5cc4965a487d54aedba6ba9634b137cfbd7eb50d"
integrity sha512-q006uOkD2JGSJgF0qBt7rVhUvUPBWCxpGayALmHvXx2iNlMfNVz7PDGeXEUjNGgIDjADz59VZCv6UE3U8XRWVw==
dompurify@^2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.7.tgz#f8266ad38fe1602fb5b3222f31eedbf5c16c4fd5"
integrity sha512-S3O0lk6rFJtO01ZTzMollCOGg+WAtCwS3U5E2WSDY/x/sy7q70RjEC4Dmrih5/UqzLLB9XoKJ8KqwBxaNvBu4A==
elliptic@^6.0.0:
version "6.5.0"
@ -652,11 +649,6 @@ emoji-regex@^7.0.1:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
end-of-stream@^1.1.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
@ -725,11 +717,6 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
fast-levenshtein@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@ -783,14 +770,6 @@ glob-parent@^5.0.0:
dependencies:
is-glob "^4.0.1"
global@^4.3.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
dependencies:
min-document "^2.19.0"
process "^0.11.10"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@ -808,7 +787,7 @@ grapheme-splitter@^1.0.4:
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
handlebars@*, handlebars@^4.1.2:
handlebars@*:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
@ -819,6 +798,17 @@ handlebars@*, handlebars@^4.1.2:
optionalDependencies:
uglify-js "^3.1.4"
handlebars@^4.1.2:
version "4.6.0"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.6.0.tgz#33af6c3eda930d7a924f5d8f1c6d8edc3180512e"
integrity sha512-i1ZUP7Qp2JdkMaFon2a+b0m5geE8Z4ZTLaGkgrObkEd+OkUKyRbRWw4KxuFCoHfdETSY1yf9/574eVoNSiK7pw==
dependencies:
neo-async "^2.6.0"
optimist "^0.6.1"
source-map "^0.6.1"
optionalDependencies:
uglify-js "^3.1.4"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@ -849,13 +839,6 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
dependencies:
react-is "^16.7.0"
http2-client@^1.2.5:
version "1.3.2"
resolved "https://registry.yarnpkg.com/http2-client/-/http2-client-1.3.2.tgz#80e31d90275844c0ccad8020b2de342a538a7971"
@ -999,13 +982,6 @@ json-to-ast@^2.0.3:
code-error-fragment "0.0.230"
grapheme-splitter "^1.0.4"
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
dependencies:
minimist "^1.2.0"
jsonpointer@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
@ -1023,15 +999,6 @@ leven@^2.1.0:
resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA=
loader-utils@^1.1.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
dependencies:
big.js "^5.2.2"
emojis-list "^2.0.0"
json5 "^1.0.1"
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
@ -1052,10 +1019,10 @@ loose-envify@^1.1.0, loose-envify@^1.4.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lunr@2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.6.tgz#f278beee7ffd56ad86e6e478ce02ab2b98c78dd5"
integrity sha512-swStvEyDqQ85MGpABCMBclZcLI/pBIlu8FFDtmX197+oEgKloJ67QnB+Tidh0340HmLMs39c4GrkPY3cmkXp6Q==
lunr@2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072"
integrity sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==
map-age-cleaner@^0.1.1:
version "0.1.3"
@ -1092,11 +1059,16 @@ mem@^4.0.0:
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
memoize-one@^5.0.0, memoize-one@~5.0.5:
memoize-one@^5.0.0:
version "5.0.5"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e"
integrity sha512-ey6EpYv0tEaIbM/nTDOpHciXUvd+ackQrJgEzBwemhZZIWZjcyodqEcrmqDy2BKRTM3a65kKBV4WtLXJDt26SQ==
memoize-one@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
merge-anything@^2.2.4:
version "2.4.0"
resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-2.4.0.tgz#86959caf02bb8969d1ae5e1b652862bc5fe54e44"
@ -1117,13 +1089,6 @@ mimic-fn@^2.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
dependencies:
dom-walk "^0.1.0"
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@ -1139,11 +1104,6 @@ minimist@0.0.8:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
@ -1156,17 +1116,17 @@ mkdirp@^0.5.1:
dependencies:
minimist "0.0.8"
mobx-react-lite@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.4.0.tgz#193beb5fdddf17ae61542f65ff951d84db402351"
integrity sha512-5xCuus+QITQpzKOjAOIQ/YxNhOl/En+PlNJF+5QU4Qxn9gnNMJBbweAdEW3HnuVQbfqDYEUnkGs5hmkIIStehg==
mobx-react-lite@^1.4.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.5.1.tgz#8eac90985b4d2bee475dd90a0d4d903be578f154"
integrity sha512-40Gn8hFq+MuNHqCaeSo2adN4WvpWkIeSYZVJWzRzm0rbEf0BFow6Ir9IefErql0pX9q650TN1JAQXvrXxKR8Mg==
mobx-react@^6.1.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.3.tgz#ad07880ea60cdcdb2a7e2a0d54e01379710cf00a"
integrity sha512-eT/jO9dYIoB1AlZwI2VC3iX0gPOeOIqZsiwg7tDJV1B7Z69h+TZZL3dgOE0UeS2zoHhGeKbP+K+OLeLMnnkGnA==
mobx-react@^6.1.4:
version "6.1.4"
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.4.tgz#818e7991c321c05bd9b8156d94be17dad165501e"
integrity sha512-wzrJF1RflhyLh8ne4FJfMbG8ZgRFmZ62b4nbyhJzwQpAmrkSnSsAWG9mIff4ffV/Q7OU+uOYf7rXvSmiuUe4cw==
dependencies:
mobx-react-lite "1.4.0"
mobx-react-lite "^1.4.2"
mobx@^4.2.0:
version "4.13.0"
@ -1430,12 +1390,12 @@ picomatch@^2.0.4:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
polished@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.1.tgz#1eb5597ec1792206365635811d465751f5cbf71c"
integrity sha512-GflTnlP5rrpDoigjczEkS6Ye7NDA4sFvAnlr5hSDrEvjiVj97Xzev3hZlLi3UB27fpxyTS9rWU64VzVLWkG+mg==
polished@^3.4.2:
version "3.4.2"
resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.2.tgz#b4780dad81d64df55615fbfc77acb52fd17d88cd"
integrity sha512-9Rch6iMZckABr6EFCLPZsxodeBpXMo9H4fRlfR/9VjMEyy5xpo1/WgXlJGgSjPyVhEZNycbW7UmYMNyWS5MI0g==
dependencies:
"@babel/runtime" "^7.4.5"
"@babel/runtime" "^7.6.3"
postcss-value-parser@^3.3.0:
version "3.3.1"
@ -1459,7 +1419,7 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
prop-types@^15.5.0, prop-types@^15.5.4, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.5.0, prop-types@^15.5.4, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -1540,30 +1500,11 @@ react-dropdown@^1.6.4:
dependencies:
classnames "^2.2.3"
react-hot-loader@^4.12.14:
version "4.12.14"
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.12.14.tgz#81ca06ffda0b90aad15d6069339f73ed6428340a"
integrity sha512-ecxH4eBvEaJ9onT8vkEmK1FAAJUh1PqzGqds9S3k+GeihSp7nKAp4fOxytO+Ghr491LiBD38jaKyDXYnnpI9pQ==
dependencies:
fast-levenshtein "^2.0.6"
global "^4.3.0"
hoist-non-react-statics "^3.3.0"
loader-utils "^1.1.0"
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
shallowequal "^1.1.0"
source-map "^0.7.3"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
react-is@^16.6.0, react-is@^16.8.1:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-tabs@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.0.0.tgz#60311a17c755eb6aa9b3310123e67db421605127"
@ -1602,31 +1543,30 @@ readdirp@^3.1.1:
dependencies:
picomatch "^2.0.4"
redoc@2.0.0-rc.16:
version "2.0.0-rc.16"
resolved "https://registry.yarnpkg.com/redoc/-/redoc-2.0.0-rc.16.tgz#01d5dafba6ae266a5934dc9904b87bc8a175b222"
integrity sha512-5YWk7NBebYZ8xMbKXA1sD++QsSh7NbnB2sStJRKLeP/rU4oX586SIqHXl+MW1OhIZW44mYFMHpYzxpZKCllk9w==
redoc@2.0.0-rc.23:
version "2.0.0-rc.23"
resolved "https://registry.yarnpkg.com/redoc/-/redoc-2.0.0-rc.23.tgz#3b8a47d9357e6ee52a0d93d08fb03ce00f424728"
integrity sha512-ifrewYzrCrGBv6bFSh5FEnDTywVm6IL/VEb7PUpVPCC1lMceMAB1HrlyKlBCyNqjq9LcRO+y9q881LfPXS4PUw==
dependencies:
classnames "^2.2.6"
decko "^1.2.0"
dompurify "^2.0.3"
dompurify "^2.0.7"
eventemitter3 "^4.0.0"
json-pointer "^0.6.0"
json-schema-ref-parser "^6.1.0"
lunr "2.3.6"
lunr "2.3.8"
mark.js "^8.11.1"
marked "^0.7.0"
memoize-one "~5.0.5"
mobx-react "^6.1.3"
memoize-one "~5.1.1"
mobx-react "^6.1.4"
openapi-sampler "1.0.0-beta.15"
perfect-scrollbar "^1.4.0"
polished "^3.4.1"
polished "^3.4.2"
prismjs "^1.17.1"
prop-types "^15.7.2"
react-dropdown "^1.6.4"
react-hot-loader "^4.12.14"
react-tabs "^3.0.0"
slugify "^1.3.5"
slugify "^1.3.6"
stickyfill "^1.1.1"
swagger2openapi "^5.3.1"
tslib "^1.10.0"
@ -1716,11 +1656,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@ -1782,10 +1717,10 @@ signal-exit@^3.0.0:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
slugify@^1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.5.tgz#90210678818b6d533cb060083aed0e8238133508"
integrity sha512-5VCnH7aS13b0UqWOs7Ef3E5rkhFe8Od+cp7wybFv5mv/sYSRkucZlJX0bamAJky7b2TTtGvrJBWVdpdEicsSrA==
slugify@^1.3.6:
version "1.3.6"
resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.6.tgz#ba5fd6159b570fe4811d02ea9b1f4906677638c3"
integrity sha512-wA9XS475ZmGNlEnYYLPReSfuz/c3VQsEMoU43mi6OnKMCdbnFXd4/Yg7J0lBv8jkPolacMpOrWEaoYxuE1+hoQ==
source-map@^0.5.0:
version "0.5.7"
@ -1797,11 +1732,6 @@ source-map@^0.6.1, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
@ -1995,11 +1925,11 @@ tty-browserify@0.0.0:
integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
version "3.7.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.4.tgz#e6d83a1aa32ff448bd1679359ab13d8db0fe0743"
integrity sha512-tinYWE8X1QfCHxS1lBS8yiDekyhSXOO6R66yNOCdUJeojxxw+PX2BHAz/BWyW7PQ7pkiWVxJfIEbiDxyLWvUGg==
dependencies:
commander "~2.20.0"
commander "~2.20.3"
source-map "~0.6.1"
url-template@^2.0.8:

View File

@ -1,6 +1,6 @@
#!/bin/bash
# DockerHub cd into Dockerfile location before buil
# DockerHub cd into Dockerfile location before build
# So we have to undo this.
cd ../..
docker build -f config/docker/Dockerfile -t $IMAGE_NAME .

View File

@ -53,7 +53,7 @@
},
{
"name": "Contacts",
"description": "Contacts are Customer's address book.\nAll contact information used in Invoices, Subscriptions, Transacions, etc is enlisted here. Hovewer, changing a Contact won't change corresponding contact information in related resources\n"
"description": "Contacts are Customer's address book.\nAll contact information used in Invoices, Subscriptions, Transacions, etc is enlisted here. However, changing a Contact won't change corresponding contact information in related resources\n"
},
{
"name": "Coupons",
@ -93,7 +93,7 @@
},
{
"name": "Files",
"description": "A File is an entity that can store a phyiscal file and some metadata. It also provides an easy access to\nits size, mime-type, user-defined tags and description thus allowing easy sorting and searching among stored\nfiles.\nThere are several methods of file uploading available: multipart/form-data encoded form, RAW POST (by sending\nfile contents as POST body), fetching from URL (by providing the file URL via 'url' param)\nAttachment is an entity that is used to link a File to one or multiple objects like Customer, Dispute, Payment,\nTransaction, Subscription, Plan, Product, Invoice, Note. That allows to quickly find and use files related to\nthose specific entities.\n"
"description": "A File is an entity that can store a physical file and some metadata. It also provides an easy access to\nits size, mime-type, user-defined tags and description thus allowing easy sorting and searching among stored\nfiles.\nThere are several methods of file uploading available: multipart/form-data encoded form, RAW POST (by sending\nfile contents as POST body), fetching from URL (by providing the file URL via 'url' param)\nAttachment is an entity that is used to link a File to one or multiple objects like Customer, Dispute, Payment,\nTransaction, Subscription, Plan, Product, Invoice, Note. That allows to quickly find and use files related to\nthose specific entities.\n"
},
{
"name": "Gateway Accounts",
@ -15623,7 +15623,7 @@
"description": "Reset user password\n",
"responses": {
"201": {
"description": "Password was reseted successfully",
"description": "Password was reset successfully",
"headers": {
"Rate-Limit-Limit": {
"description": "The number of allowed requests in the current period",
@ -23851,17 +23851,17 @@
"type": "string"
},
"totpRequired": {
"description": "The user setting of two-factor authentification",
"description": "The user setting of two-factor authentication",
"readOnly": true,
"type": "boolean"
},
"totpSecret": {
"description": "The user TOTP key for authentification app (if TOTP enabled)",
"description": "The user TOTP key for authentication app (if TOTP enabled)",
"readOnly": true,
"type": "string"
},
"totpUrl": {
"description": "The user link to QR-code for TOTP authentification app (if TOTP enabled)",
"description": "The user link to QR-code for TOTP authentication app (if TOTP enabled)",
"readOnly": true,
"type": "string",
"format": "url"
@ -24250,7 +24250,7 @@
},
"bodyHtml": {
"type": "string",
"description": "Leave empty to recieve \"text/plain\" email.\nThe template palceholders are allowed.\n"
"description": "Leave empty to receive \"text/plain\" email.\nThe template palceholders are allowed.\n"
}
},
"required": [
@ -26495,15 +26495,15 @@
}
},
"totpRequired": {
"description": "The user setting of two-factor authentification",
"description": "The user setting of two-factor authentication",
"type": "boolean"
},
"totpSecret": {
"description": "The user TOTP key for authentification app (if TOTP enabled)",
"description": "The user TOTP key for authentication app (if TOTP enabled)",
"type": "string"
},
"totpUrl": {
"description": "The user link to QR-code for TOTP authentification app (if TOTP enabled)",
"description": "The user link to QR-code for TOTP authentication app (if TOTP enabled)",
"type": "string",
"format": "url"
},
@ -26984,7 +26984,7 @@
"collectionExpand": {
"name": "expand",
"in": "query",
"description": "Expand response to get full related object intead of ID. See the expand guide for more info.",
"description": "Expand response to get full related object instead of ID. See the expand guide for more info.",
"schema": {
"type": "string"
}

View File

@ -11,7 +11,7 @@ const demos = [
value: 'https://api.apis.guru/v2/specs/googleapis.com/calendar/v3/swagger.yaml',
label: 'Google Calendar',
},
{ value: 'https://api.apis.guru/v2/specs/slack.com/1.0.6/swagger.yaml', label: 'Slack' },
{ value: 'https://api.apis.guru/v2/specs/slack.com/1.2.0/swagger.yaml', label: 'Slack' },
{ value: 'https://api.apis.guru/v2/specs/zoom.us/2.0.0/swagger.yaml', label: 'Zoom.us' },
{
value: 'https://api.apis.guru/v2/specs/graphhopper.com/1.0/swagger.yaml',

View File

@ -84,6 +84,14 @@ x-tagGroups:
paths:
/pet:
parameters:
- name: Accept-Language
in: header
description: "The language you prefer for messages. Supported values are en-AU, en-CA, en-GB, en-US"
example: en-US
required: false
schema:
type: string
default: en-AU
- name: cookieParam
in: cookie
description: Some cookie
@ -296,7 +304,7 @@ paths:
tags:
- pet
summary: Finds Pets by status
description: Multiple status values can be provided with comma seperated strings
description: Multiple status values can be provided with comma separated strings
operationId: findPetsByStatus
parameters:
- name: status
@ -341,7 +349,7 @@ paths:
- pet
summary: Finds Pets by tags
description: >-
Muliple tags can be provided with comma seperated strings. Use tag1,
Multiple tags can be provided with comma separated strings. Use tag1,
tag2, tag3 for testing.
operationId: findPetsByTags
deprecated: true
@ -621,7 +629,7 @@ paths:
type: integer
format: int32
X-Expires-After:
description: date in UTC when toekn expires
description: date in UTC when token expires
schema:
type: string
format: date-time
@ -676,6 +684,7 @@ components:
type: string
description: The measured skill for hunting
default: lazy
example: adventurous
enum:
- clueless
- lazy
@ -727,6 +736,7 @@ components:
type: number
description: Average amount of honey produced per day in ounces
example: 3.14
multipleOf: .01
required:
- honeyPerDay
Id:
@ -765,7 +775,7 @@ components:
type: boolean
default: false
readOnly: true
rqeuestId:
requestId:
description: Unique Request Id
type: string
writeOnly: true
@ -888,7 +898,6 @@ components:
type: string
pattern: '/^\+(?:[0-9]-?){6,14}[0-9]$/'
example: +1-202-555-0192
nullable: true
userStatus:
description: User status
type: integer

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import { render } from 'react-dom';
// tslint:disable-next-line
import { AppContainer } from 'react-hot-loader';
// import DevTools from 'mobx-react-devtools';

View File

@ -631,7 +631,7 @@ paths:
X-Expires-After:
type: string
format: date-time
description: date in UTC when toekn expires
description: date in UTC when token expires
'400':
description: Invalid username/password supplied
/user/logout:

View File

@ -42,7 +42,7 @@ describe('Servers', () => {
// TODO add cy-data attributes
cy.get('[data-section-id="operation/addPet"]').should(
'contain',
'http://localhost:' + win.location.port + '/e2e/pet',
'http://localhost:' + win.location.port + '/pet',
);
});
});
@ -57,7 +57,7 @@ describe('Servers', () => {
// TODO add cy-data attributes
cy.get('[data-section-id="operation/addPet"]').should(
'contain',
'http://localhost:' + win.location.port + '/e2e/pet',
'http://localhost:' + win.location.port + '/pet',
);
});
});

View File

@ -1,6 +1,6 @@
{
"name": "redoc",
"version": "2.0.0-rc.16",
"version": "2.0.0-rc.23",
"description": "ReDoc",
"repository": {
"type": "git",
@ -40,7 +40,7 @@
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:standalone",
"declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/",
"stats": "webpack --env.standalone --json --profile --mode=production > stats.json",
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
"prettier": "prettier --write \"cli/index.ts\" \"src/**/*.{ts,tsx}\"",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
"lint": "tslint --project tsconfig.json",
"benchmark": "node ./benchmark/benchmark.js",
@ -52,77 +52,78 @@
"docker:build": "docker build -f config/docker/Dockerfile -t redoc ."
},
"devDependencies": {
"@babel/core": "7.5.5",
"@babel/plugin-syntax-decorators": "7.2.0",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-syntax-jsx": "7.2.0",
"@babel/plugin-syntax-typescript": "7.3.3",
"@cypress/webpack-preprocessor": "4.1.0",
"@hot-loader/react-dom": "^16.8.6",
"@types/chai": "4.1.7",
"@types/dompurify": "^0.0.33",
"@types/enzyme": "^3.10.3",
"@babel/core": "7.7.5",
"@babel/plugin-syntax-decorators": "7.7.4",
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
"@babel/plugin-syntax-jsx": "7.7.4",
"@babel/plugin-syntax-typescript": "7.7.4",
"@cypress/webpack-preprocessor": "4.1.1",
"@hot-loader/react-dom": "^16.11.0",
"@types/chai": "4.2.7",
"@types/dompurify": "^2.0.0",
"@types/enzyme": "^3.10.4",
"@types/enzyme-to-json": "^1.5.3",
"@types/jest": "^24.0.15",
"@types/jest": "^24.0.23",
"@types/json-pointer": "^1.0.30",
"@types/lodash": "^4.14.136",
"@types/lodash": "^4.14.149",
"@types/lunr": "^2.3.2",
"@types/mark.js": "^8.11.4",
"@types/marked": "^0.6.5",
"@types/mark.js": "^8.11.5",
"@types/marked": "^0.7.2",
"@types/prismjs": "^1.16.0",
"@types/promise": "^7.1.30",
"@types/prop-types": "^15.7.1",
"@types/prop-types": "^15.7.3",
"@types/qs": "^6.5.1",
"@types/react": "^16.8.23",
"@types/react-dom": "^16.8.5",
"@types/react": "^16.9.16",
"@types/react-dom": "^16.9.4",
"@types/react-hot-loader": "^4.1.0",
"@types/react-tabs": "^2.3.1",
"@types/styled-components": "^4.1.18",
"@types/styled-components": "^4.4.1",
"@types/tapable": "1.0.4",
"@types/webpack": "^4.32.1",
"@types/webpack-env": "^1.14.0",
"@types/yargs": "^13.0.0",
"@types/webpack": "^4.41.0",
"@types/webpack-env": "^1.14.1",
"@types/yargs": "^13.0.3",
"babel-loader": "8.0.6",
"babel-plugin-styled-components": "^1.10.6",
"beautify-benchmark": "^0.2.4",
"bundlesize": "^0.18.0",
"conventional-changelog-cli": "^2.0.23",
"copy-webpack-plugin": "^5.0.4",
"core-js": "^3.1.4",
"coveralls": "^3.0.5",
"css-loader": "^3.1.0",
"cypress": "~3.4.0",
"conventional-changelog-cli": "^2.0.28",
"copy-webpack-plugin": "^5.1.1",
"core-js": "^3.5.0",
"coveralls": "^3.0.9",
"css-loader": "^3.3.0",
"cypress": "~3.7.0",
"deploy-to-gh-pages": "^1.3.7",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.3.5",
"fork-ts-checker-webpack-plugin": "1.4.3",
"enzyme-adapter-react-16": "^1.15.1",
"enzyme-to-json": "^3.4.3",
"fork-ts-checker-webpack-plugin": "3.1.1",
"html-webpack-plugin": "^3.1.0",
"jest": "^24.8.0",
"jest": "^24.9.0",
"license-checker": "^25.0.1",
"lodash": "^4.17.15",
"mobx": "^4.3.1",
"prettier": "^1.18.2",
"prettier-eslint": "^9.0.0",
"prettier": "^1.19.1",
"prettier-eslint": "^9.0.1",
"raf": "^3.4.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"rimraf": "^2.6.3",
"react": "^16.12.0",
"react-hot-loader": "^4.12.18",
"react-dom": "^16.12.0",
"rimraf": "^3.0.0",
"shelljs": "^0.8.3",
"source-map-loader": "^0.2.4",
"style-loader": "^0.23.1",
"styled-components": "^4.3.2",
"ts-jest": "24.0.2",
"ts-loader": "6.0.4",
"ts-node": "^8.3.0",
"tslint": "^5.18.0",
"tslint-react": "^4.0.0",
"typescript": "^3.5.3",
"style-loader": "^1.0.1",
"styled-components": "^4.4.1",
"ts-jest": "24.2.0",
"ts-loader": "6.2.1",
"ts-node": "^8.5.4",
"tslint": "^5.20.1",
"tslint-react": "^4.1.0",
"typescript": "^3.7.3",
"unfetch": "^4.1.0",
"url-polyfill": "^1.1.7",
"webpack": "^4.38.0",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0",
"webpack-node-externals": "^1.6.0",
"workerize-loader": "^1.0.4",
"yaml-js": "^0.2.3"
@ -140,27 +141,26 @@
"brace": "^0.11.1",
"classnames": "^2.2.6",
"decko": "^1.2.0",
"dompurify": "^1.0.11",
"dompurify": "^2.0.7",
"eventemitter3": "^4.0.0",
"json-pointer": "^0.6.0",
"json-schema-ref-parser": "^6.1.0",
"lunr": "2.3.6",
"lunr": "2.3.8",
"mark.js": "^8.11.1",
"marked": "^0.7.0",
"memoize-one": "^5.0.5",
"mobx-react": "^6.1.1",
"memoize-one": "~5.1.1",
"mobx-react": "^6.1.4",
"openapi-sampler": "1.0.0-beta.15",
"perfect-scrollbar": "^1.4.0",
"polished": "^3.4.1",
"polished": "^3.4.2",
"prismjs": "^1.17.1",
"prop-types": "^15.7.2",
"qs": "^6.5.2",
"react-ace": "^6.0.0",
"react-dropdown": "^1.6.4",
"react-hot-loader": "^4.12.10",
"react-switch": "^5.0.1",
"react-tabs": "^3.0.0",
"slugify": "^1.3.4",
"slugify": "^1.3.6",
"stickyfill": "^1.1.1",
"swagger2openapi": "^5.3.1",
"tslib": "^1.10.0",

View File

@ -55,7 +55,7 @@ export const StyledDropdown = styled(Dropdown)`
display: block;
height: 0;
position: absolute;
right: 0.6em;
right: 0.3em;
top: 50%;
margin-top: -0.125em;
width: 0;
@ -97,7 +97,7 @@ export const StyledDropdown = styled(Dropdown)`
export const SimpleDropdown = styled(StyledDropdown)`
margin-left: 10px;
text-transform: none;
font-size: 0.929em;
font-size: 0.969em;
.Dropdown-control {
font-size: 1em;

View File

@ -64,7 +64,7 @@ export const PropertyNameCell = styled(PropertyCell)`
line-height: 20px;
white-space: nowrap;
font-size: 0.929em;
font-family: ${props => props.theme.typography.headings.fontFamily};
font-family: ${props => props.theme.typography.code.fontFamily};
&.deprecated {
${deprecatedCss};

View File

@ -72,7 +72,6 @@ export const ExampleValue = styled(FieldLabel)`
padding: 0 ${theme.spacing.unit}px;
border: 1px solid ${transparentize(0.9, theme.colors.text.primary)};
font-family: ${theme.typography.code.fontFamily};
color: ${theme.typography.code.color};
}`};
& + & {
margin-left: 0;
@ -91,6 +90,7 @@ export const ConstraintItem = styled(FieldLabel)`
margin: 0 ${theme.spacing.unit}px;
padding: 0 ${theme.spacing.unit}px;
border: 1px solid ${transparentize(0.9, theme.colors.primary.main)};
font-family: ${theme.typography.code.fontFamily};
}`};
& + & {
margin-left: 0;

View File

@ -11,13 +11,14 @@ export const OneOfLabel = styled.span`
font-size: 0.9em;
margin-right: 10px;
color: ${props => props.theme.colors.primary.main};
font-family: Montserrat;
font-family: ${props => props.theme.typography.headings.fontFamily};
}
`;
export const OneOfButton = styled.li<{ active: boolean }>`
display: inline-block;
margin-right: 10px;
margin-bottom: 5px;
font-size: 0.8em;
cursor: pointer;
border: 1px solid ${props => props.theme.colors.primary.main};

View File

@ -76,7 +76,7 @@ export class SectionItem extends React.Component<ContentItemProps> {
return (
<>
<Row>
<MiddlePanel compact={level !== 1}>
<MiddlePanel compact={false}>
<Header>
<ShareLink to={this.props.item.id} />
{name}

View File

@ -27,16 +27,19 @@ export class FieldDetails extends React.PureComponent<FieldProps> {
static contextType = OptionsContext;
render() {
const { showExamples, field, renderDiscriminatorSwitch } = this.props;
const { enumSkipQuotes } = this.context;
const { enumSkipQuotes, hideSchemaTitles } = this.context;
const { schema, description, example, deprecated } = field;
const rawDefault = !!enumSkipQuotes || field.in === 'header'; // having quotes around header field default values is confusing and inappropriate
let exampleField: JSX.Element | null = null;
if (showExamples && example !== undefined) {
const label = l('example') + ':';
if (field.in && (field.style || field.serializationMime)) {
const serializedValue = serializeParameterValue(field, example);
// decode for better readability in examples: see https://github.com/Redocly/redoc/issues/1138
const serializedValue = decodeURIComponent(serializeParameterValue(field, example));
exampleField = <FieldDetail label={label} value={serializedValue} raw={true} />;
} else {
exampleField = <FieldDetail label={label} value={example} />;
@ -56,7 +59,7 @@ export class FieldDetails extends React.PureComponent<FieldProps> {
&gt;{' '}
</TypeFormat>
)}
{schema.title && <TypeTitle> ({schema.title}) </TypeTitle>}
{schema.title && !hideSchemaTitles && <TypeTitle> ({schema.title}) </TypeTitle>}
<ConstraintsView constraints={schema.constraints} />
{schema.nullable && <NullableLabel> {l('nullable')} </NullableLabel>}
{schema.pattern && <PatternLabel> {schema.pattern} </PatternLabel>}
@ -67,7 +70,7 @@ export class FieldDetails extends React.PureComponent<FieldProps> {
<Badge type="warning"> {l('deprecated')} </Badge>
</div>
)}
<FieldDetail raw={enumSkipQuotes} label={l('default') + ':'} value={schema.default} />
<FieldDetail raw={rawDefault} label={l('default') + ':'} value={schema.default} />
{!renderDiscriminatorSwitch && <EnumValues type={schema.type} values={schema.enum} />}{' '}
{exampleField}
{<Extensions extensions={{ ...field.extensions, ...schema.extensions }} />}

View File

@ -25,7 +25,7 @@ export class AdvancedMarkdown extends React.Component<AdvancedMarkdownProps> {
renderWithOptionsAndStore(options: RedocNormalizedOptions, store?: AppStore) {
const { source, htmlWrap = i => i } = this.props;
if (!store) {
throw new Error('When using componentes in markdown, store prop must be provided');
throw new Error('When using components in markdown, store prop must be provided');
}
const renderer = new MarkdownRenderer(options);

View File

@ -1,6 +1,6 @@
import { observer } from 'mobx-react';
import * as React from 'react';
import { OperationModel, RedocNormalizedOptions } from '../../services';
import { isPayloadSample, OperationModel, RedocNormalizedOptions } from '../../services';
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
@ -19,15 +19,10 @@ export class RequestSamples extends React.Component<RequestSamplesProps> {
render() {
const { operation } = this.props;
const requestBodyContent = operation.requestBody && operation.requestBody.content;
const hasBodySample = requestBodyContent && requestBodyContent.hasSample;
const samples = operation.codeSamples;
const hasSamples = hasBodySample || samples.length > 0;
const hideTabList =
samples.length + (hasBodySample ? 1 : 0) === 1
? this.context.hideSingleRequestSampleTab
: false;
const hasSamples = samples.length > 0;
const hideTabList = samples.length === 1 ? this.context.hideSingleRequestSampleTab : false;
return (
(hasSamples && (
<div>
@ -35,23 +30,21 @@ export class RequestSamples extends React.Component<RequestSamplesProps> {
<Tabs defaultIndex={0}>
<TabList hidden={hideTabList}>
{hasBodySample && <Tab key="payload"> Payload </Tab>}
{samples.map(sample => (
<Tab key={sample.lang + '_' + (sample.label || '')}>
{sample.label !== undefined ? sample.label : sample.lang}
</Tab>
))}
</TabList>
{hasBodySample && (
<TabPanel key="payload">
<div>
<PayloadSamples content={requestBodyContent!} />
</div>
</TabPanel>
)}
{samples.map(sample => (
<TabPanel key={sample.lang}>
<TabPanel key={sample.lang + '_' + (sample.label || '')}>
{isPayloadSample(sample) ? (
<div>
<PayloadSamples content={sample.requestBodyContent} />
</div>
) : (
<SourceCodeWithCopy lang={sample.lang} source={sample.source} />
)}
</TabPanel>
))}
</Tabs>

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import { darken } from 'polished';
import { darken, getLuminance, lighten } from 'polished';
import styled from '../../styled-components';
import { MenuItemLabel } from '../SideMenu/styled.elements';
@ -17,7 +17,12 @@ export const SearchInput = styled.input.attrs(() => ({
padding: 5px ${props => props.theme.spacing.unit * 2}px 5px
${props => props.theme.spacing.unit * 4}px;
border: 0;
border-bottom: 1px solid ${({ theme }) => darken(0.1, theme.menu.backgroundColor)};
border-bottom: 1px solid
${({ theme }) =>
(getLuminance(theme.menu.backgroundColor) > 0.5 ? darken : lighten)(
0.1,
theme.menu.backgroundColor,
)};
font-family: ${({ theme }) => theme.typography.fontFamily};
font-weight: bold;
font-size: 13px;
@ -53,11 +58,12 @@ export const SearchIcon = styled((props: { className?: string }) => (
export const SearchResultsBox = styled.div`
padding: ${props => props.theme.spacing.unit}px 0;
background-color: #ededed;
background-color: ${({ theme }) => darken(0.05, theme.menu.backgroundColor)}};
color: ${props => props.theme.menu.textColor};
min-height: 150px;
max-height: 250px;
border-top: 1px solid #e1e1e1;
border-bottom: 1px solid #e1e1e1;
border-top: ${({ theme }) => darken(0.1, theme.menu.backgroundColor)}};
border-bottom: ${({ theme }) => darken(0.1, theme.menu.backgroundColor)}};
margin-top: 10px;
line-height: 1.4;
font-size: 0.9em;
@ -66,17 +72,14 @@ export const SearchResultsBox = styled.div`
padding-top: 6px;
padding-bottom: 6px;
&:hover {
background-color: #e1e1e1;
&:hover,
&.active {
background-color: ${({ theme }) => darken(0.1, theme.menu.backgroundColor)};
}
> svg {
display: none;
}
&.active {
background-color: #e1e1e1;
}
}
`;

View File

@ -108,7 +108,7 @@ export class SecurityDefs extends React.PureComponent<SecurityDefsProps, Securit
<table className="security-details">
<tbody>
<tr>
<th> Security scheme type: </th>
<th> Security Scheme Type </th>
<td> {AUTH_TYPES[scheme.type] || scheme.type} </td>
<td> Value </td>
</tr>

View File

@ -1,3 +1,4 @@
// import { observe } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@ -15,7 +16,7 @@ export interface MenuItemProps {
@observer
export class MenuItem extends React.Component<MenuItemProps> {
ref: Element | null;
ref = React.createRef<HTMLLabelElement>();
activate = (evt: React.MouseEvent<HTMLElement>) => {
this.props.onActivate!(this.props.item);
@ -31,28 +32,19 @@ export class MenuItem extends React.Component<MenuItemProps> {
}
scrollIntoViewIfActive() {
if (this.props.item.active && this.ref) {
this.ref.scrollIntoViewIfNeeded();
if (this.props.item.active && this.ref.current) {
this.ref.current.scrollIntoViewIfNeeded();
}
}
saveRef = ref => {
this.ref = ref;
};
render() {
const { item, withoutChildren } = this.props;
return (
<MenuItemLi
onClick={this.activate}
depth={item.depth}
ref={this.saveRef}
data-item-id={item.id}
>
<MenuItemLi onClick={this.activate} depth={item.depth} data-item-id={item.id}>
{item.type === 'operation' ? (
<OperationMenuItemContent {...this.props} item={item as OperationModel} />
) : (
<MenuItemLabel depth={item.depth} active={item.active} type={item.type}>
<MenuItemLabel depth={item.depth} active={item.active} type={item.type} ref={this.ref}>
<MenuItemTitle title={item.name}>
{item.name}
{this.props.children}
@ -81,10 +73,23 @@ export interface OperationMenuItemContentProps {
@observer
export class OperationMenuItemContent extends React.Component<OperationMenuItemContentProps> {
ref = React.createRef<HTMLLabelElement>();
componentDidUpdate() {
if (this.props.item.active && this.ref.current) {
this.ref.current.scrollIntoViewIfNeeded();
}
}
render() {
const { item } = this.props;
return (
<MenuItemLabel depth={item.depth} active={item.active} deprecated={item.deprecated}>
<MenuItemLabel
depth={item.depth}
active={item.active}
deprecated={item.deprecated}
ref={this.ref}
>
<OperationBadge type={item.httpVerb}>{shortenHTTPVerb(item.httpVerb)}</OperationBadge>
<MenuItemTitle width="calc(100% - 38px)">
{item.name}

View File

@ -104,7 +104,7 @@ export const menuItemDepth = {
font-size: 0.929em;
text-transform: ${({ theme }) => theme.menu.level1Items.textTransform};
&:hover {
color: ${props => props.theme.colors.primary.main};
color: ${props => props.theme.menu.activeTextColor};
}
`,
2: css`
@ -126,7 +126,7 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
}),
}))<MenuItemLabelType>`
cursor: pointer;
color: ${props => (props.active ? props.theme.colors.primary.main : props.theme.menu.textColor)};
color: ${props => (props.active ? props.theme.menu.activeTextColor : props.theme.menu.textColor)};
margin: 0;
padding: 12.5px ${props => props.theme.spacing.unit * 4}px;
${({ depth, type, theme }) =>

View File

@ -33,7 +33,7 @@ const StyledStickySidebar = styled.div<{ open?: boolean }>`
flex-direction: column;
backface-visibility: hidden;
contain: strict;
/* contain: strict; TODO: breaks layout since Chrome 80*/
height: 100vh;
position: sticky;
@ -44,7 +44,7 @@ const StyledStickySidebar = styled.div<{ open?: boolean }>`
position: fixed;
z-index: 20;
width: 100%;
background: #ffffff;
background: ${({ theme }) => theme.menu.backgroundColor};
display: ${props => (props.open ? 'flex' : 'none')};
`};

View File

@ -1,4 +1,4 @@
import memoize from 'memoize-one';
import * as memoize from 'memoize-one/dist/memoize-one.cjs'; // fixme: https://github.com/alexreardon/memoize-one/issues/37
import { Component, createContext } from 'react';
import { AppStore } from '../services/';

View File

@ -24,14 +24,14 @@ describe('Components', () => {
});
test('should collapse/uncollapse', () => {
expect(component.html()).not.toContain('class="hoverable"'); // all are collapesed by default
expect(component.html()).not.toContain('class="hoverable"'); // all are collapsed by default
const expandAll = component.find('div > span[children=" Expand all "]');
expandAll.simulate('click');
expect(component.html()).toContain('class="hoverable"'); // all are collapesed
expect(component.html()).toContain('class="hoverable"'); // all are collapsed
const collapseAll = component.find('div > span[children=" Collapse all "]');
collapseAll.simulate('click');
expect(component.html()).not.toContain('class="hoverable"'); // all are collapesed
expect(component.html()).not.toContain('class="hoverable"'); // all are collapsed
});
test('should collapse/uncollapse', () => {

View File

@ -101,6 +101,9 @@ export class AppStore {
dispose() {
this.scroll.dispose();
this.menu.dispose();
if (this.search) {
this.search.dispose();
}
if (this.disposer != null) {
this.disposer();
}

View File

@ -45,6 +45,14 @@ export class MarkdownRenderer {
return compRegexp.test(rawText);
}
static getTextBeforeHading(md: string, heading: string): string {
const headingLinePos = md.search(new RegExp(`^##?\\s+${heading}`, 'm'));
if (headingLinePos > -1) {
return md.substring(0, headingLinePos);
}
return md;
}
headings: MarkdownHeading[] = [];
currentTopHeading: MarkdownHeading;
@ -119,7 +127,12 @@ export class MarkdownRenderer {
.trim();
}
headingRule = (text: string, level: number, raw: string, slugger: marked.Slugger) => {
headingRule = (
text: string,
level: 1 | 2 | 3 | 4 | 5 | 6,
raw: string,
slugger: marked.Slugger,
) => {
if (level === 1) {
this.currentTopHeading = this.saveHeading(text, level);
} else if (level === 2) {

View File

@ -66,6 +66,13 @@ export class MenuBuilder {
const renderer = new MarkdownRenderer(options);
const headings = renderer.extractHeadings(description || '');
if (headings.length && parent && parent.description) {
parent.description = MarkdownRenderer.getTextBeforeHading(
parent.description,
headings[0].name,
);
}
const mapHeadingsDeep = (_parent, items, depth = 1) =>
items.map(heading => {
const group = new GroupModel('section', heading, _parent);
@ -88,7 +95,7 @@ export class MenuBuilder {
}
/**
* Returns array of OperationsGroup items for the tag groups (x-tagGroups vendor extenstion)
* Returns array of OperationsGroup items for the tag groups (x-tagGroups vendor extension)
* @param tags value of `x-tagGroups` vendor extension
*/
static getTagGroupsItems(

View File

@ -190,7 +190,7 @@ export class MenuStore {
* activate menu item
* @param item item to activate
* @param updateLocation [true] whether to update location
* @param rewriteHistory [false] whether to rewrite browser history (do not create new enrty)
* @param rewriteHistory [false] whether to rewrite browser history (do not create new entry)
*/
@action
activate(

View File

@ -112,7 +112,7 @@ export class OpenAPIParser {
};
/**
* checks if the objectt is OpenAPI reference (containts $ref property)
* checks if the object is OpenAPI reference (contains $ref property)
*/
isRef(obj: any): obj is OpenAPIRef {
if (!obj) {
@ -122,7 +122,7 @@ export class OpenAPIParser {
}
/**
* resets visited enpoints. should be run after
* resets visited endpoints. should be run after
*/
resetVisited() {
if (process.env.NODE_ENV !== 'production') {
@ -146,7 +146,7 @@ export class OpenAPIParser {
/**
* Resolve given reference object or return as is if it is not a reference
* @param obj object to dereference
* @param forceCircular whether to dereference even if it is cirular ref
* @param forceCircular whether to dereference even if it is circular ref
*/
deref<T extends object>(obj: OpenAPIRef | T, forceCircular: boolean = false): T {
if (this.isRef(obj)) {
@ -177,10 +177,10 @@ export class OpenAPIParser {
}
/**
* Merge allOf contsraints.
* Merge allOf constraints.
* @param schema schema with allOF
* @param $ref pointer of the schema
* @param forceCircular whether to dereference children even if it is a cirular ref
* @param forceCircular whether to dereference children even if it is a circular ref
*/
mergeAllOf(
schema: OpenAPISchema,
@ -275,13 +275,13 @@ export class OpenAPIParser {
}
// merge rest of constraints
// TODO: do more intelegent merge
// TODO: do more intelligent merge
receiver = { ...subSchema, ...receiver };
if (subSchemaRef) {
receiver.parentRefs!.push(subSchemaRef);
if (receiver.title === undefined && isNamedDefinition(subSchemaRef)) {
// this is not so correct behaviour. comented out for now
// this is not so correct behaviour. commented out for now
// ref: https://github.com/Redocly/redoc/issues/601
// receiver.title = JsonPointer.baseName(subSchemaRef);
}
@ -296,8 +296,8 @@ export class OpenAPIParser {
* returns map of definition pointer to definition name
* @param $refs array of references to find derived from
*/
findDerived($refs: string[]): Dict<string> {
const res: Dict<string> = {};
findDerived($refs: string[]): Dict<string[] | string> {
const res: Dict<string[]> = {};
const schemas = (this.spec.components && this.spec.components.schemas) || {};
for (const defName in schemas) {
const def = this.deref(schemas[defName]);
@ -305,7 +305,7 @@ export class OpenAPIParser {
def.allOf !== undefined &&
def.allOf.find(obj => obj.$ref !== undefined && $refs.indexOf(obj.$ref) > -1)
) {
res['#/components/schemas/' + defName] = def['x-discriminator-value'] || defName;
res['#/components/schemas/' + defName] = [def['x-discriminator-value'] || defName];
}
}
return res;

View File

@ -26,6 +26,8 @@ export interface RedocRawOptions {
hideSingleRequestSampleTab?: boolean | string;
menuToggle?: boolean | string;
jsonSampleExpandLevel?: number | string | 'all';
hideSchemaTitles?: boolean | string;
payloadSampleIdx?: number;
providedByName?: string;
providedByUri?: string;
@ -43,12 +45,12 @@ export interface RedocRawOptions {
expandDefaultServerVariables?: boolean;
}
function argValueToBoolean(val?: string | boolean): boolean {
function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean {
if (val === undefined) {
return false;
return defaultValue || false;
}
if (typeof val === 'string') {
return true;
return val === 'false' ? false : true;
}
return val;
}
@ -123,6 +125,18 @@ export class RedocNormalizedOptions {
return value;
}
static normalizePayloadSampleIdx(value: RedocRawOptions['payloadSampleIdx']): number {
if (typeof value === 'number') {
return Math.max(0, value); // always greater or equal than 0
}
if (typeof value === 'string') {
return isFinite(value) ? parseInt(value, 10) : 0;
}
return 0;
}
private static normalizeJsonSampleExpandLevel(level?: number | string | 'all'): number {
if (level === 'all') {
return +Infinity;
@ -151,6 +165,8 @@ export class RedocNormalizedOptions {
menuToggle: boolean;
jsonSampleExpandLevel: number;
enumSkipQuotes: boolean;
hideSchemaTitles: boolean;
payloadSampleIdx: number;
enableConsole: boolean;
additionalHeaders: object;
providedByName: string;
@ -190,11 +206,13 @@ export class RedocNormalizedOptions {
this.onlyRequiredInSamples = argValueToBoolean(raw.onlyRequiredInSamples);
this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions);
this.hideSingleRequestSampleTab = argValueToBoolean(raw.hideSingleRequestSampleTab);
this.menuToggle = argValueToBoolean(raw.menuToggle);
this.menuToggle = argValueToBoolean(raw.menuToggle, true);
this.jsonSampleExpandLevel = RedocNormalizedOptions.normalizeJsonSampleExpandLevel(
raw.jsonSampleExpandLevel,
);
this.enumSkipQuotes = argValueToBoolean(raw.enumSkipQuotes);
this.hideSchemaTitles = argValueToBoolean(raw.hideSchemaTitles);
this.payloadSampleIdx = RedocNormalizedOptions.normalizePayloadSampleIdx(raw.payloadSampleIdx);
this.enableConsole = argValueToBoolean(raw.enableConsole);
this.additionalHeaders = raw.additionalHeaders || {};
this.providedByName = raw.providedByName || 'Documentation Powered by ReDoc';

View File

@ -38,6 +38,10 @@ export class SearchStore<T> {
this.searchWorker.add(title, body, meta);
}
dispose() {
(this.searchWorker as any).terminate();
}
search(q: string) {
return this.searchWorker.search<T>(q);
}

View File

@ -6,7 +6,7 @@ import { SecuritySchemesModel } from './models/SecuritySchemes';
import { OpenAPIParser } from './OpenAPIParser';
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
/**
* Store that containts all the specification related information in the form of tree
* Store that contains all the specification related information in the form of tree
*/
export class SpecStore {
parser: OpenAPIParser;

View File

@ -13,7 +13,7 @@ describe('History service', () => {
expect(fn).toHaveBeenCalled();
});
test('History subscribe should return unsubsribe function', () => {
test('History subscribe should return unsubscribe function', () => {
const fn = jest.fn();
const unsubscribe = history.subscribe(fn);
history.emit();

View File

@ -22,7 +22,7 @@ describe('Models', () => {
expect(resp.type).toEqual('error');
});
test('default should be sucessful by default', () => {
test('default should be successful by default', () => {
const resp = new ResponseModel(parser, 'default', false, {}, opts);
expect(resp.type).toEqual('success');
});

View File

@ -17,6 +17,7 @@ export class ApiInfoModel implements OpenAPIInfo {
constructor(private parser: OpenAPIParser) {
Object.assign(this, parser.spec.info);
this.description = parser.spec.info.description || '';
const firstHeadingLinePos = this.description.search(/^##?\s+/m);
if (firstHeadingLinePos > -1) {
this.description = this.description.substring(0, firstHeadingLinePos);

View File

@ -2,7 +2,7 @@ import { action, observable } from 'mobx';
import { OpenAPIExternalDocumentation, OpenAPITag } from '../../types';
import { safeSlugify } from '../../utils';
import { MarkdownHeading } from '../MarkdownRenderer';
import { MarkdownHeading, MarkdownRenderer } from '../MarkdownRenderer';
import { ContentItemModel } from '../MenuBuilder';
import { IMenuItem, MenuItemGroupType } from '../MenuStore';
@ -43,9 +43,10 @@ export class GroupModel implements IMenuItem {
// remove sections from markdown, same as in ApiInfo
this.description = tagOrGroup.description || '';
const firstHeadingLinePos = this.description.search(/^##?\s+/m);
if (firstHeadingLinePos > -1) {
this.description = this.description.substring(0, firstHeadingLinePos);
const items = (tagOrGroup as MarkdownHeading).items;
if (items && items.length) {
this.description = MarkdownRenderer.getTextBeforeHading(this.description, items[0].name);
}
this.parent = parent;

View File

@ -21,7 +21,7 @@ export class MediaContentModel {
* @param isRequestType needed to know if skipe RO/RW fields in objects
*/
constructor(
public parser: OpenAPIParser,
parser: OpenAPIParser,
info: Dict<OpenAPIMediaType>,
public isRequestType: boolean,
options: RedocNormalizedOptions,

View File

@ -27,9 +27,23 @@ import { ContentItemModel, ExtendedOpenAPIOperation } from '../MenuBuilder';
import { OpenAPIParser } from '../OpenAPIParser';
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
import { FieldModel } from './Field';
import { MediaContentModel } from './MediaContent';
import { RequestBodyModel } from './RequestBody';
import { ResponseModel } from './Response';
interface XPayloadSample {
lang: 'payload';
label: string;
requestBodyContent: MediaContentModel;
source: string;
}
export function isPayloadSample(
sample: XPayloadSample | OpenAPIXCodeSample,
): sample is XPayloadSample {
return sample.lang === 'payload' && (sample as any).requestBodyContent;
}
/**
* Operation model ready to be used by components
*/
@ -62,7 +76,6 @@ export class OperationModel implements IMenuItem {
path: string;
servers: OpenAPIServer[];
security: SecurityRequirementModel[];
codeSamples: OpenAPIXCodeSample[];
extensions: Dict<any>;
constructor(
@ -89,7 +102,6 @@ export class OperationModel implements IMenuItem {
this.httpVerb = operationSpec.httpVerb;
this.deprecated = !!operationSpec.deprecated;
this.operationId = operationSpec.operationId;
this.codeSamples = operationSpec['x-code-samples'] || [];
this.path = operationSpec.pathName;
const pathInfo = parser.byRef<OpenAPIPath>(
@ -144,6 +156,30 @@ export class OperationModel implements IMenuItem {
);
}
@memoize
get codeSamples() {
let samples: Array<OpenAPIXCodeSample | XPayloadSample> =
this.operationSpec['x-code-samples'] || [];
const requestBodyContent = this.requestBody && this.requestBody.content;
if (requestBodyContent && requestBodyContent.hasSample) {
const insertInx = Math.min(samples.length, this.options.payloadSampleIdx);
samples = [
...samples.slice(0, insertInx),
{
lang: 'payload',
label: 'Payload',
source: '',
requestBodyContent,
},
...samples.slice(insertInx),
];
}
return samples;
}
@memoize
get parameters() {
const _parameters = mergeParams(
@ -154,11 +190,12 @@ export class OperationModel implements IMenuItem {
).map(paramOrRef => new FieldModel(this.parser, paramOrRef, this.pointer, this.options));
if (this.options.sortPropsAlphabetically) {
sortByField(_parameters, 'name');
return sortByField(_parameters, 'name');
}
if (this.options.requiredPropsFirst) {
sortByRequired(_parameters);
return sortByRequired(_parameters);
}
return _parameters;
}

View File

@ -75,6 +75,7 @@ export class SchemaModel {
this.pointer = schemaOrRef.$ref || pointer || '';
this.rawSchema = parser.deref(schemaOrRef);
this.schema = parser.mergeAllOf(this.rawSchema, this.pointer, isChild);
this.init(parser, isChild);
parser.exitRef(schemaOrRef);
@ -125,6 +126,13 @@ export class SchemaModel {
if (!isChild && getDiscriminator(schema) !== undefined) {
this.initDiscriminator(schema, parser);
return;
} else if (
isChild &&
Array.isArray(schema.oneOf) &&
schema.oneOf.find(s => s.$ref === this.pointer)
) {
// we hit allOf of the schema with the parent discriminator
delete schema.oneOf;
}
if (schema.oneOf !== undefined) {
@ -216,7 +224,10 @@ export class SchemaModel {
) {
const discriminator = getDiscriminator(schema)!;
this.discriminatorProp = discriminator.propertyName;
const derived = parser.findDerived([...(schema.parentRefs || []), this.pointer]);
const implicitInversedMapping = parser.findDerived([
...(schema.parentRefs || []),
this.pointer,
]);
if (schema.oneOf) {
for (const variant of schema.oneOf) {
@ -224,19 +235,41 @@ export class SchemaModel {
continue;
}
const name = JsonPointer.baseName(variant.$ref);
derived[variant.$ref] = name;
implicitInversedMapping[variant.$ref] = name;
}
}
const mapping = discriminator.mapping || {};
const explicitInversedMapping = {};
for (const name in mapping) {
derived[mapping[name]] = name;
const $ref = mapping[name];
if (Array.isArray(explicitInversedMapping[$ref])) {
explicitInversedMapping[$ref].push(name);
} else {
// overrides implicit mapping here
explicitInversedMapping[$ref] = [name];
}
}
const refs = Object.keys(derived);
this.oneOf = refs.map(ref => {
const innerSchema = new SchemaModel(parser, parser.byRef(ref)!, ref, this.options, true);
innerSchema.title = derived[ref];
const inversedMapping = { ...implicitInversedMapping, ...explicitInversedMapping };
const refs: Array<{ $ref; name }> = [];
for (const $ref of Object.keys(inversedMapping)) {
const names = inversedMapping[$ref];
if (Array.isArray(names)) {
for (const name of names) {
refs.push({ $ref, name });
}
} else {
refs.push({ $ref, name: names });
}
}
this.oneOf = refs.map(({ $ref, name }) => {
const innerSchema = new SchemaModel(parser, parser.byRef($ref)!, $ref, this.options, true);
innerSchema.title = name;
return innerSchema;
});
}
@ -251,7 +284,7 @@ function buildFields(
const props = schema.properties || {};
const additionalProps = schema.additionalProperties;
const defaults = schema.default || {};
const fields = Object.keys(props || []).map(fieldName => {
let fields = Object.keys(props || []).map(fieldName => {
let field = props[fieldName];
if (!field) {
@ -280,11 +313,11 @@ function buildFields(
});
if (options.sortPropsAlphabetically) {
sortByField(fields, 'name');
fields = sortByField(fields, 'name');
}
if (options.requiredPropsFirst) {
// if not sort alphabetically sort in the order from required keyword
sortByRequired(fields, !options.sortPropsAlphabetically ? schema.required : undefined);
fields = sortByRequired(fields, !options.sortPropsAlphabetically ? schema.required : undefined);
}
if (typeof additionalProps === 'object' || additionalProps === true) {

View File

@ -126,6 +126,10 @@ const defaultTheme: ThemeInterface = {
width: '260px',
backgroundColor: '#fafafa',
textColor: '#333333',
activeTextColor: theme =>
theme.menu.textColor !== defaultTheme.menu!.textColor
? theme.menu.textColor
: theme.colors.primary.main,
groupItems: {
textTransform: 'uppercase',
},
@ -302,6 +306,7 @@ export interface ResolvedThemeInterface {
width: string;
backgroundColor: string;
textColor: string;
activeTextColor: string;
groupItems: {
textTransform: string;
};

View File

@ -9,6 +9,7 @@ import {
normalizeServers,
pluralizeType,
serializeParameterValue,
sortByRequired,
} from '../';
import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services';
@ -249,7 +250,7 @@ describe('Utils', () => {
expect(res).toEqual([{ url: 'http://base.com/sandbox/test', description: '' }]);
});
it('should correcly resolve url with server relative path', () => {
it('should correctly resolve url with server relative path', () => {
const res = normalizeServers('http://base.com/subpath/spec.yaml', [
{
url: '/sandbox/test',
@ -258,7 +259,7 @@ describe('Utils', () => {
expect(res).toEqual([{ url: 'http://base.com/sandbox/test', description: '' }]);
});
it('should correcly resolve url with relative path', () => {
it('should correctly resolve url with relative path', () => {
const res = normalizeServers('http://base.com/subpath/spec.yaml', [
{
url: 'sandbox/test',
@ -333,7 +334,8 @@ describe('Utils', () => {
const itemConstraintSchema = (
min: number | undefined = undefined,
max: number | undefined = undefined,
) => ({ type: 'array', minItems: min, maxItems: max });
multipleOf: number | undefined = undefined,
) => ({ type: 'array', minItems: min, maxItems: max, multipleOf });
it('should not have a humanized constraint without schema constraints', () => {
expect(humanizeConstraints(itemConstraintSchema())).toHaveLength(0);
@ -355,9 +357,21 @@ describe('Utils', () => {
expect(humanizeConstraints(itemConstraintSchema(7, 7))).toContain('7 items');
});
it('should have a humazined constraint when justMinItems is set, and it is equal to 1', () => {
it('should have a humanized constraint when justMinItems is set, and it is equal to 1', () => {
expect(humanizeConstraints(itemConstraintSchema(1))).toContain('non-empty');
});
it('should have a humanized constraint when multipleOf is set, and it is in format of /^0\\.0*1$/', () => {
expect(humanizeConstraints(itemConstraintSchema(undefined, undefined, 0.01))).toContain(
'decimal places <= 2',
);
});
it('should have a humanized constraint when multipleOf is set, and it is in format other than /^0\\.0*1$/', () => {
expect(humanizeConstraints(itemConstraintSchema(undefined, undefined, 0.5))).toContain(
'multiple of 0.5',
);
});
});
describe('OpenAPI pluralizeType', () => {
@ -370,17 +384,27 @@ describe('Utils', () => {
expect(pluralizeType('array')).toEqual('arrays');
});
it('should pluralize complex dislay types', () => {
it('should pluralize complex display types', () => {
expect(pluralizeType('object (Pet)')).toEqual('objects (Pet)');
expect(pluralizeType('string <email>')).toEqual('strings <email>');
});
it('should pluralize oneOf-ed dislay types', () => {
it('should pluralize oneOf-ed display types', () => {
expect(pluralizeType('object or string')).toEqual('objects or strings');
expect(pluralizeType('object (Pet) or number <int64>')).toEqual(
'objects (Pet) or numbers <int64>',
);
});
it('should not pluralize display types that are already pluralized', () => {
expect(pluralizeType('strings')).toEqual('strings');
expect(pluralizeType('objects (Pet)')).toEqual('objects (Pet)');
expect(pluralizeType('strings <email>')).toEqual('strings <email>');
expect(pluralizeType('objects or strings')).toEqual('objects or strings');
expect(pluralizeType('objects (Pet) or numbers <int64>')).toEqual(
'objects (Pet) or numbers <int64>',
);
});
});
describe('openapi serializeParameter', () => {
@ -613,4 +637,370 @@ describe('Utils', () => {
});
});
});
describe('OpenAPI sortByRequired', () => {
it('should equal to the old data when all items have no required props', () => {
let fields = [
{
name: 'loginName',
required: false,
},
{
name: 'displayName',
required: false,
},
{
name: 'email',
required: false,
},
{
name: 'space',
required: false,
},
{
name: 'type',
required: false,
},
{
name: 'depIds',
required: false,
},
{
name: 'depNames',
required: false,
},
{
name: 'password',
required: false,
},
{
name: 'pwdControl',
required: false,
},
{
name: 'csfLevel',
required: false,
},
{
name: 'priority',
required: false,
},
{
name: 'siteId',
required: false,
},
];
expect(sortByRequired(fields as FieldModel[])).toEqual(fields);
});
it('other item should be the same order when some of items are required', () => {
let fields = [
{
name: 'loginName',
required: true,
},
{
name: 'displayName',
required: false,
},
{
name: 'email',
required: true,
},
{
name: 'space',
required: false,
},
{
name: 'type',
required: false,
},
{
name: 'depIds',
required: false,
},
{
name: 'depNames',
required: false,
},
{
name: 'password',
required: false,
},
{
name: 'pwdControl',
required: false,
},
{
name: 'csfLevel',
required: false,
},
{
name: 'priority',
required: false,
},
{
name: 'siteId',
required: false,
},
];
let sortedFields = [
{
name: 'loginName',
required: true,
},
{
name: 'email',
required: true,
},
{
name: 'displayName',
required: false,
},
{
name: 'space',
required: false,
},
{
name: 'type',
required: false,
},
{
name: 'depIds',
required: false,
},
{
name: 'depNames',
required: false,
},
{
name: 'password',
required: false,
},
{
name: 'pwdControl',
required: false,
},
{
name: 'csfLevel',
required: false,
},
{
name: 'priority',
required: false,
},
{
name: 'siteId',
required: false,
},
];
expect(sortByRequired(fields as FieldModel[])).toEqual(sortedFields);
});
it('should the order of required items is as same as the order parameter ', () => {
let fields = [
{
name: 'loginName',
required: true,
},
{
name: 'displayName',
required: true,
},
{
name: 'email',
required: true,
},
{
name: 'space',
required: false,
},
{
name: 'type',
required: false,
},
{
name: 'depIds',
required: false,
},
{
name: 'depNames',
required: false,
},
{
name: 'password',
required: false,
},
{
name: 'pwdControl',
required: false,
},
{
name: 'csfLevel',
required: false,
},
{
name: 'priority',
required: false,
},
{
name: 'siteId',
required: false,
},
];
expect(
sortByRequired(fields as FieldModel[], ['siteId', 'displayName', 'loginName', 'email']),
).toEqual([
{
name: 'displayName',
required: true,
},
{
name: 'loginName',
required: true,
},
{
name: 'email',
required: true,
},
{
name: 'space',
required: false,
},
{
name: 'type',
required: false,
},
{
name: 'depIds',
required: false,
},
{
name: 'depNames',
required: false,
},
{
name: 'password',
required: false,
},
{
name: 'pwdControl',
required: false,
},
{
name: 'csfLevel',
required: false,
},
{
name: 'priority',
required: false,
},
{
name: 'siteId',
required: false,
},
]);
expect(sortByRequired(fields as FieldModel[], ['email', 'displayName'])).toEqual([
{
name: 'email',
required: true,
},
{
name: 'displayName',
required: true,
},
{
name: 'loginName',
required: true,
},
{
name: 'space',
required: false,
},
{
name: 'type',
required: false,
},
{
name: 'depIds',
required: false,
},
{
name: 'depNames',
required: false,
},
{
name: 'password',
required: false,
},
{
name: 'pwdControl',
required: false,
},
{
name: 'csfLevel',
required: false,
},
{
name: 'priority',
required: false,
},
{
name: 'siteId',
required: false,
},
]);
expect(sortByRequired(fields as FieldModel[], ['displayName'])).toEqual([
{
name: 'displayName',
required: true,
},
{
name: 'loginName',
required: true,
},
{
name: 'email',
required: true,
},
{
name: 'space',
required: false,
},
{
name: 'type',
required: false,
},
{
name: 'depIds',
required: false,
},
{
name: 'depNames',
required: false,
},
{
name: 'password',
required: false,
},
{
name: 'pwdControl',
required: false,
},
{
name: 'csfLevel',
required: false,
},
{
name: 'priority',
required: false,
},
{
name: 'siteId',
required: false,
},
]);
});
});
});

View File

@ -2,7 +2,7 @@ import slugify from 'slugify';
import { format, parse } from 'url';
/**
* Maps over array passing `isLast` bool to iterator as the second arguemnt
* Maps over array passing `isLast` bool to iterator as the second argument
*/
export function mapWithLast<T, P>(array: T[], iteratee: (item: T, isLast: boolean) => P) {
const res: P[] = [];
@ -118,7 +118,7 @@ const isMergebleObject = (item): boolean => {
/**
* slugify() returns empty string when failed to slugify.
* so try to return minimun slugified-string with failed one which keeps original value
* so try to return minimum slugified-string with failed one which keeps original value
* the regex codes are referenced with https://gist.github.com/mathewbyrne/1280286
*/
export function safeSlugify(value: string): string {

View File

@ -6,6 +6,7 @@ import 'prismjs/components/prism-coffeescript.js';
import 'prismjs/components/prism-cpp.js';
import 'prismjs/components/prism-csharp.js';
import 'prismjs/components/prism-go.js';
import 'prismjs/components/prism-http.js';
import 'prismjs/components/prism-java.js';
import 'prismjs/components/prism-lua.js';
import 'prismjs/components/prism-markup-templating.js'; // dep of php
@ -65,7 +66,7 @@ export function mapLang(lang: string): string {
* Highlight source code string using Prism.js
* @param source source code to highlight
* @param lang highlight language
* @return highlighted souce code as **html string**
* @return highlighted source code as **html string**
*/
export function highlight(source: string, lang: string = DEFAULT_LANG): string {
lang = lang.toLowerCase();

View File

@ -4,7 +4,9 @@ export function jsonToHTML(json, maxExpandLevel) {
level = 1;
let output = '';
output += '<div class="redoc-json">';
output += '<code>';
output += valueToHTML(json, maxExpandLevel);
output += '</code>';
output += '</div>';
return output;
}

View File

@ -1,6 +1,7 @@
import { dirname } from 'path';
const URLtemplate = require('url-template');
import { FieldModel } from '../services/models';
import { OpenAPIParser } from '../services/OpenAPIParser';
import {
OpenAPIEncoding,
@ -13,7 +14,7 @@ import {
Referenced,
} from '../types';
import { IS_BROWSER } from './dom';
import { isNumeric, removeQueryString, resolveUrl, stripTrailingSlash } from './helpers';
import { isNumeric, removeQueryString, resolveUrl } from './helpers';
function isWildcardStatusCode(statusCode: string | number): statusCode is string {
return typeof statusCode === 'string' && /\dxx/i.test(statusCode);
@ -137,13 +138,13 @@ export function isFormUrlEncoded(contentType: string): boolean {
return contentType === 'application/x-www-form-urlencoded';
}
function delimitedEncodeField(fieldVal: any, fieldName: string, delimeter: string): string {
function delimitedEncodeField(fieldVal: any, fieldName: string, delimiter: string): string {
if (Array.isArray(fieldVal)) {
return fieldVal.map(v => v.toString()).join(delimeter);
return fieldVal.map(v => v.toString()).join(delimiter);
} else if (typeof fieldVal === 'object') {
return Object.keys(fieldVal)
.map(k => `${k}${delimeter}${fieldVal[k]}`)
.join(delimeter);
.map(k => `${k}${delimiter}${fieldVal[k]}`)
.join(delimiter);
} else {
return fieldName + '=' + fieldVal.toString();
}
@ -165,7 +166,7 @@ function deepObjectEncodeField(fieldVal: any, fieldName: string): string {
function serializeFormValue(name: string, explode: boolean, value: any) {
// Use RFC6570 safe name ([a-zA-Z0-9_]) and replace with our name later
// e.g. URI.template doesn't parse names with hypen (-) which are valid query param names
// e.g. URI.template doesn't parse names with hyphen (-) which are valid query param names
const safeName = '__redoc_param_name__';
const suffix = explode ? '*' : '';
const template = URLtemplate.parse(`{?${safeName}${suffix}}`);
@ -177,7 +178,7 @@ function serializeFormValue(name: string, explode: boolean, value: any) {
/*
* Should be used only for url-form-encoded body payloads
* To be used for parmaters should be extended with other style values
* To be used for parameters should be extended with other style values
*/
export function urlFormEncodePayload(
payload: object,
@ -225,7 +226,7 @@ function serializePathParameter(
}
// Use RFC6570 safe name ([a-zA-Z0-9_]) and replace with our name later
// e.g. URI.template doesn't parse names with hypen (-) which are valid query param names
// e.g. URI.template doesn't parse names with hyphen (-) which are valid query param names
const safeName = '__redoc_param_name__';
const template = URLtemplate.parse(`{${prefix}${safeName}${suffix}}`);
@ -368,6 +369,17 @@ export function isNamedDefinition(pointer?: string): boolean {
return /^#\/components\/schemas\/[^\/]+$/.test(pointer || '');
}
function humanizeMultipleOfConstraint(multipleOf: number | undefined): string | undefined {
if (multipleOf === undefined) {
return;
}
const strigifiedMultipleOf = multipleOf.toString(10);
if (!/^0\.0*1$/.test(strigifiedMultipleOf)) {
return `multiple of ${strigifiedMultipleOf}`;
}
return `decimal places <= ${strigifiedMultipleOf.split('.')[1].length}`;
}
function humanizeRangeConstraint(
description: string,
min: number | undefined,
@ -406,6 +418,11 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
res.push(arrayRange);
}
const multipleOfConstraint = humanizeMultipleOfConstraint(schema.multipleOf);
if (multipleOfConstraint !== undefined) {
res.push(multipleOfConstraint);
}
let numberRange;
if (schema.minimum !== undefined && schema.maximum !== undefined) {
numberRange = schema.exclusiveMinimum ? '( ' : '[ ';
@ -428,25 +445,29 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
return res;
}
export function sortByRequired(
fields: Array<{ required: boolean; name: string }>,
order: string[] = [],
) {
fields.sort((a, b) => {
if (!a.required && b.required) {
return 1;
} else if (a.required && !b.required) {
return -1;
} else if (a.required && b.required) {
return order.indexOf(a.name) - order.indexOf(b.name);
export function sortByRequired(fields: FieldModel[], order: string[] = []) {
const unrequiredFields: FieldModel[] = [];
const orderedFields: FieldModel[] = [];
const unorderedFields: FieldModel[] = [];
fields.forEach(field => {
if (field.required) {
order.includes(field.name) ? orderedFields.push(field) : unorderedFields.push(field);
} else {
return 0;
unrequiredFields.push(field);
}
});
orderedFields.sort((a, b) => order.indexOf(a.name) - order.indexOf(b.name));
return [...orderedFields, ...unorderedFields, ...unrequiredFields];
}
export function sortByField<T extends string>(fields: Array<{ [P in T]: string }>, param: T) {
fields.sort((a, b) => {
export function sortByField(
fields: FieldModel[],
param: keyof Pick<FieldModel, 'name' | 'description' | 'kind'>,
) {
return [...fields].sort((a, b) => {
return a[param].localeCompare(b[param]);
});
}
@ -462,7 +483,7 @@ export function mergeParams(
operationParamNames[param.name + '_' + param.in] = true;
});
// filter out path params overriden by operation ones with the same name
// filter out path params overridden by operation ones with the same name
pathParams = pathParams.filter(param => {
param = parser.shalowDeref(param);
return !operationParamNames[param.name + '_' + param.in];
@ -509,9 +530,10 @@ export function normalizeServers(
const baseUrl = specUrl === undefined ? removeQueryString(getHref()) : dirname(specUrl);
if (servers.length === 0) {
return [
// Behaviour defined in OpenAPI spec: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#openapi-object
servers = [
{
url: stripTrailingSlash(baseUrl),
url: '/',
},
];
}
@ -579,6 +601,6 @@ export function extractExtensions(obj: object, showExtensions: string[] | true):
export function pluralizeType(displayType: string): string {
return displayType
.split(' or ')
.map(type => type.replace(/^(string|object|number|integer|array|boolean)( ?.*)/, '$1s$2'))
.map(type => type.replace(/^(string|object|number|integer|array|boolean)s?( ?.*)/, '$1s$2'))
.join(' or ');
}

View File

@ -34,6 +34,7 @@
"e2e/**"
],
"include": [
"cli/index.ts",
"./custom.d.ts",
"./demo/playground/hmr-playground.tsx",
"./src/**/*.ts?",

View File

@ -17,7 +17,7 @@
"quotemark": [true, "single", "avoid-template", "jsx-double"],
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
"arrow-parens": [true, "ban-single-arg-parens"],
"no-submodule-imports": [true, "prismjs", "perfect-scrollbar", "react-dom", "core-js", "brace"],
"no-submodule-imports": [true, "prismjs", "perfect-scrollbar", "react-dom", "core-js", "brace", "memoize-one"],
"object-literal-key-quotes": [true, "as-needed"],
"no-unused-expression": [true, "allow-tagged-template"],
"semicolon": [true, "always", "ignore-bound-class-methods"],

View File

@ -5,7 +5,7 @@ import * as webpack from 'webpack';
import * as path from 'path';
const nodeExternals = require('webpack-node-externals')({
// bundle in moudules that need transpiling + non-js (e.g. css)
// bundle in modules that need transpiling + non-js (e.g. css)
whitelist: [
'swagger2openapi',
/reftools/,

3932
yarn.lock

File diff suppressed because it is too large Load Diff