Merge branch 'master' into issue-1334

* master: (50 commits)
  update NoErrorsPlugin to NoEmitOnErrorsPlugin
  Undo change to `swagger-client` dependency
  trigger setScheme when a new set of schemes come in
  fix eslint issues
  pin yams version
  update dist
  revert dependencies
  minify bundle css
  migrate webpack to v2.6.1
  #3110 - Fix models down arrow icon in firefox
  Fixes #3299 - export validateNumber and validateInteger for easy reuse and testing. Broke validateParam required check onto multiple lines. Added tests for validateNumber, validateInteger, and validateParam
  Improve README with more information about `urls`
  Rename variable: "selectedName" -> "primaryName"
  "name" -> "urls.primaryName"
  Update selectedIndex when a new URL is loaded
  Use select value to avoid react warning
  Properly added name config Now access it through getConfigs Documented it in README
  Add displayRequestDuration configuration option.
  Fix for #2947 - Display property names for non-object models
  #3256 - Remove unnecessary JSON.stringify call on example values that are already strings
  ...

# Conflicts:
#	dist/swagger-ui-bundle.js
#	dist/swagger-ui-bundle.js.map
#	dist/swagger-ui-standalone-preset.js
#	dist/swagger-ui-standalone-preset.js.map
#	dist/swagger-ui.css
#	dist/swagger-ui.css.map
#	dist/swagger-ui.js
#	dist/swagger-ui.js.map
#	make-webpack-config.js
#	package.json
#	webpack-dist.config.js
#	webpack-hot-dev-server.config.js
This commit is contained in:
RVKen
2017-06-30 23:24:43 +02:00
68 changed files with 690 additions and 207 deletions

View File

