提交 8a1e447f 编写于 作者: R Robert Barnwell 提交者: GitHub

Merge branch 'master' into searchbar-update

root = true
[*]
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
{
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true,
"es6": true
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
}
},
"extends": ["eslint:recommended", "plugin:react/recommended"],
"plugins": [
"react"
],
"rules": {
"semi": [2, "never"],
"strict": 0,
"quotes": 2,
"no-unused-vars": 2,
"no-multi-spaces": 1,
"camelcase": 1,
"no-use-before-define": [2,"nofunc"],
"no-underscore-dangle": 0,
"no-unused-expressions": 1,
"comma-dangle": 0,
"no-console": ["error", { allow: ["warn", "error"] }],
"react/jsx-no-bind": 1,
"react/display-name": 0
}
}
When reporting an issue, please provide the following details:
- swagger-ui version
- a swagger file reproducing the issue
......@@ -3,3 +3,4 @@ node_modules
.deps_check
.DS_Store
npm-debug.log
.eslintcache
language: node_js
node_js:
- '6.9'
services:
- docker
branches:
only:
- master
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
before_deploy: "npm run build-core"
before_deploy:
- npm run build
env:
- DOCKER_IMAGE_NAME=swaggerapi/swagger-ui
deploy:
provider: npm
email: apiteam@swagger.io
skip_cleanup: true
api_key:
secure: "IJkLaACa+rfERf1O5nwlqOyuo9sbul3FBhBt4Un9P+DvEet3AoDPV9NQVLd8SkmQYKGbGQWF4BIdjrO5nqFD6Te+JTeUX5Uo/DFS/fu9qw1xv0dQpvbJFuoYnnFlbzGTEs4CFa8lbu3ZromFHQGOQxRobjsG1Kf0dWFSSzmND3g="
on:
tags: true
repo: swagger-api/swagger-ui
node: '6.9'
- provider: npm
email: apiteam@swagger.io
skip_cleanup: true
api_key:
secure: "IJkLaACa+rfERf1O5nwlqOyuo9sbul3FBhBt4Un9P+DvEet3AoDPV9NQVLd8SkmQYKGbGQWF4BIdjrO5nqFD6Te+JTeUX5Uo/DFS/fu9qw1xv0dQpvbJFuoYnnFlbzGTEs4CFa8lbu3ZromFHQGOQxRobjsG1Kf0dWFSSzmND3g="
on:
tags: true
repo: swagger-api/swagger-ui
node: '6.9'
- provider: script
skip_cleanup: true
script: swagger-ui-dist-package/deploy.sh
on:
tags: true
repo: swagger-api/swagger-ui
node: '6.9'
after_success:
- if [ $DOCKER_HUB_USERNAME ]; then
docker login --email=$DOCKER_HUB_EMAIL --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD;
if [ ! -z "$TRAVIS_TAG" ]; then
DOCKER_IMAGE_TAG=$TRAVIS_TAG;
else
DOCKER_IMAGE_TAG=unstable;
fi;
docker build -t $DOCKER_IMAGE_NAME .;
if [ ! -z "$TRAVIS_TAG" ]; then
docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:latest;
docker push $DOCKER_IMAGE_NAME:latest;
else
docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
fi;
fi;
......@@ -2,18 +2,27 @@ FROM alpine:3.4
MAINTAINER fehguy
ENV VERSION "v2.2.10"
ENV FOLDER "swagger-ui-2.2.10"
ENV API_URL "http://petstore.swagger.io/v2/swagger.json"
ENV API_KEY "**None**"
ENV OAUTH_CLIENT_ID "**None**"
ENV OAUTH_CLIENT_SECRET "**None**"
ENV OAUTH_REALM "**None**"
ENV OAUTH_APP_NAME "**None**"
ENV OAUTH_ADDITIONAL_PARAMS "**None**"
ENV SWAGGER_JSON "/app/swagger.json"
ENV PORT 80
RUN apk add --update nginx
RUN mkdir -p /run/nginx
COPY nginx.conf /etc/nginx/
# copy swagger files to the `/js` folder
ADD ./dist/ /usr/share/nginx/html/js
ADD ./public/index.html /usr/share/nginx/html
# change the folder structure
RUN sed -i 's/\.\.\/dist/js/g' /usr/share/nginx/html/index.html
ADD ./dist/* /usr/share/nginx/html/
ADD ./docker-run.sh /usr/share/nginx/
EXPOSE 8080
CMD exec nginx -g 'daemon off;'
CMD ["sh", "/usr/share/nginx/docker-run.sh"]
......@@ -4,7 +4,9 @@
## New!
This is the new version of swagger-ui, 3.x.
**This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).**
As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details.
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
......@@ -13,7 +15,7 @@ The OpenAPI Specification has undergone 4 revisions since initial creation in 20
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes | Status
------------------ | ------------ | -------------------------- | ----- | ------
3.0.1 | 2017-03-18 | 2.0 | [tag v3.0.1](https://github.com/swagger-api/swagger-ui/tree/v3.0.1) |
3.0.7 | 2017-03-19 | 2.0 | [tag v3.0.7](https://github.com/swagger-api/swagger-ui/tree/v3.0.7) |
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10) |
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5) |
2.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24) |
......@@ -37,14 +39,57 @@ Will start nginx with swagger-ui on port 80.
- Node 6.x
- NPM 3.x
If you just want to see your specs, open `public/index.html` in your browser directly from your filesystem.
If you just want to see your specs, open `dist/index.html` in your browser directly from your filesystem.
If you'd like to make modifications to the codebase, run the dev server with: `npm run dev`.
##### Browser support
Swagger UI works in the latest versions of Chrome, Safari, Firefox, Edge and IE11.
### Known Issues
To help with the migration, here are the currently known issues with 3.X. This list will update regularly, and will not include features that were not implemented in previous versions.
- Only part of the [parameters](#parameters) previously supported are available.
- The JSON Form Editor is not implemented.
- Shebang URL support for operations is missing.
- Support for `collectionFormat` is partial.
- l10n (translations) is not implemented.
- Relative path support for external files is not implemented.
### SwaggerUIBundle
To use swagger-ui's bundles, you should take a look at the [source of swagger-ui html page](https://github.com/swagger-api/swagger-ui/blob/master/dist/index.html) and customize it. This basically requires you to instantiate a SwaggerUi object as below:
```javascript
const ui = SwaggerUIBundle({
url: "http://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
```
If you'd like to use the bundle files via npm, check out the [`swagger-ui-dist` package](https://www.npmjs.com/package/swagger-ui-dist).
#### Parameters
Parameter Name | Description
--- | ---
url | The url pointing to API definition (normally `swagger.json` or `swagger.yaml`).
spec | A JSON object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them.
validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation.
dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger.
oauth2RedirectUrl | OAuth redirect URL
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
## CORS Support
CORS is a technique to prevent websites from doing bad things with your personal data. Most browsers + JavaScript toolkits not only support CORS but enforce it, which has implications for your API server which supports Swagger.
......
{
"name": "swagger-api/swagger-ui",
"description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.",
"keywords": [
"Swagger",
"OpenAPI",
"specification",
"documentation",
"API",
"UI"
],
"homepage": "http://swagger.io",
"license": "Apache-2.0",
"authors": [
{
"name": "Anna Bodnia",
"email": "anna.bodnia@gmail.com"
},
{
"name": "Buu Nguyen",
"email": "buunguyen@gmail.com"
},
{
"name": "Josh Ponelat",
"email": "jponelat@gmail.com"
},
{
"name": "Kyle Shockey",
"email": "kyleshockey1@gmail.com"
},
{
"name": "Robert Barnwell",
"email": "robert@robertismy.name"
},
{
"name": "Sahar Jafari",
"email": "shr.jafari@gmail.com"
}
]
}
<!-- HTML for dev server -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="../dist/swagger-ui.css" >
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
......@@ -66,18 +67,19 @@
<div id="swagger-ui"></div>
<script src="../dist/swagger-ui-bundle.js"> </script>
<script src="../dist/swagger-ui-standalone-preset.js"> </script>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
window["SwaggerUIBundle"] = window["swagger-ui-bundle"]
window["SwaggerUIStandalonePreset"] = window["swagger-ui-standalone-preset"]
// Build a system
const ui = SwaggerUIBundle({
url: "http://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
// yay ES6 modules ↘
Array.isArray(SwaggerUIStandalonePreset) ? SwaggerUIStandalonePreset : SwaggerUIStandalonePreset.default
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
......
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<!-- this is for the dev server -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
......@@ -64,9 +67,8 @@
<div id="swagger-ui"></div>
<!-- don't be alarmed, these don't match what's in dist, because webpack-dev-server serves them in memory. -->
<script src="/dist/SwaggerUIBundle.js"> </script>
<script src="/dist/SwaggerUIStandalonePreset.js"> </script>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Build a system
......@@ -75,8 +77,7 @@ window.onload = function() {
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
// yay ES6 modules ↘
Array.isArray(SwaggerUIStandalonePreset) ? SwaggerUIStandalonePreset : SwaggerUIStandalonePreset.default
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
......
......@@ -8,11 +8,13 @@
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var isValid, qp;
var isValid, qp, arr;
qp = (window.location.hash || location.search).substring(1);
qp = qp ? JSON.parse('{"' + qp.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
......@@ -33,51 +35,19 @@
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
createForm(oauth2.auth, qp).submit();
oauth2.callback(oauth2.auth);
} else {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: "Authorization failed: no accessCode came from the server"
message: "Authorization failed: no accessCode received from the server"
});
window.close();
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid});
window.close();
}
}
function createForm(auth, qp) {
var form = document.createElement("form");
var schema = auth.schema;
var action = schema.get("tokenUrl");
var name, input;
var fields = {
code: qp.code,
"redirect_uri": location.protocol + "//" + location.host + location.pathname,
"grant_type": "authorization_code",
"client_secret": auth.clientSecret,
"client_id": auth.clientId
}
for ( name in fields ) {
input = document.createElement("input");
input.name = name;
input.value = fields[name];
input.type = "hidden";
form.appendChild(input);
}
form.method = "POST";
form.action = action;
document.body.appendChild(form);
return form;
window.close();
}
</script>
此差异已折叠。
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;AA6OA;;;;;;AAoIA;AAm7FA;AAwtCA;AAg0IA;;;;;AAkxBA;AAo8IA;AA41GA;AA23FA;AAqqFA;AA0nFA;AA49CA;AAwhDA;AAkrCA;AAumFA;AAmnHA;;;;;;;;;;;;;;AAqjHA;AAyoIA;AAkuJA;AAilHA;AA4kGA;AAwkEA;AAs3DA;AAovDA;AAotBA;AAoqGA;;;;;;AAueA;AAimGA;AA44EA;;;;;AAoGA;AA2qFA;AAo2CA;AAkvDA;AA8tCA;AAoiEA;AA69FA;;;;;;;;;AA20BA;AA2zIA;AAm4DA","sourceRoot":""}
\ No newline at end of file
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;AAu/FA;AA++FA;;;;;;;;;;;;;;;;;;;;;;;;;;AAgeA;;;;;;AAoIA;AAk7FA;AAmtCA;;;;;AA0uIA;AAg2IA;AA64FA;AAiyGA;AA2mFA;AA4nFA;AA+9CA;AA+gDA;AAwrCA;AA60EA;AA66HA;;;;;;;;;;;;;;AA0wIA;AA4mIA;AAquJA;AAwsHA;AA2mGA;AAiiEA;AAq4DA;AA+2DA;AA4lBA;;;;;;AA0kFA;AAs1FA;;;;;AAy3CA;AA2qFA;AAw2CA;AAwkCA;AAs/CA;AA4kFA;AAy1FA;;;;;;;;;AAm5CA;AA2zIA;AAk4DA;AAolDA","sourceRoot":""}
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA0SA;AAyiGA;AAqwFA;;;;;;AA4eA;AAkvFA;AAu+CA;AAo+CA;AAgrCA;AAgyEA","sourceRoot":""}
\ No newline at end of file
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA4QA;AAitGA","sourceRoot":""}
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;AAooGA;AA20HA;AAgjGA;AA6lCA;AA69BA;AAmwCA;AAw4BA","sourceRoot":""}
\ No newline at end of file
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AA0xCA;AAoyHA;AAuxHA;AAy4FA;AA2sCA;AAmgCA;AA0iCA;AA+3BA","sourceRoot":""}
\ No newline at end of file
#! /bin/sh
set -e
INDEX_FILE=/usr/share/nginx/html/index.html
replace_in_index () {
if [ "$1" != "**None**" ]; then
sed -i "s|/\*||g" $INDEX_FILE
sed -i "s|\*/||g" $INDEX_FILE
sed -i "s|$1|$2|g" $INDEX_FILE
fi
}
replace_or_delete_in_index () {
if [ -z "$2" ]; then
sed -i "/$1/d" $INDEX_FILE
else
replace_in_index $1 $2
fi
}
replace_in_index myApiKeyXXXX123456789 $API_KEY
replace_or_delete_in_index your-client-id $OAUTH_CLIENT_ID
replace_or_delete_in_index your-client-secret-if-required $OAUTH_CLIENT_SECRET
replace_or_delete_in_index your-realms $OAUTH_REALM
replace_or_delete_in_index your-app-name $OAUTH_APP_NAME
if [ "$OAUTH_ADDITIONAL_PARAMS" != "**None**" ]; then
replace_in_index "additionalQueryStringParams: {}" "additionalQueryStringParams: {$OAUTH_ADDITIONAL_PARAMS}"
fi
if [[ -f $SWAGGER_JSON ]]; then
sed -i "s|http://petstore.swagger.io/v2/swagger.json|swagger.json|g" $INDEX_FILE
sed -i "s|http://example.com/api|swagger.json|g" $INDEX_FILE
else
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$API_URL|g" $INDEX_FILE
sed -i "s|http://example.com/api|$API_URL|g" $INDEX_FILE
fi
if [[ -n "$VALIDATOR_URL" ]]; then
sed -i "s|.*validatorUrl:.*$||g" $INDEX_FILE
TMP_VU="$VALIDATOR_URL"
[[ "$VALIDATOR_URL" != "null" && "$VALIDATOR_URL" != "undefined" ]] && TMP_VU="\"${VALIDATOR_URL}\""
sed -i "s|\(url: .*,\)|\1\n validatorUrl: ${TMP_VU},|g" $INDEX_FILE
unset TMP_VU
fi
exec nginx -g 'daemon off;'
......@@ -59,7 +59,7 @@ module.exports = function(options) {
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: specialOptions.minimize ? JSON.stringify('production') : null,
WEBPACK_INLINE_STYLES: !Boolean(specialOptions.separateStylesheets)
WEBPACK_INLINE_STYLES: !Boolean(specialOptions.separateStylesheets)
},
}))
......
{
"name": "swagger-ui",
"version": "3.0.1",
"version": "3.0.7",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
......@@ -14,7 +14,6 @@
],
"license": "Apache-2.0",
"scripts": {
"start": "http-server -i -a 0.0.0.0 -p 3001",
"build": "npm run build-core && npm run build-bundle && npm run build-standalone",
"build-bundle": "webpack --config webpack-dist-bundle.config.js --colors",
"build-core": "webpack --config webpack-dist.config.js --colors",
......@@ -23,22 +22,28 @@
"dev": "npm-run-all --parallel hot-server watch open-localhost",
"watch": "webpack --config webpack-watch.config.js --watch --progress",
"open-localhost": "node -e 'require(\"open\")(\"http://localhost:3200\")'",
"hot-server": "webpack-dev-server --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress --content-base dist/",
"hot-server": "webpack-dev-server --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress --content-base dev-helpers/",
"deps-license": "license-checker --production --csv --out $npm_package_config_deps_check_dir/licenses.csv && license-checker --development --csv --out $npm_package_config_deps_check_dir/licenses-dev.csv",
"deps-size": "webpack -p --config webpack.check.js --json | webpack-bundle-size-analyzer >| $npm_package_config_deps_check_dir/sizes.txt",
"deps-check": "npm run deps-license && npm run deps-size",
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core"
"lint": "eslint --cache --ext '.js,.jsx' src test",
"lint-errors": "eslint --cache --quiet --ext '.js,.jsx' src test",
"lint-fix": "eslint --cache --ext '.js,.jsx' src test --fix",
"test": "npm run lint-errors && npm run just-test-in-node",
"test-in-node": "npm run lint-errors && npm run just-test-in-node",
"just-test": "karma start --config karma.conf.js",
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components"
},
"dependencies": {
"babel-polyfill": "^6.23.0",
"base64-js": "^1.2.0",
"brace": "0.7.0",
"btoa": "^1.1.2",
"debounce": "1.0.0",
"deep-extend": "0.4.1",
"expect": "1.20.2",
"getbase": "^2.8.2",
"ieee754": "^1.1.8",
"immutable": "^3.x.x",
"js-yaml": "^3.5.5",
"jsonschema": "^1.1.0",
"less": "2.7.1",
"lodash": "4.17.2",
"matcher": "^0.1.2",
......@@ -47,7 +52,7 @@
"react": "^15.4.0",
"react-addons-perf": "0.14.8",
"react-addons-shallow-compare": "0.14.8",
"react-addons-test-utils": "0.14.8",
"react-addons-test-utils": "^15.4.0",
"react-collapse": "2.3.1",
"react-dom": "^15.4.0",
"react-height": "^2.0.0",
......@@ -64,12 +69,12 @@
"reselect": "2.5.3",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "^3.0.1",
"swagger-client": "^3.0.7",
"url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1",
"xml": "1.0.1",
"yaml-js": "^0.1.3",
"yaml-worker": "^2.1.0"
"yaml-js": "^0.1.3"
},
"devDependencies": {
"autoprefixer": "6.6.1",
......@@ -85,11 +90,19 @@
"css-loader": "0.22.0",
"deep-extend": "^0.4.1",
"deepmerge": "^1.3.2",
"enzyme": "^2.7.1",
"eslint": "^2.13.1",
"eslint-plugin-react": "^6.10.3",
"extract-text-webpack-plugin": "0.8.2",
"file-loader": "0.8.4",
"html-webpack-plugin": "^2.28.0",
"imports-loader": "0.6.5",
"json-loader": "0.5.3",
"karma": "^0.13.22",
"karma-chrome-launcher": "^0.2.3",
"karma-mocha": "^0.2.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "1.8.0",
"less": "2.5.3",
"less-loader": "2.2.1",
"license-checker": "^8.0.4",
......@@ -101,6 +114,7 @@
"postcss-loader": "0.7.0",
"raw-loader": "0.5.1",
"react-hot-loader": "^1.3.1",
"react-test-renderer": "^15.5.4",
"rimraf": "^2.6.0",
"sass-loader": "^6.0.2",
"standard": "^8.6.0",
......
name: swagger-ui
version: master
summary: The World's Most Popular API Framework
description: |
Swagger UI is part of the Swagger project. The Swagger project allows you to
produce, visualize and consume your OWN RESTful services. No proxy or 3rd
party services required. Do it your own way.
Swagger UI is a dependency-free collection of HTML, Javascript, and CSS
assets that dynamically generate beautiful documentation and sandbox from a
Swagger-compliant API. Because Swagger UI has no dependencies, you can host
it in any server environment, or on your local machine.
grade: devel
confinement: strict
apps:
swagger-ui:
command: sh -c \"cd $SNAP/lib/node_modules/swagger-ui/dist && http-server -a localhost -p 8080\"
daemon: simple
plugs: [network, network-bind]
parts:
swagger-ui:
source: .
plugin: nodejs
npm-run: [build]
node-packages: [handlebars, http-server]
......@@ -64,11 +64,10 @@ export default class ApiKeyAuth extends React.Component {
</Row>
<Row>
<label>Value:</label>
<Col>
{
value || <Input type="text" onChange={ this.onChange }/>
}
</Col>
{
value ? <code> ****** </code>
: <Col><Input type="text" onChange={ this.onChange }/></Col>
}
</Row>
{
errors.valueSeq().map( (error, key) => {
......
......@@ -6,7 +6,7 @@ export default class AuthorizeBtn extends React.Component {
}
onClick =() => {
let { authActions, authSelectors, errActions} = this.props
let { authActions, authSelectors } = this.props
let definitions = authSelectors.definitionsToAuthorize()
authActions.showDefinitions(definitions)
......
......@@ -16,6 +16,10 @@ export default class AuthorizeOperationBtn extends React.Component {
let isAuthorized = authSelectors.isAuthorized(security)
if(isAuthorized === null) {
return null
}
return (
<button className={isAuthorized ? "authorization__btn locked" : "authorization__btn unlocked"} onClick={ this.onClick }>
<svg width="20" height="20">
......
......@@ -42,14 +42,12 @@ export default class Auths extends React.Component {
}
render() {
let { definitions, getComponent, authSelectors, errSelectors, specSelectors } = this.props
let { definitions, getComponent, authSelectors, errSelectors } = this.props
const ApiKeyAuth = getComponent("apiKeyAuth")
const BasicAuth = getComponent("basicAuth")
const Oauth2 = getComponent("oauth2", true)
const Button = getComponent("Button")
const JumpToPath = getComponent("JumpToPath", true)
let specStr = specSelectors.specStr()
let authorized = authSelectors.authorized()
let authorizedAuth = definitions.filter( (definition, key) => {
......
......@@ -63,19 +63,23 @@ export default class BasicAuth extends React.Component {
source={ schema.get("description") } />
</Row>
<Row>
<Col tablet={2} desktop={2}>username:</Col>
<Col tablet={10} desktop={10}>
<label>Username:</label>
{
username ? <code> { username } </code>
: <Col><Input type="text" required="required" name="username" onChange={ this.onChange }/></Col>
}
</Row>
<Row>
<label>Password:</label>
{
username || <Input type="text" required="required" name="username" onChange={ this.onChange }/>
username ? <code> ****** </code>
: <Col><Input required="required"
autoComplete="new-password"
name="password"
type="password"
onChange={ this.onChange }/></Col>
}
</Col>
</Row>
{
!username && <Row>
<Col tablet={2} desktop={2}>password:</Col>
<Col tablet={10} desktop={10}><Input required="required" autoComplete="new-password" name="password" type="password" onChange={ this.onChange }/></Col>
</Row>
}
{
errors.valueSeq().map( (error, key) => {
return <AuthError error={ error }
......
......@@ -10,13 +10,13 @@ export default class Oauth2 extends React.Component {
static propTypes = {
name: PropTypes.string,
authorized: PropTypes.object,
configs: PropTypes.object,
getComponent: PropTypes.func.isRequired,
schema: PropTypes.object.isRequired,
authSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
errSelectors: PropTypes.object.isRequired,
errActions: PropTypes.object.isRequired
errActions: PropTypes.object.isRequired,
getConfigs: PropTypes.any
}
constructor(props, context) {
......@@ -26,7 +26,7 @@ export default class Oauth2 extends React.Component {
let username = auth && auth.get("username") || ""
let clientId = auth && auth.get("clientId") || ""
let clientSecret = auth && auth.get("clientSecret") || ""
let passwordType = auth && auth.get("passwordType") || "none"
let passwordType = auth && auth.get("passwordType") || "basic"
this.state = {
name: name,
......@@ -108,71 +108,74 @@ export default class Oauth2 extends React.Component {
<p className="flow">Flow: <code>{ schema.get("flow") }</code></p>
{
flow === PASSWORD && ( !isAuthorized || isAuthorized && this.state.username) && <Row>
<Col tablet={2} desktop={2}>username:</Col>
<Col tablet={10} desktop={10}>
flow !== PASSWORD ? null
: <Row>
<Row>
<label htmlFor="oauth_username">username:</label>
{
isAuthorized ? <code> { this.state.username } </code>
: <Col tablet={10} desktop={10}>
<input id="oauth_username" type="text" data-name="username" onChange={ this.onInputChange }/>
</Col>
}
</Row>
{
isAuthorized ? <span>{ this.state.username }</span>
: <input type="text" data-name="username" onChange={ this.onInputChange }/>
}
</Col>
</Row>
}
{
flow === PASSWORD && !isAuthorized && <Row>
<Col tablet={2} desktop={2}>password:</Col>
<Col tablet={10} desktop={10}>
<input type="password" data-name="password" onChange={ this.onInputChange }/>
</Col>
</Row>
}
{
flow === PASSWORD && <Row>
<Col tablet={2} desktop={2}>type:</Col>
<Col tablet={10} desktop={10}>
{
isAuthorized ? <span>{ this.state.passwordType }</span>
: <select data-name="passwordType" onChange={ this.onInputChange }>
<option value="none">None or other</option>
<option value="basic">Basic auth</option>
<option value="request">Request body</option>
</select>
}
</Col>
</Row>
<Row>
<label htmlFor="oauth_password">password:</label>
{
isAuthorized ? <code> ****** </code>
: <Col tablet={10} desktop={10}>
<input id="oauth_password" type="password" data-name="password" onChange={ this.onInputChange }/>
</Col>
}
</Row>
<Row>
<label htmlFor="password_type">type:</label>
{
isAuthorized ? <code> { this.state.passwordType } </code>
: <Col tablet={10} desktop={10}>
<select id="password_type" data-name="passwordType" onChange={ this.onInputChange }>
<option value="basic">Basic auth</option>
<option value="request-body">Request body</option>
<option value="query">Query parameters</option>
</select>
</Col>
}
</Row>
</Row>
}
{
( flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) &&
( flow === APPLICATION || flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "basic") ) &&
( !isAuthorized || isAuthorized && this.state.clientId) && <Row>
<label htmlFor="client_id">client_id:</label>
<Col tablet={10} desktop={10}>
{
isAuthorized ? <span>{ this.state.clientId }</span>
: <input id="client_id" type="text" required={ flow === PASSWORD } data-name="clientId"
{
isAuthorized ? <code> ****** </code>
: <Col tablet={10} desktop={10}>
<input id="client_id" type="text" required={ flow === PASSWORD } data-name="clientId"
onChange={ this.onInputChange }/>
}
</Col>
</Col>
}
</Row>
}
{
( flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && <Row>
( flow === APPLICATION || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "basic") ) && <Row>
<label htmlFor="client_secret">client_secret:</label>
<Col tablet={10} desktop={10}>
{
isAuthorized ? <span>{ this.state.clientSecret }</span>
: <input id="client_secret" type="text" data-name="clientSecret"
{
isAuthorized ? <code> ****** </code>
: <Col tablet={10} desktop={10}>
<input id="client_secret" type="text" data-name="clientSecret"
onChange={ this.onInputChange }/>
}
</Col>
</Col>
}
</Row>
}
{
!isAuthorized && flow !== PASSWORD && scopes && scopes.size ? <div className="scopes">
!isAuthorized && scopes && scopes.size ? <div className="scopes">
<h2>Scopes:</h2>
{ scopes.map((description, name) => {
return (
......@@ -205,7 +208,7 @@ export default class Oauth2 extends React.Component {
} )
}
<div className="auth-btn-wrapper">
{ isValid && flow !== APPLICATION &&
{ isValid &&
( isAuthorized ? <Button className="btn modal-btn auth authorize" onClick={ this.logout }>Logout</Button>
: <Button className="btn modal-btn auth authorize" onClick={ this.authorize }>Authorize</Button>
)
......
import React, { PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
import { fromJS } from 'immutable'
import { fromJS } from "immutable"
const noop = ()=>{}
......
......@@ -19,7 +19,7 @@ export default class Curl extends React.Component {
<div>
<h4>Curl</h4>
<div className="copy-paste">
<textarea onFocus={this.handleFocus} className="curl" style={{ whiteSpace: "normal" }} defaultValue={curl}></textarea>
<textarea onFocus={this.handleFocus} className="curl" style={{ whiteSpace: "normal" }} value={curl}></textarea>
</div>
</div>
)
......
import React, { PropTypes } from "react"
import Im, { List } from "immutable"
import { List } from "immutable"
import Collapse from "react-collapse"
import sortBy from "lodash/sortBy"
export default class Errors extends React.Component {
......@@ -69,7 +68,7 @@ const ThrownErrorItem = ( { error, jumpToLine } ) => {
{ error.get("message") }
</span>
<div>
{ errorLine ? <a onClick={jumpToLine.bind(null, errorLine)}>Jump to line { errorLine }</a> : null }
{ errorLine && jumpToLine ? <a onClick={jumpToLine.bind(null, errorLine)}>Jump to line { errorLine }</a> : null }
</div>
</div>
}
......@@ -78,11 +77,23 @@ const ThrownErrorItem = ( { error, jumpToLine } ) => {
}
const SpecErrorItem = ( { error, jumpToLine } ) => {
let locationMessage = null
if(error.get("path")) {
if(List.isList(error.get("path"))) {
locationMessage = <small>at { error.get("path").join(".") }</small>
} else {
locationMessage = <small>at { error.get("path") }</small>
}
} else if(error.get("line") && !jumpToLine) {
locationMessage = <small>on line { error.get("line") }</small>
}
return (
<div className="error-wrapper">
{ !error ? null :
<div>
<h4>{ toTitleCase(error.get("source")) + " " + error.get("level") }{ error.get("path") ? <small> at {List.isList(error.get("path")) ? error.get("path").join(".") : error.get("path")}</small>: null }</h4>
<h4>{ toTitleCase(error.get("source")) + " " + error.get("level") }&nbsp;{ locationMessage }</h4>
<span style={{ whiteSpace: "pre-line"}}>{ error.get("message") }</span>
<div>
{ jumpToLine ? (
......@@ -107,6 +118,10 @@ ThrownErrorItem.propTypes = {
jumpToLine: PropTypes.func
}
ThrownErrorItem.defaultProps = {
jumpToLine: null
}
SpecErrorItem.propTypes = {
error: PropTypes.object.isRequired,
jumpToLine: PropTypes.func
......
import React, { Component, PropTypes } from "react"
import { fromJS } from "immutable"
export default class Execute extends Component {
......@@ -29,9 +28,6 @@ export default class Execute extends Component {
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val)
render(){
let { getComponent, operation, specActions, path, method } = this.props
const ContentType = getComponent( "contentType" )
return (
<button className="btn execute opblock-control__btn" onClick={ this.onClick }>
Execute
......
......@@ -58,7 +58,7 @@ class License extends React.Component {
return (
<div>
{
url ? <a href={ url }>{ name }</a>
url ? <a target="_blank" href={ url }>{ name }</a>
: <span>{ name }</span>
}
</div>
......@@ -95,7 +95,7 @@ export default class Info extends React.Component {
{ version && <small><pre className="version"> { version } </pre></small> }
</h2>
{ host || basePath ? <Path host={ host } basePath={ basePath } /> : null }
{ url && <a href={ url }><span className="url"> { url } </span></a> }
{ url && <a target="_blank" href={ url }><span className="url"> { url } </span></a> }
</hgroup>
<div className="description">
......@@ -104,7 +104,7 @@ export default class Info extends React.Component {
{
termsOfService && <div>
<a href={ termsOfService }>Terms of service</a>
<a target="_blank" href={ termsOfService }>Terms of service</a>
</div>
}
......
......@@ -2,8 +2,6 @@ import React, { PropTypes } from "react"
import OriCollapse from "react-collapse"
import _Markdown from "react-remarkable"
const noop = () => {}
function xclass(...args) {
return args.filter(a => !!a).join(" ").trim()
}
......@@ -18,7 +16,7 @@ export class Container extends React.Component {
if(fullscreen)
return <section {...rest}/>
let containerClass = "container" + (full ? "-full" : "")
let containerClass = "swagger-container" + (full ? "-full" : "")
return (
<section {...rest} className={xclass(rest.className, containerClass)}/>
)
......@@ -44,12 +42,14 @@ export class Col extends React.Component {
const {
hide,
keepContents,
mobile, /* we don't want these in the final component, since React now complains. So we extract them */
/* we don't want these in the `rest` object that passes to the final component,
since React now complains. So we extract them */
/* eslint-disable no-unused-vars */
mobile,
tablet,
desktop,
large,
/* eslint-enable no-unused-vars */
...rest
} = this.props
......
import React, { PropTypes } from "react"
export default class BaseLayout extends React.Component {
static propTypes = {
errSelectors: PropTypes.object.isRequired,
errActions: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
}
render() {
let { specSelectors, specActions, getComponent } = this.props
let info = specSelectors.info()
let url = specSelectors.url()
let basePath = specSelectors.basePath()
let host = specSelectors.host()
let securityDefinitions = specSelectors.securityDefinitions()
let externalDocs = specSelectors.externalDocs()
let schemes = specSelectors.schemes()
let Info = getComponent("info")
let Operations = getComponent("operations", true)
let Models = getComponent("models", true)
let AuthorizeBtn = getComponent("authorizeBtn", true)
let Row = getComponent("Row")
let Col = getComponent("Col")
let Errors = getComponent("errors", true)
const Schemes = getComponent("schemes")
const isSpecEmpty = !specSelectors.specStr()
if(isSpecEmpty) {
return <h4>No spec provided.</h4>
}
return (
<div className='swagger-ui'>
<div>
<Errors/>
<Row className="information-container">
<Col mobile={12}>
{ info.count() ? (
<Info info={ info } url={ url } host={ host } basePath={ basePath } externalDocs={externalDocs} getComponent={getComponent}/>
) : null }
</Col>
</Row>
{ schemes && schemes.size || securityDefinitions ? (
<div className="scheme-container">
<Col className="schemes wrapper" mobile={12}>
{ schemes && schemes.size ? (
<Schemes schemes={ schemes } specActions={ specActions } />
) : null }
{ securityDefinitions ? (
<AuthorizeBtn />
) : null }
</Col>
</div>
) : null }
<Row>
<Col mobile={12} desktop={12} >
<Operations/>
</Col>
</Row>
<Row>
<Col mobile={12} desktop={12} >
<Models/>
</Col>
</Row>
</div>
</div>
)
}
}
import React, { Component, PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
import isObject from "lodash/isObject"
import { List } from "immutable"
const braceOpen = "{"
const braceClose = "}"
const propStyle = { color: "#999", fontStyle: "italic" }
const EnumModel = ({ value }) => {
let collapsedContent = <span>Array [ { value.count() } ]</span>
return <span className="prop-enum">
......@@ -128,10 +129,8 @@ class Primitive extends Component {
let format = schema.get("format")
let xml = schema.get("xml")
let enumArray = schema.get("enum")
let description = schema.get("description")
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "$$ref"].indexOf(key) === -1 )
let style = required ? { fontWeight: "bold" } : {}
let propStyle = { color: "#999", fontStyle: "italic" }
return <span className="prop">
<span className="prop-type" style={ style }>{ type }</span> { required && <span style={{ color: "red" }}>*</span>}
......@@ -169,12 +168,23 @@ class ArrayModel extends Component {
render(){
let { required, schema, depth, expandDepth } = this.props
let items = schema.get("items")
let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 )
return <span>
return <span className="model">
<span className="model-title">
<span className="model-title__text">{ schema.get("title") }</span>
</span>
<Collapse collapsed={ depth > expandDepth } collapsedContent="[...]">
[
<span><Model { ...this.props } schema={ items } required={ false }/></span>
]
{
properties.size ? <span>
{ properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={propStyle}>
<br />{ `${key}:`}{ String(v) }</span>)
}<br /></span>
: null
}
</Collapse>
{ required && <span style={{ color: "red" }}>*</span>}
</span>
......@@ -251,9 +261,6 @@ export default class ModelComponent extends Component {
}
render(){
let { name, schema } = this.props
let title = schema.get("title") || name
return <div className="model-box">
<Model { ...this.props } depth={ 1 } expandDepth={ this.props.expandDepth || 0 }/>
</div>
......
......@@ -4,13 +4,15 @@ import React, { Component, PropTypes } from "react"
export default class Models extends Component {
static propTypes = {
getComponent: PropTypes.func,
specSelectors: PropTypes.object
specSelectors: PropTypes.object,
layoutSelectors: PropTypes.object,
layoutActions: PropTypes.object
}
render(){
let { specSelectors, getComponent, layoutSelectors, layoutActions } = this.props
let definitions = specSelectors.definitions()
let showModels = layoutSelectors.isShown('models', true)
let showModels = layoutSelectors.isShown("models", true)
const Model = getComponent("model")
const Collapse = getComponent("Collapse")
......@@ -18,7 +20,7 @@ export default class Models extends Component {
if (!definitions.size) return null
return <section className={ showModels ? "models is-open" : "models"}>
<h4 onClick={() => layoutActions.show('models', !showModels)}>
<h4 onClick={() => layoutActions.show("models", !showModels)}>
<span>Models</span>
<svg width="20" height="20">
<use xlinkHref="#large-arrow" />
......
import React from "react"
import React, { PropTypes } from "react"
export default class OnlineValidatorBadge extends React.Component {
static propTypes = {
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired
}
constructor(props, context) {
super(props, context)
let { specSelectors, getConfigs } = props
let { validatorUrl } = getConfigs()
this.state = {
url: specSelectors.url(),
validatorUrl: validatorUrl
validatorUrl: validatorUrl === undefined ? "https://online.swagger.io/validator" : validatorUrl
}
}
......@@ -17,7 +23,7 @@ export default class OnlineValidatorBadge extends React.Component {
this.setState({
url: specSelectors.url(),
validatorUrl: validatorUrl
validatorUrl: validatorUrl === undefined ? "https://online.swagger.io/validator" : validatorUrl
})
}
......@@ -27,14 +33,72 @@ export default class OnlineValidatorBadge extends React.Component {
if ( typeof spec === "object" && Object.keys(spec).length) return null
if (!this.state.url) {
if (!this.state.url || !this.state.validatorUrl || this.state.url.indexOf("localhost") >= 0
|| this.state.url.indexOf("127.0.0.1") >= 0) {
return null
}
return (<span style={{ float: "right"}}>
return (<span style={{ float: "right"}}>
<a target="_blank" href={`${ this.state.validatorUrl }/debug?url=${ this.state.url }`}>
<img alt="Online validator badge" src={`${ this.state.validatorUrl }?url=${ this.state.url }`} />
<ValidatorImage src={`${ this.state.validatorUrl }?url=${ this.state.url }`} alt="Online validator badge"/>
</a>
</span>)
}
}
class ValidatorImage extends React.Component {
static propTypes = {
src: PropTypes.string,
alt: PropTypes.string
}
constructor(props) {
super(props)
this.state = {
loaded: false,
error: false
}
}
componentDidMount() {
const img = new Image()
img.onload = () => {
this.setState({
loaded: true
})
}
img.onerror = () => {
this.setState({
error: true
})
}
img.src = this.props.src
}
componentWillReceiveProps(nextProps) {
if (nextProps.src !== this.props.src) {
const img = new Image()
img.onload = () => {
this.setState({
loaded: true
})
}
img.onerror = () => {
this.setState({
error: true
})
}
img.src = nextProps.src
}
}
render() {
if (this.state.error) {
return <img alt={"Error"} />
} else if (!this.state.loaded) {
return <img alt= {"Loading..."} />
}
return <img src={this.props.src} alt={this.props.alt} />
}
}
import React, { PropTypes } from "react"
import { Map, fromJS } from "immutable"
import shallowCompare from "react-addons-shallow-compare"
import { getList } from "core/utils"
import * as CustomPropTypes from "core/proptypes"
......@@ -112,9 +111,7 @@ export default class Operation extends React.Component {
specActions,
specSelectors,
authActions,
authSelectors,
layoutSelectors,
layoutActions,
authSelectors
} = this.props
let summary = operation.get("summary")
......@@ -205,11 +202,12 @@ export default class Operation extends React.Component {
pathMethod={ [path, method] }
/>
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <Schemes schemes={ schemes }
path={ path }
method={ method }
specActions={ specActions }/>
: null
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
<Schemes schemes={ schemes }
path={ path }
method={ method }
specActions={ specActions }/>
</div> : null
}
<div className={(!tryItOutEnabled || !response || !allowTryItOut) ? "execute-wrapper" : "btn-group"}>
......
import React, { PropTypes } from "react"
import {presets} from "react-motion"
export default class Operations extends React.Component {
......@@ -33,7 +32,6 @@ export default class Operations extends React.Component {
const Operation = getComponent("operation")
const Collapse = getComponent("Collapse")
const Schemes = getComponent("schemes")
let showSummary = layoutSelectors.showSummary()
......@@ -59,12 +57,6 @@ export default class Operations extends React.Component {
</small>
}
<button className="expand-methods" title="Expand all methods">
<svg className="expand" width="20" height="20">
<use xlinkHref="#expand" />
</svg>
</button>
<button className="expand-operation" title="Expand operation" onClick={() => layoutActions.show(isShownKey, !showTag)}>
<svg className="arrow" width="20" height="20">
<use xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
......
......@@ -30,7 +30,6 @@ export default class Overview extends React.Component {
{
taggedOps.map( (tagObj, tag) => {
let operations = tagObj.get("operations")
let tagDetails = tagObj.get("tagDetails")
let showTagId = ["overview-tags", tag]
let showTag = layoutSelectors.isShown(showTagId, true)
......@@ -45,7 +44,7 @@ export default class Overview extends React.Component {
<Collapse isOpened={showTag} animated>
{
operations.map( op => {
let { path, method, operation, id } = op.toObject() // toObject is shallow
let { path, method, id } = op.toObject() // toObject is shallow
let showOpIdPrefix = "operations"
let showOpId = id
let shown = layoutSelectors.isShown([showOpIdPrefix, showOpId])
......
import React, { Component, PropTypes } from "react"
import shallowCompare from "react-addons-shallow-compare"
import { Set, fromJS, List } from "immutable"
import { fromJS, List } from "immutable"
import { getSampleSchema } from "core/utils"
const NOOP = Function.prototype
......@@ -50,14 +50,15 @@ export default class ParamBody extends Component {
}
updateValues = (props) => {
let { specSelectors, pathMethod, param, isExecute, consumesValue="", onChangeConsumes } = props
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : {}
let isXml = /xml/i.test(consumesValue)
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
if ( paramValue ) {
this.setState({ value: paramValue })
this.onChange(paramValue, {isXml: isXml, isEditBox: isExecute})
if ( paramValue !== undefined ) {
let val = !paramValue && !isXml ? "{}" : paramValue
this.setState({ value: val })
this.onChange(val, {isXml: isXml, isEditBox: isExecute})
} else {
if (isXml) {
this.onChange(this.sample("xml"), {isXml: isXml, isEditBox: isExecute})
......
import React, { Component, PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
import Im, { fromJS } from "immutable"
import Im from "immutable"
// More readable, just iterate over maps, only
const eachMap = (iterable, fn) => iterable.valueSeq().filter(Im.Map.isMap).map(fn)
......@@ -87,7 +87,7 @@ export default class Parameters extends Component {
</thead>
<tbody>
{
eachMap(parameters, (parameter, k) => (
eachMap(parameters, (parameter) => (
<ParameterRow fn={ fn }
getComponent={ getComponent }
param={ parameter }
......
import React, { PropTypes } from "react"
import { fromJS } from 'immutable'
import { fromJS } from "immutable"
import { getSampleSchema } from "core/utils"
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
if ( examples && examples.size ) {
return examples.entrySeq().map( ([ key, example ]) => {
let exampleValue
try {
exampleValue = example && example.toJS ? example.toJS() : example
exampleValue = JSON.stringify(exampleValue)
}
catch(e) {
exampleValue = String(example)
}
return (<div key={ key }>
<h5>{ key }</h5>
<HighlightCode className="example" value={ example } />
<HighlightCode className="example" value={ exampleValue } />
</div>)
}).toArray()
}
......
......@@ -17,8 +17,6 @@ export default class Schemes extends React.Component {
}
onChange =( e ) => {
let { path, method, specActions } = this.props
this.setScheme( e.target.value )
}
......@@ -33,7 +31,7 @@ export default class Schemes extends React.Component {
return (
<label htmlFor="schemes">
<span>Schemes</span>
<span className="schemes-title">Schemes</span>
<select onChange={ this.onChange }>
{ schemes.valueSeq().map(
( scheme ) => <option value={ scheme } key={ scheme }>{ scheme }</option>
......
......@@ -4,11 +4,13 @@ export default class TryItOutButton extends React.Component {
static propTypes = {
onTryoutClick: PropTypes.func,
onCancelClick: PropTypes.func,
enabled: PropTypes.bool, // Try it out is enabled, ie: the user has access to the form
};
static defaultProps = {
onTryoutClick: Function.prototype,
onCancelClick: Function.prototype,
enabled: false,
};
......
......@@ -4,7 +4,7 @@ export default function curl( request ){
let headers = request.get("headers")
curlified.push( "curl" )
curlified.push( "-X", request.get("method") )
curlified.push( request.get("url") )
curlified.push( `"${request.get("url")}"`)
if ( headers && headers.size ) {
for( let p of request.get("headers").entries() ){
......
......@@ -4,6 +4,7 @@ import System from "core/system"
import ApisPreset from "core/presets/apis"
import * as AllPlugins from "core/plugins/all"
import { filterConfigs } from "plugins/configs"
import { parseSeach } from "core/utils"
module.exports = function SwaggerUI(opts) {
......@@ -12,9 +13,9 @@ module.exports = function SwaggerUI(opts) {
dom_id: null,
spec: {},
url: "",
layout: "Layout",
layout: "BaseLayout",
validatorUrl: "https://online.swagger.io/validator",
configs: {
validatorUrl: "https://online.swagger.io/validator"
},
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
......@@ -35,79 +36,73 @@ module.exports = function SwaggerUI(opts) {
store: { },
}
const config = deepExtend({}, defaults, opts)
const constructorConfig = deepExtend({}, defaults, opts)
const storeConfigs = deepExtend({}, config.store, {
const storeConfigs = deepExtend({}, constructorConfig.store, {
system: {
configs: config.configs
configs: constructorConfig.configs
},
plugins: config.presets,
plugins: constructorConfig.presets,
state: {
layout: {
layout: config.layout
layout: constructorConfig.layout
},
spec: {
spec: "",
url: config.url
url: constructorConfig.url
}
}
})
let inlinePlugin = ()=> {
return {
fn: config.fn,
components: config.components,
state: config.state,
fn: constructorConfig.fn,
components: constructorConfig.components,
state: constructorConfig.state,
}
}
var store = new System(storeConfigs)
store.register([config.plugins, inlinePlugin])
store.register([constructorConfig.plugins, inlinePlugin])
var system = store.getSystem()
let queryConfig = parseSeach()
const downloadSpec = (configs) => {
if(typeof config !== "object") {
const downloadSpec = (fetchedConfig) => {
if(typeof constructorConfig !== "object") {
return system
}
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
let mergedConfig = deepExtend({}, config, configs, localConfig)
let mergedConfig = deepExtend({}, constructorConfig, localConfig, fetchedConfig || {}, queryConfig)
store.setConfigs(filterConfigs(mergedConfig))
if(typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
system.specActions.updateUrl("")
system.specActions.updateLoadingStatus("success");
system.specActions.updateSpec(JSON.stringify(mergedConfig.spec))
} else if(mergedConfig.url) {
system.specActions.updateUrl(mergedConfig.url)
system.specActions.download(mergedConfig.url)
if (fetchedConfig !== null) {
if (!queryConfig.url && typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
system.specActions.updateUrl("")
system.specActions.updateLoadingStatus("success")
system.specActions.updateSpec(JSON.stringify(mergedConfig.spec))
} else if (system.specActions.download && mergedConfig.url) {
system.specActions.updateUrl(mergedConfig.url)
system.specActions.download(mergedConfig.url)
}
}
if(mergedConfig.dom_id)
if(mergedConfig.dom_id) {
system.render(mergedConfig.dom_id, "App")
} else {
console.error("Skipped rendering: no `dom_id` was specified")
}
return system
}
if (system.specActions.getConfigByUrl && !system.specActions.getConfigByUrl(downloadSpec)) {
return downloadSpec(config)
}
if (system.specActions.download && config.url) {
system.specActions.download(config.url)
}
if(config.spec && typeof config.spec === "string")
system.specActions.updateSpec(config.spec)
let configUrl = queryConfig.config || constructorConfig.configUrl
if(config.dom_id) {
system.render(config.dom_id, "App")
} else {
console.error("Skipped rendering: no `dom_id` was specified")
if (!configUrl || !system.specActions.getConfigByUrl || system.specActions.getConfigByUrl && !system.specActions.getConfigByUrl(configUrl, downloadSpec)) {
return downloadSpec()
}
return system
}
// Add presets
......
import React, { PropTypes, Component } from "react"
import { arrayify } from "core/utils"
import shallowCompare from "react-addons-shallow-compare"
import { List, fromJS } from "immutable"
import assign from "object-assign"
//import "less/json-schema-form"
const noop = ()=> {}
......@@ -53,7 +51,7 @@ export class JsonSchema_string extends Component {
}
onEnumChange = (val) => this.props.onChange(val)
render() {
let { getComponent, value, schema, fn, required, description } = this.props
let { getComponent, value, schema, required, description } = this.props
let enumValue = schema["enum"]
let errors = schema.errors || []
......@@ -119,13 +117,13 @@ export class JsonSchema_array extends Component {
}
onEnumChange = (value) => {
this.setState(state => ({
this.setState(() => ({
value: value
}), this.onChange)
}
render() {
let { getComponent, onChange, required, schema, fn } = this.props
let { getComponent, required, schema, fn } = this.props
let itemSchema = fn.inferSchema(schema.items)
......@@ -152,9 +150,9 @@ export class JsonSchema_array extends Component {
(errors.length ? <span style={{ color: "red", fortWeight: "bold" }}>{ errors[0] }</span> : null) :
value.map( (item,i) => {
let schema = Object.assign({}, itemSchema)
let err = errors.filter((err) => err.index === i)
if ( err.length ) {
schema.errors = [ err[0].error + i ]
if ( errors.length ) {
let err = errors.filter((err) => err.index === i)
if (err.length) schema.errors = [ err[0].error + i ]
}
return (
<div key={i} className="json-schema-form-item">
......
import win from "core/window"
import { btoa } from "core/utils"
export default function authorize ( auth, authActions, errActions, configs ) {
let { schema, scopes, name, clientId } = auth
let redirectUrl = configs.oauth2RedirectUrl
let scopeSeparator = " "
let state = name
let state = btoa(new Date())
let flow = schema.get("flow")
let url
......@@ -14,6 +15,11 @@ export default function authorize ( auth, authActions, errActions, configs ) {
return
}
if (flow === "application") {
authActions.authorizeApplication(auth)
return
}
// todo move to parser
if ( !redirectUrl ) {
errActions.newAuthErr( {
......@@ -39,7 +45,7 @@ export default function authorize ( auth, authActions, errActions, configs ) {
win.swaggerUIRedirectOauth2 = {
auth: auth,
state: state,
callback: authActions.preAuthorizeOauth2,
callback: flow === "implicit" ? authActions.preAuthorizeImplicit : authActions.authorizeAccessCode,
errCb: errActions.newAuthErr
}
......
......@@ -26,7 +26,7 @@ export function transformPathToArray(property, jsSpec) {
return a.concat(b)
}, [])
.concat([""]) // add an empty item into the array, so we don't get stuck with something in our buffer below
.reduce((buffer, curr, i, arr) => {
.reduce((buffer, curr) => {
let obj = pathArr.length ? get(jsSpec, pathArr) : jsSpec
if(get(obj, makeAccessArray(buffer, curr))) {
......
import React, { PropTypes } from "react"
export default function (system) {
return {
components: {
NoHostWarning,
},
statePlugins: {
spec: {
selectors: {
allowTryItOutFor,
}
}
}
}
}
// This is a quick style. How do we improve this?
const style = {
backgroundColor: "#e7f0f7",
padding: "1rem",
borderRadius: "3px",
}
function NoHostWarning() {
return (
<div style={style}>Note: The interactive forms are disabled, as no `host` property was found in the specification. Please see: <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#swagger-object" target="_blank">OAI 2.0/#swagger-object</a></div>
)
}
// Only allow if, there is a host field
function allowTryItOutFor(state) {
return ({specSelectors}) => {
return specSelectors.hasHost(state)
}
}
......@@ -277,8 +277,6 @@ export let getLineNumberForPathAsync = promisifySyncFn(getLineNumberForPath)
function promisifySyncFn(fn) {
return function(...args) {
return new Promise(function(resolve, reject) {
resolve(fn(...args))
})
return new Promise((resolve) => resolve(fn(...args)))
}
}
import win from "core/window"
import btoa from "btoa"
import { btoa, buildFormData } from "core/utils"
export const SHOW_AUTH_POPUP = "show_popup"
export const AUTHORIZE = "authorize"
......@@ -8,6 +8,8 @@ export const PRE_AUTHORIZE_OAUTH2 = "pre_authorize_oauth2"
export const AUTHORIZE_OAUTH2 = "authorize_oauth2"
export const VALIDATE = "validate"
const scopeSeparator = " "
export function showDefinitions(payload) {
return {
type: SHOW_AUTH_POPUP,
......@@ -29,7 +31,7 @@ export function logout(payload) {
}
}
export const preAuthorizeOauth2 = (payload) => ( { authActions, errActions } ) => {
export const preAuthorizeImplicit = (payload) => ( { authActions, errActions } ) => {
let { auth , token, isValid } = payload
let { schema, name } = auth
let flow = schema.get("flow")
......@@ -66,28 +68,72 @@ export function authorizeOauth2(payload) {
}
}
export const authorizePassword = ( auth ) => ( { fn, authActions, errActions } ) => {
export const authorizePassword = ( auth ) => ( { authActions } ) => {
let { schema, name, username, password, passwordType, clientId, clientSecret } = auth
let req = {
url: schema.get("tokenUrl"),
method: "post",
headers: {
"content-type": "application/x-www-form-urlencoded"
},
query: {
grant_type: "password",
username,
password
}
let form = {
grant_type: "password",
scopes: encodeURIComponent(auth.scopes.join(scopeSeparator))
}
let query = {}
let headers = {}
if ( passwordType === "basic") {
req.headers.authorization = "Basic " + btoa(clientId + ":" + clientSecret)
} else if ( passwordType === "request") {
req.query = Object.assign(req.query, { client_id: clientId, client_secret: clientSecret })
headers.Authorization = "Basic " + btoa(username + ":" + password)
} else {
Object.assign(form, {username}, {password})
if ( passwordType === "query") {
if ( clientId ) { query.client_id = clientId }
if ( clientSecret ) { query.client_secret = clientSecret }
} else {
Object.assign(form, {client_id: clientId}, {client_secret: clientSecret})
}
}
return fn.fetch(req)
.then(( response ) => {
return authActions.authorizeRequest({ body: buildFormData(form), url: schema.get("tokenUrl"), name, headers, query, auth})
}
export const authorizeApplication = ( auth ) => ( { authActions } ) => {
let { schema, scopes, name, clientId, clientSecret } = auth
let form = {
grant_type: "client_credentials",
client_id: clientId,
client_secret: clientSecret,
scope: scopes.join(scopeSeparator)
}
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth })
}
export const authorizeAccessCode = ( auth ) => ( { authActions } ) => {
let { schema, name, clientId, clientSecret } = auth
let form = {
grant_type: "authorization_code",
code: auth.code,
client_id: clientId,
client_secret: clientSecret
}
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth})
}
export const authorizeRequest = ( data ) => ( { fn, authActions, errActions } ) => {
let { body, query={}, headers={}, name, url, auth } = data
let _headers = Object.assign({
"Accept":"application/json, text/plain, */*",
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/x-www-form-urlencoded"
}, headers)
fn.fetch({
url: url,
method: "post",
headers: _headers,
query: query,
body: body
})
.then(function (response) {
let token = JSON.parse(response.data)
let error = token && ( token.error || "" )
let parseError = token && ( token.parseError || "" )
......@@ -112,7 +158,14 @@ export const authorizePassword = ( auth ) => ( { fn, authActions, errActions } )
return
}
authActions.authorizeOauth2({ auth, token })
authActions.authorizeOauth2({ auth, token})
})
.catch(err => { errActions.newAuthErr( err ) })
.catch(e => {
let err = new Error(e)
errActions.newAuthErr( {
authId: name,
level: "error",
source: "auth",
message: err.message
} ) })
}
import { fromJS, Map } from "immutable"
import btoa from "btoa"
import { btoa } from "core/utils"
import {
SHOW_AUTH_POPUP,
AUTHORIZE,
PRE_AUTHORIZE_OAUTH2,
AUTHORIZE_OAUTH2,
LOGOUT
} from "./actions"
......@@ -21,7 +20,6 @@ export default {
// refactor withMutations
securities.entrySeq().forEach( ([ key, security ]) => {
let type = security.getIn(["schema", "type"])
let name = security.get("name")
if ( type === "apiKey" ) {
map = map.set(key, security)
......
......@@ -10,7 +10,7 @@ export const shownDefinitions = createSelector(
export const definitionsToAuthorize = createSelector(
state,
auth =>( { specSelectors } ) => {
() =>( { specSelectors } ) => {
let definitions = specSelectors.securityDefinitions()
let list = List()
......@@ -66,7 +66,10 @@ export const authorized = createSelector(
export const isAuthorized = ( state, securities ) =>( { authSelectors } ) => {
let authorized = authSelectors.authorized()
let isAuth = false
if(!List.isList(securities)) {
return null
}
return !!securities.toJS().filter( ( security ) => {
let isAuthorized = true
......
import { Map } from "immutable"
// Add security to the final `execute` call ( via `extras` )
export const execute = ( oriAction, { authSelectors, specSelectors }) => ({ path, method, operation, extras }) => {
let securities = {
......@@ -10,4 +8,3 @@ export const execute = ( oriAction, { authSelectors, specSelectors }) => ({ path
return oriAction({ path, method, operation, securities, ...extras })
}
......@@ -4,16 +4,19 @@ import { createSelector } from "reselect"
import { Map } from "immutable"
export default function downloadUrlPlugin (toolbox) {
let { fn, Im } = toolbox
let { fn } = toolbox
const actions = {
download: (url)=> ({ errActions, specSelectors, specActions }) => {
let { fetch } = fn
url = url || specSelectors.url()
specActions.updateLoadingStatus("loading")
fetch(url, {
fetch({
url,
loadSpec: true,
credentials: "same-origin",
headers: {
"Accept": "application/json"
"Accept": "application/json,*/*"
}
}).then(next,next)
......@@ -30,7 +33,7 @@ export default function downloadUrlPlugin (toolbox) {
},
updateLoadingStatus: (status) => {
let enums = [null, "loading", "failed", "success"]
let enums = [null, "loading", "failed", "success", "failedConfig"]
if(enums.indexOf(status) === -1) {
console.error(`Error: ${status} is not one of ${JSON.stringify(enums)}`)
}
......
......@@ -20,14 +20,14 @@ export function newThrownErrBatch(errors) {
}
}
export function newSpecErr(err, action) {
export function newSpecErr(err) {
return {
type: NEW_SPEC_ERR,
payload: err
}
}
export function newAuthErr(err, action) {
export function newAuthErr(err) {
return {
type: NEW_AUTH_ERR,
payload: err
......
import concat from "lodash/concat"
import reduce from "lodash/reduce"
let request = require.context("./transformers/", true, /\.js$/)
let errorTransformers = []
......
import get from "lodash/get"
import last from "lodash/get"
import { fromJS, List } from "immutable"
import { fromJS } from "immutable"
export function transform(errors, { jsSpec }) {
// LOOK HERE THIS TRANSFORMER IS CURRENTLY DISABLED 😃
......
......@@ -47,7 +47,7 @@ export const sampleFromSchema = (schema, config={}) => {
let obj = {}
for (var name in props) {
if ( !props[name].readOnly || includeReadOnly ) {
obj[name] = sampleFromSchema(props[name])
obj[name] = sampleFromSchema(props[name], { includeReadOnly: includeReadOnly })
}
}
......@@ -55,7 +55,7 @@ export const sampleFromSchema = (schema, config={}) => {
obj.additionalProp1 = {}
} else if ( additionalProperties ) {
let additionalProps = objectify(additionalProperties)
let additionalPropVal = sampleFromSchema(additionalProps)
let additionalPropVal = sampleFromSchema(additionalProps, { includeReadOnly: includeReadOnly })
for (let i = 1; i < 4; i++) {
obj["additionalProp" + i] = additionalPropVal
......@@ -65,7 +65,7 @@ export const sampleFromSchema = (schema, config={}) => {
}
if(type === "array") {
return [ sampleFromSchema(items) ]
return [ sampleFromSchema(items, { includeReadOnly: includeReadOnly }) ]
}
if(schema["enum"]) {
......@@ -127,8 +127,12 @@ export const sampleXmlFromSchema = (schema, config={}) => {
if (xml.wrapped) {
res[displayName] = []
if (Array.isArray(defaultValue)) {
if (Array.isArray(example)) {
example.forEach((v)=>{
items.example = v
res[displayName].push(sampleXmlFromSchema(items, config))
})
} else if (Array.isArray(defaultValue)) {
defaultValue.forEach((v)=>{
items.default = v
res[displayName].push(sampleXmlFromSchema(items, config))
......@@ -145,14 +149,20 @@ export const sampleXmlFromSchema = (schema, config={}) => {
let _res = []
if (Array.isArray(defaultValue)) {
if (Array.isArray(example)) {
example.forEach((v)=>{
items.example = v
_res.push(sampleXmlFromSchema(items, config))
})
return _res
} else if (Array.isArray(defaultValue)) {
defaultValue.forEach((v)=>{
items.default = v
_res.push(sampleXmlFromSchema(items, config))
})
return _res
}
return sampleXmlFromSchema(items, config)
}
}
......@@ -176,7 +186,13 @@ export const sampleXmlFromSchema = (schema, config={}) => {
} else {
props[propName].xml.name = props[propName].xml.name || propName
props[propName].example = props[propName].example !== undefined ? props[propName].example : example[propName]
res[displayName].push(sampleXmlFromSchema(props[propName]))
let t = sampleXmlFromSchema(props[propName])
if (Array.isArray(t)) {
res[displayName] = res[displayName].concat(t)
} else {
res[displayName].push(t)
}
}
}
}
......
import YAML from "js-yaml"
import parseUrl from "url-parse"
import serializeError from "serialize-error"
// Actions conform to FSA (flux-standard-actions)
......@@ -184,8 +185,12 @@ export const logRequest = (req) => {
// Actually fire the request via fn.execute
// (For debugging) and ease of testing
export const executeRequest = (req) => ({fn, specActions, errActions}) => {
export const executeRequest = (req) => ({fn, specActions, specSelectors}) => {
let { pathName, method } = req
// if url is relative, parseUrl makes it absolute by inferring from `window.location`
req.contextUrl = parseUrl(specSelectors.url()).toString()
let parsedRequest = Object.assign({}, req)
if ( pathName && method ) {
parsedRequest.operationId = method.toLowerCase() + "-" + pathName
......
......@@ -51,7 +51,6 @@ export default {
[VALIDATE_PARAMS]: ( state, { payload: { pathMethod } } ) => {
let operation = state.getIn( [ "resolved", "paths", ...pathMethod ] )
let parameters = operation.get("parameters")
let isXml = /xml/i.test(operation.get("consumes_value"))
return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
......@@ -64,9 +63,6 @@ export default {
})
},
[ClEAR_VALIDATE_PARAMS]: ( state, { payload: { pathMethod } } ) => {
let operation = state.getIn( [ "resolved", "paths", ...pathMethod ] )
let parameters = operation.get("parameters")
return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
return parameters.withMutations( parameters => {
for ( let i = 0, len = parameters.count(); i < len; i++ ) {
......@@ -101,7 +97,11 @@ export default {
},
[UPDATE_OPERATION_VALUE]: (state, { payload: { path, value, key } }) => {
return state.setIn(["resolved", "paths", ...path, key], fromJS(value))
let operationPath = ["resolved", "paths", ...path]
if(!state.getIn(operationPath)) {
return state
}
return state.setIn([...operationPath, key], fromJS(value))
},
[CLEAR_RESPONSE]: (state, { payload: { path, method } } ) =>{
......
import { createSelector } from "reselect"
import { sorters } from "core/utils"
import { fromJS, Set, Map, List } from "immutable"
const DEFAULT_TAG = "default"
......@@ -198,13 +199,16 @@ export const operationsWithTags = createSelector(
}
)
export const taggedOperations = createSelector(
state,
operationsWithTags,
(state, tagMap) => {
return tagMap.map((ops, tag) => Map({tagDetails: tagDetails(state, tag), operations: ops}))
}
)
export const taggedOperations = ( state ) =>( { getConfigs } ) => {
let { operationsSorter }= getConfigs()
return operationsWithTags(state).map((ops, tag) => {
let sortFn = typeof operationsSorter === "function" ? operationsSorter
: sorters.operationsSorter[operationsSorter]
let operations = !sortFn ? ops : ops.sort(sortFn)
return Map({tagDetails: tagDetails(state, tag), operations: operations})})
}
export const responses = createSelector(
state,
......@@ -224,7 +228,7 @@ export const requestFor = (state, path, method) => {
return requests(state).getIn([path, method], null)
}
export const allowTryItOutFor = (state, path, method ) => {
export const allowTryItOutFor = () => {
// This is just a hook for now.
return true
}
......@@ -291,7 +295,11 @@ export function operationConsumes(state, pathMethod) {
}
export const operationScheme = ( state, path, method ) => {
return state.getIn(["scheme", path, method]) || state.getIn(["scheme", "_defaultScheme"]) || "http"
let url = state.get("url")
let matchResult = url.match(/^([a-z][a-z0-9+\-.]*):/)
let urlScheme = Array.isArray(matchResult) ? matchResult[1] : null
return state.getIn(["scheme", path, method]) || state.getIn(["scheme", "_defaultScheme"]) || urlScheme || ""
}
export const canExecuteScheme = ( state, path, method ) => {
......
......@@ -57,14 +57,14 @@ export default class SplitPaneMode extends React.Component {
const mode = layoutSelectors.whatMode(MODE_KEY)
const left = mode === MODE_RIGHT ? <noscript/> : children[0]
const right = mode === MODE_LEFT ? <noscript/> : children[1]
const size = this.sizeFromMode(mode, '50%')
const size = this.sizeFromMode(mode, "50%")
return (
<SplitPane
disabledClass={''}
ref={'splitPane'}
disabledClass={""}
ref={"splitPane"}
split='vertical'
defaultSize={'50%'}
defaultSize={"50%"}
primary="second"
minSize={0}
size={size}
......
......@@ -3,10 +3,6 @@ import ReactDOM from "react-dom"
import { connect, Provider } from "react-redux"
import omit from "lodash/omit"
const NotFoundComponent = name => ()=> <span style={{color: "red"}}> "{name}" component not found </span>
const SystemWrapper = (getSystem, ComponentToWrap ) => class extends Component {
render() {
return <ComponentToWrap {...getSystem() } {...this.props} {...this.context} />
......@@ -75,10 +71,10 @@ const createClass = component => React.createClass({
}
})
const Fallback = ({ error, name }) => <div style={{ // eslint-disable-line react/prop-types
const Fallback = ({ name }) => <div style={{ // eslint-disable-line react/prop-types
padding: "1em",
"color": "#aaa"
}}>😱 <i>Could not render { name ? name : "this component" }, see console.</i></div>
}}>😱 <i>Could not render { name === "t" ? "this component" : name }, see the console.</i></div>
const wrapRender = (component) => {
const isStateless = component => !(component.prototype && component.prototype.isReactComponent)
......
import BasePreset from "./base"
import allowTryItOutIfHost from "core/plugins/allow-try-it-out-if-host"
// Just the base, for now.
export default function PresetApis() {
return [
BasePreset,
allowTryItOutIfHost,
]
}
......@@ -46,6 +46,8 @@ import Model from "core/components/model"
import Models from "core/components/models"
import TryItOutButton from "core/components/try-it-out-button"
import BaseLayout from "core/components/layouts/base"
import * as LayoutUtils from "core/components/layout-utils"
import * as JsonSchemaComponents from "core/json-schema-components"
......@@ -87,6 +89,7 @@ export default function() {
model: Model,
models: Models,
TryItOutButton,
BaseLayout
}
}
......
import { createStore, applyMiddleware, bindActionCreators, compose } from "redux"
import Im, { fromJS, Map } from "immutable"
import deepExtend from "deep-extend"
import createLogger from "redux-logger"
import { combineReducers } from "redux-immutable"
import assign from "object-assign"
import serializeError from "serialize-error"
......
......@@ -135,12 +135,11 @@ export function getList(iterable, keys) {
// Adapted from http://stackoverflow.com/a/2893259/454004
// Note: directly ported from CoffeeScript
export function formatXml (xml) {
var contexp, fn, formatted, indent, l, lastType, len, lines, ln, pad, reg, transitions, wsexp
var contexp, fn, formatted, indent, l, lastType, len, lines, ln, reg, transitions, wsexp
reg = /(>)(<)(\/*)/g
wsexp = /[ ]*(.*)[ ]+\n/g
contexp = /(<.+>)(.+\n)/g
xml = xml.replace(/\r\n/g, "\n").replace(reg, "$1\n$2$3").replace(wsexp, "$1\n").replace(contexp, "$1\n$2")
pad = 0
formatted = ""
lines = xml.split("\n")
indent = 0
......@@ -164,7 +163,7 @@ export function formatXml (xml) {
"other->other": 0
}
fn = function(ln) {
var fromTo, j, key, padding, type, types, value
var fromTo, key, padding, type, types, value
types = {
single: Boolean(ln.match(/<.+\/>/)),
closing: Boolean(ln.match(/<\/.+>/)),
......@@ -187,11 +186,13 @@ export function formatXml (xml) {
padding = ""
indent += transitions[fromTo]
padding = ((function() {
var m, ref1, results
/* eslint-disable no-unused-vars */
var m, ref1, results, j
results = []
for (j = m = 0, ref1 = indent; 0 <= ref1 ? m < ref1 : m > ref1; j = 0 <= ref1 ? ++m : --m) {
results.push(" ")
}
/* eslint-enable no-unused-vars */
return results
})()).join("")
if (fromTo === "opening->closing") {
......@@ -215,19 +216,9 @@ export function formatXml (xml) {
export function highlight (el) {
const MAX_LENGTH = 5000
var
_window = window,
_document = document,
appendChild = "appendChild",
test = "test",
// style and color templates
textShadow = ";text-shadow:",
opacity = "opacity:.",
_0px_0px = " 0px 0px ",
_3px_0px_5 = "3px 0px 5",
brace = ")",
i,
microlighted
test = "test"
if (!el) return ""
if (el.textContent.length > MAX_LENGTH) { return el.textContent }
......@@ -260,14 +251,7 @@ export function highlight (el) {
lastTokenType,
// flag determining if token is multi-character
multichar,
node,
// calculating the colors for the style templates
colorArr = /(\d*\, \d*\, \d*)(, ([.\d]*))?/g.exec(
_window.getComputedStyle(el).color
),
pxColor = "px rgba("+colorArr[1]+",",
alpha = colorArr[3]||1
node
// running through characters and highlighting
while (prev2 = prev1,
......@@ -468,6 +452,17 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
}
const validateNumber = ( val ) => {
if ( !/^-?\d+(.?\d+)?$/.test(val)) {
return "Value must be a number"
}
}
const validateInteger = ( val ) => {
if ( !/^-?\d+$/.test(val)) {
return "Value must be integer"
}
}
// validation of parameters before execute
export const validateParam = (param, isXml) => {
......@@ -517,29 +512,16 @@ export const validateParam = (param, isXml) => {
return errors
}
const validateNumber = ( val ) => {
if ( !/^\d+(.?\d+)?$/.test(val)) {
return "Value must be a number"
}
}
const validateInteger = ( val ) => {
if ( !/^\d+$/.test(val)) {
return "Value must be integer"
}
}
export const getSampleSchema = (schema, contentType="", config={}) => {
if (/xml/.test(contentType)) {
if (!schema.xml || !schema.xml.name) {
let name
schema.xml = schema.xml || {}
if (schema.$$ref) {
let match = schema.$$ref.match(/\S*\/(\S+)$/)
schema.xml.name = match[1]
} else if (schema.type || schema.items || schema.properties || schema.additionalProperties) {
return '<?xml version="1.0" encoding="UTF-8"?>\n<!-- XML example cannot be generated -->'
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- XML example cannot be generated -->"
} else {
return null
}
......@@ -549,3 +531,50 @@ export const getSampleSchema = (schema, contentType="", config={}) => {
return JSON.stringify(memoizedSampleFromSchema(schema, config), null, 2)
}
export const parseSeach = () => {
let map = {}
let search = window.location.search
if ( search != "" ) {
let params = search.substr(1).split("&")
for (let i in params) {
i = params[i].split("=")
map[decodeURIComponent(i[0])] = decodeURIComponent(i[1])
}
}
return map
}
export const btoa = (str) => {
let buffer
if (str instanceof Buffer) {
buffer = str
} else {
buffer = new Buffer(str.toString(), "utf-8")
}
return buffer.toString("base64")
}
export const sorters = {
operationsSorter: {
alpha: (a, b) => a.get("path").localeCompare(b.get("path")),
method: (a, b) => a.get("method").localeCompare(b.get("method"))
}
}
export const buildFormData = (data) => {
let formArr = []
for (let name in data) {
let val = data[name]
if (val !== undefined && val !== "") {
formArr.push([name, "=", encodeURIComponent(val).replace(/%20/g,"+")].join(""))
}
}
return formArr.join("&")
}
var win = {
location: {},
history: {},
open: () => {},
close: () => {}
}
function makeWindow() {
var win = {
location: {},
history: {},
open: () => {},
close: () => {}
}
try {
win = window
var props = ["File", "Blob", "FormData"]
for (var prop of props) {
if (prop in window) {
win[prop] = window[prop]
if(typeof window === "undefined") {
return win
}
try {
win = window
var props = ["File", "Blob", "FormData"]
for (var prop of props) {
if (prop in window) {
win[prop] = window[prop]
}
}
} catch( e ) {
console.error(e)
}
} catch( e ) {
console.error(e)
return win
}
export default win
module.exports = makeWindow()
......@@ -16,22 +16,6 @@ const parseYamlConfig = (yaml, system) => {
}
}
const parseSeach = () => {
let map = {}
let search = window.location.search
if ( search != "" ) {
let params = search.substr(1).split("&");
for (let i in params) {
i = params[i].split("=");
map[decodeURIComponent(i[0])] = decodeURIComponent(i[1]);
}
}
return map;
}
export default function configPlugin (toolbox) {
let { fn } = toolbox
......@@ -42,9 +26,7 @@ export default function configPlugin (toolbox) {
return fetch(url)
},
getConfigByUrl: (callback)=> ({ specActions }) => {
let config = parseSeach()
let configUrl = config.config
getConfigByUrl: (configUrl, cb)=> ({ specActions }) => {
if (configUrl) {
return specActions.downloadConfig(configUrl).then(next, next)
}
......@@ -52,9 +34,12 @@ export default function configPlugin (toolbox) {
function next(res) {
if (res instanceof Error || res.status >= 400) {
specActions.updateLoadingStatus("failedConfig")
console.log(res.statusText + " " + configUrl)
specActions.updateLoadingStatus("failedConfig")
specActions.updateUrl("")
console.error(res.statusText + " " + configUrl)
cb(null)
} else {
callback(parseYamlConfig(res.text))
cb(parseYamlConfig(res.text))
}
}
}
......@@ -85,4 +70,4 @@ export function filterConfigs (configs) {
}
return filteredConfigs
}
\ No newline at end of file
}
import Topbar from './topbar.jsx'
import Topbar from "./topbar.jsx"
export default function () {
return {
......
import StandaloneLayout from './layout'
import '../style/main.scss'
import StandaloneLayout from "./layout"
import "../style/main.scss"
import TopbarPlugin from "plugins/topbar"
import ConfigsPlugin from "plugins/configs"
// the Standalone preset
let preset = [
TopbarPlugin,
ConfigsPlugin,
() => {
return {
components: { StandaloneLayout }
......@@ -16,4 +14,4 @@ let preset = [
}
]
export default preset
module.exports = preset
import React, { PropTypes } from 'react'
import React, { PropTypes } from "react"
export default class StandaloneLayout extends React.Component {
......@@ -6,35 +6,23 @@ export default class StandaloneLayout extends React.Component {
errSelectors: PropTypes.object.isRequired,
errActions: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired
layoutActions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
}
render() {
let { specSelectors, specActions, getComponent, errSelectors, errActions, spec, readOnly } = this.props
let { getComponent, specSelectors } = this.props
let info = specSelectors.info()
let url = specSelectors.url()
let basePath = specSelectors.basePath()
let host = specSelectors.host()
let securityDefinitions = specSelectors.securityDefinitions()
let externalDocs = specSelectors.externalDocs()
let schemes = specSelectors.schemes()
let Info = getComponent("info")
let Operations = getComponent("operations", true)
let Models = getComponent("models", true)
let AuthorizeBtn = getComponent("authorizeBtn", true)
let Container = getComponent("Container")
let Row = getComponent("Row")
let Col = getComponent("Col")
let Button = getComponent("Button")
let Errors = getComponent("errors", true)
const SplitPaneMode = getComponent("SplitPaneMode", true)
const Schemes = getComponent("schemes")
const Topbar = getComponent("Topbar", true)
const BaseLayout = getComponent("BaseLayout", true)
const OnlineValidatorBadge = getComponent("onlineValidatorBadge", true)
const loadingStatus = specSelectors.loadingStatus()
return (
......@@ -56,43 +44,12 @@ export default class StandaloneLayout extends React.Component {
<h4 className="title">Failed to load config.</h4>
</div>
}
{ loadingStatus === "success" &&
<div>
<Errors/>
<Row className="information-container">
<Col mobile={12}>
{ info.count() ? (
<Info info={ info } url={ url } host={ host } basePath={ basePath } externalDocs={externalDocs} getComponent={getComponent}/>
) : null }
</Col>
</Row>
<div className="scheme-container">
<Col className="schemes wrapper" mobile={12}>
{ schemes && schemes.size ? (
<Schemes schemes={ schemes } specActions={ specActions } />
) : null }
{ securityDefinitions ? (
<AuthorizeBtn />
) : null }
</Col>
</div>
<Row>
<Col mobile={12} desktop={12} >
<Operations/>
</Col>
</Row>
<Row>
<Col mobile={12} desktop={12} >
<Models/>
</Col>
</Row>
</div> }
<Row>
<Col>
<OnlineValidatorBadge />
</Col>
</Row>
{ !loadingStatus || loadingStatus === "success" && <BaseLayout/> }
<Row>
<Col>
<OnlineValidatorBadge />
</Col>
</Row>
</Container>
)
}
......
......@@ -136,8 +136,8 @@
svg
{
width: 100%;
height: 100%;
width: 20px;
height: 20px;
}
}
......
......@@ -9,16 +9,26 @@
border-radius: 4px;
background: rgba($_color-delete, .1);
.error-wrapper
{
margin: 0 0 10px 0;
}
.errors
{
h4
{
font-size: 14px;
margin: 0 0 10px 0;
margin: 0;
@include text_code();
}
small
{
color: #666;
}
}
hgroup
......
......@@ -286,12 +286,37 @@ body
@include method($_color-get);
}
&.opblock-patch
{
@include method($_color-patch);
}
&.opblock-head
{
@include method($_color-head);
}
&.opblock-options
{
@include method($_color-options);
}
&.opblock-deprecated
{
opacity: .6;
@include method($_color-disabled);
}
.opblock-schemes
{
padding: 8px 20px;
.schemes-title
{
padding: 0 10px 0 0;
}
}
}
......@@ -467,6 +492,8 @@ body
margin: 0;
padding: 10px;
white-space: pre-wrap;
border-radius: 4px;
background: #41444e;
......@@ -475,6 +502,11 @@ body
{
color: #fff !important;
}
.headerline
{
display: block;
}
}
.scheme-container
......
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
This module, `swagger-ui-dist`, exposes Swagger-UI's entire dist folder as a dependency-free npm module.
Use `swagger-ui` instead, if you'd like to have npm install dependencies for you.
# Deploy `swagger-ui-dist` to npm.
# Parameter Expansion: http://stackoverflow.com/questions/6393551/what-is-the-meaning-of-0-in-a-bash-script
cd "${0%/*}"
# Get UI version
UI_VERSION=$(node -p "require('../package.json').version")
# Replace our version placeholder with UI's version
sed -i "s|\$\$VERSION|$UI_VERSION|g" package.json
# Copy UI's dist files to our directory
cp ../dist/* .
if [ "$PUBLISH_DIST" = "true" ] || [ "$TRAVIS" = "true" ] ; then
npm publish .
else
npm pack .
fi
find . -not -name .npmignore -not -name .npmrc -not -name deploy.sh -not -name package.json -not -name README.md -not -name *.tgz -delete
{
"name": "swagger-ui-dist",
"version": "$$VERSION",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
"(in alphabetical order)",
"Anna Bodnia <anna.bodnia@gmail.com>",
"Buu Nguyen <buunguyen@gmail.com>",
"Josh Ponelat <jponelat@gmail.com>",
"Kyle Shockey <kyleshockey1@gmail.com>",
"Robert Barnwell <robert@robertismy.name>",
"Sahar Jafari <shr.jafari@gmail.com>"
],
"license": "Apache-2.0",
"dependencies": {},
"devDependencies": {}
}
......@@ -3,10 +3,9 @@ import React from "react"
import expect, { createSpy } from "expect"
import { shallow } from "enzyme"
import Operation from "components/operation"
import Collapse from "react-collapse"
describe("<Operation/>", function(){
it("blanket tests", function(){
it.skip("blanket tests", function(){
let props = {
operation: {get: ()=>{}},
......
......@@ -21,7 +21,7 @@ describe("curlify", function() {
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X POST http://example.com -H "Accept: application/json" -H "content-type: application/json" -d {"id":0,"name":"doggie","status":"available"}')
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"Accept: application/json\" -H \"content-type: application/json\" -d {\"id\":0,\"name\":\"doggie\",\"status\":\"available\"}")
})
it("does not change the case of header in curl", function() {
......@@ -35,7 +35,7 @@ describe("curlify", function() {
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X POST http://example.com -H "conTenT Type: application/Moar"')
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"conTenT Type: application/Moar\"")
})
it("prints a curl statement with an array of query params", function() {
......@@ -46,7 +46,7 @@ describe("curlify", function() {
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X GET http://swaggerhub.com/v1/one?name=john|smith')
expect(curlified).toEqual("curl -X GET \"http://swaggerhub.com/v1/one?name=john|smith\"")
})
it("prints a curl statement with an array of query params and auth", function() {
......@@ -60,7 +60,7 @@ describe("curlify", function() {
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X GET http://swaggerhub.com/v1/one?name=john|smith -H "authorization: Basic Zm9vOmJhcg=="')
expect(curlified).toEqual("curl -X GET \"http://swaggerhub.com/v1/one?name=john|smith\" -H \"authorization: Basic Zm9vOmJhcg==\"")
})
it("prints a curl statement with html", function() {
......@@ -71,13 +71,13 @@ describe("curlify", function() {
accept: "application/json"
},
body: {
description: '<b>Test</b>'
description: "<b>Test</b>"
}
}
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X GET http://swaggerhub.com/v1/one?name=john|smith -H "accept: application/json" -d {"description":"<b>Test</b>"}')
expect(curlified).toEqual("curl -X GET \"http://swaggerhub.com/v1/one?name=john|smith\" -H \"accept: application/json\" -d {\"description\":\"<b>Test</b>\"}")
})
it("handles post body with html", function() {
......@@ -88,13 +88,13 @@ describe("curlify", function() {
accept: "application/json"
},
body: {
description: '<b>Test</b>'
description: "<b>Test</b>"
}
}
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X POST http://swaggerhub.com/v1/one?name=john|smith -H "accept: application/json" -d {"description":"<b>Test</b>"}')
expect(curlified).toEqual("curl -X POST \"http://swaggerhub.com/v1/one?name=john|smith\" -H \"accept: application/json\" -d {\"description\":\"<b>Test</b>\"}")
})
it("handles post body with special chars", function() {
......@@ -102,14 +102,14 @@ describe("curlify", function() {
url: "http://swaggerhub.com/v1/one?name=john|smith",
method: "POST",
body: {
description: '@prefix nif:<http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#> .\n' +
'@prefix itsrdf: <http://www.w3.org/2005/11/its/rdf#> .'
description: "@prefix nif:<http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#> .\n" +
"@prefix itsrdf: <http://www.w3.org/2005/11/its/rdf#> ."
}
}
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X POST http://swaggerhub.com/v1/one?name=john|smith -d {"description":"@prefix nif:<http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#> .@prefix itsrdf: <http://www.w3.org/2005/11/its/rdf#> ."}')
expect(curlified).toEqual("curl -X POST \"http://swaggerhub.com/v1/one?name=john|smith\" -d {\"description\":\"@prefix nif:<http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#> .@prefix itsrdf: <http://www.w3.org/2005/11/its/rdf#> .\"}")
})
it("handles delete form with parameters", function() {
......@@ -123,7 +123,7 @@ describe("curlify", function() {
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X DELETE http://example.com -H "accept: application/x-www-form-urlencoded"')
expect(curlified).toEqual("curl -X DELETE \"http://example.com\" -H \"accept: application/x-www-form-urlencoded\"")
})
it("should print a curl with formData", function() {
......@@ -136,7 +136,7 @@ describe("curlify", function() {
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X POST http://example.com -H "content-type: multipart/form-data" -F id=123 -F name=Sahar')
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"content-type: multipart/form-data\" -F id=123 -F name=Sahar")
})
it("prints a curl post statement from an object", function() {
......@@ -153,7 +153,7 @@ describe("curlify", function() {
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X POST http://example.com -H "accept: application/json" -d {"id":10101}')
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"accept: application/json\" -d {\"id\":10101}")
})
it("prints a curl post statement from a string containing a single quote", function() {
......@@ -163,12 +163,12 @@ describe("curlify", function() {
headers: {
accept: "application/json"
},
body: '{"id":"foo\'bar"}'
body: "{\"id\":\"foo'bar\"}"
}
let curlified = curl(Im.fromJS(req))
expect(curlified).toEqual('curl -X POST http://example.com -H "accept: application/json" -d "{\\"id\\":\\"foo\'bar\\"}"')
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"accept: application/json\" -d \"{\\\"id\\\":\\\"foo'bar\\\"}\"")
})
})
/* eslint-env mocha */
import expect, { createSpy } from "expect"
import expect from "expect"
import { transformPathToArray } from "core/path-translator"
describe("validation plugin - path translator", function(){
......
/* eslint-env mocha */
import expect from "expect"
import { pathForPosition, positionRangeForPath } from "corePlugins/ast/ast"
describe.skip("ASTManager", function() {
describe("#pathForPosition", function() {
describe("out of range", function() {
it("returns empty array for out of range row", function(done) {
var position = {line: 3, column: 0}
var assertPath = function(path) {
expect(path).toEqual([])
done()
}
pathForPosition("swagger: 2.0", position)
.then(assertPath)
})
it("returns empty array for out of range column", function(done) {
var position = {line: 0, column: 100}
var assertPath = function(path) {
expect(path).toEqual([])
done()
}
pathForPosition("swagger: 2.0", position)
.then(assertPath)
})
})
describe("when document is a simple hash `swagger: 2.0`", function() {
it("should return empty array when pointer is at middle of the hash key", function(done) {
var position = {line: 0, column: 3}
pathForPosition("swagger: 2.0", position).then(function(path) {
expect(path).toEqual([])
done()
})
})
it("should return ['swagger'] when pointer is at the value", function(done) {
var position = {line: 0, column: 10}
pathForPosition("swagger: 2.0", position).then(function(path) {
expect(path).toEqual(["swagger"])
done()
})
})
})
describe("when document is an array: ['abc', 'cde']", function() {
var yaml = [
/*
0
01234567 */
/* 0 */ "- abc",
/* 1 */ "- def"
].join("\n")
it("should return empty array when pointer is at array dash", function(done) {
var position = {line: 0, column: 0}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual([])
done()
})
})
it("should return ['0'] when pointer is at abc", function(done) {
var position = {line: 0, column: 3}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual(["0"])
done()
})
})
it("should return ['1'] when pointer is at abc", function(done) {
var position = {line: 1, column: 3}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual(["1"])
done()
})
})
})
describe("when document is an array of arrays", function() {
var yaml = [
/*
0 10
0123456789012345 */
/* 0 */ "-",
/* 1 */ " - abc",
/* 2 */ " - def",
/* 3 */ "-",
/* 4 */ " - ABC",
/* 5 */ " - DEF"
].join("\n")
it("should return ['0', '0'] when pointer is at 'abc'", function(done) {
var position = {line: 1, column: 5}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual(["0", "0"])
done()
})
})
})
describe("when document is an array of hashs", function() {
var yaml = [
/*
0 10
0123456789012345 */
/* 0 */ "- key: value",
/* 1 */ " num: 1",
/* 2 */ "- name: Tesla",
/* 3 */ " year: 2016"
].join("\n")
it("should return ['0'] when pointer is at 'key'", function(done) {
var position = {line: 0, column: 3}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual(["0"])
done()
})
})
it("should return ['0', 'key'] when pointer is at 'value'", function(done) {
var position = {line: 0, column: 9}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual(["0", "key"])
done()
})
})
it("should return ['1', 'year'] when pointer is at '2016'", function(done) {
var position = {line: 3, column: 10}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual(["1", "year"])
done()
})
})
})
describe("full document", function() {
var yaml = [
/*
0 10 20 30
012345678901234567890123456789012345678 */
/* 0 */ "swagger: '2.0'",
/* 1 */ "info:",
/* 2 */ " title: Test document",
/* 3 */ " version: 0.0.1",
/* 4 */ " contact:",
/* 5 */ " name: Sahar",
/* 6 */ " url: github.com",
/* 7 */ " email: me@example.com",
/* 8 */ " "
].join("\n")
it("should return ['info', 'contact', 'email'] when pointer is at me@", function(done) {
var position = {line: 7, column: 13}
pathForPosition(yaml, position).then(function(path) {
expect(path).toEqual(["info", "contact", "email"])
done()
})
})
})
})
describe("#positionRangeForPath", function() {
it("return {{-1, -1}, {-1, -1}} for invalid paths", function(done) {
var yaml = [
"key: value",
"anotherKey: value"
].join("\n")
positionRangeForPath(yaml, ["invalid"])
.then(function(position) {
expect(position.start).toEqual({line: -1, column: -1})
expect(position.end).toEqual({line: -1, column: -1})
done()
})
})
describe("when document is a simple hash `swagger: 2.0`", function() {
var yaml = "swagger: 2.0"
it("return {0, 0} for start of empty array path (root)", function(done) {
positionRangeForPath(yaml, []).then(function(position) {
expect(position.start).toEqual({line: 0, column: 0})
done()
})
})
it("return {0, 12} for end of empty array path (root)", function(done) {
positionRangeForPath(yaml, []).then(function(position) {
expect(position.end).toEqual({line: 0, column: 12})
done()
})
})
it("return {0, 9} for start of ['swagger']", function(done) {
positionRangeForPath(yaml, ["swagger"]).then(function(position) {
expect(position.start).toEqual({line: 0, column: 9})
done()
})
})
it("return {0, 12} for end of ['swagger']", function(done) {
positionRangeForPath(yaml, ["swagger"]).then(function(position) {
expect(position.end).toEqual({line: 0, column: 12})
done()
})
})
})
describe("when document is an array of primitives", function() {
var yaml = [
"key:",
" - value1",
" - value2"
].join("\n")
it("returns {1, 4} for ['key', '0']", function(done) {
positionRangeForPath(yaml, ["key", "0"]).then(function(position) {
expect(position.start).toEqual({line: 1, column: 4})
done()
})
})
})
describe("full document", function() {
var yaml = [
/*
0 10 20 30
012345678901234567890123456789012345678 */
/* 0 */ "swagger: '2.0'",
/* 1 */ "info:",
/* 2 */ " title: Test document",
/* 3 */ " version: 0.0.1",
/* 4 */ " contact:",
/* 5 */ " name: Sahar",
/* 6 */ " url: github.com",
/* 7 */ " email: me@example.com",
/* 8 */ " "
].join("\n")
it("returns {2, 2} for start of ['info']", function(done) {
positionRangeForPath(yaml, ["info"]).then(function(position) {
expect(position.start).toEqual({line: 2, column: 2})
done()
})
})
it("returns {5, 10} for start of ['info', 'contact', 'name']", function(done) {
positionRangeForPath(yaml, ["info", "contact", "name"]).then(function(position) {
expect(position.start).toEqual({line: 5, column: 10})
done()
})
})
it("returns {5, 15} for end of ['info', 'contact', 'name']", function(done) {
positionRangeForPath(yaml, ["info", "contact", "name"]).then(function(position) {
expect(position.end).toEqual({line: 5, column: 15})
done()
})
})
})
})
})
/* eslint-env mocha */
import expect, { createSpy } from "expect"
import { fromJS } from "immutable"
import { execute } from "corePlugins/auth/spec-wrap-actions"
describe("spec plugin - actions", function(){
......@@ -18,7 +17,7 @@ describe("spec plugin - actions", function(){
// When
let executeFn = execute(oriExecute, system)
let executePromise = executeFn({})
executeFn({})
// Then
expect(oriExecute.calls.length).toEqual(1)
......
import expect, { createSpy } from "expect"
import expect from "expect"
import { Map, List } from "immutable"
import { transform } from "corePlugins/err/error-transformers/transformers/not-of-type"
......
import expect, { createSpy } from "expect"
import { Map, List, fromJS } from "immutable"
import expect from "expect"
import { fromJS } from "immutable"
import { transform } from "corePlugins/err/error-transformers/transformers/parameter-oneof"
describe.skip("err plugin - tranformers - parameter oneof", () => {
......
......@@ -396,7 +396,7 @@ describe("createXMLExample", function () {
})
it("returns array with default values with wrapped=true", function () {
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<animal>one</animal>\n</animals>"
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<animal>1</animal>\n\t<animal>2</animal>\n</animals>"
var definition = {
items: {
"enum": ["one", "two"],
......@@ -405,6 +405,7 @@ describe("createXMLExample", function () {
name: "animal"
}
},
"default": ["1", "2"],
xml: {
wrapped: true,
name: "animals"
......@@ -413,8 +414,53 @@ describe("createXMLExample", function () {
expect(sut(definition)).toEqual(expected)
})
it("returns array with example values with ", function () {
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<animal>1</animal>\n\t<animal>2</animal>\n</animals>"
var definition = {
type: "object",
properties: {
"animal": {
"type": "array",
"items": {
"type": "string"
},
"example": [
"1",
"2"
]
}
},
xml: {
name: "animals"
}
}
expect(sut(definition)).toEqual(expected)
})
it("returns array with example values with wrapped=true", function () {
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<animal>1</animal>\n\t<animal>2</animal>\n</animals>"
var definition = {
type: "array",
items: {
type: "string",
xml: {
name: "animal"
}
},
"example": [ "1", "2" ],
xml: {
wrapped: true,
name: "animals"
}
}
expect(sut(definition)).toEqual(expected)
})
})
describe("object", function () {
it("returns object with 2 properties", function () {
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<aliens>\n\t<alien>string</alien>\n\t<dog>0</dog>\n</aliens>"
......
/* eslint-env mocha */
import expect from "expect"
import { fromJS } from "immutable"
import reducer from "corePlugins/spec/reducers"
describe("spec plugin - reducer", function(){
describe("update operation value", function() {
it("should update the operation at the specified key", () => {
const updateOperationValue = reducer["spec_update_operation_value"]
const state = fromJS({
resolved: {
"paths": {
"/pet": {
"post": {
"description": "my operation"
}
}
}
}
})
let result = updateOperationValue(state, {
payload: {
path: ["/pet", "post"],
value: "application/json",
key: "consumes_value"
}
})
let expectedResult = {
resolved: {
"paths": {
"/pet": {
"post": {
"description": "my operation",
"consumes_value": "application/json"
}
}
}
}
}
expect(result.toJS()).toEqual(expectedResult)
})
it("shouldn't throw an error if we try to update the consumes_value of a null operation", () => {
const updateOperationValue = reducer["spec_update_operation_value"]
const state = fromJS({
resolved: {
"paths": {
"/pet": {
"post": null
}
}
}
})
let result = updateOperationValue(state, {
payload: {
path: ["/pet", "post"],
value: "application/json",
key: "consumes_value"
}
})
expect(result.toJS()).toEqual(state.toJS())
})
})
})
......@@ -25,7 +25,7 @@ describe("spec plugin - actions", function(){
// When
let executeFn = execute({ path: "/one", method: "get"})
let executePromise = executeFn(system)
executeFn(system)
// Then
expect(system.specActions.executeRequest.calls[0].arguments[0]).toEqual({
......@@ -60,7 +60,7 @@ describe("spec plugin - actions", function(){
// When
let executeFn = execute({ hi: "hello" })
let executePromise = executeFn(system)
executeFn(system)
// Then
expect(system.specActions.executeRequest.calls[0].arguments[0]).toInclude({hi: "hello"})
......@@ -72,7 +72,6 @@ describe("spec plugin - actions", function(){
xit("should call fn.execute with arg ", function(){
const response = {}
const system = {
fn: {
execute: createSpy().andReturn(Promise.resolve())
......
/* eslint-env mocha */
import expect, { createSpy } from "expect"
import expect from "expect"
import { fromJS } from "immutable"
import { parameterValues, contentTypeValues } from "corePlugins/spec/selectors"
import { parameterValues, contentTypeValues, operationScheme } from "corePlugins/spec/selectors"
describe("spec plugin - selectors", function(){
......@@ -92,4 +92,43 @@ describe("spec plugin - selectors", function(){
})
describe("operationScheme", function(){
it("should return the correct scheme for a remote spec that doesn't specify a scheme", function(){
// Given
let state = fromJS({
url: "https://generator.swagger.io/api/swagger.json",
resolved: {
paths: {
"/one": {
get: {
"consumes_value": "one",
"produces_value": "two"
}
}
}
}
})
// When
let scheme = operationScheme(state, ["/one"], "get")
// Then
expect(scheme).toEqual("https")
})
// it("should be ok, if no operation found", function(){
// // Given
// let state = fromJS({ })
//
// // When
// let contentTypes = contentTypeValues(state, [ "/one", "get" ])
// // Then
// expect(contentTypes.toJS()).toEqual({
// requestContentType: undefined,
// responseContentType: undefined
// })
// })
})
})
......@@ -240,6 +240,7 @@ describe("bound system", function(){
statePlugins: {
kyle: {
wrapActions: {
// eslint-disable-next-line no-unused-vars
simple: (ori) => (arg) => (sys) => {
return { type: "called" }
}
......@@ -256,7 +257,7 @@ describe("bound system", function(){
})
})
describe("selectors", function(){
......
/* eslint-env mocha */
import expect, { createSpy } from "expect"
import expect from "expect"
import { fromJS } from "immutable"
import { mapToList } from "core/utils"
......
......@@ -13,6 +13,7 @@ module.exports = require('./make-webpack-config.js')({
entry: {
'swagger-ui-bundle': [
'babel-polyfill',
'./src/core/index.js'
]
},
......
......@@ -15,13 +15,18 @@ module.exports = require('./make-webpack-config.js')({
entry: {
"swagger-ui": [
'babel-polyfill',
'./src/style/main.scss',
'./src/core/index.js'
]
},
externals: function(context, request, cb) {
if(node_modules.indexOf(request) !== -1) {
// webpack injects some stuff into the resulting file,
// these libs need to be pulled in to keep that working.
var exceptionsForWebpack = ["ieee754", "base64-js"]
if(node_modules.indexOf(request) !== -1 || exceptionsForWebpack.indexOf(request) !== -1) {
console.log(request)
cb(null, 'commonjs ' + request)
return;
}
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册