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 # dev-server, watch and auto reload playground
$ yarn start $ yarn start
# start playground app in production environement # start playground app in production environment
$ yarn start:prod $ yarn start:prod
# runt tslint # 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`**: 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/components`**: contains main visual components
- **`src/services`**: contains different services used by ReDoc including MobX stores - **`src/services`**: contains different services used by ReDoc including MobX stores
- **`src/services/models`**: contains classes for OpenAPI entities (e.g. Response, Operations, etc) - **`src/services/models`**: contains classes for OpenAPI entities (e.g. Response, Operations, etc)
- **`src/types`**: contains extra typescript typings including OpenAPI doc typings - **`src/types`**: contains extra typescript typings including OpenAPI doc typings
- **`src/utils`**: utility functions - **`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 - **`src/theme.ts`**: - default theme (colors, fonts, etc) used by all the components

View File

@ -4,23 +4,22 @@ node_js:
cache: cache:
yarn: true yarn: true
directories: directories:
# we also need to cache folder with Cypress binary - "~/.cache"
- ~/.cache
env: env:
global: global:
- GH_REF: github.com/Redocly/redoc.git - GH_REF: github.com/Redocly/redoc.git
- GIT_AUTHOR_EMAIL: redoc-bot@users.noreply.github.com - GIT_AUTHOR_EMAIL: redoc-bot@users.noreply.github.com
- GIT_AUTHOR_NAME: RedocBot - GIT_AUTHOR_NAME: RedocBot
- secure: H2GClDJ7TEQaWgnk8d2fIVDpLwG3rTmN8TalUzrCqXGoG6ylCVmlwzKLgfPPWrVgSA7QTdfNV0ab7c2KyPoZBinHmeGMSuKNLVbhOXRc2VFxTBntBTuyJhfCgQEpUKvJesJUuv5RuBn//wC7VZcVVNc06TZDEe8+aDVYQuCRMXZJ4X3e6nSZ64QX2veyVcr+TjnRsZPkeBVcK9hngvuaxLb/hbJ85CvjiseZRt47PGIcrEpMn9n2GMw1m0fNnPoN+MBTSCnIklTmdjPG7t4GUSLmD6H0lNLdXuehYqmQAHgYrLec1aiFlV57QaDoDZrq2hSf4vDmCB/FVydGhD5JunI67pujoV2OnD1V80eUZhYNWOYsJ2Nfp4NxgXsPUcE6zWLYsLfktMPZADhOXInQRACt1cnx8zMYKLnch1RY/ZqjSg0nPtRjLzQ0lNsw5leixvBdBnMjxYHVyAWVwg8WiJMaLO9vog2Qnxg1NTacHO2CsOmm2rw6stpg7ndp/+nOleRlfUKggjt0Tn3FjwCIXeGup2P2EBa+WW2YMAaoMFofYviR5vRlKBgdKo9fsAruaO1r6nm2EdAjOlniyw92bEfU/qOey1nVp/oK2S82uT5In8KB7vl6rF3ak7WAsT9Q5vZUhsrG+eE4PVyIyWNBhs4A7pSwZGHDR/MYtp0E2ug= - secure: H2GClDJ7TEQaWgnk8d2fIVDpLwG3rTmN8TalUzrCqXGoG6ylCVmlwzKLgfPPWrVgSA7QTdfNV0ab7c2KyPoZBinHmeGMSuKNLVbhOXRc2VFxTBntBTuyJhfCgQEpUKvJesJUuv5RuBn//wC7VZcVVNc06TZDEe8+aDVYQuCRMXZJ4X3e6nSZ64QX2veyVcr+TjnRsZPkeBVcK9hngvuaxLb/hbJ85CvjiseZRt47PGIcrEpMn9n2GMw1m0fNnPoN+MBTSCnIklTmdjPG7t4GUSLmD6H0lNLdXuehYqmQAHgYrLec1aiFlV57QaDoDZrq2hSf4vDmCB/FVydGhD5JunI67pujoV2OnD1V80eUZhYNWOYsJ2Nfp4NxgXsPUcE6zWLYsLfktMPZADhOXInQRACt1cnx8zMYKLnch1RY/ZqjSg0nPtRjLzQ0lNsw5leixvBdBnMjxYHVyAWVwg8WiJMaLO9vog2Qnxg1NTacHO2CsOmm2rw6stpg7ndp/+nOleRlfUKggjt0Tn3FjwCIXeGup2P2EBa+WW2YMAaoMFofYviR5vRlKBgdKo9fsAruaO1r6nm2EdAjOlniyw92bEfU/qOey1nVp/oK2S82uT5In8KB7vl6rF3ak7WAsT9Q5vZUhsrG+eE4PVyIyWNBhs4A7pSwZGHDR/MYtp0E2ug=
- 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: 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: 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: 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: addons:
chrome: stable chrome: stable
apt: apt:
packages: packages:
- libgconf-2-4 # for cypress - libgconf-2-4
before_script: npm run bundle before_script: npm run bundle
script: npm test && ([ "${TRAVIS_PULL_REQUEST}" = "false" ] && npm run e2e-ci || npm script: npm test && ([ "${TRAVIS_PULL_REQUEST}" = "false" ] && npm run e2e-ci || npm
run e2e) 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) # [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) * 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)) * 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)) * 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) * 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) * 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) * 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)) * 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 * redoc-cli: Add missing content type header on compressed responses of `/` path
@ -144,7 +240,7 @@
### Bug Fixes ### 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)) * 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) * 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)) * 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)) * 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 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 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)) * 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)) * 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) * 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) * 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)) * **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 ### 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) * 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 ### Bug Fixes
* add some spacing between operation description and parameters ([597688e](https://github.com/Rebilly/ReDoc/commit/597688e)) * 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) * 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 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)) * fix linebreaks in multiparagraph field descriptions ([8fb9cd6](https://github.com/Rebilly/ReDoc/commit/8fb9cd6))
@ -675,7 +771,7 @@
### Bug Fixes ### 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) * 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)) * 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)) * 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)) * 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 ### Features
@ -899,7 +995,7 @@ Complete rewrite also means that this rewrite may introduce issues, but they sho
### Deprecations ### 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 ```html
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
@ -1268,7 +1364,7 @@ closes [#321](https://github.com/Rebilly/ReDoc/issues/321)
### Bug fixes ### Bug fixes
* Update webpack to the latest beta ([#143](https://github.com/Rebilly/ReDoc/issues/143)) * 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)) * 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 ### Features/Improvements
* Major performance optimization with new option `lazy-rendering` * 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-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-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-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-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-tagGroups`](docs/redoc-vendor-extensions.md#x-tagGroups) - group tags by categories in the side menu
* [`x-servers`](docs/redoc-vendor-extensions.md#x-servers) - ability to specify different servers for API (backported from OpenAPI 3.0) * [`x-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 ### `<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`. 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` - 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: `scrollYOffset` can be specified in various ways:
* **number**: A fixed number of pixels to be used as offset; * **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; * **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); * **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). * `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.~~ * `payloadSampleIdx` - if set, payload sample will be inserted at this index or last. Indexes start from 0.
* `hideHostname` - if set, the protocol and hostname is not shown in the operation definition. * `theme` - ReDoc theme. Not documented yet. For details check source code: [theme.ts](https://github.com/Redocly/redoc/blob/master/src/theme.ts).
* `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. * `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!**
* `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)
## Advanced usage of standalone version ## Advanced usage of standalone version
Instead of adding `spec-url` attribute to the `<redoc>` element you can initialize ReDoc via globally exposed `Redoc` object: 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}"`); console.log(`Writing config "${configDir}"`);
fs.writeFileSync(configDir, configFile); fs.writeFileSync(configDir, configFile);
console.log('Starging benchmark server'); console.log('Starting benchmark server');
const proc = spawn('npm', ['run', 'start:benchmark']); const proc = spawn('npm', ['run', 'start:benchmark']);
proc.stdout.on('data', data => { proc.stdout.on('data', data => {

View File

@ -7,7 +7,7 @@
# To run: # To run:
# To display the command line options: # To display the command line options:
# $ docker run --rm -it redoc-cli --help # $ 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' # 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 # $ 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 { createStore, loadAndBundleSpec, Redoc } from 'redoc';
import { watch } from 'chokidar'; 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 mkdirp from 'mkdirp';
import * as YargsParser from 'yargs'; import * as YargsParser from 'yargs';
@ -99,7 +106,6 @@ YargsParser.command(
yargs.options('title', { yargs.options('title', {
describe: 'Page Title', describe: 'Page Title',
type: 'string', type: 'string',
default: 'ReDoc documentation',
}); });
yargs.options('disableGoogleFont', { yargs.options('disableGoogleFont', {
@ -197,7 +203,7 @@ async function serve(port: number, pathToSpec: string, options: Options = {}) {
const watcher = watch(pathToSpecDirectory, watchOptions); const watcher = watch(pathToSpecDirectory, watchOptions);
const log = console.log.bind(console); const log = console.log.bind(console);
const handlePath = async path => { const handlePath = async _path => {
try { try {
spec = await loadAndBundleSpec(pathToSpec); spec = await loadAndBundleSpec(pathToSpec);
pageHTML = await getPageHTML(spec, pathToSpec, options); 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 src="https://unpkg.com/redoc@next/bundles/redoc.standalone.js"></script>'
: `<script>${redocStandaloneSrc}</script>`) + css : `<script>${redocStandaloneSrc}</script>`) + css
: '<script src="redoc.standalone.js"></script>', : '<script src="redoc.standalone.js"></script>',
title, title: title || spec.info.title || 'ReDoc documentation',
disableGoogleFont, disableGoogleFont,
templateOptions, templateOptions,
}); });
@ -357,13 +363,23 @@ function handleError(error: Error) {
} }
function getObjectOrJSON(options) { function getObjectOrJSON(options) {
try { switch (typeof options) {
return options && typeof options === 'string' case 'object':
? JSON.parse(options) : options return options;
? options case 'string':
: {}; try {
} catch (e) { if (existsSync(options) && lstatSync(options).isFile()) {
console.log(`Encountered error:\n${options}\nis not a valid JSON.`); return JSON.parse(readFileSync(options, 'utf-8'));
handleError(e); } else {
return JSON.parse(options);
}
} catch (e) {
console.log(
`Encountered error:\n\n${options}\n\nis neither a file with a valid JSON object neither a stringified JSON object.`,
);
handleError(e);
}
default:
return {};
} }
} }

View File

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

View File

@ -78,6 +78,13 @@
dependencies: dependencies:
regenerator-runtime "^0.13.2" 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": "@babel/template@^7.1.0":
version "7.4.4" version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" 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" jsonpointer "^4.0.1"
leven "^2.1.0" 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: binary-extensions@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" 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" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
commander@~2.20.0: commander@~2.20.3:
version "2.20.0" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
console-browserify@^1.1.0: console-browserify@^1.1.0:
version "1.1.0" version "1.1.0"
@ -619,20 +621,15 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0" miller-rabin "^4.0.0"
randombytes "^2.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: domain-browser@^1.1.1:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
dompurify@^2.0.3: dompurify@^2.0.7:
version "2.0.3" version "2.0.7"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.3.tgz#5cc4965a487d54aedba6ba9634b137cfbd7eb50d" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.7.tgz#f8266ad38fe1602fb5b3222f31eedbf5c16c4fd5"
integrity sha512-q006uOkD2JGSJgF0qBt7rVhUvUPBWCxpGayALmHvXx2iNlMfNVz7PDGeXEUjNGgIDjADz59VZCv6UE3U8XRWVw== integrity sha512-S3O0lk6rFJtO01ZTzMollCOGg+WAtCwS3U5E2WSDY/x/sy7q70RjEC4Dmrih5/UqzLLB9XoKJ8KqwBxaNvBu4A==
elliptic@^6.0.0: elliptic@^6.0.0:
version "6.5.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" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 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: end-of-stream@^1.1.0:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" 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" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 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: fill-range@^7.0.1:
version "7.0.1" version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@ -783,14 +770,6 @@ glob-parent@^5.0.0:
dependencies: dependencies:
is-glob "^4.0.1" 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: globals@^11.1.0:
version "11.12.0" version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" 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" resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
handlebars@*, handlebars@^4.1.2: handlebars@*:
version "4.1.2" version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
@ -819,6 +798,17 @@ handlebars@*, handlebars@^4.1.2:
optionalDependencies: optionalDependencies:
uglify-js "^3.1.4" 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: has-flag@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 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-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1" 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: http2-client@^1.2.5:
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/http2-client/-/http2-client-1.3.2.tgz#80e31d90275844c0ccad8020b2de342a538a7971" 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" code-error-fragment "0.0.230"
grapheme-splitter "^1.0.4" 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: jsonpointer@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" 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" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= 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: locate-path@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 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: dependencies:
js-tokens "^3.0.0 || ^4.0.0" js-tokens "^3.0.0 || ^4.0.0"
lunr@2.3.6: lunr@2.3.8:
version "2.3.6" version "2.3.8"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.6.tgz#f278beee7ffd56ad86e6e478ce02ab2b98c78dd5" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072"
integrity sha512-swStvEyDqQ85MGpABCMBclZcLI/pBIlu8FFDtmX197+oEgKloJ67QnB+Tidh0340HmLMs39c4GrkPY3cmkXp6Q== integrity sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==
map-age-cleaner@^0.1.1: map-age-cleaner@^0.1.1:
version "0.1.3" version "0.1.3"
@ -1092,11 +1059,16 @@ mem@^4.0.0:
mimic-fn "^2.0.0" mimic-fn "^2.0.0"
p-is-promise "^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" version "5.0.5"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e"
integrity sha512-ey6EpYv0tEaIbM/nTDOpHciXUvd+ackQrJgEzBwemhZZIWZjcyodqEcrmqDy2BKRTM3a65kKBV4WtLXJDt26SQ== 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: merge-anything@^2.2.4:
version "2.4.0" version "2.4.0"
resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-2.4.0.tgz#86959caf02bb8969d1ae5e1b652862bc5fe54e44" 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" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 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: minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" 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" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 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: minimist@~0.0.1:
version "0.0.10" version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
@ -1156,17 +1116,17 @@ mkdirp@^0.5.1:
dependencies: dependencies:
minimist "0.0.8" minimist "0.0.8"
mobx-react-lite@1.4.0: mobx-react-lite@^1.4.2:
version "1.4.0" version "1.5.1"
resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.4.0.tgz#193beb5fdddf17ae61542f65ff951d84db402351" resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.5.1.tgz#8eac90985b4d2bee475dd90a0d4d903be578f154"
integrity sha512-5xCuus+QITQpzKOjAOIQ/YxNhOl/En+PlNJF+5QU4Qxn9gnNMJBbweAdEW3HnuVQbfqDYEUnkGs5hmkIIStehg== integrity sha512-40Gn8hFq+MuNHqCaeSo2adN4WvpWkIeSYZVJWzRzm0rbEf0BFow6Ir9IefErql0pX9q650TN1JAQXvrXxKR8Mg==
mobx-react@^6.1.3: mobx-react@^6.1.4:
version "6.1.3" version "6.1.4"
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.3.tgz#ad07880ea60cdcdb2a7e2a0d54e01379710cf00a" resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.4.tgz#818e7991c321c05bd9b8156d94be17dad165501e"
integrity sha512-eT/jO9dYIoB1AlZwI2VC3iX0gPOeOIqZsiwg7tDJV1B7Z69h+TZZL3dgOE0UeS2zoHhGeKbP+K+OLeLMnnkGnA== integrity sha512-wzrJF1RflhyLh8ne4FJfMbG8ZgRFmZ62b4nbyhJzwQpAmrkSnSsAWG9mIff4ffV/Q7OU+uOYf7rXvSmiuUe4cw==
dependencies: dependencies:
mobx-react-lite "1.4.0" mobx-react-lite "^1.4.2"
mobx@^4.2.0: mobx@^4.2.0:
version "4.13.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" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
polished@^3.4.1: polished@^3.4.2:
version "3.4.1" version "3.4.2"
resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.1.tgz#1eb5597ec1792206365635811d465751f5cbf71c" resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.2.tgz#b4780dad81d64df55615fbfc77acb52fd17d88cd"
integrity sha512-GflTnlP5rrpDoigjczEkS6Ye7NDA4sFvAnlr5hSDrEvjiVj97Xzev3hZlLi3UB27fpxyTS9rWU64VzVLWkG+mg== integrity sha512-9Rch6iMZckABr6EFCLPZsxodeBpXMo9H4fRlfR/9VjMEyy5xpo1/WgXlJGgSjPyVhEZNycbW7UmYMNyWS5MI0g==
dependencies: dependencies:
"@babel/runtime" "^7.4.5" "@babel/runtime" "^7.6.3"
postcss-value-parser@^3.3.0: postcss-value-parser@^3.3.0:
version "3.3.1" version "3.3.1"
@ -1459,7 +1419,7 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= 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" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -1540,30 +1500,11 @@ react-dropdown@^1.6.4:
dependencies: dependencies:
classnames "^2.2.3" classnames "^2.2.3"
react-hot-loader@^4.12.14: react-is@^16.6.0, react-is@^16.8.1:
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:
version "16.8.6" version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== 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: react-tabs@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.0.0.tgz#60311a17c755eb6aa9b3310123e67db421605127" resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.0.0.tgz#60311a17c755eb6aa9b3310123e67db421605127"
@ -1602,31 +1543,30 @@ readdirp@^3.1.1:
dependencies: dependencies:
picomatch "^2.0.4" picomatch "^2.0.4"
redoc@2.0.0-rc.16: redoc@2.0.0-rc.23:
version "2.0.0-rc.16" version "2.0.0-rc.23"
resolved "https://registry.yarnpkg.com/redoc/-/redoc-2.0.0-rc.16.tgz#01d5dafba6ae266a5934dc9904b87bc8a175b222" resolved "https://registry.yarnpkg.com/redoc/-/redoc-2.0.0-rc.23.tgz#3b8a47d9357e6ee52a0d93d08fb03ce00f424728"
integrity sha512-5YWk7NBebYZ8xMbKXA1sD++QsSh7NbnB2sStJRKLeP/rU4oX586SIqHXl+MW1OhIZW44mYFMHpYzxpZKCllk9w== integrity sha512-ifrewYzrCrGBv6bFSh5FEnDTywVm6IL/VEb7PUpVPCC1lMceMAB1HrlyKlBCyNqjq9LcRO+y9q881LfPXS4PUw==
dependencies: dependencies:
classnames "^2.2.6" classnames "^2.2.6"
decko "^1.2.0" decko "^1.2.0"
dompurify "^2.0.3" dompurify "^2.0.7"
eventemitter3 "^4.0.0" eventemitter3 "^4.0.0"
json-pointer "^0.6.0" json-pointer "^0.6.0"
json-schema-ref-parser "^6.1.0" json-schema-ref-parser "^6.1.0"
lunr "2.3.6" lunr "2.3.8"
mark.js "^8.11.1" mark.js "^8.11.1"
marked "^0.7.0" marked "^0.7.0"
memoize-one "~5.0.5" memoize-one "~5.1.1"
mobx-react "^6.1.3" mobx-react "^6.1.4"
openapi-sampler "1.0.0-beta.15" openapi-sampler "1.0.0-beta.15"
perfect-scrollbar "^1.4.0" perfect-scrollbar "^1.4.0"
polished "^3.4.1" polished "^3.4.2"
prismjs "^1.17.1" prismjs "^1.17.1"
prop-types "^15.7.2" prop-types "^15.7.2"
react-dropdown "^1.6.4" react-dropdown "^1.6.4"
react-hot-loader "^4.12.14"
react-tabs "^3.0.0" react-tabs "^3.0.0"
slugify "^1.3.5" slugify "^1.3.6"
stickyfill "^1.1.1" stickyfill "^1.1.1"
swagger2openapi "^5.3.1" swagger2openapi "^5.3.1"
tslib "^1.10.0" tslib "^1.10.0"
@ -1716,11 +1656,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1" inherits "^2.0.1"
safe-buffer "^5.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: shebang-command@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 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" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
slugify@^1.3.5: slugify@^1.3.6:
version "1.3.5" version "1.3.6"
resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.5.tgz#90210678818b6d533cb060083aed0e8238133508" resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.6.tgz#ba5fd6159b570fe4811d02ea9b1f4906677638c3"
integrity sha512-5VCnH7aS13b0UqWOs7Ef3E5rkhFe8Od+cp7wybFv5mv/sYSRkucZlJX0bamAJky7b2TTtGvrJBWVdpdEicsSrA== integrity sha512-wA9XS475ZmGNlEnYYLPReSfuz/c3VQsEMoU43mi6OnKMCdbnFXd4/Yg7J0lBv8jkPolacMpOrWEaoYxuE1+hoQ==
source-map@^0.5.0: source-map@^0.5.0:
version "0.5.7" 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" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 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: sprintf-js@~1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 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= integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
uglify-js@^3.1.4: uglify-js@^3.1.4:
version "3.6.0" version "3.7.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.4.tgz#e6d83a1aa32ff448bd1679359ab13d8db0fe0743"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg== integrity sha512-tinYWE8X1QfCHxS1lBS8yiDekyhSXOO6R66yNOCdUJeojxxw+PX2BHAz/BWyW7PQ7pkiWVxJfIEbiDxyLWvUGg==
dependencies: dependencies:
commander "~2.20.0" commander "~2.20.3"
source-map "~0.6.1" source-map "~0.6.1"
url-template@^2.0.8: url-template@^2.0.8:

View File

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

View File

@ -53,7 +53,7 @@
}, },
{ {
"name": "Contacts", "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", "name": "Coupons",
@ -93,7 +93,7 @@
}, },
{ {
"name": "Files", "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", "name": "Gateway Accounts",
@ -15623,7 +15623,7 @@
"description": "Reset user password\n", "description": "Reset user password\n",
"responses": { "responses": {
"201": { "201": {
"description": "Password was reseted successfully", "description": "Password was reset successfully",
"headers": { "headers": {
"Rate-Limit-Limit": { "Rate-Limit-Limit": {
"description": "The number of allowed requests in the current period", "description": "The number of allowed requests in the current period",
@ -23851,17 +23851,17 @@
"type": "string" "type": "string"
}, },
"totpRequired": { "totpRequired": {
"description": "The user setting of two-factor authentification", "description": "The user setting of two-factor authentication",
"readOnly": true, "readOnly": true,
"type": "boolean" "type": "boolean"
}, },
"totpSecret": { "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, "readOnly": true,
"type": "string" "type": "string"
}, },
"totpUrl": { "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, "readOnly": true,
"type": "string", "type": "string",
"format": "url" "format": "url"
@ -24250,7 +24250,7 @@
}, },
"bodyHtml": { "bodyHtml": {
"type": "string", "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": [ "required": [
@ -26495,15 +26495,15 @@
} }
}, },
"totpRequired": { "totpRequired": {
"description": "The user setting of two-factor authentification", "description": "The user setting of two-factor authentication",
"type": "boolean" "type": "boolean"
}, },
"totpSecret": { "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" "type": "string"
}, },
"totpUrl": { "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", "type": "string",
"format": "url" "format": "url"
}, },
@ -26984,7 +26984,7 @@
"collectionExpand": { "collectionExpand": {
"name": "expand", "name": "expand",
"in": "query", "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": { "schema": {
"type": "string" "type": "string"
} }

View File

@ -11,7 +11,7 @@ const demos = [
value: 'https://api.apis.guru/v2/specs/googleapis.com/calendar/v3/swagger.yaml', value: 'https://api.apis.guru/v2/specs/googleapis.com/calendar/v3/swagger.yaml',
label: 'Google Calendar', 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/zoom.us/2.0.0/swagger.yaml', label: 'Zoom.us' },
{ {
value: 'https://api.apis.guru/v2/specs/graphhopper.com/1.0/swagger.yaml', value: 'https://api.apis.guru/v2/specs/graphhopper.com/1.0/swagger.yaml',

View File

@ -84,6 +84,14 @@ x-tagGroups:
paths: paths:
/pet: /pet:
parameters: 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 - name: cookieParam
in: cookie in: cookie
description: Some cookie description: Some cookie
@ -296,7 +304,7 @@ paths:
tags: tags:
- pet - pet
summary: Finds Pets by status 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 operationId: findPetsByStatus
parameters: parameters:
- name: status - name: status
@ -341,7 +349,7 @@ paths:
- pet - pet
summary: Finds Pets by tags summary: Finds Pets by tags
description: >- 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. tag2, tag3 for testing.
operationId: findPetsByTags operationId: findPetsByTags
deprecated: true deprecated: true
@ -621,7 +629,7 @@ paths:
type: integer type: integer
format: int32 format: int32
X-Expires-After: X-Expires-After:
description: date in UTC when toekn expires description: date in UTC when token expires
schema: schema:
type: string type: string
format: date-time format: date-time
@ -676,6 +684,7 @@ components:
type: string type: string
description: The measured skill for hunting description: The measured skill for hunting
default: lazy default: lazy
example: adventurous
enum: enum:
- clueless - clueless
- lazy - lazy
@ -727,6 +736,7 @@ components:
type: number type: number
description: Average amount of honey produced per day in ounces description: Average amount of honey produced per day in ounces
example: 3.14 example: 3.14
multipleOf: .01
required: required:
- honeyPerDay - honeyPerDay
Id: Id:
@ -765,7 +775,7 @@ components:
type: boolean type: boolean
default: false default: false
readOnly: true readOnly: true
rqeuestId: requestId:
description: Unique Request Id description: Unique Request Id
type: string type: string
writeOnly: true writeOnly: true
@ -888,7 +898,6 @@ components:
type: string type: string
pattern: '/^\+(?:[0-9]-?){6,14}[0-9]$/' pattern: '/^\+(?:[0-9]-?){6,14}[0-9]$/'
example: +1-202-555-0192 example: +1-202-555-0192
nullable: true
userStatus: userStatus:
description: User status description: User status
type: integer type: integer

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,16 +27,19 @@ export class FieldDetails extends React.PureComponent<FieldProps> {
static contextType = OptionsContext; static contextType = OptionsContext;
render() { render() {
const { showExamples, field, renderDiscriminatorSwitch } = this.props; const { showExamples, field, renderDiscriminatorSwitch } = this.props;
const { enumSkipQuotes } = this.context; const { enumSkipQuotes, hideSchemaTitles } = this.context;
const { schema, description, example, deprecated } = field; 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; let exampleField: JSX.Element | null = null;
if (showExamples && example !== undefined) { if (showExamples && example !== undefined) {
const label = l('example') + ':'; const label = l('example') + ':';
if (field.in && (field.style || field.serializationMime)) { 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} />; exampleField = <FieldDetail label={label} value={serializedValue} raw={true} />;
} else { } else {
exampleField = <FieldDetail label={label} value={example} />; exampleField = <FieldDetail label={label} value={example} />;
@ -56,10 +59,10 @@ export class FieldDetails extends React.PureComponent<FieldProps> {
&gt;{' '} &gt;{' '}
</TypeFormat> </TypeFormat>
)} )}
{schema.title && <TypeTitle> ({schema.title}) </TypeTitle>} {schema.title && !hideSchemaTitles && <TypeTitle> ({schema.title}) </TypeTitle>}
<ConstraintsView constraints={schema.constraints} /> <ConstraintsView constraints={schema.constraints} />
{schema.nullable && <NullableLabel> {l('nullable')} </NullableLabel>} {schema.nullable && <NullableLabel> {l('nullable')} </NullableLabel>}
{schema.pattern && <PatternLabel>{schema.pattern}</PatternLabel>} {schema.pattern && <PatternLabel> {schema.pattern} </PatternLabel>}
{schema.isCircular && <RecursiveLabel> {l('recursive')} </RecursiveLabel>} {schema.isCircular && <RecursiveLabel> {l('recursive')} </RecursiveLabel>}
</div> </div>
{deprecated && ( {deprecated && (
@ -67,7 +70,7 @@ export class FieldDetails extends React.PureComponent<FieldProps> {
<Badge type="warning"> {l('deprecated')} </Badge> <Badge type="warning"> {l('deprecated')} </Badge>
</div> </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} />}{' '} {!renderDiscriminatorSwitch && <EnumValues type={schema.type} values={schema.enum} />}{' '}
{exampleField} {exampleField}
{<Extensions extensions={{ ...field.extensions, ...schema.extensions }} />} {<Extensions extensions={{ ...field.extensions, ...schema.extensions }} />}

View File

@ -25,7 +25,7 @@ export class AdvancedMarkdown extends React.Component<AdvancedMarkdownProps> {
renderWithOptionsAndStore(options: RedocNormalizedOptions, store?: AppStore) { renderWithOptionsAndStore(options: RedocNormalizedOptions, store?: AppStore) {
const { source, htmlWrap = i => i } = this.props; const { source, htmlWrap = i => i } = this.props;
if (!store) { 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); const renderer = new MarkdownRenderer(options);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,14 +24,14 @@ describe('Components', () => {
}); });
test('should collapse/uncollapse', () => { 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 "]'); const expandAll = component.find('div > span[children=" Expand all "]');
expandAll.simulate('click'); 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 "]'); const collapseAll = component.find('div > span[children=" Collapse all "]');
collapseAll.simulate('click'); 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', () => { test('should collapse/uncollapse', () => {

View File

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

View File

@ -45,6 +45,14 @@ export class MarkdownRenderer {
return compRegexp.test(rawText); 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[] = []; headings: MarkdownHeading[] = [];
currentTopHeading: MarkdownHeading; currentTopHeading: MarkdownHeading;
@ -119,7 +127,12 @@ export class MarkdownRenderer {
.trim(); .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) { if (level === 1) {
this.currentTopHeading = this.saveHeading(text, level); this.currentTopHeading = this.saveHeading(text, level);
} else if (level === 2) { } else if (level === 2) {

View File

@ -66,6 +66,13 @@ export class MenuBuilder {
const renderer = new MarkdownRenderer(options); const renderer = new MarkdownRenderer(options);
const headings = renderer.extractHeadings(description || ''); 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) => const mapHeadingsDeep = (_parent, items, depth = 1) =>
items.map(heading => { items.map(heading => {
const group = new GroupModel('section', heading, _parent); 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 * @param tags value of `x-tagGroups` vendor extension
*/ */
static getTagGroupsItems( static getTagGroupsItems(

View File

@ -190,7 +190,7 @@ export class MenuStore {
* activate menu item * activate menu item
* @param item item to activate * @param item item to activate
* @param updateLocation [true] whether to update location * @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 @action
activate( 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 { isRef(obj: any): obj is OpenAPIRef {
if (!obj) { if (!obj) {
@ -122,7 +122,7 @@ export class OpenAPIParser {
} }
/** /**
* resets visited enpoints. should be run after * resets visited endpoints. should be run after
*/ */
resetVisited() { resetVisited() {
if (process.env.NODE_ENV !== 'production') { 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 * Resolve given reference object or return as is if it is not a reference
* @param obj object to dereference * @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 { deref<T extends object>(obj: OpenAPIRef | T, forceCircular: boolean = false): T {
if (this.isRef(obj)) { if (this.isRef(obj)) {
@ -177,10 +177,10 @@ export class OpenAPIParser {
} }
/** /**
* Merge allOf contsraints. * Merge allOf constraints.
* @param schema schema with allOF * @param schema schema with allOF
* @param $ref pointer of the schema * @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( mergeAllOf(
schema: OpenAPISchema, schema: OpenAPISchema,
@ -275,13 +275,13 @@ export class OpenAPIParser {
} }
// merge rest of constraints // merge rest of constraints
// TODO: do more intelegent merge // TODO: do more intelligent merge
receiver = { ...subSchema, ...receiver }; receiver = { ...subSchema, ...receiver };
if (subSchemaRef) { if (subSchemaRef) {
receiver.parentRefs!.push(subSchemaRef); receiver.parentRefs!.push(subSchemaRef);
if (receiver.title === undefined && isNamedDefinition(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 // ref: https://github.com/Redocly/redoc/issues/601
// receiver.title = JsonPointer.baseName(subSchemaRef); // receiver.title = JsonPointer.baseName(subSchemaRef);
} }
@ -296,8 +296,8 @@ export class OpenAPIParser {
* returns map of definition pointer to definition name * returns map of definition pointer to definition name
* @param $refs array of references to find derived from * @param $refs array of references to find derived from
*/ */
findDerived($refs: string[]): Dict<string> { findDerived($refs: string[]): Dict<string[] | string> {
const res: Dict<string> = {}; const res: Dict<string[]> = {};
const schemas = (this.spec.components && this.spec.components.schemas) || {}; const schemas = (this.spec.components && this.spec.components.schemas) || {};
for (const defName in schemas) { for (const defName in schemas) {
const def = this.deref(schemas[defName]); const def = this.deref(schemas[defName]);
@ -305,7 +305,7 @@ export class OpenAPIParser {
def.allOf !== undefined && def.allOf !== undefined &&
def.allOf.find(obj => obj.$ref !== undefined && $refs.indexOf(obj.$ref) > -1) 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; return res;

View File

@ -26,6 +26,8 @@ export interface RedocRawOptions {
hideSingleRequestSampleTab?: boolean | string; hideSingleRequestSampleTab?: boolean | string;
menuToggle?: boolean | string; menuToggle?: boolean | string;
jsonSampleExpandLevel?: number | string | 'all'; jsonSampleExpandLevel?: number | string | 'all';
hideSchemaTitles?: boolean | string;
payloadSampleIdx?: number;
providedByName?: string; providedByName?: string;
providedByUri?: string; providedByUri?: string;
@ -43,12 +45,12 @@ export interface RedocRawOptions {
expandDefaultServerVariables?: boolean; expandDefaultServerVariables?: boolean;
} }
function argValueToBoolean(val?: string | boolean): boolean { function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean {
if (val === undefined) { if (val === undefined) {
return false; return defaultValue || false;
} }
if (typeof val === 'string') { if (typeof val === 'string') {
return true; return val === 'false' ? false : true;
} }
return val; return val;
} }
@ -123,6 +125,18 @@ export class RedocNormalizedOptions {
return value; 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 { private static normalizeJsonSampleExpandLevel(level?: number | string | 'all'): number {
if (level === 'all') { if (level === 'all') {
return +Infinity; return +Infinity;
@ -151,6 +165,8 @@ export class RedocNormalizedOptions {
menuToggle: boolean; menuToggle: boolean;
jsonSampleExpandLevel: number; jsonSampleExpandLevel: number;
enumSkipQuotes: boolean; enumSkipQuotes: boolean;
hideSchemaTitles: boolean;
payloadSampleIdx: number;
enableConsole: boolean; enableConsole: boolean;
additionalHeaders: object; additionalHeaders: object;
providedByName: string; providedByName: string;
@ -190,11 +206,13 @@ export class RedocNormalizedOptions {
this.onlyRequiredInSamples = argValueToBoolean(raw.onlyRequiredInSamples); this.onlyRequiredInSamples = argValueToBoolean(raw.onlyRequiredInSamples);
this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions); this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions);
this.hideSingleRequestSampleTab = argValueToBoolean(raw.hideSingleRequestSampleTab); this.hideSingleRequestSampleTab = argValueToBoolean(raw.hideSingleRequestSampleTab);
this.menuToggle = argValueToBoolean(raw.menuToggle); this.menuToggle = argValueToBoolean(raw.menuToggle, true);
this.jsonSampleExpandLevel = RedocNormalizedOptions.normalizeJsonSampleExpandLevel( this.jsonSampleExpandLevel = RedocNormalizedOptions.normalizeJsonSampleExpandLevel(
raw.jsonSampleExpandLevel, raw.jsonSampleExpandLevel,
); );
this.enumSkipQuotes = argValueToBoolean(raw.enumSkipQuotes); this.enumSkipQuotes = argValueToBoolean(raw.enumSkipQuotes);
this.hideSchemaTitles = argValueToBoolean(raw.hideSchemaTitles);
this.payloadSampleIdx = RedocNormalizedOptions.normalizePayloadSampleIdx(raw.payloadSampleIdx);
this.enableConsole = argValueToBoolean(raw.enableConsole); this.enableConsole = argValueToBoolean(raw.enableConsole);
this.additionalHeaders = raw.additionalHeaders || {}; this.additionalHeaders = raw.additionalHeaders || {};
this.providedByName = raw.providedByName || 'Documentation Powered by ReDoc'; this.providedByName = raw.providedByName || 'Documentation Powered by ReDoc';

View File

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

View File

@ -6,7 +6,7 @@ import { SecuritySchemesModel } from './models/SecuritySchemes';
import { OpenAPIParser } from './OpenAPIParser'; import { OpenAPIParser } from './OpenAPIParser';
import { RedocNormalizedOptions } from './RedocNormalizedOptions'; 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 { export class SpecStore {
parser: OpenAPIParser; parser: OpenAPIParser;

View File

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

View File

@ -22,7 +22,7 @@ describe('Models', () => {
expect(resp.type).toEqual('error'); 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); const resp = new ResponseModel(parser, 'default', false, {}, opts);
expect(resp.type).toEqual('success'); expect(resp.type).toEqual('success');
}); });

View File

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

View File

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

View File

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

View File

@ -27,9 +27,23 @@ import { ContentItemModel, ExtendedOpenAPIOperation } from '../MenuBuilder';
import { OpenAPIParser } from '../OpenAPIParser'; import { OpenAPIParser } from '../OpenAPIParser';
import { RedocNormalizedOptions } from '../RedocNormalizedOptions'; import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
import { FieldModel } from './Field'; import { FieldModel } from './Field';
import { MediaContentModel } from './MediaContent';
import { RequestBodyModel } from './RequestBody'; import { RequestBodyModel } from './RequestBody';
import { ResponseModel } from './Response'; 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 * Operation model ready to be used by components
*/ */
@ -62,7 +76,6 @@ export class OperationModel implements IMenuItem {
path: string; path: string;
servers: OpenAPIServer[]; servers: OpenAPIServer[];
security: SecurityRequirementModel[]; security: SecurityRequirementModel[];
codeSamples: OpenAPIXCodeSample[];
extensions: Dict<any>; extensions: Dict<any>;
constructor( constructor(
@ -89,7 +102,6 @@ export class OperationModel implements IMenuItem {
this.httpVerb = operationSpec.httpVerb; this.httpVerb = operationSpec.httpVerb;
this.deprecated = !!operationSpec.deprecated; this.deprecated = !!operationSpec.deprecated;
this.operationId = operationSpec.operationId; this.operationId = operationSpec.operationId;
this.codeSamples = operationSpec['x-code-samples'] || [];
this.path = operationSpec.pathName; this.path = operationSpec.pathName;
const pathInfo = parser.byRef<OpenAPIPath>( 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 @memoize
get parameters() { get parameters() {
const _parameters = mergeParams( const _parameters = mergeParams(
@ -154,11 +190,12 @@ export class OperationModel implements IMenuItem {
).map(paramOrRef => new FieldModel(this.parser, paramOrRef, this.pointer, this.options)); ).map(paramOrRef => new FieldModel(this.parser, paramOrRef, this.pointer, this.options));
if (this.options.sortPropsAlphabetically) { if (this.options.sortPropsAlphabetically) {
sortByField(_parameters, 'name'); return sortByField(_parameters, 'name');
} }
if (this.options.requiredPropsFirst) { if (this.options.requiredPropsFirst) {
sortByRequired(_parameters); return sortByRequired(_parameters);
} }
return _parameters; return _parameters;
} }

View File

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

View File

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

View File

@ -9,6 +9,7 @@ import {
normalizeServers, normalizeServers,
pluralizeType, pluralizeType,
serializeParameterValue, serializeParameterValue,
sortByRequired,
} from '../'; } from '../';
import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services'; import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services';
@ -249,7 +250,7 @@ describe('Utils', () => {
expect(res).toEqual([{ url: 'http://base.com/sandbox/test', description: '' }]); 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', [ const res = normalizeServers('http://base.com/subpath/spec.yaml', [
{ {
url: '/sandbox/test', url: '/sandbox/test',
@ -258,7 +259,7 @@ describe('Utils', () => {
expect(res).toEqual([{ url: 'http://base.com/sandbox/test', description: '' }]); 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', [ const res = normalizeServers('http://base.com/subpath/spec.yaml', [
{ {
url: 'sandbox/test', url: 'sandbox/test',
@ -333,7 +334,8 @@ describe('Utils', () => {
const itemConstraintSchema = ( const itemConstraintSchema = (
min: number | undefined = undefined, min: number | undefined = undefined,
max: 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', () => { it('should not have a humanized constraint without schema constraints', () => {
expect(humanizeConstraints(itemConstraintSchema())).toHaveLength(0); expect(humanizeConstraints(itemConstraintSchema())).toHaveLength(0);
@ -355,9 +357,21 @@ describe('Utils', () => {
expect(humanizeConstraints(itemConstraintSchema(7, 7))).toContain('7 items'); 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'); 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', () => { describe('OpenAPI pluralizeType', () => {
@ -370,17 +384,27 @@ describe('Utils', () => {
expect(pluralizeType('array')).toEqual('arrays'); 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('object (Pet)')).toEqual('objects (Pet)');
expect(pluralizeType('string <email>')).toEqual('strings <email>'); 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 or string')).toEqual('objects or strings');
expect(pluralizeType('object (Pet) or number <int64>')).toEqual( expect(pluralizeType('object (Pet) or number <int64>')).toEqual(
'objects (Pet) or numbers <int64>', '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', () => { 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'; 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) { export function mapWithLast<T, P>(array: T[], iteratee: (item: T, isLast: boolean) => P) {
const res: P[] = []; const res: P[] = [];
@ -118,7 +118,7 @@ const isMergebleObject = (item): boolean => {
/** /**
* slugify() returns empty string when failed to slugify. * 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 * the regex codes are referenced with https://gist.github.com/mathewbyrne/1280286
*/ */
export function safeSlugify(value: string): string { 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-cpp.js';
import 'prismjs/components/prism-csharp.js'; import 'prismjs/components/prism-csharp.js';
import 'prismjs/components/prism-go.js'; import 'prismjs/components/prism-go.js';
import 'prismjs/components/prism-http.js';
import 'prismjs/components/prism-java.js'; import 'prismjs/components/prism-java.js';
import 'prismjs/components/prism-lua.js'; import 'prismjs/components/prism-lua.js';
import 'prismjs/components/prism-markup-templating.js'; // dep of php 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 * Highlight source code string using Prism.js
* @param source source code to highlight * @param source source code to highlight
* @param lang highlight language * @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 { export function highlight(source: string, lang: string = DEFAULT_LANG): string {
lang = lang.toLowerCase(); lang = lang.toLowerCase();

View File

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

View File

@ -1,6 +1,7 @@
import { dirname } from 'path'; import { dirname } from 'path';
const URLtemplate = require('url-template'); const URLtemplate = require('url-template');
import { FieldModel } from '../services/models';
import { OpenAPIParser } from '../services/OpenAPIParser'; import { OpenAPIParser } from '../services/OpenAPIParser';
import { import {
OpenAPIEncoding, OpenAPIEncoding,
@ -13,7 +14,7 @@ import {
Referenced, Referenced,
} from '../types'; } from '../types';
import { IS_BROWSER } from './dom'; 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 { function isWildcardStatusCode(statusCode: string | number): statusCode is string {
return typeof statusCode === 'string' && /\dxx/i.test(statusCode); 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'; 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)) { 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') { } else if (typeof fieldVal === 'object') {
return Object.keys(fieldVal) return Object.keys(fieldVal)
.map(k => `${k}${delimeter}${fieldVal[k]}`) .map(k => `${k}${delimiter}${fieldVal[k]}`)
.join(delimeter); .join(delimiter);
} else { } else {
return fieldName + '=' + fieldVal.toString(); return fieldName + '=' + fieldVal.toString();
} }
@ -165,7 +166,7 @@ function deepObjectEncodeField(fieldVal: any, fieldName: string): string {
function serializeFormValue(name: string, explode: boolean, value: any) { function serializeFormValue(name: string, explode: boolean, value: any) {
// Use RFC6570 safe name ([a-zA-Z0-9_]) and replace with our name later // 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 safeName = '__redoc_param_name__';
const suffix = explode ? '*' : ''; const suffix = explode ? '*' : '';
const template = URLtemplate.parse(`{?${safeName}${suffix}}`); 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 * 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( export function urlFormEncodePayload(
payload: object, payload: object,
@ -225,7 +226,7 @@ function serializePathParameter(
} }
// Use RFC6570 safe name ([a-zA-Z0-9_]) and replace with our name later // 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 safeName = '__redoc_param_name__';
const template = URLtemplate.parse(`{${prefix}${safeName}${suffix}}`); const template = URLtemplate.parse(`{${prefix}${safeName}${suffix}}`);
@ -368,6 +369,17 @@ export function isNamedDefinition(pointer?: string): boolean {
return /^#\/components\/schemas\/[^\/]+$/.test(pointer || ''); 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( function humanizeRangeConstraint(
description: string, description: string,
min: number | undefined, min: number | undefined,
@ -406,6 +418,11 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
res.push(arrayRange); res.push(arrayRange);
} }
const multipleOfConstraint = humanizeMultipleOfConstraint(schema.multipleOf);
if (multipleOfConstraint !== undefined) {
res.push(multipleOfConstraint);
}
let numberRange; let numberRange;
if (schema.minimum !== undefined && schema.maximum !== undefined) { if (schema.minimum !== undefined && schema.maximum !== undefined) {
numberRange = schema.exclusiveMinimum ? '( ' : '[ '; numberRange = schema.exclusiveMinimum ? '( ' : '[ ';
@ -428,25 +445,29 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
return res; return res;
} }
export function sortByRequired( export function sortByRequired(fields: FieldModel[], order: string[] = []) {
fields: Array<{ required: boolean; name: string }>, const unrequiredFields: FieldModel[] = [];
order: string[] = [], const orderedFields: FieldModel[] = [];
) { const unorderedFields: FieldModel[] = [];
fields.sort((a, b) => {
if (!a.required && b.required) { fields.forEach(field => {
return 1; if (field.required) {
} else if (a.required && !b.required) { order.includes(field.name) ? orderedFields.push(field) : unorderedFields.push(field);
return -1;
} else if (a.required && b.required) {
return order.indexOf(a.name) - order.indexOf(b.name);
} else { } 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) { export function sortByField(
fields.sort((a, b) => { fields: FieldModel[],
param: keyof Pick<FieldModel, 'name' | 'description' | 'kind'>,
) {
return [...fields].sort((a, b) => {
return a[param].localeCompare(b[param]); return a[param].localeCompare(b[param]);
}); });
} }
@ -462,7 +483,7 @@ export function mergeParams(
operationParamNames[param.name + '_' + param.in] = true; 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 => { pathParams = pathParams.filter(param => {
param = parser.shalowDeref(param); param = parser.shalowDeref(param);
return !operationParamNames[param.name + '_' + param.in]; return !operationParamNames[param.name + '_' + param.in];
@ -509,9 +530,10 @@ export function normalizeServers(
const baseUrl = specUrl === undefined ? removeQueryString(getHref()) : dirname(specUrl); const baseUrl = specUrl === undefined ? removeQueryString(getHref()) : dirname(specUrl);
if (servers.length === 0) { 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 { export function pluralizeType(displayType: string): string {
return displayType return displayType
.split(' or ') .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 '); .join(' or ');
} }

View File

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

View File

@ -17,7 +17,7 @@
"quotemark": [true, "single", "avoid-template", "jsx-double"], "quotemark": [true, "single", "avoid-template", "jsx-double"],
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
"arrow-parens": [true, "ban-single-arg-parens"], "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"], "object-literal-key-quotes": [true, "as-needed"],
"no-unused-expression": [true, "allow-tagged-template"], "no-unused-expression": [true, "allow-tagged-template"],
"semicolon": [true, "always", "ignore-bound-class-methods"], "semicolon": [true, "always", "ignore-bound-class-methods"],

View File

@ -5,7 +5,7 @@ import * as webpack from 'webpack';
import * as path from 'path'; import * as path from 'path';
const nodeExternals = require('webpack-node-externals')({ 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: [ whitelist: [
'swagger2openapi', 'swagger2openapi',
/reftools/, /reftools/,

3932
yarn.lock

File diff suppressed because it is too large Load Diff