@@ -5,6 +5,7 @@
"stage-0"
],
"plugins": [
"transform-runtime",
[
"module-alias",
[

View File

@@ -6,6 +6,8 @@
**This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).**
**👉🏼 Want to score an easy open-source contribution?** Check out our [Good first contribution](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+contribution%22) label.
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.
This repo publishes to two different NPM packages:
@@ -20,7 +22,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.16 | 2017-06-17 | 2.0 | [tag v3.0.16](https://github.com/swagger-api/swagger-ui/tree/v3.0.16) |
3.0.17 | 2017-06-23 | 2.0 | [tag v3.0.17](https://github.com/swagger-api/swagger-ui/tree/v3.0.17) |
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) |
@@ -131,9 +133,13 @@ If you'd like to use the bundle files via npm, check out the [`swagger-ui-dist`
#### Parameters
Parameters with dots in their names are single strings used to organize subordinate parameters, and are not indicative of a nested structure.
Parameter Name | Description
--- | ---
url | The url pointing to API definition (normally `swagger.json` or `swagger.yaml`).
url | The url pointing to API definition (normally `swagger.json` or `swagger.yaml`). Will be ignored if `urls` or `spec` is used.
urls | An array of API definition objects (`{url: "<url>", name: "<name>"}`) used by Topbar plugin. When used and Topbar plugin is enabled, the `url` parameter will not be parsed. Names and URLs must be unique among all items in this array, since they're used as identifiers.
urls.primaryName | When using `urls`, you can use this subparameter. If the value matches the name of a spec provided in `urls`, that spec will be displayed when Swagger-UI loads, instead of defaulting to the first spec in `urls`.
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.
@@ -144,11 +150,12 @@ parameterMacro | MUST be a function. Function to set default value to parameters
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
docExpansion | Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). The default is 'list'.
displayOperationId | Controls the display of operationId in operations list. The default is `false`.
displayRequestDuration | Controls the display of the request duration (in milliseconds) for `Try it out` requests. The default is `false`.
### Plugins
#### Topbar plugin
Topbar plugin enables top bar with input for spec path and explore button. By default the plugin is enabled, and to disable it you need to remove Topbar plugin from presets in `src/standalone/index.js`:
Topbar plugin enables top bar with input for spec path and explore button or a dropdown if `urls` is used. By default the plugin is enabled, and to disable it you need to remove Topbar plugin from presets in `src/standalone/index.js`:
```
let preset = [

1
dist/index.html vendored
View File

@@ -71,6 +71,7 @@
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://petstore.swagger.io/v2/swagger.json",

View File

@@ -73,7 +73,7 @@ module.exports = function(rules, options) {
})
)
plugins.push( new webpack.NoErrorsPlugin())
plugins.push( new webpack.NoEmitOnErrorsPlugin())
} else { // development mode
var spec
@@ -141,7 +141,7 @@ module.exports = function(rules, options) {
],
extensions: [".web.js", ".js", ".jsx", ".json", ".less"],
alias: {
base: "getbase/src/less/base"
base: "getbase/src/less/base",
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "3.0.16",
"version": "3.0.17",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
@@ -38,7 +38,6 @@
"dev:e2e": "TEST_SPEC_NAME=1.json webpack-dev-server --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress --content-base dev-helpers/"
},
"dependencies": {
"babel-polyfill": "^6.23.0",
"base64-js": "^1.2.0",
"brace": "0.10.0",
"deep-extend": "0.4.1",
@@ -52,6 +51,7 @@
"matcher": "^1.0.0",
"memoizee": "0.4.5",
"promise-worker": "^1.1.1",
"prop-types": "^15.5.10",
"react": "^15.4.0",
"react-addons-perf": "15.4.2",
"react-addons-shallow-compare": "15.6.0",
@@ -71,14 +71,14 @@
"redux-logger": "*",
"reselect": "3.0.1",
"sanitize-html": "^1.14.1",
"serialize-error": "2.1.0",
"shallowequal": "1.0.1",
"swagger-client": "~3.0.15",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "3.0.16",
"url-parse": "^1.1.8",
"whatwg-fetch": "2.0.3",
"worker-loader": "^0.8.0",
"xml": "1.0.1",
"yaml-js": "^0.2.0"
"yaml-js": "0.2.0"
},
"devDependencies": {
"autoprefixer": "7.1.1",
@@ -86,6 +86,7 @@
"babel-eslint": "^7.1.1",
"babel-loader": "^7.1.0",
"babel-plugin-module-alias": "^1.6.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-es2015-ie": "^6.6.2",
"babel-preset-react": "^6.23.0",
@@ -139,7 +140,7 @@
"browserslist": [
"> 1%",
"last 2 versions",
"IE 10"
"IE 11"
],
"optionalDependencies": {
"webpack-dev-server": "2.5.0"

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class App extends React.Component {
@@ -6,7 +7,7 @@ export default class App extends React.Component {
let { getComponent, layoutSelectors } = this.props
const layoutName = layoutSelectors.current()
const Component = getComponent(layoutName, true)
return Component ? Component : ()=> <h1> No layout defined for "{layoutName}" </h1>
return Component ? Component : ()=> <h1> No layout defined for &quot;{layoutName}&quot; </h1>
}
render() {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class ApiKeyAuth extends React.Component {
static propTypes = {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class AuthorizationPopup extends React.Component {
close =() => {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class AuthorizeBtn extends React.Component {
static propTypes = {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
export default class AuthorizeOperationBtn extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
export default class Auths extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
export default class BasicAuth extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class AuthError extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import oauth2Authorize from "core/oauth2-authorize"
const IMPLICIT = "implicit"

View File

@@ -1,4 +1,5 @@
import React, { Component, PropTypes } from "react"
import React, { Component } from "react"
import PropTypes from "prop-types"
export default class Clear extends Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { fromJS } from "immutable"

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import curlify from "core/curlify"
export default class Curl extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import Collapse from "react-collapse"
import { presets } from "react-motion"
import ObjectInspector from "react-object-inspector"

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import { List } from "immutable"
import Collapse from "react-collapse"

View File

@@ -1,4 +1,5 @@
import React, { Component, PropTypes } from "react"
import React, { Component } from "react"
import PropTypes from "prop-types"
export default class Execute extends Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import Im from "immutable"
export default class Headers extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { Component, PropTypes } from "react"
import React, { Component } from "react"
import PropTypes from "prop-types"
import { highlight } from "core/utils"
export default class HighlightCode extends Component {
@@ -8,17 +9,21 @@ export default class HighlightCode extends Component {
}
componentDidMount() {
highlight(this.refs.el)
highlight(this.el)
}
componentDidUpdate() {
highlight(this.refs.el)
highlight(this.el)
}
initializeComponent = (c) => {
this.el = c
}
render () {
let { value, className } = this.props
className = className || ""
return <pre ref="el" className={className + " microlight"}>{ value }</pre>
return <pre ref={this.initializeComponent} className={className + " microlight"}>{ value }</pre>
}
}

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import { fromJS } from "immutable"
import ImPropTypes from "react-immutable-proptypes"

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import OriCollapse from "react-collapse"
function xclass(...args) {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class BaseLayout extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class XPane extends React.Component {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
const Headers = ( { headers } )=>{
@@ -8,28 +9,40 @@ const Headers = ( { headers } )=>{
<pre>{headers}</pre>
</div>)
}
Headers.propTypes = {
headers: PropTypes.array.isRequired
}
const Duration = ( { duration } ) => {
return (
<div>
<h5>Request duration</h5>
<pre>{duration} ms</pre>
</div>
)
}
Duration.propTypes = {
duration: PropTypes.number.isRequired
}
export default class LiveResponse extends React.Component {
static propTypes = {
response: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
getComponent: PropTypes.func.isRequired,
displayRequestDuration: PropTypes.bool.isRequired
}
render() {
const { request, response, getComponent } = this.props
const { request, response, getComponent, displayRequestDuration } = this.props
const status = response.get("status")
const url = response.get("url")
const headers = response.get("headers").toJS()
const notDocumented = response.get("notDocumented")
const isError = response.get("error")
const body = isError ? response.get("response").get("text") : response.get("text")
const body = response.get("text")
const duration = response.get("duration")
const headersKeys = Object.keys(headers)
const contentType = headers["content-type"]
@@ -80,6 +93,9 @@ export default class LiveResponse extends React.Component {
{
hasHeaders ? <Headers headers={ returnObject }/> : null
}
{
displayRequestDuration && duration ? <Duration duration={ duration } /> : null
}
</td>
</tr>
</tbody>

View File

@@ -1,5 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class ModelExample extends React.Component {
static propTypes = {

View File

@@ -1,4 +1,5 @@
import React, { Component, PropTypes } from "react"
import React, { Component } from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { List } from "immutable"
const braceOpen = "{"
@@ -117,12 +118,13 @@ class ObjectModel extends Component {
class Primitive extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
name: PropTypes.string,
getComponent: PropTypes.func.isRequired,
required: PropTypes.bool
}
render(){
let { schema, getComponent, required } = this.props
let { schema, getComponent, name, required } = this.props
if(!schema || !schema.get) {
// don't render if schema isn't correctly formed
@@ -133,12 +135,18 @@ class Primitive extends Component {
let format = schema.get("format")
let xml = schema.get("xml")
let enumArray = schema.get("enum")
let title = schema.get("title") || name
let description = schema.get("description")
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
let style = required ? { fontWeight: "bold" } : {}
const Markdown = getComponent("Markdown")
return <span className="prop">
return <span className="model">
{
title && <span className="model-title" style={{ marginRight: "2em" }}>
<span className="model-title__text">{ title }</span>
</span>
}
<span className="prop-type" style={ style }>{ type }</span> { required && <span style={{ color: "red" }}>*</span>}
{ format && <span className="prop-format">(${format})</span>}
{
@@ -176,17 +184,20 @@ class ArrayModel extends Component {
}
render(){
let { required, schema, depth, expandDepth } = this.props
let { required, schema, depth, name, expandDepth } = this.props
let items = schema.get("items")
let title = schema.get("title") || name
let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 )
return <span className="model">
<span className="model-title">
<span className="model-title__text">{ schema.get("title") }</span>
{
title && <span className="model-title">
<span className="model-title__text">{ title }</span>
</span>
}
<Collapse collapsed={ depth > expandDepth } collapsedContent="[...]">
[
<span><Model { ...this.props } schema={ items } required={ false }/></span>
<span><Model { ...this.props } name="" schema={ items } required={ false }/></span>
]
{
properties.size ? <span>
@@ -249,13 +260,13 @@ class Model extends Component {
name={ name || modelName }
isRef={ isRef!== undefined ? isRef : !!$$ref }/>
case "array":
return <ArrayModel className="array" { ...this.props } schema={ modelSchema } required={ required } />
return <ArrayModel className="array" { ...this.props } schema={ modelSchema } name={ name || modelName } required={ required } />
case "string":
case "number":
case "integer":
case "boolean":
default:
return <Primitive getComponent={ getComponent } schema={ modelSchema } required={ required }/>
return <Primitive { ...this.props } getComponent={ getComponent } schema={ modelSchema } name={ name || modelName } required={ required }/>
}
}
}

View File

@@ -1,5 +1,5 @@
import React, { Component, PropTypes } from "react"
import React, { Component } from "react"
import PropTypes from "prop-types"
export default class Models extends Component {
static propTypes = {
@@ -24,8 +24,8 @@ export default class Models extends Component {
return <section className={ showModels ? "models is-open" : "models"}>
<h4 onClick={() => layoutActions.show("models", !showModels)}>
<span>Models</span>
<svg width="20" height="20">
<use xlinkHref="#large-arrow" />
<svg className="arrow" width="20" height="20">
<use xlinkHref={showModels ? "#large-arrow-down" : "#large-arrow"} />
</svg>
</h4>
<Collapse isOpened={showModels} animated>

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class OnlineValidatorBadge extends React.Component {
static propTypes = {

View File

@@ -1,11 +1,11 @@
import React, { PropTypes } from "react"
import shallowCompare from "react-addons-shallow-compare"
import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import { getList } from "core/utils"
import * as CustomPropTypes from "core/proptypes"
//import "less/opblock"
export default class Operation extends React.Component {
export default class Operation extends PureComponent {
static propTypes = {
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
@@ -18,6 +18,7 @@ export default class Operation extends React.Component {
allowTryItOut: PropTypes.bool,
displayOperationId: PropTypes.bool,
displayRequestDuration: PropTypes.bool,
response: PropTypes.object,
request: PropTypes.object,
@@ -38,6 +39,7 @@ export default class Operation extends React.Component {
response: null,
allowTryItOut: true,
displayOperationId: false,
displayRequestDuration: false
}
constructor(props, context) {
@@ -70,10 +72,6 @@ export default class Operation extends React.Component {
}
}
shouldComponentUpdate(props, state) {
return shallowCompare(this, props, state)
}
toggleShown =() => {
let { layoutActions, isShownKey } = this.props
layoutActions.show(isShownKey, !this.isShown())
@@ -112,7 +110,7 @@ export default class Operation extends React.Component {
request,
allowTryItOut,
displayOperationId,
displayRequestDuration,
fn,
getComponent,
specActions,
@@ -131,6 +129,7 @@ export default class Operation extends React.Component {
let schemes = operation.get("schemes")
let parameters = getList(operation, ["parameters"])
let operationId = operation.get("__originalOperationId")
let operationScheme = specSelectors.operationScheme(path, method)
const Responses = getComponent("responses")
const Parameters = getComponent( "parameters" )
@@ -216,7 +215,8 @@ export default class Operation extends React.Component {
<Schemes schemes={ schemes }
path={ path }
method={ method }
specActions={ specActions }/>
specActions={ specActions }
operationScheme={ operationScheme } />
</div> : null
}
@@ -255,6 +255,7 @@ export default class Operation extends React.Component {
produces={ produces }
producesValue={ operation.get("produces_value") }
pathMethod={ [path, method] }
displayRequestDuration={ displayRequestDuration }
fn={fn} />
}
</div>

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class Operations extends React.Component {
@@ -32,7 +33,7 @@ export default class Operations extends React.Component {
const Collapse = getComponent("Collapse")
let showSummary = layoutSelectors.showSummary()
let { docExpansion, displayOperationId } = getConfigs()
let { docExpansion, displayOperationId, displayRequestDuration } = getConfigs()
return (
<div>
@@ -87,6 +88,7 @@ export default class Operations extends React.Component {
allowTryItOut={allowTryItOut}
displayOperationId={displayOperationId}
displayRequestDuration={displayRequestDuration}
specActions={ specActions }
specSelectors={ specSelectors }

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import { Link } from "core/components/layout-utils"
export default class Overview extends React.Component {

View File

@@ -1,11 +1,11 @@
import React, { Component, PropTypes } from "react"
import shallowCompare from "react-addons-shallow-compare"
import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import { fromJS, List } from "immutable"
import { getSampleSchema } from "core/utils"
const NOOP = Function.prototype
export default class ParamBody extends Component {
export default class ParamBody extends PureComponent {
static propTypes = {
param: PropTypes.object,
@@ -41,10 +41,6 @@ export default class ParamBody extends Component {
this.updateValues.call(this, this.props)
}
shouldComponentUpdate(props, state) {
return shallowCompare(this, props, state)
}
componentWillReceiveProps(nextProps) {
this.updateValues.call(this, nextProps)
}

View File

@@ -1,7 +1,7 @@
import React, { Component, PropTypes } from "react"
import React, { Component } from "react"
import PropTypes from "prop-types"
import win from "core/window"
export default class ParameterRow extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,

View File

@@ -1,4 +1,5 @@
import React, { Component, PropTypes } from "react"
import React, { Component } from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import Im from "immutable"

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import Remarkable from "react-remarkable"
import sanitize from "sanitize-html"
@@ -11,6 +12,12 @@ const sanitizeOptions = {
function Markdown({ source }) {
const sanitized = sanitize(source, sanitizeOptions)
// sometimes the sanitizer returns "undefined" as a string
if(!source || !sanitized || sanitized === "undefined") {
return null
}
return <Remarkable
options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
source={sanitized}

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import { formatXml } from "core/utils"
import lowerCase from "lodash/lowerCase"
@@ -6,7 +7,7 @@ export default class ResponseBody extends React.Component {
static propTypes = {
content: PropTypes.any.isRequired,
contentType: PropTypes.string.isRequired,
contentType: PropTypes.string,
getComponent: PropTypes.func.isRequired,
headers: PropTypes.object,
url: PropTypes.string

View File

@@ -1,18 +1,21 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
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
let exampleValue = example
if ( example.toJS ) {
try {
exampleValue = example && example.toJS ? example.toJS() : example
exampleValue = JSON.stringify(exampleValue, null, 2)
exampleValue = JSON.stringify(example.toJS(), null, 2)
}
catch(e) {
exampleValue = String(example)
}
}
return (<div key={ key }>
<h5>{ key }</h5>
<HighlightCode className="example" value={ exampleValue } />

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import { fromJS } from "immutable"
import { defaultStatusCode } from "core/utils"
@@ -14,19 +15,21 @@ export default class Responses extends React.Component {
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired,
displayRequestDuration: PropTypes.bool.isRequired,
fn: PropTypes.object.isRequired
}
static defaultProps = {
request: null,
tryItOutResponse: null,
produces: fromJS(["application/json"])
produces: fromJS(["application/json"]),
displayRequestDuration: false
}
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val)
render() {
let { responses, request, tryItOutResponse, getComponent, specSelectors, fn, producesValue } = this.props
let { responses, request, tryItOutResponse, getComponent, specSelectors, fn, producesValue, displayRequestDuration } = this.props
let defaultCode = defaultStatusCode( responses )
const ContentType = getComponent( "contentType" )
@@ -53,7 +56,8 @@ export default class Responses extends React.Component {
: <div>
<LiveResponse request={ request }
response={ tryItOutResponse }
getComponent={ getComponent } />
getComponent={ getComponent }
displayRequestDuration={ displayRequestDuration } />
<h4>Responses</h4>
</div>

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class Schemes extends React.Component {
@@ -6,7 +7,8 @@ export default class Schemes extends React.Component {
specActions: PropTypes.object.isRequired,
schemes: PropTypes.object.isRequired,
path: PropTypes.string,
method: PropTypes.string
method: PropTypes.string,
operationScheme: PropTypes.string
}
componentWillMount() {
@@ -16,11 +18,18 @@ export default class Schemes extends React.Component {
this.setScheme(schemes.first())
}
componentWillReceiveProps(nextProps) {
if ( this.props.operationScheme && !nextProps.schemes.has(this.props.operationScheme) ) {
//fire 'change' event if our selected scheme is no longer an option
this.setScheme(nextProps.schemes.first())
}
}
onChange =( e ) => {
this.setScheme( e.target.value )
}
setScheme =( value ) => {
setScheme = ( value ) => {
let { path, method, specActions } = this.props
specActions.setScheme( value, path, method )

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class TryItOutButton extends React.Component {

View File

@@ -6,9 +6,9 @@ import ApisPreset from "core/presets/apis"
import * as AllPlugins from "core/plugins/all"
import { parseSeach, filterConfigs } from "core/utils"
const CONFIGS = [ "url", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion",
const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion",
"apisSorter", "operationsSorter", "supportedSubmitMethods", "dom_id", "defaultModelRendering", "oauth2RedirectUrl",
"showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" ]
"showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" , "displayRequestDuration"]
// eslint-disable-next-line no-undef
const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION } = buildInfo
@@ -23,12 +23,14 @@ module.exports = function SwaggerUI(opts) {
dom_id: null,
spec: {},
url: "",
urls: null,
layout: "BaseLayout",
docExpansion: "list",
validatorUrl: "https://online.swagger.io/validator",
configs: {},
custom: {},
displayOperationId: false,
displayRequestDuration: false,
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
@@ -117,6 +119,7 @@ module.exports = function SwaggerUI(opts) {
return downloadSpec()
}
return system
}
// Add presets

View File

@@ -1,5 +1,5 @@
import React, { PropTypes, Component } from "react"
import shallowCompare from "react-addons-shallow-compare"
import React, { PureComponent, Component } from "react"
import PropTypes from "prop-types"
import { List, fromJS } from "immutable"
//import "less/json-schema-form"
@@ -74,7 +74,7 @@ export class JsonSchema_string extends Component {
}
}
export class JsonSchema_array extends Component {
export class JsonSchema_array extends PureComponent {
static propTypes = JsonSchemaPropShape
static defaultProps = JsonSchemaDefaultProps
@@ -89,10 +89,6 @@ export class JsonSchema_array extends Component {
this.setState({value: props.value})
}
shouldComponentUpdate(props, state) {
return shallowCompare(this, props, state)
}
onChange = () => this.props.onChange(this.state.value)
onItemChange = (itemVal, i) => {

View File

@@ -9,7 +9,7 @@ const primitives = {
"number": () => 0,
"number_float": () => 0.0,
"integer": () => 0,
"boolean": () => true
"boolean": (schema) => typeof schema.default === "boolean" ? schema.default : true
}
const primitive = (schema) => {
@@ -74,6 +74,10 @@ export const sampleFromSchema = (schema, config={}) => {
return normalizeArray(schema["enum"])[0]
}
if (type === "file") {
return
}
return primitive(schema)
}

View File

@@ -207,8 +207,14 @@ export const executeRequest = (req) => ({fn, specActions, specSelectors}) => {
specActions.setRequest(req.pathName, req.method, parsedRequest)
// track duration of request
const startTime = Date.now()
return fn.execute(req)
.then( res => specActions.setResponse(req.pathName, req.method, res))
.then( res => {
res.duration = Date.now() - startTime
specActions.setResponse(req.pathName, req.method, res)
} )
.catch( err => specActions.setResponse(req.pathName, req.method, { error: true, err: serializeError(err) } ) )
}

View File

@@ -41,7 +41,7 @@ export default {
[UPDATE_PARAM]: ( state, {payload} ) => {
let { path, paramName, value, isXml } = payload
return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
let index = parameters.findIndex( p => p.get( "name" ) === paramName )
const index = parameters.findIndex(p => p.get( "name" ) === paramName )
if (!(value instanceof win.File)) {
value = fromJSOrdered( value )
}
@@ -75,7 +75,12 @@ export default {
[SET_RESPONSE]: (state, { payload: { res, path, method } } ) =>{
let result
if ( res.error ) {
result = Object.assign({error: true}, res.err)
result = Object.assign({
error: true,
name: res.err.name,
message: res.err.message,
statusCode: res.err.statusCode
}, res.err.response)
} else {
result = res
}
@@ -86,7 +91,7 @@ export default {
let newState = state.setIn( [ "responses", path, method ], fromJSOrdered(result) )
// ImmutableJS messes up Blob. Needs to reset its value.
if (res.data instanceof win.Blob) {
if (win.Blob && res.data instanceof win.Blob) {
newState = newState.setIn( [ "responses", path, method, "text" ], res.data)
}
return newState

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
import SplitPane from "react-split-pane"
import "./split-pane-mode.less"
@@ -23,9 +24,13 @@ export default class SplitPaneMode extends React.Component {
children: [],
};
initializeComponent = (c) => {
this.splitPane = c
}
onDragFinished = () => {
let { threshold, layoutActions } = this.props
let { position, draggedSize } = this.refs.splitPane.state
let { position, draggedSize } = this.splitPane.state
this.draggedSize = draggedSize
let nearLeftEdge = position <= threshold
@@ -62,7 +67,7 @@ export default class SplitPaneMode extends React.Component {
return (
<SplitPane
disabledClass={""}
ref={"splitPane"}
ref={this.initializeComponent}
split='vertical'
defaultSize={"50%"}
primary="second"

View File

@@ -65,11 +65,11 @@ export const render = (getSystem, getStore, getComponent, getComponents, dom) =>
}
// Render try/catch wrapper
const createClass = component => React.createClass({
const createClass = component => class extends Component {
render() {
return component(this.props)
}
})
}
const Fallback = ({ name }) => <div style={{ // eslint-disable-line react/prop-types
padding: "1em",

View File

@@ -1,4 +1,4 @@
import { PropTypes } from "react"
import PropTypes from "prop-types"
// Takes a list and proptype, and returns a PropType.shape({ [item]: propType })
const mapListToPropTypeShape = (list, propType) => PropTypes.shape(

View File

@@ -240,7 +240,7 @@ export default class Store {
action = {type: NEW_THROWN_ERR, error: true, payload: serializeError(e) }
}
finally{
return action
return action // eslint-disable-line no-unsafe-finally
}
}

View File

@@ -1,9 +1,9 @@
import Im from "immutable"
import shallowEqual from "shallowequal"
import camelCase from "lodash/camelCase"
import upperFirst from "lodash/upperFirst"
import _memoize from "lodash/memoize"
import find from "lodash/find"
import some from "lodash/some"
import eq from "lodash/eq"
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
@@ -343,7 +343,7 @@ export function highlight (el) {
while (![
1, // 0: whitespace
// 1: operator or braces
/[\/{}[(\-+*=<>:;|\\.,?!&@~]/[test](chr),
/[\/{}[(\-+*=<>:;|\\.,?!&@~]/[test](chr), // eslint-disable-line no-useless-escape
/[\])]/[test](chr), // 2: closing brace
/[$\w]/[test](chr), // 3: (key)word
chr == "/" && // 4: regex
@@ -418,11 +418,6 @@ export function pascalCaseFilename(filename) {
return pascalCase(filename.replace(/\.[^./]*$/, ""))
}
// Only compare a set of props
export function shallowEqualKeys(a,b, keys) {
return !!keys.find(key => !shallowEqual(a[key], b[key]))
}
// Check if ...
// - new props
// - If immutable, use .is()
@@ -455,15 +450,15 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
}
const validateNumber = ( val ) => {
if ( !/^-?\d+(.?\d+)?$/.test(val)) {
export const validateNumber = ( val ) => {
if ( !/^-?\d+(\.?\d+)?$/.test(val)) {
return "Value must be a number"
}
}
const validateInteger = ( val ) => {
export const validateInteger = ( val ) => {
if ( !/^-?\d+$/.test(val)) {
return "Value must be integer"
return "Value must be an integer"
}
}
@@ -474,13 +469,14 @@ export const validateParam = (param, isXml) => {
let required = param.get("required")
let type = param.get("type")
if ( required && (!value || (type==="array" && Array.isArray(value) && !value.length ))) {
let stringCheck = type === "string" && !value
let arrayCheck = type === "array" && Array.isArray(value) && !value.length
let listCheck = type === "array" && Im.List.isList(value) && !value.count()
if ( required && (stringCheck || arrayCheck || listCheck) ) {
errors.push("Required field is not provided")
return errors
}
if ( !value ) return errors
if ( type === "number" ) {
let err = validateNumber(value)
if (!err) return errors
@@ -593,3 +589,10 @@ export const filterConfigs = (configs, allowed) => {
return filteredConfigs
}
// Is this really required as a helper? Perhaps. TODO: expose the system of presets.apis in docs, so we know what is supported
export const shallowEqualKeys = (a,b, keys) => {
return !!find(keys, (key) => {
return eq(a[key], b[key])
})
}

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
//import "./topbar.less"
import Logo from "./logo_small.png"
@@ -7,7 +8,7 @@ export default class Topbar extends React.Component {
constructor(props, context) {
super(props, context)
this.state = { url: props.specSelectors.url() }
this.state = { url: props.specSelectors.url(), selectedIndex: 0 }
}
componentWillReceiveProps(nextProps) {
@@ -19,14 +20,68 @@ export default class Topbar extends React.Component {
this.setState({url: value})
}
downloadUrl = (e) => {
this.props.specActions.updateUrl(this.state.url)
this.props.specActions.download(this.state.url)
loadSpec = (url) => {
this.props.specActions.updateUrl(url)
this.props.specActions.download(url)
}
onUrlSelect =(e)=> {
let url = e.target.value || e.target.href
this.loadSpec(url)
this.setSelectedUrl(url)
e.preventDefault()
}
downloadUrl = (e) => {
this.loadSpec(this.state.url)
e.preventDefault()
}
setSelectedUrl = (selectedUrl) => {
const configs = this.props.getConfigs()
const urls = configs.urls || []
if(urls && urls.length) {
if(selectedUrl)
{
urls.forEach((spec, i) => {
if(spec.url === selectedUrl)
{
this.setState({selectedIndex: i})
}
})
}
}
}
componentWillMount() {
const configs = this.props.getConfigs()
const urls = configs.urls || []
if(urls && urls.length) {
let primaryName = configs["urls.primaryName"]
if(primaryName)
{
urls.forEach((spec, i) => {
if(spec.name === primaryName)
{
this.setState({selectedIndex: i})
}
})
}
}
}
componentDidMount() {
const urls = this.props.getConfigs().urls || []
if(urls && urls.length) {
this.loadSpec(urls[this.state.selectedIndex].url)
}
}
render() {
let { getComponent, specSelectors } = this.props
let { getComponent, specSelectors, getConfigs } = this.props
const Button = getComponent("Button")
const Link = getComponent("Link")
@@ -36,6 +91,31 @@ export default class Topbar extends React.Component {
let inputStyle = {}
if(isFailed) inputStyle.color = "red"
if(isLoading) inputStyle.color = "#aaa"
const { urls } = getConfigs()
let control = []
let formOnSubmit = null
if(urls) {
let rows = []
urls.forEach((link, i) => {
rows.push(<option key={i} value={link.url}>{link.name}</option>)
})
control.push(
<label className="select-label" htmlFor="select"><span>Select a spec</span>
<select id="select" disabled={isLoading} onChange={ this.onUrlSelect } value={urls[this.state.selectedIndex].url}>
{rows}
</select>
</label>
)
}
else {
formOnSubmit = this.downloadUrl
control.push(<input className="download-url-input" type="text" onChange={ this.onUrlChange } value={this.state.url} disabled={isLoading} style={inputStyle} />)
control.push(<Button className="download-url-button" onClick={ this.downloadUrl }>Explore</Button>)
}
return (
<div className="topbar">
<div className="wrapper">
@@ -44,14 +124,12 @@ export default class Topbar extends React.Component {
<img height="30" width="30" src={ Logo } alt="Swagger UX"/>
<span>swagger</span>
</Link>
<form className="download-url-wrapper" onSubmit={this.downloadUrl}>
<input className="download-url-input" type="text" onChange={ this.onUrlChange } value={this.state.url} disabled={isLoading} style={inputStyle} />
<Button className="download-url-button" onClick={ this.downloadUrl }>Explore</Button>
<form className="download-url-wrapper" onSubmit={formOnSubmit}>
{control}
</form>
</div>
</div>
</div>
)
}
}
@@ -59,5 +137,6 @@ export default class Topbar extends React.Component {
Topbar.propTypes = {
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired
}

View File

@@ -1,11 +1,10 @@
.swagger-ui {
.topbar {
background-color: #89bf04;
}
.topbar-wrapper {
padding: 0.7em
padding: 0.7em;
}
.topbar-logo__img {

2
src/polyfills.js Normal file
View File

@@ -0,0 +1,2 @@
// Promise global, Used ( at least ) by 'whatwg-fetch'. And required by IE 11
require("core-js/fn/promise")

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from "react"
import React from "react"
import PropTypes from "prop-types"
export default class StandaloneLayout extends React.Component {

View File

@@ -95,14 +95,7 @@ section.models
h4
{
margin: 0 0 5px 0;
border-bottom: 1px solid rgba(#3b4151, .3);
svg
{
transform: rotate(90deg);
}
}
}
h4

View File

@@ -6,7 +6,6 @@
.topbar-wrapper
{
display: flex;
align-items: center;
}
a
@@ -15,13 +14,13 @@
font-weight: bold;
display: flex;
align-items: center;
flex: 1;
max-width: 300px;
text-decoration: none;
flex: 1;
align-items: center;
@include text_headline(#fff);
span
@@ -34,8 +33,8 @@
.download-url-wrapper
{
display: flex;
flex: 3;
justify-content: flex-end;
input[type=text]
{
@@ -48,6 +47,38 @@
outline: none;
}
.select-label
{
display: flex;
align-items: center;
width: 100%;
max-width: 600px;
margin: 0;
span
{
font-size: 16px;
flex: 1;
padding: 0 10px 0 0;
text-align: right;
}
select
{
flex: 2;
width: 100%;
border: 2px solid #547f00;
outline: none;
box-shadow: none;
}
}
.download-url-button
{
font-size: 16px;

View File

@@ -3,7 +3,7 @@
* @return {string} When run in NodeJS env, returns the absolute path to the current directory
* When run outside of NodeJS, will return an error message
*/
const getAbsoluteFSPath = () => {
const getAbsoluteFSPath = function () {
// detect whether we are running in a browser or nodejs
if (typeof module !== "undefined" && module.exports) {
return require("path").resolve(__dirname)

View File

@@ -0,0 +1,37 @@
/* eslint-env mocha */
import React from "react"
import expect from "expect"
import { render } from "enzyme"
import Markdown from "components/providers/markdown"
describe("UI-3279: Empty Markdown inputs causing bare `undefined` in output", function(){
it("should return no text for `null` as source input", function(){
let props = {
source: null
}
let el = render(<Markdown {...props}/>)
expect(el.text()).toEqual("")
})
it("should return no text for `undefined` as source input", function(){
let props = {
source: undefined
}
let el = render(<Markdown {...props}/>)
expect(el.text()).toEqual("")
})
it("should return no text for empty string as source input", function(){
let props = {
source: ""
}
let el = render(<Markdown {...props}/>)
expect(el.text()).toEqual("")
})
})

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-useless-escape */
import expect from "expect"
import { fromJS } from "immutable"
import { transform } from "corePlugins/err/error-transformers/transformers/parameter-oneof"

View File

@@ -69,4 +69,56 @@ describe("spec plugin - reducer", function(){
expect(result.toJS()).toEqual(state.toJS())
})
})
describe("set response value", function() {
it("should combine the response and error objects", () => {
const setResponse = reducer["spec_set_response"]
const path = "/pet/post"
const method = "POST"
const state = fromJS({})
const result = setResponse(state, {
payload: {
path: path,
method: method,
res: {
error: true,
err: {
message: "Not Found",
name: "Error",
response: {
data: "response data",
headers: {
key: "value"
},
ok: false,
status: 404,
statusText: "Not Found"
},
status: 404,
statusCode: 404
}
}
}
})
let expectedResult = {
error: true,
message: "Not Found",
name: "Error",
data: "response data",
headers: {
key: "value"
},
ok: false,
status: 404,
statusCode: 404,
statusText: "Not Found"
}
const response = result.getIn(["responses", path, method]).toJS()
expect(response).toEqual(expectedResult)
})
})
})

View File

@@ -1,7 +1,7 @@
/* eslint-env mocha */
import expect from "expect"
import { fromJS } from "immutable"
import { mapToList } from "core/utils"
import { mapToList, validateNumber, validateInteger, validateParam } from "core/utils"
describe("utils", function(){
@@ -67,9 +67,181 @@ describe("utils", function(){
// Then
expect(aList.toJS()).toEqual([])
})
})
describe("validateNumber", function() {
let errorMessage = "Value must be a number"
it("doesn't return for whole numbers", function() {
expect(validateNumber(0)).toBeFalsy()
expect(validateNumber(1)).toBeFalsy()
expect(validateNumber(20)).toBeFalsy()
expect(validateNumber(5000000)).toBeFalsy()
expect(validateNumber("1")).toBeFalsy()
expect(validateNumber("2")).toBeFalsy()
expect(validateNumber(-1)).toBeFalsy()
expect(validateNumber(-20)).toBeFalsy()
expect(validateNumber(-5000000)).toBeFalsy()
})
it("doesn't return for negative numbers", function() {
expect(validateNumber(-1)).toBeFalsy()
expect(validateNumber(-20)).toBeFalsy()
expect(validateNumber(-5000000)).toBeFalsy()
})
it("doesn't return for decimal numbers", function() {
expect(validateNumber(1.1)).toBeFalsy()
expect(validateNumber(2.5)).toBeFalsy()
expect(validateNumber(-30.99)).toBeFalsy()
})
it("returns a message for strings", function() {
expect(validateNumber("")).toEqual(errorMessage)
expect(validateNumber(" ")).toEqual(errorMessage)
expect(validateNumber("test")).toEqual(errorMessage)
})
it("returns a message for invalid input", function() {
expect(validateNumber(undefined)).toEqual(errorMessage)
expect(validateNumber(null)).toEqual(errorMessage)
expect(validateNumber({})).toEqual(errorMessage)
expect(validateNumber([])).toEqual(errorMessage)
expect(validateNumber(true)).toEqual(errorMessage)
expect(validateNumber(false)).toEqual(errorMessage)
})
})
describe("validateInteger", function() {
let errorMessage = "Value must be an integer"
it("doesn't return for positive integers", function() {
expect(validateInteger(0)).toBeFalsy()
expect(validateInteger(1)).toBeFalsy()
expect(validateInteger(20)).toBeFalsy()
expect(validateInteger(5000000)).toBeFalsy()
expect(validateInteger("1")).toBeFalsy()
expect(validateInteger("2")).toBeFalsy()
expect(validateInteger(-1)).toBeFalsy()
expect(validateInteger(-20)).toBeFalsy()
expect(validateInteger(-5000000)).toBeFalsy()
})
it("doesn't return for negative integers", function() {
expect(validateInteger(-1)).toBeFalsy()
expect(validateInteger(-20)).toBeFalsy()
expect(validateInteger(-5000000)).toBeFalsy()
})
it("returns a message for decimal values", function() {
expect(validateInteger(1.1)).toEqual(errorMessage)
expect(validateInteger(2.5)).toEqual(errorMessage)
expect(validateInteger(-30.99)).toEqual(errorMessage)
})
it("returns a message for strings", function() {
expect(validateInteger("")).toEqual(errorMessage)
expect(validateInteger(" ")).toEqual(errorMessage)
expect(validateInteger("test")).toEqual(errorMessage)
})
it("returns a message for invalid input", function() {
expect(validateInteger(undefined)).toEqual(errorMessage)
expect(validateInteger(null)).toEqual(errorMessage)
expect(validateInteger({})).toEqual(errorMessage)
expect(validateInteger([])).toEqual(errorMessage)
expect(validateInteger(true)).toEqual(errorMessage)
expect(validateInteger(false)).toEqual(errorMessage)
})
})
describe("validateParam", function() {
let param = null
let result = null
it("validates required strings", function() {
param = fromJS({
required: true,
type: "string",
value: ""
})
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
})
it("validates required arrays", function() {
param = fromJS({
required: true,
type: "array",
value: []
})
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
param = fromJS({
required: true,
type: "array",
value: []
})
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
})
it("validates numbers", function() {
param = fromJS({
required: false,
type: "number",
value: "test"
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be a number"] )
})
it("validates integers", function() {
param = fromJS({
required: false,
type: "integer",
value: "test"
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be an integer"] )
})
it("validates arrays", function() {
// empty array
param = fromJS({
required: false,
type: "array",
value: []
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
// numbers
param = fromJS({
required: false,
type: "array",
value: ["number"],
items: {
type: "number"
}
})
result = validateParam( param, false )
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
// integers
param = fromJS({
required: false,
type: "array",
value: ["not", "numbers"],
items: {
type: "integer"
}
})
result = validateParam( param, false )
expect( result ).toEqual( [{index: 0, error: "Value must be an integer"}, {index: 1, error: "Value must be an integer"}] )
})
})
})

View File

@@ -57,7 +57,7 @@ module.exports = require('./make-webpack-config.js')(rules, {
entry: {
'swagger-ui-bundle': [
'babel-polyfill',
'./src/polyfills',
'./src/core/index.js'
]
},

View File

@@ -58,6 +58,7 @@ module.exports = require('./make-webpack-config.js')(rules, {
entry: {
'swagger-ui-standalone-preset': [
'./src/polyfills',
'./src/standalone/index.js'
]
},

View File

@@ -1,6 +1,6 @@
var path = require('path')
var fs = require('fs')
var node_modules = fs.readdirSync('node_modules').filter(function(x) { return x !== '.bin' })
const nodeModules = fs.readdirSync("node_modules").filter(function(x) { return x !== ".bin" })
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var rules = [
@@ -29,7 +29,10 @@ var rules = [
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'css-loader',
options: { minimize: true }
},
{
loader: 'postcss-loader',
options: { sourceMap: true }
@@ -66,9 +69,9 @@ module.exports = require('./make-webpack-config.js')(rules, {
entry: {
"swagger-ui": [
'babel-polyfill',
'./src/style/main.scss',
'./src/core/index.js'
"./src/style/main.scss",
"./src/polyfills",
"./src/core/index.js"
]
},
@@ -76,11 +79,11 @@ module.exports = require('./make-webpack-config.js')(rules, {
// 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) {
cb(null, 'commonjs ' + request)
return;
if(nodeModules.indexOf(request) !== -1 || exceptionsForWebpack.indexOf(request) !== -1) {
cb(null, "commonjs " + request)
return
}
cb();
cb()
},
output: {

View File

@@ -62,10 +62,11 @@ module.exports = require("./make-webpack-config")(rules, {
devtool: "eval",
entry: {
'swagger-ui-bundle': [
'babel-polyfill',
'./src/core/index.js',
'./src/polyfills',
'./src/core/index.js'
],
'swagger-ui-standalone-preset': [
'./src/polyfills',
'./src/standalone/index.js',
]
},