Merge tag 'v2.0.0-rc.58' into sections-at-the-end

This commit is contained in:
Roberto Fernández 2021-12-03 13:43:52 +01:00
commit 9360bc9974
67 changed files with 1307 additions and 302 deletions

View File

@ -100,6 +100,7 @@ jobs:
- uses: actions/setup-node@v1 - uses: actions/setup-node@v1
with: with:
node-version: "14.x" node-version: "14.x"
registry-url: 'https://registry.npmjs.org'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Download cli bundled artifact - name: Download cli bundled artifact
uses: actions/download-artifact@v2 uses: actions/download-artifact@v2

View File

@ -98,5 +98,3 @@ jobs:
run: npm publish run: npm publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: After script
run: cat ./coverage/lcov.info | coveralls

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run pre-commit

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
*.md

View File

@ -1,3 +1,15 @@
# [2.0.0-rc.58](https://github.com/Redocly/redoc/compare/v2.0.0-rc.57...v2.0.0-rc.58) (2021-11-29)
### Bug Fixes
* add browser build for webpack 5 ([#1796](https://github.com/Redocly/redoc/issues/1796)) ([0e43ad3](https://github.com/Redocly/redoc/commit/0e43ad3102cfba8c4b30e59500ad4efc53f01c2d))
* Default boolean property value not rendered [#1779](https://github.com/Redocly/redoc/issues/1779) ([#1781](https://github.com/Redocly/redoc/issues/1781)) ([734080c](https://github.com/Redocly/redoc/commit/734080c35471d16f87004f7f9a51dcdeee1278a6))
* exclusiveMin/Max shows incorect range ([#1799](https://github.com/Redocly/redoc/issues/1799)) ([b604bd8](https://github.com/Redocly/redoc/commit/b604bd8da874f07e9e9f8b193ad10117a5f5059c))
* mobile view in docker image ([#1795](https://github.com/Redocly/redoc/issues/1795)) ([ad652b9](https://github.com/Redocly/redoc/commit/ad652b9c7fbcd84a6e83397272de64e57213fe9a))
# [2.0.0-rc.57](https://github.com/Redocly/redoc/compare/v2.0.0-rc.56...v2.0.0-rc.57) (2021-10-11) # [2.0.0-rc.57](https://github.com/Redocly/redoc/compare/v2.0.0-rc.56...v2.0.0-rc.57) (2021-10-11)

View File

@ -3,7 +3,7 @@
# Generate interactive API documentation from OpenAPI definitions # Generate interactive API documentation from OpenAPI definitions
[![Build Status](https://travis-ci.com/Redocly/redoc.svg?branch=master)](https://travis-ci.com/Redocly/redoc) [![Coverage Status](https://coveralls.io/repos/Redocly/redoc/badge.svg?branch=master&service=github)](https://coveralls.io/github/Redocly/redoc?branch=master) [![dependencies Status](https://david-dm.org/Redocly/redoc/status.svg)](https://david-dm.org/Redocly/redoc) [![devDependencies Status](https://david-dm.org/Redocly/redoc/dev-status.svg)](https://david-dm.org/Redocly/redoc#info=devDependencies) [![npm](http://img.shields.io/npm/v/redoc.svg)](https://www.npmjs.com/package/redoc) [![License](https://img.shields.io/npm/l/redoc.svg)](https://github.com/Redocly/redoc/blob/master/LICENSE) [![Build Status](https://travis-ci.com/Redocly/redoc.svg?branch=master)](https://travis-ci.com/Redocly/redoc) [![Coverage Status](https://coveralls.io/repos/Redocly/redoc/badge.svg?branch=master&service=github)](https://coveralls.io/github/Redocly/redoc?branch=master) [![npm](http://img.shields.io/npm/v/redoc.svg)](https://www.npmjs.com/package/redoc) [![License](https://img.shields.io/npm/l/redoc.svg)](https://github.com/Redocly/redoc/blob/master/LICENSE)
[![bundle size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js?compression=gzip&max=300000)](https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js) [![npm](https://img.shields.io/npm/dm/redoc.svg)](https://www.npmjs.com/package/redoc) [![](https://data.jsdelivr.com/v1/package/npm/redoc/badge)](https://www.jsdelivr.com/package/npm/redoc) [![Docker Build Status](https://img.shields.io/docker/build/redocly/redoc.svg)](https://hub.docker.com/r/redocly/redoc/) [![bundle size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js?compression=gzip&max=300000)](https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js) [![npm](https://img.shields.io/npm/dm/redoc.svg)](https://www.npmjs.com/package/redoc) [![](https://data.jsdelivr.com/v1/package/npm/redoc/badge)](https://www.jsdelivr.com/package/npm/redoc) [![Docker Build Status](https://img.shields.io/docker/build/redocly/redoc.svg)](https://hub.docker.com/r/redocly/redoc/)
</div> </div>
@ -183,6 +183,7 @@ IE support for Redoc.
For more information on Redoc's commmand-line interface, refer to For more information on Redoc's commmand-line interface, refer to
[**Using the Redoc CLI**](https://redoc.ly/docs/redoc/quickstart/cli/). [**Using the Redoc CLI**](https://redoc.ly/docs/redoc/quickstart/cli/).
## Configuration ## Configuration
### Security Definition location ### Security Definition location

125
cli/npm-shrinkwrap.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "redoc-cli", "name": "redoc-cli",
"version": "0.12.3", "version": "0.13.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "redoc-cli", "name": "redoc-cli",
"version": "0.12.3", "version": "0.13.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chokidar": "^3.5.1", "chokidar": "^3.5.1",
@ -17,7 +17,7 @@
"node-libs-browser": "^2.2.1", "node-libs-browser": "^2.2.1",
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"redoc": "2.0.0-rc.56", "redoc": "2.0.0-rc.57",
"styled-components": "^5.3.0", "styled-components": "^5.3.0",
"yargs": "^17.0.1" "yargs": "^17.0.1"
}, },
@ -198,13 +198,13 @@
"integrity": "sha512-GoXw0U2Qaa33m3eUcxuHnHpNvHjNlLo0gtV091XBpaRINaB4X6FGCG5XKxSFNFiPpugUDqNruHzaqpTdDm4AOg==" "integrity": "sha512-GoXw0U2Qaa33m3eUcxuHnHpNvHjNlLo0gtV091XBpaRINaB4X6FGCG5XKxSFNFiPpugUDqNruHzaqpTdDm4AOg=="
}, },
"node_modules/@redocly/ajv": { "node_modules/@redocly/ajv": {
"version": "6.12.4", "version": "8.6.2",
"resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-6.12.4.tgz", "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.6.2.tgz",
"integrity": "sha512-RB6vWO78v6c+SW/3bZh+XZMr4nGdJKAiPGsBALuUZnLuCiQ7aXCT1AuFHqnfS2gyXbEUEj+kw8p4ux8KdAfs3A==", "integrity": "sha512-tU8fQs0D76ZKhJ2cWtnfQthWqiZgGBx0gH0+5D8JvaBEBaqA8foPPBt3Nonwr3ygyv5xrw2IzKWgIY86BlGs+w==",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^1.0.0",
"json-schema-traverse": "^0.4.1", "require-from-string": "^2.0.2",
"uri-js": "^4.2.2" "uri-js": "^4.2.2"
}, },
"funding": { "funding": {
@ -213,11 +213,11 @@
} }
}, },
"node_modules/@redocly/openapi-core": { "node_modules/@redocly/openapi-core": {
"version": "1.0.0-beta.50", "version": "1.0.0-beta.62",
"resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.50.tgz", "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.62.tgz",
"integrity": "sha512-GuXn4IETxpbRd8dlAQDQPtvqOpbMvPMeC/e5mv5MOXkLIznNk4vjiQVe6QSCbZbCHzzpb2+89B6S7asebPm4Rg==", "integrity": "sha512-g4iPB7qpSNFCOpf/FgKiic+QCaCn4mdNQOWVEPuwpN7l72hlQ7J3YUa9cssJomkJXXxZ1zdP4h208s12LkhwVA==",
"dependencies": { "dependencies": {
"@redocly/ajv": "^6.12.3", "@redocly/ajv": "^8.6.2",
"@types/node": "^14.11.8", "@types/node": "^14.11.8",
"colorette": "^1.2.0", "colorette": "^1.2.0",
"js-levenshtein": "^1.1.6", "js-levenshtein": "^1.1.6",
@ -232,9 +232,9 @@
} }
}, },
"node_modules/@redocly/openapi-core/node_modules/@types/node": { "node_modules/@redocly/openapi-core/node_modules/@types/node": {
"version": "14.17.3", "version": "14.17.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.21.tgz",
"integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw==" "integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA=="
}, },
"node_modules/@redocly/react-dropdown-aria": { "node_modules/@redocly/react-dropdown-aria": {
"version": "2.0.12", "version": "2.0.12",
@ -283,7 +283,8 @@
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "15.12.2", "version": "15.12.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz",
"integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==" "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==",
"dev": true
}, },
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
@ -637,9 +638,9 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
}, },
"node_modules/colorette": { "node_modules/colorette": {
"version": "1.2.2", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
"integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="
}, },
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
@ -893,11 +894,6 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
}, },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/fast-safe-stringify": { "node_modules/fast-safe-stringify": {
"version": "2.0.7", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
@ -1175,9 +1171,9 @@
} }
}, },
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
}, },
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
@ -1751,14 +1747,13 @@
} }
}, },
"node_modules/redoc": { "node_modules/redoc": {
"version": "2.0.0-rc.56", "version": "2.0.0-rc.57",
"resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.56.tgz", "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.57.tgz",
"integrity": "sha512-ir2TtQ2d/1FqZWIoLmUZ3qvAAnO6jg8dt0SV75TanmfCXpEABcElXWH3mtUf6qKlvgDVt40diDCVuSvyPPxkAw==", "integrity": "sha512-f8XIqvZF1agphq6xmOU9jTDVNDFHJt3MzDq1lUgZojb/7YY4eqLyDi6er/yCWYkY9DuB+v2jHCOn5UUbMuKAfg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.14.0", "@babel/runtime": "^7.14.0",
"@redocly/openapi-core": "^1.0.0-beta.50", "@redocly/openapi-core": "^1.0.0-beta.54",
"@redocly/react-dropdown-aria": "^2.0.11", "@redocly/react-dropdown-aria": "^2.0.11",
"@types/node": "^15.6.1",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"decko": "^1.2.0", "decko": "^1.2.0",
"dompurify": "^2.2.8", "dompurify": "^2.2.8",
@ -1819,6 +1814,14 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ripemd160": { "node_modules/ripemd160": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
@ -2451,22 +2454,22 @@
"integrity": "sha512-GoXw0U2Qaa33m3eUcxuHnHpNvHjNlLo0gtV091XBpaRINaB4X6FGCG5XKxSFNFiPpugUDqNruHzaqpTdDm4AOg==" "integrity": "sha512-GoXw0U2Qaa33m3eUcxuHnHpNvHjNlLo0gtV091XBpaRINaB4X6FGCG5XKxSFNFiPpugUDqNruHzaqpTdDm4AOg=="
}, },
"@redocly/ajv": { "@redocly/ajv": {
"version": "6.12.4", "version": "8.6.2",
"resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-6.12.4.tgz", "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.6.2.tgz",
"integrity": "sha512-RB6vWO78v6c+SW/3bZh+XZMr4nGdJKAiPGsBALuUZnLuCiQ7aXCT1AuFHqnfS2gyXbEUEj+kw8p4ux8KdAfs3A==", "integrity": "sha512-tU8fQs0D76ZKhJ2cWtnfQthWqiZgGBx0gH0+5D8JvaBEBaqA8foPPBt3Nonwr3ygyv5xrw2IzKWgIY86BlGs+w==",
"requires": { "requires": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^1.0.0",
"json-schema-traverse": "^0.4.1", "require-from-string": "^2.0.2",
"uri-js": "^4.2.2" "uri-js": "^4.2.2"
} }
}, },
"@redocly/openapi-core": { "@redocly/openapi-core": {
"version": "1.0.0-beta.50", "version": "1.0.0-beta.62",
"resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.50.tgz", "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.62.tgz",
"integrity": "sha512-GuXn4IETxpbRd8dlAQDQPtvqOpbMvPMeC/e5mv5MOXkLIznNk4vjiQVe6QSCbZbCHzzpb2+89B6S7asebPm4Rg==", "integrity": "sha512-g4iPB7qpSNFCOpf/FgKiic+QCaCn4mdNQOWVEPuwpN7l72hlQ7J3YUa9cssJomkJXXxZ1zdP4h208s12LkhwVA==",
"requires": { "requires": {
"@redocly/ajv": "^6.12.3", "@redocly/ajv": "^8.6.2",
"@types/node": "^14.11.8", "@types/node": "^14.11.8",
"colorette": "^1.2.0", "colorette": "^1.2.0",
"js-levenshtein": "^1.1.6", "js-levenshtein": "^1.1.6",
@ -2478,9 +2481,9 @@
}, },
"dependencies": { "dependencies": {
"@types/node": { "@types/node": {
"version": "14.17.3", "version": "14.17.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.21.tgz",
"integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw==" "integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA=="
} }
} }
}, },
@ -2525,7 +2528,8 @@
"@types/node": { "@types/node": {
"version": "15.12.2", "version": "15.12.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz",
"integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==" "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==",
"dev": true
}, },
"ansi-regex": { "ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
@ -2841,9 +2845,9 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
}, },
"colorette": { "colorette": {
"version": "1.2.2", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
"integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
@ -3064,11 +3068,6 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
}, },
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-safe-stringify": { "fast-safe-stringify": {
"version": "2.0.7", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
@ -3273,9 +3272,9 @@
} }
}, },
"json-schema-traverse": { "json-schema-traverse": {
"version": "0.4.1", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
}, },
"lodash": { "lodash": {
"version": "4.17.21", "version": "4.17.21",
@ -3741,14 +3740,13 @@
} }
}, },
"redoc": { "redoc": {
"version": "2.0.0-rc.56", "version": "2.0.0-rc.57",
"resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.56.tgz", "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.57.tgz",
"integrity": "sha512-ir2TtQ2d/1FqZWIoLmUZ3qvAAnO6jg8dt0SV75TanmfCXpEABcElXWH3mtUf6qKlvgDVt40diDCVuSvyPPxkAw==", "integrity": "sha512-f8XIqvZF1agphq6xmOU9jTDVNDFHJt3MzDq1lUgZojb/7YY4eqLyDi6er/yCWYkY9DuB+v2jHCOn5UUbMuKAfg==",
"requires": { "requires": {
"@babel/runtime": "^7.14.0", "@babel/runtime": "^7.14.0",
"@redocly/openapi-core": "^1.0.0-beta.50", "@redocly/openapi-core": "^1.0.0-beta.54",
"@redocly/react-dropdown-aria": "^2.0.11", "@redocly/react-dropdown-aria": "^2.0.11",
"@types/node": "^15.6.1",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"decko": "^1.2.0", "decko": "^1.2.0",
"dompurify": "^2.2.8", "dompurify": "^2.2.8",
@ -3794,6 +3792,11 @@
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
}, },
"require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
},
"ripemd160": { "ripemd160": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "redoc-cli", "name": "redoc-cli",
"version": "0.12.3", "version": "0.13.0",
"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": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"redoc": "2.0.0-rc.56", "redoc": "2.0.0-rc.57",
"styled-components": "^5.3.0", "styled-components": "^5.3.0",
"yargs": "^17.0.1" "yargs": "^17.0.1"
}, },

View File

@ -1,26 +1,28 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>%PAGE_TITLE%</title>
<link rel="icon" href="%PAGE_FAVICON%" />
<style>
body {
margin: 0;
padding: 0;
}
<head> redoc {
<meta charset="UTF-8" /> display: block;
<title>%PAGE_TITLE%</title> }
<link rel="icon" href="%PAGE_FAVICON%"> </style>
<style> <link
body { href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
margin: 0; rel="stylesheet"
padding: 0; />
} </head>
redoc { <body>
display: block; <redoc spec-url="%SPEC_URL%" %REDOC_OPTIONS%></redoc>
} <script src="redoc.standalone.js"></script>
</style> </body>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet"> </html>
</head>
<body>
<redoc spec-url="%SPEC_URL%" %REDOC_OPTIONS%></redoc>
<script src="redoc.standalone.js"></script>
</body>
</html>

114
docs/deployment/cli.md Normal file
View File

@ -0,0 +1,114 @@
---
title: Using the Redoc CLI
redirectFrom:
- /docs/quickstart/cli/
---
# Using the Redoc CLI
With Redoc's command-line interface you can bundle your OpenAPI definition and API documentation
(made with Redoc) into a zero-dependency HTML file and locally render your
OpenAPI definition with Redoc.
## Step 1 - Install Redoc CLI
You can install the `redoc-cli` package globally using one of the following package managers:
- [npm](https://docs.npmjs.com/about-npm)
- [yarn](https://classic.yarnpkg.com/en/docs/getting-started)
Or you can install `redoc-cli` using [npx](https://www.freecodecamp.org/news/npm-vs-npx-whats-the-difference/).
### Install Redoc CLI with yarn
To install the `redoc-cli` package globally with yarn:
```bash
yarn global add redoc-cli
```
### Install Redoc with npm
To install the `redoc-cli` package globally with npm:
```bash
npm i -g redoc-cli
```
### Install with `npx`
To install the `redoc-cli` package locally with `npx`, navigate to your project
directory in your terminal, then use the following command:
```bash
npx redoc-cli
```
## Step 2 - Use the CLI
### Redoc CLI commands
The CLI includes the following commands:
- **`redoc-cli serve [spec]`:** Starts a local server with Redoc. You must include the required parameter, spec, which is
a reference to an OpenAPI definition. Options include:
- `--ssr`: Implements a server-side rendering model.
- `--watch`: Automatically reloads the server while you edit your OpenAPI definition.
- `--options`: Customizes your output using [Redoc options](https://redoc.ly/docs/api-reference-docs/configuration/).
To add nested options, use dot notation.
- **`redoc-cli bundle [spec]`:** Bundles `spec` and Redoc into a zero-dependency HTML file. Options include:
- `-t` or `--template`: Uses custom [Handlebars](https://handlebarsjs.com/) templates to render your OpenAPI definition.
- `--templateOptions`: Adds template options you want to pass to your
custom Handlebars template. To add options, use dot notation.
- **`--help`:** Prints help text for the Redoc CLI commands and options.
- **`--version`:** Prints the version of the `redoc-cli` package you have installed.
### Redoc CLI examples
#### Bundle
Bundle with the main color changed to `orange`:
```bash
redoc-cli bundle openapi.yaml --options.theme.colors.primary.main=orange
```
Bundle using a custom Handlebars template and add custom `templateOptions`:
```bash
redoc-cli bundle http://petstore.swagger.io/v2/swagger.json -t custom.hbs --templateOptions.metaDescription "Page meta description"
```
Sample Handlebars template:
```handlebars
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8" />
<title>{{title}}</title>
<!-- needed for adaptive design -->
<meta description="{{{templateOptions.metaDescription}}}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
padding: 0;
margin: 0;
}
</style>
{{{redocHead}}}
{{#unless disableGoogleFont}}<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">{{/unless}}
</head>
<body>
{{{redocHTML}}}
</body>
</html>
```
#### Serve
Serve with the `nativeScrollbars` option set to `true`:
```bash
redoc-cli serve openapi/dist.yaml --options.nativeScrollbars
```

41
docs/deployment/docker.md Normal file
View File

@ -0,0 +1,41 @@
---
title: Using the Redoc Docker image
redirectFrom:
- /docs/quickstart/docker/
---
# Using the Redoc Docker image
Redoc is available as a pre-built Docker image in [Docker Hub](https://hub.docker.com/r/redocly/redoc/).
If you have [Docker](https://docs.docker.com/get-docker/) installed, pull the image with the following command:
```docker
docker pull redocly/redoc
```
Then run the image with the following command:
```docker
docker run -p 8080:80 redocly/redoc
```
The preview starts on port 8080, based on the port used in the command,
and can be accessed at `http://localhost:8080`.
To exit the preview, use `control+C`.
By default Redoc starts with a demo Swagger Petstore OpenAPI definition located at
http://petstore.swagger.io/v2/swagger.json. You can update this URL using
the environment variable `SPEC_URL`.
For example:
```bash
docker run -p 8080:80 -e SPEC_URL=https://api.example.com/openapi.json redocly/redoc
```
## Using a Dockerfile
You can also create a Dockerfile with some predefined environment variables. Check out
a sample [Dockerfile](https://github.com/Redocly/redoc/blob/master/config/docker/Dockerfile)
in our code repo.

123
docs/deployment/html.md Normal file
View File

@ -0,0 +1,123 @@
---
title: Using the Redoc HTML element
redirectFrom:
- /docs/quickstart/html/
---
# Using the Redoc HTML element
## Step 1 - Install Redoc
You can install Redoc using one of the following package managers:
- [npm](https://docs.npmjs.com/about-npm)
- [yarn](https://classic.yarnpkg.com/en/docs/getting-started)
:::attention Initialize your package manager
If you do not have a `package.json` file in your project directory,
you need to add one by initializing npm or yarn in your project. Use the command `npm init` for npm,
or `yarn init` for yarn. These initialization commands will lead you through the process
of creating a `package.json` file in your project.
For more information, see
[Creating a package.json file](https://docs.npmjs.com/creating-a-package-json-file)
in the npm documentation or [Yarn init](https://classic.yarnpkg.com/en/docs/cli/init/)
in the yarn documentation.
:::
### Install Redoc with yarn
After navigating to your project directory in your terminal, use the following command:
```bash
yarn add redoc
```
### Install Redoc with npm
After navigating to your project directory in your terminal, use the following command:
```bash
npm i redoc
```
## Step 2 - Reference the Redoc script
You can reference the Redoc script using either a link to the files hosted on a CDN
or the files located in your `node modules` folder.
### CDN link
To reference the Redoc script with a CDN link:
```html
<script src="https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js"> </script>
```
### Node modules link
To reference the Redoc script with a node modules link:
```html
<script src="node_modules/redoc/bundles/redoc.standalone.js"> </script>
```
## Step 3 - Add the <redoc> element
You can add the <redoc> element to your HTML page and reference your OpenAPI
definition using the `spec-url` attribute, or you can initialize Redoc using
a globally exposed Redoc object.
### Using the `spec-url` attribute
To add the <redoc> element with the `spec-url` attribute:
```html
<redoc spec-url="url/to/your/spec"></redoc>
```
#### Examples
```html
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
```
You can also use a local file (JSON or YAML) in your project, for instance:
```html
<redoc spec-url="dist.json"></redoc>
```
### Using a Redoc object
To add the <redoc> element with a globally exposed Redoc object:
```js
Redoc.init(specOrSpecUrl, options, element, callback)
```
- `specOrSpecUrl`: Either a JSON object with the OpenAPI definition or a URL to the
definition in JSON or YAML format.
- `options`: See [options object](https://redoc.ly/docs/api-reference-docs/configuration/) reference.
- `element`: DOM element Redoc will be inserted into.
- `callback`(optional): Callback to be called after Redoc has been fully rendered.
It is also called on errors with `error` as the first argument.
#### Examples
```html
<script>
Redoc.init('http://petstore.swagger.io/v2/swagger.json', {
scrollYOffset: 50
}, document.getElementById('redoc-container'))
</script>
```
You can also use a local file (JSON or YAML) in your project, for instance:
```html
<script>
Redoc.init('dist.yaml', {
scrollYOffset: 50
}, document.getElementById('redoc-container'))
</script>
```

112
docs/deployment/intro.md Normal file
View File

@ -0,0 +1,112 @@
---
title: Redoc deployment guide
redirectFrom:
- /docs/quickstart/intro/
---
# Redoc deployment guide
Redoc offers multiple options for rendering your OpenAPI definition.
You should select the option that best fits your needs.
The following options are supported:
- **[Live demo](https://redocly.github.io/redoc/):**
The live demo offers a fast way to see how your OpenAPI will render with Redoc.
A version of the Swagger Petstore API is displayed by default. To test it with your own OpenAPI definition, enter the URL for your
definition and select **TRY IT**.
- **[HTML element](./html.md):**
Using the HTML element works well for typical website deployments.
- **[React component](./react.md):**
Using the React component is an option for users with a React-based application.
- **[Docker image](./docker.md):**
Using the Docker image works in a container-based deployment.
- **[CLI](./cli.md):**
Using the CLI is an option for users who prefer to use a command-line interface.
## Before you start
### OpenAPI definition
You will need an OpenAPI definition. For testing purposes, you can use one of the following sample OpenAPI definitions:
- OpenAPI 3.0
- [Rebilly Users OpenAPI Definition](https://raw.githubusercontent.com/Rebilly/api-definitions/main/openapi/users.yaml)
- [Swagger Petstore Sample OpenAPI Definition](https://petstore3.swagger.io/api/v3/openapi.json)
- OpenAPI 2.0
- [Thingful OpenAPI Definition](https://raw.githubusercontent.com/thingful/openapi-spec/master/spec/swagger.yaml)
- [Fitbit Plus OpenAPI Definition](https://raw.githubusercontent.com/TwineHealth/TwineDeveloperDocs/master/spec/swagger.yaml)
:::info OpenAPI specification
For more information on the OpenAPI specification, refer to the [Learning OpenAPI 3](https://redoc.ly/docs/resources/learning-openapi/)
section in the documentation.
:::
### Running Redoc locally
If you want to view your Redoc output locally, you can simulate an HTTP server.
#### Using Redocly OpenAPI CLI
Redocly OpenAPI CLI is an open source command-line tool that includes a command
for simulating an HTTP server to provide a preview of your OpenAPI definition locally.
If you have [OpenAPI CLI](https://redoc.ly/docs/cli/#installation-and-usage) installed, `cd` into your
project directory and run the following command:
```bash
openapi preview-docs openapi.yaml
```
Replace `openapi.yaml` in the example command with the file path to your OpenAPI definition.
By default, without providing a port, the preview starts on port 8080, and can be accessed at `http://localhost:8080`.
To exit the preview, use `control+C`.
You can alter the port if you are using 8080 already, for example:
```bash
openapi preview-docs -p 8888 openapi.yaml
```
Replace `openapi.yaml` in the example command with the file path to your OpenAPI definition.
For more information about the `preview-docs` command, refer to
[OpenAPI CLI commands](https://redoc.ly/docs/cli/commands/preview-docs/#preview-docs) in the OpenAPI CLI documentation.
#### Using Python
If you have [Python 3](https://www.python.org/downloads/) installed, `cd` into your
project directory and run the following command:
```python
python3 -m http.server
```
If you have [Python 2](https://www.python.org/downloads/) installed, `cd` into your
project directory and run the following command:
```python
python -m SimpleHTTPServer 8000
```
The output after entering the command provides the local URL where the preview can be accessed.
To exit the preview, use `control-C`.
#### Using Node.js
If you have [Node.js](https://nodejs.org/en/download/) installed, install `http-server`
using the following npm command:
```bash
npm install -g http-server
```
Then, `cd` into your project directory and run the following command:
```node
http-server
```
The output after entering the command provides the local URL where the preview can be accessed.
To exit the preview, use `control-C`.

80
docs/deployment/react.md Normal file
View File

@ -0,0 +1,80 @@
---
title: Using the Redoc React component
redirectFrom:
- /docs/quickstart/react/
---
# Using the Redoc React component
## Before you start
Install the following dependencies required by Redoc if you do not already have them installed:
- `react`
- `react-dom`
- `mobx`
- `styled-components`
- `core-js`
If you have npm installed, you can install these dependencies using the following command:
```js
npm i react react-dom mobx styled-components core-js
```
## Step 1 - Import the `RedocStandalone` component
```js
import { RedocStandalone } from 'redoc';
```
## Step 2 - Use the component
You can either link to your OpenAPI definition with a URL, using the following format:
```react
<RedocStandalone specUrl="url/to/your/spec"/>
```
Or you can pass your OpenAPI definition as an object, using the following format:
```js
<RedocStandalone spec={/* spec as an object */}/>
```
## Optional - Pass options
Options can be passed into the RedocStandalone component to alter how it renders.
For example:
```js
<RedocStandalone
specUrl="http://petstore.swagger.io/v2/swagger.json"
options={{
nativeScrollbars: true,
theme: { colors: { primary: { main: '#dd5522' } } },
}}
/>
```
For more information on configuration options, refer to the
[Configuration options for Reference docs](https://redoc.ly/docs/api-reference-docs/configuration/)
section of the documentation. Options available for Redoc are noted,
"Supported in Redoc CE".
## Optional - Specify `onLoaded` callback
You can also specify the `onLoaded` callback, which is called each time Redoc
is fully rendered or when an error occurs (with an error as the first argument).
```js
<RedocStandalone
specUrl="http://petstore.swagger.io/v2/swagger.json"
onLoaded={error => {
if (!error) {
console.log('Yay!');
}
}}
/>
```

53
docs/quickstart.md Normal file
View File

@ -0,0 +1,53 @@
---
title: Redoc quickstart guide
---
# Redoc quickstart guide
To render your OpenAPI definition using Redoc, use the following HTML code sample and
replace the `spec-url` attribute with the URL or local file address to your definition.
```html
<!DOCTYPE html>
<html>
<head>
<title>Redoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
<!--
Redoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<!--
Redoc element with link to your OpenAPI definition
-->
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
<!--
Link to Redoc JavaScript on CDN for rendering standalone element
-->
<script src="https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js"></script>
</body>
</html>
```
:::attention Running Redoc locally requires an HTTP server
Loading local OpenAPI definitions is impossible without running a web server because of issues with
[same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) and
other security reasons. Refer to [Running Redoc locally](./deployment/intro.md#running-redoc-locally) for
more information.
:::
For a more detailed explanation with step-by-step instructions and additional options for using Redoc, refer to the [Redoc deployment guide](./deployment/intro.md).

View File

@ -1,13 +0,0 @@
redoc:
- group: Quickstart
expanded: false
page: redoc/quickstart/intro.md
pages:
- label: HTML element
page: redoc/quickstart/html.md
- label: React component
page: redoc/quickstart/react.md
- label: Docker image
page: redoc/quickstart/docker.md
- label: Command-line interface
page: redoc/quickstart/cli.md

392
package-lock.json generated
View File

@ -1,11 +1,12 @@
{ {
"name": "redoc", "name": "redoc",
"version": "2.0.0-rc.57", "version": "2.0.0-rc.58",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "2.0.0-rc.57", "name": "redoc",
"version": "2.0.0-rc.58",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.14.0", "@babel/runtime": "^7.14.0",
@ -89,12 +90,14 @@
"eslint-plugin-react": "^7.24.0", "eslint-plugin-react": "^7.24.0",
"fork-ts-checker-webpack-plugin": "^6.2.10", "fork-ts-checker-webpack-plugin": "^6.2.10",
"html-webpack-plugin": "^5.3.1", "html-webpack-plugin": "^5.3.1",
"husky": "^7.0.0",
"jest": "^27.0.3", "jest": "^27.0.3",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"license-checker": "^25.0.1", "license-checker": "^25.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mobx": "^6.3.2", "mobx": "^6.3.2",
"prettier": "^2.3.0", "prettier": "^2.3.2",
"pretty-quick": "^3.0.0",
"raf": "^3.4.1", "raf": "^3.4.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
@ -3888,6 +3891,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/array-differ": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
"integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/array-find-index": { "node_modules/array-find-index": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@ -10204,6 +10216,21 @@
"node": ">=8.12.0" "node": ">=8.12.0"
} }
}, },
"node_modules/husky": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
"integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
"dev": true,
"bin": {
"husky": "lib/bin.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -14466,6 +14493,15 @@
"integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==", "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==",
"dev": true "dev": true
}, },
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -14490,6 +14526,31 @@
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
"dev": true "dev": true
}, },
"node_modules/multimatch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz",
"integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==",
"dev": true,
"dependencies": {
"@types/minimatch": "^3.0.3",
"array-differ": "^3.0.0",
"array-union": "^2.1.0",
"arrify": "^2.0.1",
"minimatch": "^3.0.4"
},
"engines": {
"node": ">=8"
}
},
"node_modules/multimatch/node_modules/arrify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/nan": { "node_modules/nan": {
"version": "2.14.2", "version": "2.14.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
@ -15782,9 +15843,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "2.3.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
"integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin-prettier.js" "prettier": "bin-prettier.js"
@ -15925,6 +15986,166 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/pretty-quick": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.2.tgz",
"integrity": "sha512-T+fpTJrDjTzewql4p3lKrRA7z3MrNyjBK1MKeaBm5PpKwATgVm885TpY7TgY8KFt5Q1Qn3QDseRQcyX9AKTKkA==",
"dev": true,
"dependencies": {
"chalk": "^3.0.0",
"execa": "^4.0.0",
"find-up": "^4.1.0",
"ignore": "^5.1.4",
"mri": "^1.1.5",
"multimatch": "^4.0.0"
},
"bin": {
"pretty-quick": "bin/pretty-quick.js"
},
"engines": {
"node": ">=10.13"
},
"peerDependencies": {
"prettier": ">=2.0.0"
}
},
"node_modules/pretty-quick/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/pretty-quick/node_modules/chalk": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/pretty-quick/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/pretty-quick/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/pretty-quick/node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/pretty-quick/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/pretty-quick/node_modules/ignore": {
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
"integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==",
"dev": true,
"engines": {
"node": ">= 4"
}
},
"node_modules/pretty-quick/node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"dependencies": {
"p-locate": "^4.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/pretty-quick/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/pretty-quick/node_modules/p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"dependencies": {
"p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/pretty-quick/node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/pretty-quick/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/prettycli": { "node_modules/prettycli": {
"version": "1.4.3", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/prettycli/-/prettycli-1.4.3.tgz", "resolved": "https://registry.npmjs.org/prettycli/-/prettycli-1.4.3.tgz",
@ -23993,6 +24214,12 @@
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
"dev": true "dev": true
}, },
"array-differ": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
"integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
"dev": true
},
"array-find-index": { "array-find-index": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@ -28930,6 +29157,12 @@
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
"dev": true "dev": true
}, },
"husky": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
"integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
"dev": true
},
"iconv-lite": { "iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -32084,6 +32317,12 @@
"integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==", "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==",
"dev": true "dev": true
}, },
"mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"dev": true
},
"ms": { "ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -32105,6 +32344,27 @@
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
"dev": true "dev": true
}, },
"multimatch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz",
"integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==",
"dev": true,
"requires": {
"@types/minimatch": "^3.0.3",
"array-differ": "^3.0.0",
"array-union": "^2.1.0",
"arrify": "^2.0.1",
"minimatch": "^3.0.4"
},
"dependencies": {
"arrify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
"dev": true
}
}
},
"nan": { "nan": {
"version": "2.14.2", "version": "2.14.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
@ -33103,9 +33363,9 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "2.3.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
"integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
"dev": true "dev": true
}, },
"pretty-bytes": { "pretty-bytes": {
@ -33209,6 +33469,120 @@
} }
} }
}, },
"pretty-quick": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.2.tgz",
"integrity": "sha512-T+fpTJrDjTzewql4p3lKrRA7z3MrNyjBK1MKeaBm5PpKwATgVm885TpY7TgY8KFt5Q1Qn3QDseRQcyX9AKTKkA==",
"dev": true,
"requires": {
"chalk": "^3.0.0",
"execa": "^4.0.0",
"find-up": "^4.1.0",
"ignore": "^5.1.4",
"mri": "^1.1.5",
"multimatch": "^4.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"ignore": {
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
"integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==",
"dev": true
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"prettycli": { "prettycli": {
"version": "1.4.3", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/prettycli/-/prettycli-1.4.3.tgz", "resolved": "https://registry.npmjs.org/prettycli/-/prettycli-1.4.3.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "redoc", "name": "redoc",
"version": "2.0.0-rc.57", "version": "2.0.0-rc.58",
"description": "ReDoc", "description": "ReDoc",
"repository": { "repository": {
"type": "git", "type": "git",
@ -27,6 +27,7 @@
"React.js" "React.js"
], ],
"main": "bundles/redoc.lib.js", "main": "bundles/redoc.lib.js",
"browser": "bundles/redoc.browser.lib.js",
"types": "typings/index.d.ts", "types": "typings/index.d.ts",
"scripts": { "scripts": {
"start": "webpack serve --mode=development --env playground --hot --config demo/webpack.config.ts", "start": "webpack serve --mode=development --env playground --hot --config demo/webpack.config.ts",
@ -42,7 +43,8 @@
"bundle:clean": "rimraf bundles", "bundle:clean": "rimraf bundles",
"bundle:standalone": "webpack --env production --env standalone --mode=production", "bundle:standalone": "webpack --env production --env standalone --mode=production",
"bundle:lib": "webpack --mode=production && npm run declarations", "bundle:lib": "webpack --mode=production && npm run declarations",
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:standalone", "bundle:browser": "webpack --env production --env browser --mode=production",
"bundle": "npm run bundle:clean && npm run bundle:lib && npm run bundle:browser && npm run bundle:standalone",
"declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/", "declarations": "tsc --emitDeclarationOnly -p tsconfig.lib.json && cp -R src/types typings/",
"stats": "webpack --env production --env standalone --json --profile --mode=production > stats.json", "stats": "webpack --env production --env standalone --json --profile --mode=production > stats.json",
"prettier": "prettier --write \"cli/index.ts\" \"src/**/*.{ts,tsx}\"", "prettier": "prettier --write \"cli/index.ts\" \"src/**/*.{ts,tsx}\"",
@ -54,7 +56,9 @@
"build:demo": "webpack --mode=production --config demo/webpack.config.ts", "build:demo": "webpack --mode=production --config demo/webpack.config.ts",
"deploy:demo": "aws s3 sync demo/dist s3://production-redoc-demo --acl=public-read", "deploy:demo": "aws s3 sync demo/dist s3://production-redoc-demo --acl=public-read",
"license-check": "license-checker --production --onlyAllow 'MIT;ISC;Apache-2.0;BSD;BSD-2-Clause;BSD-3-Clause' --summary", "license-check": "license-checker --production --onlyAllow 'MIT;ISC;Apache-2.0;BSD;BSD-2-Clause;BSD-3-Clause' --summary",
"docker:build": "docker build -f config/docker/Dockerfile -t redoc ." "docker:build": "docker build -f config/docker/Dockerfile -t redoc .",
"prepare": "husky install",
"pre-commit": "pretty-quick --staged && npm run lint"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.3", "@babel/core": "^7.14.3",
@ -112,12 +116,14 @@
"eslint-plugin-react": "^7.24.0", "eslint-plugin-react": "^7.24.0",
"fork-ts-checker-webpack-plugin": "^6.2.10", "fork-ts-checker-webpack-plugin": "^6.2.10",
"html-webpack-plugin": "^5.3.1", "html-webpack-plugin": "^5.3.1",
"husky": "^7.0.0",
"jest": "^27.0.3", "jest": "^27.0.3",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"license-checker": "^25.0.1", "license-checker": "^25.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mobx": "^6.3.2", "mobx": "^6.3.2",
"prettier": "^2.3.0", "prettier": "^2.3.2",
"pretty-quick": "^3.0.0",
"raf": "^3.4.1", "raf": "^3.4.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
@ -207,6 +213,6 @@
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all",
"printWidth": 100, "printWidth": 100,
"parser": "typescript" "arrowParens": "avoid"
} }
} }

View File

@ -28,16 +28,16 @@ export const StyledDropdown = styled(Dropdown)`
width: auto; width: auto;
background: white; background: white;
color: #263238; color: #263238;
font-family: ${(props) => props.theme.typography.headings.fontFamily}; font-family: ${props => props.theme.typography.headings.fontFamily};
font-size: 0.929em; font-size: 0.929em;
line-height: 1.5em; line-height: 1.5em;
cursor: pointer; cursor: pointer;
transition: border 0.25s ease, color 0.25s ease, box-shadow 0.25s ease; transition: border 0.25s ease, color 0.25s ease, box-shadow 0.25s ease;
&:hover, &:hover,
&:focus-within { &:focus-within {
border: 1px solid ${(props) => props.theme.colors.primary.main}; border: 1px solid ${props => props.theme.colors.primary.main};
color: ${(props) => props.theme.colors.primary.main}; color: ${props => props.theme.colors.primary.main};
box-shadow: 0px 0px 0px 1px ${(props) => props.theme.colors.primary.main}; box-shadow: 0px 0px 0px 1px ${props => props.theme.colors.primary.main};
} }
.dropdown-selector { .dropdown-selector {
display: inline-flex; display: inline-flex;
@ -48,7 +48,7 @@ export const StyledDropdown = styled(Dropdown)`
margin-bottom: 5px; margin-bottom: 5px;
} }
.dropdown-selector-value { .dropdown-selector-value {
font-family: ${(props) => props.theme.typography.headings.fontFamily}; font-family: ${props => props.theme.typography.headings.fontFamily};
position: relative; position: relative;
font-size: 0.929em; font-size: 0.929em;
width: 100%; width: 100%;
@ -63,7 +63,7 @@ export const StyledDropdown = styled(Dropdown)`
right: 3px; right: 3px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
border-color: ${(props) => props.theme.colors.primary.main} transparent transparent; border-color: ${props => props.theme.colors.primary.main} transparent transparent;
border-style: solid; border-style: solid;
border-width: 0.35em 0.35em 0; border-width: 0.35em 0.35em 0;
width: 0; width: 0;
@ -128,8 +128,8 @@ export const SimpleDropdown = styled(StyledDropdown)`
border: none; border: none;
box-shadow: none; box-shadow: none;
.dropdown-selector-value { .dropdown-selector-value {
color: ${(props) => props.theme.colors.primary.main}; color: ${props => props.theme.colors.primary.main};
text-shadow: 0px 0px 0px ${(props) => props.theme.colors.primary.main}; text-shadow: 0px 0px 0px ${props => props.theme.colors.primary.main};
} }
} }
} }

View File

@ -66,7 +66,7 @@ export const PropertyNameCell = styled(PropertyCell)`
line-height: 20px; line-height: 20px;
white-space: nowrap; white-space: nowrap;
font-size: 13px; font-size: 13px;
font-family: ${(props) => props.theme.typography.code.fontFamily}; font-family: ${props => props.theme.typography.code.fontFamily};
&.deprecated { &.deprecated {
${deprecatedCss}; ${deprecatedCss};
@ -80,7 +80,7 @@ export const PropertyNameCell = styled(PropertyCell)`
export const PropertyDetailsCell = styled.td` export const PropertyDetailsCell = styled.td`
border-bottom: 1px solid #9fb4be; border-bottom: 1px solid #9fb4be;
padding: 10px 0; padding: 10px 0;
width: ${(props) => props.theme.schema.defaultDetailsWidth}; width: ${props => props.theme.schema.defaultDetailsWidth};
box-sizing: border-box; box-sizing: border-box;
tr.expanded & { tr.expanded & {
@ -90,7 +90,7 @@ export const PropertyDetailsCell = styled.td`
${media.lessThan('small')` ${media.lessThan('small')`
padding: 0 20px; padding: 0 20px;
border-bottom: none; border-bottom: none;
border-left: 1px solid ${(props) => props.theme.schema.linesColor}; border-left: 1px solid ${props => props.theme.schema.linesColor};
tr.last > & { tr.last > & {
border-left: none; border-left: none;

View File

@ -6,7 +6,7 @@ import styled, { css } from '../styled-components';
import { HistoryService } from '../services'; import { HistoryService } from '../services';
// tslint:disable-next-line // tslint:disable-next-line
export const linkifyMixin = (className) => css` export const linkifyMixin = className => css`
${className} { ${className} {
cursor: pointer; cursor: pointer;
margin-left: -20px; margin-left: -20px;
@ -33,13 +33,13 @@ export const linkifyMixin = (className) => css`
} }
`; `;
const isModifiedEvent = (event) => const isModifiedEvent = event =>
!!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
export function Link(props: { to: string; className?: string; children?: any }) { export function Link(props: { to: string; className?: string; children?: any }) {
const store = React.useContext(StoreContext); const store = React.useContext(StoreContext);
const clickHandler = React.useCallback( const clickHandler = React.useCallback(
(event: React.MouseEvent<HTMLAnchorElement>) => { (event: React.MouseEvent<HTMLAnchorElement>) => {
if (!store) return; if (!store) return;
navigate(store.menu.history, event, props.to); navigate(store.menu.history, event, props.to);
}, },

View File

@ -12,7 +12,7 @@ import styled, { createGlobalStyle } from '../styled-components';
* That's why the following ugly fix is required * That's why the following ugly fix is required
*/ */
const PerfectScrollbarConstructor = const PerfectScrollbarConstructor =
PerfectScrollbarNamespace.default || ((PerfectScrollbarNamespace as any) as PerfectScrollbarType); PerfectScrollbarNamespace.default || (PerfectScrollbarNamespace as any as PerfectScrollbarType);
const PSStyling = createGlobalStyle`${psStyles && psStyles.toString()}`; const PSStyling = createGlobalStyle`${psStyles && psStyles.toString()}`;

View File

@ -39,7 +39,12 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
const license = const license =
(info.license && ( (info.license && (
<InfoSpan> <InfoSpan>
License: {info.license.identifier ? info.license.identifier : (<a href={info.license.url}>{info.license.name}</a>)} License:{' '}
{info.license.identifier ? (
info.license.identifier
) : (
<a href={info.license.url}>{info.license.name}</a>
)}
</InfoSpan> </InfoSpan>
)) || )) ||
null; null;
@ -101,8 +106,8 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
)) || )) ||
null} null}
</StyledMarkdownBlock> </StyledMarkdownBlock>
<Markdown source={store.spec.info.summary} data-role="redoc-summary"/> <Markdown source={store.spec.info.summary} data-role="redoc-summary" />
<Markdown source={store.spec.info.description} data-role="redoc-description"/> <Markdown source={store.spec.info.description} data-role="redoc-description" />
{externalDocs && <ExternalDocumentation externalDocs={externalDocs} />} {externalDocs && <ExternalDocumentation externalDocs={externalDocs} />}
</MiddlePanel> </MiddlePanel>
</Row> </Row>

View File

@ -48,10 +48,10 @@ const CallbackTitleWrapper = styled.button`
`; `;
const CallbackName = styled.span<{ deprecated?: boolean }>` const CallbackName = styled.span<{ deprecated?: boolean }>`
text-decoration: ${(props) => (props.deprecated ? 'line-through' : 'none')}; text-decoration: ${props => (props.deprecated ? 'line-through' : 'none')};
margin-right: 8px; margin-right: 8px;
`; `;
const OperationBadgeStyled = styled(OperationBadge)` const OperationBadgeStyled = styled(OperationBadge)`
margin: 0px 5px 0px 0px; margin: 0 5px 0 0;
`; `;

View File

@ -35,7 +35,7 @@ export const EndpointInfo = styled.button<{ expanded?: boolean; inverted?: boole
(props.expanded && !props.inverted && `border-color: ${props.theme.colors.border.dark};`) || ''} (props.expanded && !props.inverted && `border-color: ${props.theme.colors.border.dark};`) || ''}
.${ServerRelativeURL} { .${ServerRelativeURL} {
color: ${props => (props.inverted ? props.theme.colors.text.primary : '#ffffff')} color: ${props => (props.inverted ? props.theme.colors.text.primary : '#ffffff')};
} }
&:focus { &:focus {
box-shadow: inset 0 2px 2px rgba(0, 0, 0, 0.45), 0 2px 0 rgba(128, 128, 128, 0.25); box-shadow: inset 0 2px 2px rgba(0, 0, 0, 0.45), 0 2px 0 rgba(128, 128, 128, 0.25);

View File

@ -59,7 +59,7 @@ export class EnumValues extends React.PureComponent<EnumValuesProps, EnumValuesS
{values.length === 1 ? l('enumSingleValue') : l('enum')}: {values.length === 1 ? l('enumSingleValue') : l('enum')}:
</FieldLabel>{' '} </FieldLabel>{' '}
{displayedItems.map((value, idx) => { {displayedItems.map((value, idx) => {
const exampleValue = enumSkipQuotes ? value : JSON.stringify(value); const exampleValue = enumSkipQuotes ? String(value) : JSON.stringify(value);
return ( return (
<React.Fragment key={idx}> <React.Fragment key={idx}>
<ExampleValue>{exampleValue}</ExampleValue>{' '} <ExampleValue>{exampleValue}</ExampleValue>{' '}

View File

@ -13,7 +13,7 @@ export class FieldDetail extends React.PureComponent<FieldDetailProps> {
return null; return null;
} }
const value = this.props.raw ? this.props.value : JSON.stringify(this.props.value); const value = this.props.raw ? String(this.props.value) : JSON.stringify(this.props.value);
return ( return (
<div> <div>

View File

@ -59,7 +59,9 @@ export class FieldDetails extends React.PureComponent<FieldProps, { patternShown
} else { } else {
const label = l('example') + ':'; const label = l('example') + ':';
const raw = !!field.in; const raw = !!field.in;
renderedExamples = <FieldDetail label={label} value={getSerializedValue(field, field.example)} raw={raw} />; renderedExamples = (
<FieldDetail label={label} value={getSerializedValue(field, field.example)} raw={raw} />
);
} }
} }
@ -78,14 +80,16 @@ export class FieldDetails extends React.PureComponent<FieldProps, { patternShown
)} )}
{schema.contentEncoding && ( {schema.contentEncoding && (
<TypeFormat> <TypeFormat>
{' '}&lt; {' '}
&lt;
{schema.contentEncoding} {schema.contentEncoding}
&gt;{' '} &gt;{' '}
</TypeFormat> </TypeFormat>
)} )}
{schema.contentMediaType && ( {schema.contentMediaType && (
<TypeFormat> <TypeFormat>
{' '}&lt; {' '}
&lt;
{schema.contentMediaType} {schema.contentMediaType}
&gt;{' '} &gt;{' '}
</TypeFormat> </TypeFormat>
@ -124,7 +128,7 @@ export class FieldDetails extends React.PureComponent<FieldProps, { patternShown
<ExternalDocumentation externalDocs={schema.externalDocs} compact={true} /> <ExternalDocumentation externalDocs={schema.externalDocs} compact={true} />
)} )}
{(renderDiscriminatorSwitch && renderDiscriminatorSwitch(this.props)) || null} {(renderDiscriminatorSwitch && renderDiscriminatorSwitch(this.props)) || null}
{field.const && (<FieldDetail label={l('const') + ':'} value={field.const} />) || null} {(field.const && <FieldDetail label={l('const') + ':'} value={field.const} />) || null}
</div> </div>
); );
} }
@ -142,7 +146,8 @@ function Examples({ field }: { field: FieldModel }) {
{Object.values(field.examples).map((example, idx) => { {Object.values(field.examples).map((example, idx) => {
return ( return (
<li key={idx}> <li key={idx}>
<ExampleValue>{getSerializedValue(field, example.value)}</ExampleValue> - {example.summary || example.description} <ExampleValue>{getSerializedValue(field, example.value)}</ExampleValue> -{' '}
{example.summary || example.description}
</li> </li>
); );
})} })}
@ -160,7 +165,6 @@ function getSerializedValue(field: FieldModel, example: any) {
} }
} }
const ExamplesList = styled.ul` const ExamplesList = styled.ul`
margin-top: 1em; margin-top: 1em;
padding-left: 0; padding-left: 0;

View File

@ -34,11 +34,11 @@ class Json extends React.PureComponent<JsonProps> {
<button onClick={this.collapseAll}> Collapse all </button> <button onClick={this.collapseAll}> Collapse all </button>
</SampleControls> </SampleControls>
<OptionsContext.Consumer> <OptionsContext.Consumer>
{(options) => ( {options => (
<PrismDiv <PrismDiv
className={this.props.className} className={this.props.className}
// tslint:disable-next-line // tslint:disable-next-line
ref={(node) => (this.node = node!)} ref={node => (this.node = node!)}
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: jsonToHTML(this.props.data, options.jsonSampleExpandLevel), __html: jsonToHTML(this.props.data, options.jsonSampleExpandLevel),
}} }}

View File

@ -6,8 +6,8 @@ export const jsonStyles = css`
pointer-events: none; pointer-events: none;
} }
font-family: ${(props) => props.theme.typography.code.fontFamily}; font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${(props) => props.theme.typography.code.fontSize}; font-size: ${props => props.theme.typography.code.fontSize};
white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')}; white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
contain: content; contain: content;
@ -51,8 +51,8 @@ export const jsonStyles = css`
background-color: transparent; background-color: transparent;
border: 0; border: 0;
color: #fff; color: #fff;
font-family: ${(props) => props.theme.typography.code.fontFamily}; font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${(props) => props.theme.typography.code.fontSize}; font-size: ${props => props.theme.typography.code.fontSize};
padding-right: 6px; padding-right: 6px;
padding-left: 6px; padding-left: 6px;
padding-top: 0; padding-top: 0;

View File

@ -26,7 +26,6 @@ export const StyledMarkdownBlock = styled(
{ compact?: boolean; inline?: boolean } { compact?: boolean; inline?: boolean }
>, >,
)` )`
font-family: ${props => props.theme.typography.fontFamily}; font-family: ${props => props.theme.typography.fontFamily};
font-weight: ${props => props.theme.typography.fontWeightRegular}; font-weight: ${props => props.theme.typography.fontWeightRegular};
line-height: ${props => props.theme.typography.lineHeight}; line-height: ${props => props.theme.typography.lineHeight};
@ -81,7 +80,7 @@ export const StyledMarkdownBlock = styled(
pre { pre {
font-family: ${props => props.theme.typography.code.fontFamily}; font-family: ${props => props.theme.typography.code.fontFamily};
white-space:${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')}; white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
background-color: ${({ theme }) => theme.codeBlock.backgroundColor}; background-color: ${({ theme }) => theme.codeBlock.backgroundColor};
color: white; color: white;
padding: ${props => props.theme.spacing.unit * 4}px; padding: ${props => props.theme.spacing.unit * 4}px;
@ -121,7 +120,8 @@ export const StyledMarkdownBlock = styled(
margin: 0; margin: 0;
margin-bottom: 1em; margin-bottom: 1em;
ul, ol { ul,
ol {
margin-bottom: 0; margin-bottom: 0;
margin-top: 0; margin-top: 0;
} }

View File

@ -42,7 +42,7 @@ export class Operation extends React.Component<OperationProps> {
return ( return (
<OptionsContext.Consumer> <OptionsContext.Consumer>
{(options) => ( {options => (
<OperationRow> <OperationRow>
<MiddlePanel> <MiddlePanel>
<H2> <H2>

View File

@ -67,7 +67,10 @@ function DropdownWithinHeader(props) {
); );
} }
export function BodyContent(props: { content: MediaContentModel; description?: string }): JSX.Element { export function BodyContent(props: {
content: MediaContentModel;
description?: string;
}): JSX.Element {
const { content, description } = props; const { content, description } = props;
const { isRequestType } = content; const { isRequestType } = content;
return ( return (

View File

@ -1,6 +1,10 @@
import * as React from 'react'; import * as React from 'react';
import { argValueToBoolean, RedocNormalizedOptions, RedocRawOptions } from '../services/RedocNormalizedOptions'; import {
argValueToBoolean,
RedocNormalizedOptions,
RedocRawOptions,
} from '../services/RedocNormalizedOptions';
import { ErrorBoundary } from './ErrorBoundary'; import { ErrorBoundary } from './ErrorBoundary';
import { Loading } from './Loading/Loading'; import { Loading } from './Loading/Loading';
import { Redoc } from './Redoc/Redoc'; import { Redoc } from './Redoc/Redoc';
@ -32,4 +36,4 @@ export const RedocStandalone = function (props: RedocStandaloneProps) {
</StoreBuilder> </StoreBuilder>
</ErrorBoundary> </ErrorBoundary>
); );
} };

View File

@ -14,13 +14,13 @@ export const StyledResponseTitle = styled(ResponseTitle)`
background-color: #f2f2f2; background-color: #f2f2f2;
cursor: pointer; cursor: pointer;
color: ${(props) => props.theme.colors.responses[props.type].color}; color: ${props => props.theme.colors.responses[props.type].color};
background-color: ${(props) => props.theme.colors.responses[props.type].backgroundColor}; background-color: ${props => props.theme.colors.responses[props.type].backgroundColor};
&:focus { &:focus {
outline: auto; outline: auto;
outline-color: ${(props) => props.theme.colors.responses[props.type].color}; outline-color: ${props => props.theme.colors.responses[props.type].color};
} }
${(props) => ${props =>
(props.empty && (props.empty &&
` `
cursor: default; cursor: default;

View File

@ -16,14 +16,17 @@ export class ArraySchema extends React.PureComponent<SchemaProps> {
const schema = this.props.schema; const schema = this.props.schema;
const itemsSchema = schema.items; const itemsSchema = schema.items;
const minMaxItems = schema.minItems === undefined && schema.maxItems === undefined ? const minMaxItems =
'' : schema.minItems === undefined && schema.maxItems === undefined
`(${humanizeConstraints(schema)})`; ? ''
: `(${humanizeConstraints(schema)})`;
if (schema.displayType && !itemsSchema && !minMaxItems.length) { if (schema.displayType && !itemsSchema && !minMaxItems.length) {
return (<div> return (
<TypeName>{schema.displayType}</TypeName> <div>
</div>); <TypeName>{schema.displayType}</TypeName>
</div>
);
} }
return ( return (

View File

@ -73,7 +73,7 @@ export class Schema extends React.Component<Partial<SchemaProps>> {
} }
// TODO: maybe adjust FieldDetails to accept schema // TODO: maybe adjust FieldDetails to accept schema
const field = ({ const field = {
schema, schema,
name: '', name: '',
required: false, required: false,
@ -82,7 +82,7 @@ export class Schema extends React.Component<Partial<SchemaProps>> {
deprecated: false, deprecated: false,
toggle: () => null, toggle: () => null,
expanded: false, expanded: false,
} as any) as FieldModel; // cast needed for hot-loader to not fail } as any as FieldModel; // cast needed for hot-loader to not fail
return ( return (
<div> <div>

View File

@ -100,7 +100,7 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
setResults(results: SearchResult[], term: string) { setResults(results: SearchResult[], term: string) {
this.setState({ this.setState({
results, results,
noResults: results.length === 0 noResults: results.length === 0,
}); });
this.props.marker.mark(term); this.props.marker.mark(term);
} }

View File

@ -7,8 +7,8 @@ import { SecurityRequirementModel } from '../../services/models/SecurityRequirem
import { linksCss } from '../Markdown/styled.elements'; import { linksCss } from '../Markdown/styled.elements';
const ScopeName = styled.code` const ScopeName = styled.code`
font-size: ${(props) => props.theme.typography.code.fontSize}; font-size: ${props => props.theme.typography.code.fontSize};
font-family: ${(props) => props.theme.typography.code.fontFamily}; font-family: ${props => props.theme.typography.code.fontFamily};
border: 1px solid ${({ theme }) => theme.colors.border.dark}; border: 1px solid ${({ theme }) => theme.colors.border.dark};
margin: 0 3px; margin: 0 3px;
padding: 0.2em; padding: 0.2em;
@ -67,12 +67,12 @@ export class SecurityRequirement extends React.PureComponent<SecurityRequirement
return ( return (
<SecurityRequirementOrWrap> <SecurityRequirementOrWrap>
{security.schemes.length ? ( {security.schemes.length ? (
security.schemes.map((scheme) => { security.schemes.map(scheme => {
return ( return (
<SecurityRequirementAndWrap key={scheme.id}> <SecurityRequirementAndWrap key={scheme.id}>
<Link to={scheme.sectionId}>{scheme.id}</Link> <Link to={scheme.sectionId}>{scheme.id}</Link>
{scheme.scopes.length > 0 && ' ('} {scheme.scopes.length > 0 && ' ('}
{scheme.scopes.map((scope) => ( {scheme.scopes.map(scope => (
<ScopeName key={scope}>{scope}</ScopeName> <ScopeName key={scope}>{scope}</ScopeName>
))} ))}
{scheme.scopes.length > 0 && ') '} {scheme.scopes.length > 0 && ') '}
@ -92,7 +92,7 @@ const AuthHeaderColumn = styled.div`
`; `;
const SecuritiesColumn = styled.div` const SecuritiesColumn = styled.div`
width: ${(props) => props.theme.schema.defaultDetailsWidth}; width: ${props => props.theme.schema.defaultDetailsWidth};
${media.lessThan('small')` ${media.lessThan('small')`
margin-top: 10px; margin-top: 10px;
`} `}

View File

@ -30,7 +30,7 @@ const { Provider, Consumer } = StoreContext;
export { Provider as StoreProvider, Consumer as StoreConsumer, StoreContext }; export { Provider as StoreProvider, Consumer as StoreConsumer, StoreContext };
export function StoreBuilder(props: StoreBuilderProps) { export function StoreBuilder(props: StoreBuilderProps) {
const {spec, specUrl, options, onLoaded, children } = props; const { spec, specUrl, options, onLoaded, children } = props;
const [resolvedSpec, setResolvedSpec] = React.useState<any>(null); const [resolvedSpec, setResolvedSpec] = React.useState<any>(null);
@ -44,7 +44,7 @@ export function StoreBuilder(props: StoreBuilderProps) {
setResolvedSpec(resolved); setResolvedSpec(resolved);
} }
load(); load();
}, [spec, specUrl]) }, [spec, specUrl]);
const store = React.useMemo(() => { const store = React.useMemo(() => {
if (!resolvedSpec) return null; if (!resolvedSpec) return null;
@ -62,7 +62,7 @@ export function StoreBuilder(props: StoreBuilderProps) {
if (store && onLoaded) { if (store && onLoaded) {
onLoaded(); onLoaded();
} }
}, [store, onLoaded]) }, [store, onLoaded]);
return children({ return children({
loading: !store, loading: !store,

View File

@ -10,14 +10,15 @@ const options = new RedocNormalizedOptions({});
describe('Components', () => { describe('Components', () => {
describe('SecurityRequirement', () => { describe('SecurityRequirement', () => {
describe('SecurityRequirement', () => { describe('SecurityRequirement', () => {
it('should render \'None\' when empty object in security open api', () => { it("should render 'None' when empty object in security open api", () => {
const parser = new OpenAPIParser({ openapi: '3.0', info: { title: 'test', version: '0' }, paths: {} }, const parser = new OpenAPIParser(
{ openapi: '3.0', info: { title: 'test', version: '0' }, paths: {} },
undefined, undefined,
options, options,
); );
const securityRequirement = new SecurityRequirementModel({}, parser); const securityRequirement = new SecurityRequirementModel({}, parser);
const securityElement = shallow( const securityElement = shallow(
<SecurityRequirement key={1} security={securityRequirement} /> <SecurityRequirement key={1} security={securityRequirement} />,
).getElement(); ).getElement();
expect(securityElement.props.children.type.target).toEqual('span'); expect(securityElement.props.children.type.target).toEqual('span');
expect(securityElement.props.children.props.children).toEqual('None'); expect(securityElement.props.children.props.children).toEqual('None');

View File

@ -121,10 +121,7 @@ export class MarkdownRenderer {
prevRegexp = regexp; prevRegexp = regexp;
prevPos = currentPos; prevPos = currentPos;
} }
prevHeading.description = rawText prevHeading.description = rawText.substring(prevPos).replace(prevRegexp, '').trim();
.substring(prevPos)
.replace(prevRegexp, '')
.trim();
} }
headingRule = ( headingRule = (

View File

@ -243,7 +243,7 @@ export class MenuBuilder {
getTags(parser, webhooks, true); getTags(parser, webhooks, true);
} }
if (spec.paths){ if (spec.paths) {
getTags(parser, spec.paths); getTags(parser, spec.paths);
} }

View File

@ -193,7 +193,10 @@ export class OpenAPIParser {
if (keys.length === 0) { if (keys.length === 0) {
return resolved; return resolved;
} }
if (mergeAsAllOf && keys.some((k) => k !== 'description' && k !== 'title' && k !== 'externalDocs')) { if (
mergeAsAllOf &&
keys.some(k => k !== 'description' && k !== 'title' && k !== 'externalDocs')
) {
return { return {
allOf: [rest, resolved], allOf: [rest, resolved],
}; };
@ -244,7 +247,7 @@ export class OpenAPIParser {
} }
const allOfSchemas = schema.allOf const allOfSchemas = schema.allOf
.map((subSchema) => { .map(subSchema => {
if (subSchema && subSchema.$ref && used$Refs.has(subSchema.$ref)) { if (subSchema && subSchema.$ref && used$Refs.has(subSchema.$ref)) {
return undefined; return undefined;
} }
@ -258,7 +261,7 @@ export class OpenAPIParser {
schema: subMerged, schema: subMerged,
}; };
}) })
.filter((child) => child !== undefined) as Array<{ .filter(child => child !== undefined) as Array<{
$ref: string | undefined; $ref: string | undefined;
schema: MergedOpenAPISchema; schema: MergedOpenAPISchema;
}>; }>;
@ -337,7 +340,7 @@ export class OpenAPIParser {
const def = this.deref(schemas[defName]); const def = this.deref(schemas[defName]);
if ( if (
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];
} }
@ -363,7 +366,7 @@ export class OpenAPIParser {
const beforeAllOf = allOf.slice(0, i); const beforeAllOf = allOf.slice(0, i);
const afterAllOf = allOf.slice(i + 1); const afterAllOf = allOf.slice(i + 1);
return { return {
oneOf: sub.oneOf.map((part) => { oneOf: sub.oneOf.map(part => {
const merged = this.mergeAllOf({ const merged = this.mergeAllOf({
allOf: [...beforeAllOf, part, ...afterAllOf], allOf: [...beforeAllOf, part, ...afterAllOf],
}); });

View File

@ -73,7 +73,7 @@ export class RedocNormalizedOptions {
} }
if (typeof value === 'string') { if (typeof value === 'string') {
const res = {}; const res = {};
value.split(',').forEach((code) => { value.split(',').forEach(code => {
res[code.trim()] = true; res[code.trim()] = true;
}); });
return res; return res;
@ -139,7 +139,7 @@ export class RedocNormalizedOptions {
case 'false': case 'false':
return false; return false;
default: default:
return value.split(',').map((ext) => ext.trim()); return value.split(',').map(ext => ext.trim());
} }
} }
@ -277,7 +277,7 @@ export class RedocNormalizedOptions {
this.maxDisplayedEnumValues = argValueToNumber(raw.maxDisplayedEnumValues); this.maxDisplayedEnumValues = argValueToNumber(raw.maxDisplayedEnumValues);
const ignoreNamedSchemas = Array.isArray(raw.ignoreNamedSchemas) const ignoreNamedSchemas = Array.isArray(raw.ignoreNamedSchemas)
? raw.ignoreNamedSchemas ? raw.ignoreNamedSchemas
: raw.ignoreNamedSchemas?.split(',').map((s) => s.trim()); : raw.ignoreNamedSchemas?.split(',').map(s => s.trim());
this.ignoreNamedSchemas = new Set(ignoreNamedSchemas); this.ignoreNamedSchemas = new Set(ignoreNamedSchemas);
this.hideSchemaPattern = argValueToBoolean(raw.hideSchemaPattern); this.hideSchemaPattern = argValueToBoolean(raw.hideSchemaPattern);
this.generatedPayloadSamplesMaxDepth = this.generatedPayloadSamplesMaxDepth =

View File

@ -59,7 +59,7 @@ export class SearchStore<T> {
fromExternalJS(path?: string, exportName?: string) { fromExternalJS(path?: string, exportName?: string) {
if (path && exportName) { if (path && exportName) {
this.searchWorker.fromExternalJS(path, exportName) this.searchWorker.fromExternalJS(path, exportName);
} }
} }
} }

View File

@ -1,12 +1,5 @@
import * as lunr from 'lunr'; import * as lunr from 'lunr';
try {
// tslint:disable-next-line
require('core-js/es/promise'); // bundle into worker
} catch (_) {
// nope
}
/* just for better typings */ /* just for better typings */
export default class Worker { export default class Worker {
add: typeof add = add; add: typeof add = add;

View File

@ -28,7 +28,10 @@ export class SpecStore {
this.externalDocs = this.parser.spec.externalDocs; this.externalDocs = this.parser.spec.externalDocs;
this.contentItems = MenuBuilder.buildStructure(this.parser, this.options); this.contentItems = MenuBuilder.buildStructure(this.parser, this.options);
this.securitySchemes = new SecuritySchemesModel(this.parser); this.securitySchemes = new SecuritySchemesModel(this.parser);
const webhookPath: Referenced<OpenAPIPath> = {...this.parser?.spec?.['x-webhooks'], ...this.parser?.spec.webhooks}; const webhookPath: Referenced<OpenAPIPath> = {
...this.parser?.spec?.['x-webhooks'],
...this.parser?.spec.webhooks,
};
this.webhooks = new WebhookModel(this.parser, options, webhookPath); this.webhooks = new WebhookModel(this.parser, options, webhookPath);
} }
} }

View File

@ -26,6 +26,5 @@ describe('Models', () => {
expect(parser.shallowDeref(schemaOrRef)).toMatchSnapshot(); expect(parser.shallowDeref(schemaOrRef)).toMatchSnapshot();
}); });
}); });
}); });

View File

@ -54,8 +54,8 @@ describe('Models', () => {
license: { license: {
name: 'MIT', name: 'MIT',
identifier: 'MIT', identifier: 'MIT',
url: 'https://opensource.org/licenses/MIT' url: 'https://opensource.org/licenses/MIT',
} },
}, },
} as any; } as any;

View File

@ -19,7 +19,6 @@ describe('Models', () => {
expect(contentItems[0].id).toEqual('tag/pet'); expect(contentItems[0].id).toEqual('tag/pet');
expect(contentItems[0].name).toEqual('pet'); expect(contentItems[0].name).toEqual('pet');
expect(contentItems[0].type).toEqual('tag'); expect(contentItems[0].type).toEqual('tag');
}); });
}); });
}); });

View File

@ -20,23 +20,23 @@ describe('Models', () => {
}); });
test('should calculate response type based on code', () => { test('should calculate response type based on code', () => {
let resp = new ResponseModel({...props, code: '200' }); let resp = new ResponseModel({ ...props, code: '200' });
expect(resp.type).toEqual('success'); expect(resp.type).toEqual('success');
resp = new ResponseModel({...props, code: '120' }); resp = new ResponseModel({ ...props, code: '120' });
expect(resp.type).toEqual('info'); expect(resp.type).toEqual('info');
resp = new ResponseModel({...props, code: '301' }); resp = new ResponseModel({ ...props, code: '301' });
expect(resp.type).toEqual('redirect'); expect(resp.type).toEqual('redirect');
resp = new ResponseModel({...props, code: '400' }); resp = new ResponseModel({ ...props, code: '400' });
expect(resp.type).toEqual('error'); expect(resp.type).toEqual('error');
}); });
test('default should be successful by default', () => { test('default should be successful by default', () => {
const resp = new ResponseModel({...props, code: 'default' }); const resp = new ResponseModel({ ...props, code: 'default' });
expect(resp.type).toEqual('success'); expect(resp.type).toEqual('success');
}); });
test('default should be error if defaultAsError is true', () => { test('default should be error if defaultAsError is true', () => {
const resp = new ResponseModel({...props, code: 'default', defaultAsError: true }); const resp = new ResponseModel({ ...props, code: 'default', defaultAsError: true });
expect(resp.type).toEqual('error'); expect(resp.type).toEqual('error');
}); });
}); });

View File

@ -109,7 +109,7 @@ export class OperationModel implements IMenuItem {
// NOTE: Callbacks by default should not inherit the specification's global `security` definition. // NOTE: Callbacks by default should not inherit the specification's global `security` definition.
// Can be defined individually per-callback in the specification. Defaults to none. // Can be defined individually per-callback in the specification. Defaults to none.
this.security = (operationSpec.security || []).map( this.security = (operationSpec.security || []).map(
(security) => new SecurityRequirementModel(security, parser), security => new SecurityRequirementModel(security, parser),
); );
// TODO: update getting pathInfo for overriding servers on path level // TODO: update getting pathInfo for overriding servers on path level
@ -123,7 +123,7 @@ export class OperationModel implements IMenuItem {
: this.pointer; : this.pointer;
this.security = (operationSpec.security || parser.spec.security || []).map( this.security = (operationSpec.security || parser.spec.security || []).map(
(security) => new SecurityRequirementModel(security, parser), security => new SecurityRequirementModel(security, parser),
); );
this.servers = normalizeServers( this.servers = normalizeServers(
@ -174,7 +174,8 @@ export class OperationModel implements IMenuItem {
@memoize @memoize
get requestBody() { get requestBody() {
return ( return (
this.operationSpec.requestBody && new RequestBodyModel({ this.operationSpec.requestBody &&
new RequestBodyModel({
parser: this.parser, parser: this.parser,
infoOrRef: this.operationSpec.requestBody, infoOrRef: this.operationSpec.requestBody,
options: this.options, options: this.options,
@ -219,7 +220,7 @@ export class OperationModel implements IMenuItem {
this.operationSpec.pathParameters, this.operationSpec.pathParameters,
this.operationSpec.parameters, this.operationSpec.parameters,
// TODO: fix pointer // TODO: fix pointer
).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) {
return sortByField(_parameters, 'name'); return sortByField(_parameters, 'name');
@ -235,7 +236,7 @@ export class OperationModel implements IMenuItem {
get responses() { get responses() {
let hasSuccessResponses = false; let hasSuccessResponses = false;
return Object.keys(this.operationSpec.responses || []) return Object.keys(this.operationSpec.responses || [])
.filter((code) => { .filter(code => {
if (code === 'default') { if (code === 'default') {
return true; return true;
} }
@ -246,7 +247,7 @@ export class OperationModel implements IMenuItem {
return isStatusCode(code); return isStatusCode(code);
}) // filter out other props (e.g. x-props) }) // filter out other props (e.g. x-props)
.map((code) => { .map(code => {
return new ResponseModel({ return new ResponseModel({
parser: this.parser, parser: this.parser,
code, code,
@ -260,7 +261,7 @@ export class OperationModel implements IMenuItem {
@memoize @memoize
get callbacks() { get callbacks() {
return Object.keys(this.operationSpec.callbacks || []).map((callbackEventName) => { return Object.keys(this.operationSpec.callbacks || []).map(callbackEventName => {
return new CallbackModel( return new CallbackModel(
this.parser, this.parser,
callbackEventName, callbackEventName,

View File

@ -9,7 +9,7 @@ type RequestBodyProps = {
infoOrRef: Referenced<OpenAPIRequestBody>; infoOrRef: Referenced<OpenAPIRequestBody>;
options: RedocNormalizedOptions; options: RedocNormalizedOptions;
isEvent: boolean; isEvent: boolean;
} };
export class RequestBodyModel { export class RequestBodyModel {
description: string; description: string;

View File

@ -9,13 +9,13 @@ import { FieldModel } from './Field';
import { MediaContentModel } from './MediaContent'; import { MediaContentModel } from './MediaContent';
type ResponseProps = { type ResponseProps = {
parser: OpenAPIParser, parser: OpenAPIParser;
code: string, code: string;
defaultAsError: boolean, defaultAsError: boolean;
infoOrRef: Referenced<OpenAPIResponse>, infoOrRef: Referenced<OpenAPIResponse>;
options: RedocNormalizedOptions, options: RedocNormalizedOptions;
isEvent: boolean, isEvent: boolean;
} };
export class ResponseModel { export class ResponseModel {
@observable @observable

View File

@ -134,7 +134,10 @@ export class SchemaModel {
this.maxItems = schema.maxItems; this.maxItems = schema.maxItems;
if (!!schema.nullable || schema['x-nullable']) { if (!!schema.nullable || schema['x-nullable']) {
if (Array.isArray(this.type) && !this.type.some((value) => value === null || value === 'null')) { if (
Array.isArray(this.type) &&
!this.type.some(value => value === null || value === 'null')
) {
this.type = [...this.type, 'null']; this.type = [...this.type, 'null'];
} else if (!Array.isArray(this.type) && (this.type !== null || this.type !== 'null')) { } else if (!Array.isArray(this.type) && (this.type !== null || this.type !== 'null')) {
this.type = [this.type, 'null']; this.type = [this.type, 'null'];
@ -142,7 +145,7 @@ export class SchemaModel {
} }
this.displayType = Array.isArray(this.type) this.displayType = Array.isArray(this.type)
? this.type.map(item => item === null ? 'null' : item).join(' or ') ? this.type.map(item => (item === null ? 'null' : item)).join(' or ')
: this.type; : this.type;
if (this.isCircular) { if (this.isCircular) {
@ -155,7 +158,7 @@ export class SchemaModel {
} else if ( } else if (
isChild && isChild &&
Array.isArray(schema.oneOf) && Array.isArray(schema.oneOf) &&
schema.oneOf.find((s) => s.$ref === this.pointer) schema.oneOf.find(s => s.$ref === this.pointer)
) { ) {
// we hit allOf of the schema with the parent discriminator // we hit allOf of the schema with the parent discriminator
delete schema.oneOf; delete schema.oneOf;
@ -195,8 +198,7 @@ export class SchemaModel {
} }
if (Array.isArray(this.type)) { if (Array.isArray(this.type)) {
const filteredType = this.type.filter(item => item !== 'array'); const filteredType = this.type.filter(item => item !== 'array');
if (filteredType.length) if (filteredType.length) this.displayType += ` or ${filteredType.join(' or ')}`;
this.displayType += ` or ${filteredType.join(' or ')}`;
} }
} }
@ -215,7 +217,7 @@ export class SchemaModel {
const title = const title =
isNamedDefinition(variant.$ref) && !merged.title isNamedDefinition(variant.$ref) && !merged.title
? JsonPointer.baseName(variant.$ref) ? JsonPointer.baseName(variant.$ref)
: `${(merged.title || '')}${(merged.const && JSON.stringify(merged.const)) || ''}`; : `${merged.title || ''}${(merged.const && JSON.stringify(merged.const)) || ''}`;
const schema = new SchemaModel( const schema = new SchemaModel(
parser, parser,
@ -243,7 +245,7 @@ export class SchemaModel {
this.displayType = types.join(' or '); this.displayType = types.join(' or ');
} else { } else {
this.displayType = this.oneOf this.displayType = this.oneOf
.map((schema) => { .map(schema => {
let name = let name =
schema.typePrefix + schema.typePrefix +
(schema.title ? `${schema.title} (${schema.displayType})` : schema.displayType); (schema.title ? `${schema.title} (${schema.displayType})` : schema.displayType);
@ -364,7 +366,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;
let 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) {

View File

@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import { hydrate as hydrateComponent, render } from 'react-dom'; import { hydrate as hydrateComponent, render } from 'react-dom';
import { configure } from "mobx" import { configure } from 'mobx';
import { Redoc, RedocStandalone } from './components/'; import { Redoc, RedocStandalone } from './components/';
import { AppStore, StoreState } from './services/AppStore'; import { AppStore, StoreState } from './services/AppStore';
@ -8,8 +8,8 @@ import { debugTime, debugTimeEnd } from './utils/debug';
import { querySelector } from './utils/dom'; import { querySelector } from './utils/dom';
configure({ configure({
useProxies: 'ifavailable' useProxies: 'ifavailable',
}) });
export { Redoc, AppStore } from '.'; export { Redoc, AppStore } from '.';

View File

@ -16,7 +16,7 @@ export const media = {
lessThan(breakpoint, print?: boolean, extra?: string) { lessThan(breakpoint, print?: boolean, extra?: string) {
return (...args) => css` return (...args) => css`
@media ${print ? 'print, ' : ''} screen and (max-width: ${props => @media ${print ? 'print, ' : ''} screen and (max-width: ${props =>
props.theme.breakpoints[breakpoint]})${extra || ''} { props.theme.breakpoints[breakpoint]}) ${extra || ''} {
${(css as any)(...args)}; ${(css as any)(...args)};
} }
`; `;

View File

@ -11,7 +11,9 @@ describe('#loadAndBundleSpec', () => {
}); });
it('should load And Bundle Spec demo/openapi-3-1.yaml', async () => { it('should load And Bundle Spec demo/openapi-3-1.yaml', async () => {
const spec = yaml.load(readFileSync(resolve(__dirname, '../../../demo/openapi-3-1.yaml'), 'utf-8')); const spec = yaml.load(
readFileSync(resolve(__dirname, '../../../demo/openapi-3-1.yaml'), 'utf-8'),
);
const bundledSpec = await loadAndBundleSpec(spec); const bundledSpec = await loadAndBundleSpec(spec);
expect(bundledSpec).toMatchSnapshot(); expect(bundledSpec).toMatchSnapshot();
}); });

View File

@ -10,6 +10,7 @@ import {
pluralizeType, pluralizeType,
serializeParameterValue, serializeParameterValue,
sortByRequired, sortByRequired,
humanizeNumberRange,
} from '../'; } from '../';
import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services'; import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services';
@ -103,7 +104,7 @@ describe('Utils', () => {
it('Should return pathName if no summary, operationId, description', () => { it('Should return pathName if no summary, operationId, description', () => {
const operation = { const operation = {
pathName: '/sandbox/test' pathName: '/sandbox/test',
}; };
expect(getOperationSummary(operation as any)).toBe('/sandbox/test'); expect(getOperationSummary(operation as any)).toBe('/sandbox/test');
}); });
@ -174,7 +175,7 @@ describe('Utils', () => {
expect(isPrimitiveType(schema)).toEqual(false); expect(isPrimitiveType(schema)).toEqual(false);
}); });
it('should return true for array contains object and schema hasn\'t properties', () => { it("should return true for array contains object and schema hasn't properties", () => {
const schema = { const schema = {
type: ['object', 'string'], type: ['object', 'string'],
}; };
@ -231,10 +232,10 @@ describe('Utils', () => {
const schema = { const schema = {
type: 'array', type: 'array',
items: { items: {
type: 'array', type: 'array',
items: { items: {
type: 'string' type: 'string',
}, },
}, },
}; };
expect(isPrimitiveType(schema)).toEqual(true); expect(isPrimitiveType(schema)).toEqual(true);
@ -410,12 +411,82 @@ describe('Utils', () => {
}); });
}); });
describe('openapi humanizeNumberRange', () => {
it('should return `>=` when only minimum value present or exclusiveMinimum = false', () => {
const expected = '>= 0';
expect(humanizeNumberRange({ minimum: 0 })).toEqual(expected);
expect(humanizeNumberRange({ minimum: 0, exclusiveMinimum: false })).toEqual(expected);
});
it('should return `>` when minimum value present and exclusiveMinimum set to true', () => {
expect(humanizeNumberRange({ minimum: 0, exclusiveMinimum: true })).toEqual('> 0');
});
it('should return `<=` when only maximum value present or exclusiveMinimum = false', () => {
const expected = '<= 10';
expect(humanizeNumberRange({ maximum: 10 })).toEqual(expected);
expect(humanizeNumberRange({ maximum: 10, exclusiveMaximum: false })).toEqual(expected);
});
it('should return `<` when maximum value present and exclusiveMaximum set to true', () => {
expect(humanizeNumberRange({ maximum: 10, exclusiveMaximum: true })).toEqual('< 10');
});
it('should return correct range for minimum and maximum values and with different exclusive set', () => {
expect(humanizeNumberRange({ minimum: 0, maximum: 10 })).toEqual('[ 0 .. 10 ]');
expect(
humanizeNumberRange({
minimum: 0,
exclusiveMinimum: true,
maximum: 10,
exclusiveMaximum: true,
}),
).toEqual('( 0 .. 10 )');
expect(
humanizeNumberRange({
minimum: 0,
maximum: 10,
exclusiveMaximum: true,
}),
).toEqual('[ 0 .. 10 )');
expect(
humanizeNumberRange({
minimum: 0,
exclusiveMinimum: true,
maximum: 10,
}),
).toEqual('( 0 .. 10 ]');
});
it('should return correct range exclusive values only', () => {
expect(humanizeNumberRange({ exclusiveMinimum: 0 })).toEqual('> 0');
expect(humanizeNumberRange({ exclusiveMaximum: 10 })).toEqual('< 10');
expect(humanizeNumberRange({ exclusiveMinimum: 0, exclusiveMaximum: 10 })).toEqual(
'( 0 .. 10 )',
);
});
it('should return correct min value', () => {
expect(humanizeNumberRange({ minimum: 5, exclusiveMinimum: 10 })).toEqual('> 5');
expect(humanizeNumberRange({ minimum: -5, exclusiveMinimum: -10 })).toEqual('> -10');
});
it('should return correct max value', () => {
expect(humanizeNumberRange({ maximum: 10, exclusiveMaximum: 15 })).toEqual('< 15');
expect(humanizeNumberRange({ maximum: -10, exclusiveMaximum: -15 })).toEqual('< -10');
});
it('should return undefined', () => {
expect(humanizeNumberRange({})).toEqual(undefined);
});
});
describe('openapi humanizeConstraints', () => { describe('openapi humanizeConstraints', () => {
const itemConstraintSchema = ( const itemConstraintSchema = (
min?: number, min?: number,
max?: number, max?: number,
multipleOf?: number, multipleOf?: number,
uniqueItems?: boolean uniqueItems?: boolean,
) => ({ type: 'array', minItems: min, maxItems: max, multipleOf, uniqueItems }); ) => ({ type: 'array', minItems: min, maxItems: max, multipleOf, uniqueItems });
it('should not have a humanized constraint without schema constraints', () => { it('should not have a humanized constraint without schema constraints', () => {
@ -455,9 +526,9 @@ describe('Utils', () => {
}); });
it('should have a humanized constraint when uniqueItems is set', () => { it('should have a humanized constraint when uniqueItems is set', () => {
expect(humanizeConstraints(itemConstraintSchema(undefined, undefined, undefined, true))).toContain( expect(
'unique', humanizeConstraints(itemConstraintSchema(undefined, undefined, undefined, true)),
); ).toContain('unique');
}); });
}); });

View File

@ -12,7 +12,7 @@ function throttle(func, wait) {
context = args = null; context = args = null;
} }
}; };
return function() { return function () {
const now = new Date().getTime(); const now = new Date().getTime();
const remaining = wait - (now - previous); const remaining = wait - (now - previous);
context = this; context = this;

View File

@ -27,7 +27,7 @@ export function html2Str(html: string): string {
// scrollIntoViewIfNeeded polyfill // scrollIntoViewIfNeeded polyfill
if (typeof Element !== 'undefined' && !(Element as any).prototype.scrollIntoViewIfNeeded) { if (typeof Element !== 'undefined' && !(Element as any).prototype.scrollIntoViewIfNeeded) {
(Element as any).prototype.scrollIntoViewIfNeeded = function(centerIfNeeded) { (Element as any).prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) {
centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded; centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded;
const parent = this.parentNode; const parent = this.parentNode;

View File

@ -50,7 +50,7 @@ export function flattenByProp<T extends object, P extends keyof T>(
for (const item of items) { for (const item of items) {
res.push(item); res.push(item);
if (item[prop]) { if (item[prop]) {
iterate((item[prop] as any) as T[]); iterate(item[prop] as any as T[]);
} }
} }
}; };

View File

@ -14,8 +14,8 @@ export async function loadAndBundleSpec(specUrlOrObject: object | string): Promi
const config = new Config({}); const config = new Config({});
const bundleOpts = { const bundleOpts = {
config, config,
base: IS_BROWSER ? window.location.href : process.cwd() base: IS_BROWSER ? window.location.href : process.cwd(),
} };
if (IS_BROWSER) { if (IS_BROWSER) {
config.resolve.http.customFetch = global.fetch; config.resolve.http.customFetch = global.fetch;
@ -24,13 +24,15 @@ export async function loadAndBundleSpec(specUrlOrObject: object | string): Promi
if (typeof specUrlOrObject === 'object' && specUrlOrObject !== null) { if (typeof specUrlOrObject === 'object' && specUrlOrObject !== null) {
bundleOpts['doc'] = { bundleOpts['doc'] = {
source: { absoluteRef: '' } as Source, source: { absoluteRef: '' } as Source,
parsed: specUrlOrObject parsed: specUrlOrObject,
} as Document } as Document;
} else { } else {
bundleOpts['ref'] = specUrlOrObject; bundleOpts['ref'] = specUrlOrObject;
} }
const { bundle: { parsed } } = await bundle(bundleOpts); const {
bundle: { parsed },
} = await bundle(bundleOpts);
return parsed.swagger !== undefined ? convertSwagger2OpenAPI(parsed) : parsed; return parsed.swagger !== undefined ? convertSwagger2OpenAPI(parsed) : parsed;
} }

View File

@ -3,7 +3,7 @@ const SENTINEL = {};
export function memoize<T>(target: any, name: string, descriptor: TypedPropertyDescriptor<T>) { export function memoize<T>(target: any, name: string, descriptor: TypedPropertyDescriptor<T>) {
if (typeof descriptor.value === 'function') { if (typeof descriptor.value === 'function') {
return (_memoizeMethod(target, name, descriptor) as any) as TypedPropertyDescriptor<T>; return _memoizeMethod(target, name, descriptor) as any as TypedPropertyDescriptor<T>;
} else if (typeof descriptor.get === 'function') { } else if (typeof descriptor.get === 'function') {
return _memoizeGetter(target, name, descriptor) as TypedPropertyDescriptor<T>; return _memoizeGetter(target, name, descriptor) as TypedPropertyDescriptor<T>;
} else { } else {

View File

@ -113,7 +113,10 @@ export function detectType(schema: OpenAPISchema): string {
return 'any'; return 'any';
} }
export function isPrimitiveType(schema: OpenAPISchema, type: string | string[] | undefined = schema.type) { export function isPrimitiveType(
schema: OpenAPISchema,
type: string | string[] | undefined = schema.type,
) {
if (schema.oneOf !== undefined || schema.anyOf !== undefined) { if (schema.oneOf !== undefined || schema.anyOf !== undefined) {
return false; return false;
} }
@ -122,9 +125,10 @@ export function isPrimitiveType(schema: OpenAPISchema, type: string | string[] |
const isArray = Array.isArray(type); const isArray = Array.isArray(type);
if (type === 'object' || (isArray && type?.includes('object'))) { if (type === 'object' || (isArray && type?.includes('object'))) {
isPrimitive = schema.properties !== undefined isPrimitive =
? Object.keys(schema.properties).length === 0 schema.properties !== undefined
: schema.additionalProperties === undefined; ? Object.keys(schema.properties).length === 0
: schema.additionalProperties === undefined;
} }
if (schema.items !== undefined && (type === 'array' || (isArray && type?.includes('array')))) { if (schema.items !== undefined && (type === 'array' || (isArray && type?.includes('array')))) {
@ -376,7 +380,7 @@ export function isNamedDefinition(pointer?: string): boolean {
export function getDefinitionName(pointer?: string): string | undefined { export function getDefinitionName(pointer?: string): string | undefined {
if (!pointer) return undefined; if (!pointer) return undefined;
const match = pointer.match(/^#\/components\/(schemas|pathItems)\/([^\/]+)$/); const match = pointer.match(/^#\/components\/(schemas|pathItems)\/([^\/]+)$/);
return match === null ? undefined : match[1] return match === null ? undefined : match[1];
} }
function humanizeMultipleOfConstraint(multipleOf: number | undefined): string | undefined { function humanizeMultipleOfConstraint(multipleOf: number | undefined): string | undefined {
@ -415,6 +419,29 @@ function humanizeRangeConstraint(
return stringRange; return stringRange;
} }
export function humanizeNumberRange(schema: OpenAPISchema): string | undefined {
const minimum =
typeof schema.exclusiveMinimum === 'number'
? Math.min(schema.exclusiveMinimum, schema.minimum ?? Infinity)
: schema.minimum;
const maximum =
typeof schema.exclusiveMaximum === 'number'
? Math.max(schema.exclusiveMaximum, schema.maximum ?? -Infinity)
: schema.maximum;
const exclusiveMinimum = typeof schema.exclusiveMinimum === 'number' || schema.exclusiveMinimum;
const exclusiveMaximum = typeof schema.exclusiveMaximum === 'number' || schema.exclusiveMaximum;
if (minimum !== undefined && maximum !== undefined) {
return `${exclusiveMinimum ? '( ' : '[ '}${minimum} .. ${maximum}${
exclusiveMaximum ? ' )' : ' ]'
}`;
} else if (maximum !== undefined) {
return `${exclusiveMaximum ? '< ' : '<= '}${maximum}`;
} else if (minimum !== undefined) {
return `${exclusiveMinimum ? '> ' : '>= '}${minimum}`;
}
}
export function humanizeConstraints(schema: OpenAPISchema): string[] { export function humanizeConstraints(schema: OpenAPISchema): string[] {
const res: string[] = []; const res: string[] = [];
@ -433,33 +460,7 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
res.push(multipleOfConstraint); res.push(multipleOfConstraint);
} }
let numberRange; const numberRange = humanizeNumberRange(schema);
if (schema.minimum !== undefined && schema.maximum !== undefined) {
numberRange = schema.exclusiveMinimum ? '( ' : '[ ';
numberRange += schema.minimum;
numberRange += ' .. ';
numberRange += schema.maximum;
numberRange += schema.exclusiveMaximum ? ' )' : ' ]';
} else if (schema.maximum !== undefined) {
numberRange = schema.exclusiveMaximum ? '< ' : '<= ';
numberRange += schema.maximum;
} else if (schema.minimum !== undefined) {
numberRange = schema.exclusiveMinimum ? '> ' : '>= ';
numberRange += schema.minimum;
}
if (typeof schema.exclusiveMinimum === 'number' || typeof schema.exclusiveMaximum === 'number') {
let minimum = 0;
let maximum = 0;
if (schema.minimum) minimum = schema.minimum;
if (typeof schema.exclusiveMinimum === 'number') minimum = minimum <= schema.exclusiveMinimum ? minimum : schema.exclusiveMinimum;
if (schema.maximum) maximum = schema.maximum;
if (typeof schema.exclusiveMaximum === 'number') maximum = maximum > schema.exclusiveMaximum ? maximum : schema.exclusiveMaximum;
numberRange = `[${minimum} .. ${maximum}]`
}
if (numberRange !== undefined) { if (numberRange !== undefined) {
res.push(numberRange); res.push(numberRange);
} }
@ -589,10 +590,10 @@ export function setSecuritySchemePrefix(prefix: string) {
} }
export const shortenHTTPVerb = verb => export const shortenHTTPVerb = verb =>
({ ({
delete: 'del', delete: 'del',
options: 'opts', options: 'opts',
}[verb] || verb); }[verb] || verb);
export function isRedocExtension(key: string): boolean { export function isRedocExtension(key: string): boolean {
const redocExtensions = { const redocExtensions = {

View File

@ -32,10 +32,10 @@ const BANNER = `ReDoc - OpenAPI/Swagger-generated API Reference Documentation
Version: ${VERSION} Version: ${VERSION}
Repo: https://github.com/Redocly/redoc`; Repo: https://github.com/Redocly/redoc`;
export default (env: { standalone?: boolean } = {}) => ({ export default (env: { standalone?: boolean, browser?: boolean } = {}) => ({
entry: env.standalone ? ['./src/polyfills.ts', './src/standalone.tsx'] : './src/index.ts', entry: env.standalone ? ['./src/polyfills.ts', './src/standalone.tsx'] : './src/index.ts',
output: { output: {
filename: env.standalone ? 'redoc.standalone.js' : 'redoc.lib.js', filename: env.standalone ? 'redoc.standalone.js' : env.browser ? 'redoc.browser.lib.js' : 'redoc.lib.js',
path: path.join(__dirname, '/bundles'), path: path.join(__dirname, '/bundles'),
library: 'Redoc', library: 'Redoc',
libraryTarget: 'umd', libraryTarget: 'umd',
@ -47,13 +47,13 @@ export default (env: { standalone?: boolean } = {}) => ({
fallback: { fallback: {
path: require.resolve('path-browserify'), path: require.resolve('path-browserify'),
http: false, http: false,
fs: false, fs: path.resolve(__dirname, 'src/empty.js'),
os: false, os: path.resolve(__dirname, 'src/empty.js'),
tty: path.resolve(__dirname, 'src/empty.js'),
} }
}, },
performance: false, performance: false,
// target: 'node', externalsPresets: env.standalone || env.browser ? {} : { node: true },
externalsPresets: env.standalone ? {} : { node: true },
externals: env.standalone externals: env.standalone
? { ? {
esprima: 'null', esprima: 'null',