From 4fe27786f407a0c2b038a68dc1faf6ad966307bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 27 Jun 2017 15:29:07 +0200 Subject: [PATCH 01/39] Adding apisSorter options, taking a string or a function as a configuration value --- .gitignore | 1 + README.md | 6 ++- dev-helpers/index.html | 87 +++++++++++++++--------------- src/core/plugins/spec/selectors.js | 21 +++++--- src/core/utils.js | 5 +- 5 files changed, 67 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 36ccaaa9..2e9dcf9c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules npm-debug.log* .eslintcache package-lock.json +*.iml diff --git a/README.md b/README.md index eff32bc7..13567ca6 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,10 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], - layout: "StandaloneLayout" + layout: "StandaloneLayout", + docExpansion: "none", + apisSorter: "alpha", + operationsSorter: "method" }) ``` @@ -133,6 +136,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` 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 +apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. 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. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable diff --git a/dev-helpers/index.html b/dev-helpers/index.html index 9058c220..31c1610f 100644 --- a/dev-helpers/index.html +++ b/dev-helpers/index.html @@ -4,26 +4,26 @@ Swagger UI - - - - + + + + @@ -34,7 +34,7 @@ - + @@ -67,37 +67,38 @@
- - + + diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index d8487e89..6d04473c 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -197,16 +197,21 @@ export const operationsWithTags = createSelector( } ) -export const taggedOperations = ( state ) =>( { getConfigs } ) => { - let { operationsSorter }= getConfigs() +export const taggedOperations = (state) => ({ getConfigs }) => { + let { apisSorter, 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 operationsWithTags(state) + .sort((operationA, operationB) => { + let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]); + return (!sortFn ? null : sortFn(operationA, operationB)); + }) + .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})}) -} + return Map({ tagDetails: tagDetails(state, tag), operations: operations }); + }); +}; export const responses = createSelector( state, diff --git a/src/core/utils.js b/src/core/utils.js index 1412c344..ec3c9fd3 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -562,8 +562,11 @@ export const sorters = { operationsSorter: { alpha: (a, b) => a.get("path").localeCompare(b.get("path")), method: (a, b) => a.get("method").localeCompare(b.get("method")) + }, + apisSorter: { + alpha: (a, b) => a.getIn([0, "operation", "tags", 0]).localeCompare(b.getIn([0, "operation", "tags", 0])) } -} +}; export const buildFormData = (data) => { let formArr = [] From 24bc8c4b85d300428b7fcfab6b93a6e84d2a1721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 27 Jun 2017 16:45:23 +0200 Subject: [PATCH 02/39] Complying with CI --- src/core/plugins/spec/selectors.js | 16 ++++++++-------- src/core/utils.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index 6d04473c..782f502a 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -198,20 +198,20 @@ export const operationsWithTags = createSelector( ) export const taggedOperations = (state) => ({ getConfigs }) => { - let { apisSorter, operationsSorter } = getConfigs(); + let { apisSorter, operationsSorter } = getConfigs() return operationsWithTags(state) .sort((operationA, operationB) => { - let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]); - return (!sortFn ? null : sortFn(operationA, operationB)); + let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]) + return (!sortFn ? null : sortFn(operationA, operationB)) }) .map((ops, tag) => { - let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ]); - let operations = (!sortFn ? ops : ops.sort(sortFn)); + let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ]) + let operations = (!sortFn ? ops : ops.sort(sortFn)) - return Map({ tagDetails: tagDetails(state, tag), operations: operations }); - }); -}; + return Map({ tagDetails: tagDetails(state, tag), operations: operations }) + }) +} export const responses = createSelector( state, diff --git a/src/core/utils.js b/src/core/utils.js index ec3c9fd3..a6705209 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -566,7 +566,7 @@ export const sorters = { apisSorter: { alpha: (a, b) => a.getIn([0, "operation", "tags", 0]).localeCompare(b.getIn([0, "operation", "tags", 0])) } -}; +} export const buildFormData = (data) => { let formArr = [] From d27cae00850b802c87b7bade997923468231d05e Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Wed, 28 Jun 2017 22:07:07 -0600 Subject: [PATCH 03/39] Work on #3102. Moved all the components out of model.jsx into their own files so they can be grabbed via getComponent() --- src/core/components/array-model.jsx | 43 ++++ src/core/components/enum-model.jsx | 19 ++ src/core/components/layouts/base.jsx | 2 +- src/core/components/model-collapse.jsx | 40 ++++ src/core/components/model-example.jsx | 4 +- src/core/components/model-wrapper.jsx | 22 ++ src/core/components/model.jsx | 267 +----------------------- src/core/components/models.jsx | 6 +- src/core/components/object-model.jsx | 104 +++++++++ src/core/components/primitive-model.jsx | 54 +++++ src/core/presets/base.js | 16 +- 11 files changed, 308 insertions(+), 269 deletions(-) create mode 100644 src/core/components/array-model.jsx create mode 100644 src/core/components/enum-model.jsx create mode 100644 src/core/components/model-collapse.jsx create mode 100644 src/core/components/model-wrapper.jsx create mode 100644 src/core/components/object-model.jsx create mode 100644 src/core/components/primitive-model.jsx diff --git a/src/core/components/array-model.jsx b/src/core/components/array-model.jsx new file mode 100644 index 00000000..1a01b0ff --- /dev/null +++ b/src/core/components/array-model.jsx @@ -0,0 +1,43 @@ +import React, { Component, PropTypes } from "react" + +const propStyle = { color: "#999", fontStyle: "italic" } + +export default class ArrayModel extends Component { + static propTypes = { + schema: PropTypes.object.isRequired, + getComponent: PropTypes.func.isRequired, + specSelectors: PropTypes.object.isRequired, + name: PropTypes.string, + required: PropTypes.bool, + expandDepth: PropTypes.number, + depth: PropTypes.number + } + + render(){ + let { getComponent, required, schema, depth, expandDepth } = this.props + let items = schema.get("items") + let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 ) + + const ModelCollapse = getComponent("ModelCollapse") + const Model = getComponent("Model") + + return + + { schema.get("title") } + + expandDepth } collapsedContent="[...]"> + [ + + ] + { + properties.size ? + { properties.entrySeq().map( ( [ key, v ] ) => +
{ `${key}:`}{ String(v) }
) + }
+ : null + } +
+ { required && *} +
+ } +} \ No newline at end of file diff --git a/src/core/components/enum-model.jsx b/src/core/components/enum-model.jsx new file mode 100644 index 00000000..78af10da --- /dev/null +++ b/src/core/components/enum-model.jsx @@ -0,0 +1,19 @@ +import React from "react" +import ImPropTypes from "react-immutable-proptypes" + +const EnumModel = ({ value, getComponent }) => { + let ModelCollapse = getComponent("ModelCollapse") + let collapsedContent = Array [ { value.count() } ] + return + Enum:
+ + [ { value.join(", ") } ] + +
+} +EnumModel.propTypes = { + value: ImPropTypes.iterable, + getComponent: ImPropTypes.func +} + +export default EnumModel \ No newline at end of file diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index 35cfd7b8..f8132bf0 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -25,7 +25,7 @@ export default class BaseLayout extends React.Component { let Info = getComponent("info") let Operations = getComponent("operations", true) - let Models = getComponent("models", true) + let Models = getComponent("Models", true) let AuthorizeBtn = getComponent("authorizeBtn", true) let Row = getComponent("Row") let Col = getComponent("Col") diff --git a/src/core/components/model-collapse.jsx b/src/core/components/model-collapse.jsx new file mode 100644 index 00000000..256c440e --- /dev/null +++ b/src/core/components/model-collapse.jsx @@ -0,0 +1,40 @@ +import React, { Component, PropTypes } from "react" + +export default class ModelCollapse extends Component { + static propTypes = { + collapsedContent: PropTypes.any, + collapsed: PropTypes.bool, + children: PropTypes.any + } + + static defaultProps = { + collapsedContent: "{...}", + collapsed: true, + } + + constructor(props, context) { + super(props, context) + + let { collapsed, collapsedContent } = this.props + + this.state = { + collapsed: collapsed !== undefined ? collapsed : ModelCollapse.defaultProps.collapsed, + collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent + } + } + + toggleCollapsed=()=>{ + this.setState({ + collapsed: !this.state.collapsed + }) + } + + render () { + return ( + + + + { this.state.collapsed ? this.state.collapsedContent : this.props.children } + ) + } +} \ No newline at end of file diff --git a/src/core/components/model-example.jsx b/src/core/components/model-example.jsx index 0117c9a5..e7737d12 100644 --- a/src/core/components/model-example.jsx +++ b/src/core/components/model-example.jsx @@ -28,7 +28,7 @@ export default class ModelExample extends React.Component { render() { let { getComponent, specSelectors, schema, example, isExecute } = this.props - const Model = getComponent("model") + const ModelWrapper = getComponent("ModelWrapper") return
    @@ -44,7 +44,7 @@ export default class ModelExample extends React.Component { (isExecute || this.state.activeTab === "example") && example } { - !isExecute && this.state.activeTab === "model" && diff --git a/src/core/components/model-wrapper.jsx b/src/core/components/model-wrapper.jsx new file mode 100644 index 00000000..945633a4 --- /dev/null +++ b/src/core/components/model-wrapper.jsx @@ -0,0 +1,22 @@ +import React, { Component, PropTypes } from "react" + +export default class ModelComponent extends Component { + static propTypes = { + schema: PropTypes.object.isRequired, + name: PropTypes.string, + getComponent: PropTypes.func.isRequired, + specSelectors: PropTypes.object.isRequired, + expandDepth: PropTypes.number + } + + render(){ + let { getComponent } = this.props + const Model = getComponent("Model") + + return
    + +
    + } +} + + diff --git a/src/core/components/model.jsx b/src/core/components/model.jsx index a043c325..58e0481d 100644 --- a/src/core/components/model.jsx +++ b/src/core/components/model.jsx @@ -1,208 +1,6 @@ import React, { Component, PropTypes } from "react" -import ImPropTypes from "react-immutable-proptypes" -import { List } from "immutable" -const braceOpen = "{" -const braceClose = "}" -const propStyle = { color: "#999", fontStyle: "italic" } - -const EnumModel = ({ value }) => { - let collapsedContent = Array [ { value.count() } ] - return - Enum:
    - - [ { value.join(", ") } ] - -
    -} - -EnumModel.propTypes = { - value: ImPropTypes.iterable -} - -class ObjectModel extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - specSelectors: PropTypes.object.isRequired, - name: PropTypes.string, - isRef: PropTypes.bool, - expandDepth: PropTypes.number, - depth: PropTypes.number - } - - render(){ - let { schema, name, isRef, getComponent, depth, ...props } = this.props - let { expandDepth } = this.props - const JumpToPath = getComponent("JumpToPath", true) - let description = schema.get("description") - let properties = schema.get("properties") - let additionalProperties = schema.get("additionalProperties") - let title = schema.get("title") || name - let required = schema.get("required") - const Markdown = getComponent("Markdown") - const JumpToPathSection = ({ name }) => - let collapsedContent = ( - { braceOpen }...{ braceClose } - { - isRef ? : "" - } - ) - - return - { - title && - { isRef && schema.get("$$ref") && { schema.get("$$ref") } } - { title } - - } - expandDepth } collapsedContent={ collapsedContent }> - { braceOpen } - { - !isRef ? null : - } - - { - - { - !description ? null : - - - - } - { - !(properties && properties.size) ? null : properties.entrySeq().map( - ([key, value]) => { - let isRequired = List.isList(required) && required.contains(key) - let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" } - if ( isRequired ) { - propertyStyle.fontWeight = "bold" - } - - return ( - - - ) - }).toArray() - } - { - !additionalProperties || !additionalProperties.size ? null - : - - - - } -
    description: - -
    { key }: - -
    { "< * >:" } - -
    - } -
    - { braceClose } -
    -
    - } -} - -class Primitive extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - required: PropTypes.bool - } - - render(){ - let { schema, getComponent, required } = this.props - - if(!schema || !schema.get) { - // don't render if schema isn't correctly formed - return
    - } - - let type = schema.get("type") - 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", "description", "$$ref"].indexOf(key) === -1 ) - let style = required ? { fontWeight: "bold" } : {} - const Markdown = getComponent("Markdown") - - return - { type } { required && *} - { format && (${format})} - { - properties.size ? properties.entrySeq().map( ( [ key, v ] ) => -
    { key }: { String(v) }
    ) - : null - } - { - !description ? null : - - } - { - xml && xml.size ? (
    xml: - { - xml.entrySeq().map( ( [ key, v ] ) =>
       {key}: { String(v) }
    ).toArray() - } -
    ): null - } - { - enumArray && - } -
    - } -} - -class ArrayModel extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - specSelectors: PropTypes.object.isRequired, - name: PropTypes.string, - required: PropTypes.bool, - expandDepth: PropTypes.number, - depth: PropTypes.number - } - - 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 - - { schema.get("title") } - - expandDepth } collapsedContent="[...]"> - [ - - ] - { - properties.size ? - { properties.entrySeq().map( ( [ key, v ] ) => -
    { `${key}:`}{ String(v) }
    ) - }
    - : null - } -
    - { required && *} -
    - } -} - - -class Model extends Component { +export default class Model extends Component { static propTypes = { schema: PropTypes.object.isRequired, getComponent: PropTypes.func.isRequired, @@ -228,6 +26,9 @@ class Model extends Component { render () { let { schema, getComponent, required, name, isRef } = this.props + let ObjectModel = getComponent("ObjectModel") + let ArrayModel = getComponent("ArrayModel") + let PrimitiveModel = getComponent("PrimitiveModel") let $$ref = schema && schema.get("$$ref") let modelName = $$ref && this.getModelName( $$ref ) let modelSchema, type @@ -255,63 +56,7 @@ class Model extends Component { case "integer": case "boolean": default: - return + return } } -} - - -export default class ModelComponent extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - name: PropTypes.string, - getComponent: PropTypes.func.isRequired, - specSelectors: PropTypes.object.isRequired, - expandDepth: PropTypes.number - } - - render(){ - return
    - -
    - } -} - -class Collapse extends Component { - static propTypes = { - collapsedContent: PropTypes.any, - collapsed: PropTypes.bool, - children: PropTypes.any - } - - static defaultProps = { - collapsedContent: "{...}", - collapsed: true, - } - - constructor(props, context) { - super(props, context) - - let { collapsed, collapsedContent } = this.props - - this.state = { - collapsed: collapsed !== undefined ? collapsed : Collapse.defaultProps.collapsed, - collapsedContent: collapsedContent || Collapse.defaultProps.collapsedContent - } - } - - toggleCollapsed=()=>{ - this.setState({ - collapsed: !this.state.collapsed - }) - } - - render () { - return ( - - - - { this.state.collapsed ? this.state.collapsedContent : this.props.children } - ) - } -} +} \ No newline at end of file diff --git a/src/core/components/models.jsx b/src/core/components/models.jsx index 21605199..c311f350 100644 --- a/src/core/components/models.jsx +++ b/src/core/components/models.jsx @@ -1,6 +1,5 @@ import React, { Component, PropTypes } from "react" - export default class Models extends Component { static propTypes = { getComponent: PropTypes.func, @@ -16,7 +15,7 @@ export default class Models extends Component { let { docExpansion } = getConfigs() let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" ) - const Model = getComponent("model") + const ModelWrapper = getComponent("ModelWrapper") const Collapse = getComponent("Collapse") if (!definitions.size) return null @@ -31,8 +30,9 @@ export default class Models extends Component { { definitions.entrySeq().map( ( [ name, model ])=>{ + console.log("model", name, model) return
    - + const collapsedContent = ( + { braceOpen }...{ braceClose } + { + isRef ? : "" + } + ) + + + return + { + title && + { isRef && schema.get("$$ref") && { schema.get("$$ref") } } + { title } + + } + expandDepth } collapsedContent={ collapsedContent }> + { braceOpen } + { + !isRef ? null : + } + + { + + { + !description ? null : + + + + } + { + !(properties && properties.size) ? null : properties.entrySeq().map( + ([key, value]) => { + let isRequired = List.isList(required) && required.contains(key) + let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" } + if ( isRequired ) { + propertyStyle.fontWeight = "bold" + } + + return ( + + + ) + }).toArray() + } + { + !additionalProperties || !additionalProperties.size ? null + : + + + + } +
    description: + +
    { key }: + +
    { "< * >:" } + +
    + } +
    + { braceClose } +
    +
    + } +} \ No newline at end of file diff --git a/src/core/components/primitive-model.jsx b/src/core/components/primitive-model.jsx new file mode 100644 index 00000000..24363187 --- /dev/null +++ b/src/core/components/primitive-model.jsx @@ -0,0 +1,54 @@ +import React, { Component, PropTypes } from "react" + +const propStyle = { color: "#999", fontStyle: "italic" } + +export default class Primitive extends Component { + static propTypes = { + schema: PropTypes.object.isRequired, + getComponent: PropTypes.func.isRequired, + required: PropTypes.bool + } + + render(){ + let { schema, getComponent, required } = this.props + + if(!schema || !schema.get) { + // don't render if schema isn't correctly formed + return
    + } + + let type = schema.get("type") + 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", "description", "$$ref"].indexOf(key) === -1 ) + let style = required ? { fontWeight: "bold" } : {} + const Markdown = getComponent("Markdown") + const EnumModel = getComponent("EnumModel") + + return + { type } { required && *} + { format && (${format})} + { + properties.size ? properties.entrySeq().map( ( [ key, v ] ) => +
    { key }: { String(v) }
    ) + : null + } + { + !description ? null : + + } + { + xml && xml.size ? (
    xml: + { + xml.entrySeq().map( ( [ key, v ] ) =>
       {key}: { String(v) }
    ).toArray() + } +
    ): null + } + { + enumArray && + } +
    + } +} \ No newline at end of file diff --git a/src/core/presets/base.js b/src/core/presets/base.js index 20ff4659..d5471791 100644 --- a/src/core/presets/base.js +++ b/src/core/presets/base.js @@ -41,9 +41,15 @@ import Footer from "core/components/footer" import ParamBody from "core/components/param-body" import Curl from "core/components/curl" import Schemes from "core/components/schemes" +import ModelCollapse from "core/components/model-collapse" import ModelExample from "core/components/model-example" +import ModelWrapper from "core/components/model-wrapper" import Model from "core/components/model" import Models from "core/components/models" +import EnumModel from "core/components/enum-model" +import ObjectModel from "core/components/object-model" +import ArrayModel from "core/components/array-model" +import PrimitiveModel from "core/components/primitive-model" import TryItOutButton from "core/components/try-it-out-button" import Markdown from "core/components/providers/markdown" @@ -88,8 +94,14 @@ export default function() { curl: Curl, schemes: Schemes, modelExample: ModelExample, - model: Model, - models: Models, + ModelWrapper, + ModelCollapse, + Model, + Models, + EnumModel, + ObjectModel, + ArrayModel, + PrimitiveModel, TryItOutButton, Markdown, BaseLayout From 6fd5839103a6f6d345c0289d07ab50bd79d6f2dd Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Mon, 3 Jul 2017 16:27:47 -0600 Subject: [PATCH 04/39] Fix PropTypes in model-collapse component --- src/core/components/model-collapse.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/components/model-collapse.jsx b/src/core/components/model-collapse.jsx index 256c440e..1b46e56a 100644 --- a/src/core/components/model-collapse.jsx +++ b/src/core/components/model-collapse.jsx @@ -1,4 +1,5 @@ -import React, { Component, PropTypes } from "react" +import React, { Component } from "react" +import PropTypes from "prop-types" export default class ModelCollapse extends Component { static propTypes = { From 4bfb392e4994064288a6d3b85fb22c319d0e2c6e Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Mon, 3 Jul 2017 16:41:10 -0700 Subject: [PATCH 05/39] Undo changed defaults --- README.md | 7 ++----- dev-helpers/index.html | 5 +---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a62a18ab..c7f02194 100644 --- a/README.md +++ b/README.md @@ -91,10 +91,7 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], - layout: "StandaloneLayout", - docExpansion: "none", - apisSorter: "alpha", - operationsSorter: "method" + layout: "StandaloneLayout" }) ``` @@ -147,7 +144,7 @@ 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`. +displayRequestDuration | Controls the display of the request duration (in milliseconds) for `Try it out` requests. The default is `false`. ### Plugins diff --git a/dev-helpers/index.html b/dev-helpers/index.html index 31c1610f..b23ec6f8 100644 --- a/dev-helpers/index.html +++ b/dev-helpers/index.html @@ -84,10 +84,7 @@ plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], - layout: "StandaloneLayout", - docExpansion: "none", - apisSorter: "alpha", - operationsSorter: "method" + layout: "StandaloneLayout" }); ui.initOAuth({ From 8ce2b309d84136c827b0d62b6880f2eb7e7bcdcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 4 Jul 2017 09:15:43 +0200 Subject: [PATCH 06/39] Complying with request for changes --- README.md | 27 ++++++++++++--------------- dev-helpers/index.html | 41 ++++++++++++++++++++--------------------- src/core/index.js | 2 ++ 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index a62a18ab..49523da1 100644 --- a/README.md +++ b/README.md @@ -82,20 +82,17 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui ```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", - docExpansion: "none", - apisSorter: "alpha", - operationsSorter: "method" - }) + url: "http://petstore.swagger.io/v2/swagger.json", + dom_id: '#swagger-ui', + presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIStandalonePreset + ], + plugins: [ + SwaggerUIBundle.plugins.DownloadUrl + ], + layout: "StandaloneLayout" + }) ``` #### OAuth2 configuration @@ -140,7 +137,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` 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 -apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. +apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order detemrined by Swagger-UI. 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. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable diff --git a/dev-helpers/index.html b/dev-helpers/index.html index 31c1610f..a528687b 100644 --- a/dev-helpers/index.html +++ b/dev-helpers/index.html @@ -4,26 +4,26 @@ Swagger UI - - - - + + + + @@ -67,14 +67,14 @@
    - - + + diff --git a/src/core/index.js b/src/core/index.js index 80335da5..26ab44b4 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -26,6 +26,8 @@ module.exports = function SwaggerUI(opts) { urls: null, layout: "BaseLayout", docExpansion: "list", + apisSorter: "alpha", + operationsSorter: "method", validatorUrl: "https://online.swagger.io/validator", configs: {}, custom: {}, From d031413d92d853fb48b4a4fda50ce6616a86240f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 4 Jul 2017 09:20:55 +0200 Subject: [PATCH 07/39] Fix typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 630fefe1..94f874b0 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` 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 -apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order detemrined by Swagger-UI. +apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order determined by Swagger-UI. 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. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable From d8400f872999c7ca50704e03ccd450f98ce25840 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 9 Jul 2017 14:17:18 -0600 Subject: [PATCH 08/39] Fixes #3300 - Updates to versions.swaggerUi information --- make-webpack-config.js | 66 ++++++++++++++++++++++-------------------- src/core/index.js | 10 +++++-- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/make-webpack-config.js b/make-webpack-config.js index f2628bc0..2a6ed131 100644 --- a/make-webpack-config.js +++ b/make-webpack-config.js @@ -1,11 +1,12 @@ -var path = require('path') +var path = require("path") -var webpack = require('webpack') -var ExtractTextPlugin = require('extract-text-webpack-plugin') -var deepExtend = require('deep-extend') -const {gitDescribeSync} = require('git-describe'); +var webpack = require("webpack") +var ExtractTextPlugin = require("extract-text-webpack-plugin") +var deepExtend = require("deep-extend") +const {gitDescribeSync} = require("git-describe") +const os = require("os") -var pkg = require('./package.json') +var pkg = require("./package.json") let gitInfo @@ -13,7 +14,7 @@ try { gitInfo = gitDescribeSync(__dirname) } catch(e) { gitInfo = { - hash: 'noGit', + hash: "noGit", dirty: false } } @@ -21,21 +22,21 @@ try { var commonRules = [ { test: /\.(js(x)?)(\?.*)?$/, use: [{ - loader: 'babel-loader', + loader: "babel-loader", options: { retainLines: true } }], - include: [ path.join(__dirname, 'src') ] + include: [ path.join(__dirname, "src") ] }, { test: /\.(txt|yaml)(\?.*)?$/, - loader: 'raw-loader' }, + loader: "raw-loader" }, { test: /\.(png|jpg|jpeg|gif|svg)(\?.*)?$/, - loader: 'url-loader?limit=10000' }, + loader: "url-loader?limit=10000" }, { test: /\.(woff|woff2)(\?.*)?$/, - loader: 'url-loader?limit=100000' }, + loader: "url-loader?limit=100000" }, { test: /\.(ttf|eot)(\?.*)?$/, - loader: 'file-loader' } + loader: "file-loader" } ] module.exports = function(rules, options) { @@ -54,7 +55,7 @@ module.exports = function(rules, options) { if( specialOptions.separateStylesheets ) { plugins.push(new ExtractTextPlugin({ - filename: '[name].css' + (specialOptions.longTermCaching ? '?[contenthash]' : ''), + filename: "[name].css" + (specialOptions.longTermCaching ? "?[contenthash]" : ""), allChunks: true })) } @@ -78,35 +79,36 @@ module.exports = function(rules, options) { plugins.push( new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: specialOptions.minimize ? JSON.stringify('production') : null, - WEBPACK_INLINE_STYLES: !Boolean(specialOptions.separateStylesheets) - + "process.env": { + NODE_ENV: specialOptions.minimize ? JSON.stringify("production") : null, + WEBPACK_INLINE_STYLES: !specialOptions.separateStylesheets }, - 'buildInfo': JSON.stringify({ + "buildInfo": JSON.stringify({ PACKAGE_VERSION: (pkg.version), GIT_COMMIT: gitInfo.hash, - GIT_DIRTY: gitInfo.dirty + GIT_DIRTY: gitInfo.dirty, + HOSTNAME: os.hostname(), + BUILD_TIME: new Date().toUTCString() }) })) delete options._special - var completeConfig = deepExtend({ + var completeConfig = deepExtend({ entry: {}, output: { - path: path.join(__dirname, 'dist'), - publicPath: '/', - filename: '[name].js', - chunkFilename: '[name].js' + path: path.join(__dirname, "dist"), + publicPath: "/", + filename: "[name].js", + chunkFilename: "[name].js" }, - target: 'web', + target: "web", // yaml-js has a reference to `fs`, this is a workaround node: { - fs: 'empty' + fs: "empty" }, module: { @@ -114,17 +116,17 @@ module.exports = function(rules, options) { }, resolveLoader: { - modules: [path.join(__dirname, 'node_modules')], + modules: [path.join(__dirname, "node_modules")], }, externals: { - 'buffertools': true // json-react-schema/deeper depends on buffertools, which fails. + "buffertools": true // json-react-schema/deeper depends on buffertools, which fails. }, resolve: { modules: [ - path.join(__dirname, './src'), - 'node_modules' + path.join(__dirname, "./src"), + "node_modules" ], extensions: [".web.js", ".js", ".jsx", ".json", ".less"], alias: { @@ -132,7 +134,7 @@ module.exports = function(rules, options) { } }, - devtool: specialOptions.sourcemaps ? 'cheap-module-source-map' : null, + devtool: specialOptions.sourcemaps ? "cheap-module-source-map" : null, plugins, diff --git a/src/core/index.js b/src/core/index.js index 80335da5..ed6768e1 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -11,12 +11,18 @@ const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "on "showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" , "displayRequestDuration"] // eslint-disable-next-line no-undef -const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION } = buildInfo +const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION, HOSTNAME, BUILD_TIME } = buildInfo module.exports = function SwaggerUI(opts) { win.versions = win.versions || {} - win.versions.swaggerUi = `${PACKAGE_VERSION}/${GIT_COMMIT || "unknown"}${GIT_DIRTY ? "-dirty" : ""}` + win.versions.swaggerUi = { + version: PACKAGE_VERSION, + gitRevision: GIT_COMMIT, + gitDirty: GIT_DIRTY, + buildTimestamp: BUILD_TIME, + machine: HOSTNAME + } const defaults = { // Some general settings, that we floated to the top From c3f9c094d1b6761c2a847f5c807aac86120402b6 Mon Sep 17 00:00:00 2001 From: Gwyn Judd Date: Wed, 7 Jun 2017 16:29:46 +1200 Subject: [PATCH 09/39] Added maxRows and filter support Useful for the display of very large swagger specs. Can limit the number of operations to a smaller value and search --- README.md | 2 ++ src/core/components/layouts/base.jsx | 7 ++++--- src/core/components/operations.jsx | 18 ++++++++++++++++-- src/core/index.js | 4 +++- src/plugins/topbar/topbar.jsx | 15 +++++++++++++++ src/standalone/layout.jsx | 24 +++++++++++++++++++++--- 6 files changed, 61 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c872e4c5..28943fab 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,8 @@ modelPropertyMacro | MUST be a function. Function to set default values to each 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`. +maxDisplayedTags | If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations. +filter | If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be true/false to enable or disable, or an explicit filter string in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag. ### Plugins diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index 9da4b347..7e927c0b 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -10,11 +10,12 @@ export default class BaseLayout extends React.Component { specSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired + getComponent: PropTypes.func.isRequired, + filter: PropTypes.string.isRequired } render() { - let { specSelectors, specActions, getComponent } = this.props + let { specSelectors, specActions, getComponent, filter } = this.props let info = specSelectors.info() let url = specSelectors.url() @@ -66,7 +67,7 @@ export default class BaseLayout extends React.Component { - + diff --git a/src/core/components/operations.jsx b/src/core/components/operations.jsx index 6c20d963..fff1b226 100644 --- a/src/core/components/operations.jsx +++ b/src/core/components/operations.jsx @@ -11,7 +11,8 @@ export default class Operations extends React.Component { layoutActions: PropTypes.object.isRequired, authActions: PropTypes.object.isRequired, authSelectors: PropTypes.object.isRequired, - getConfigs: PropTypes.func.isRequired + getConfigs: PropTypes.func.isRequired, + filter: PropTypes.string.isRequired }; render() { @@ -24,6 +25,7 @@ export default class Operations extends React.Component { authActions, authSelectors, getConfigs, + filter, fn } = this.props @@ -33,7 +35,19 @@ export default class Operations extends React.Component { const Collapse = getComponent("Collapse") let showSummary = layoutSelectors.showSummary() - let { docExpansion, displayOperationId, displayRequestDuration } = getConfigs() + let { docExpansion, displayOperationId, displayRequestDuration, maxDisplayedTags } = getConfigs() + + if (filter) { + if (filter !== true) { + taggedOps = taggedOps.filter((tagObj, tag) => { + return tag.indexOf(filter) !== -1 + }) + } + } + + if (maxDisplayedTags && !isNaN(maxDisplayedTags) && maxDisplayedTags >= 0) { + taggedOps = taggedOps.slice(0, maxDisplayedTags) + } return (
    diff --git a/src/core/index.js b/src/core/index.js index 80335da5..381748d4 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -6,7 +6,7 @@ import ApisPreset from "core/presets/apis" import * as AllPlugins from "core/plugins/all" import { parseSeach, filterConfigs } from "core/utils" -const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion", +const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion", "maxDisplayedTags", "filter", "apisSorter", "operationsSorter", "supportedSubmitMethods", "dom_id", "defaultModelRendering", "oauth2RedirectUrl", "showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" , "displayRequestDuration"] @@ -26,6 +26,8 @@ module.exports = function SwaggerUI(opts) { urls: null, layout: "BaseLayout", docExpansion: "list", + maxDisplayedTags: null, + filter: null, validatorUrl: "https://online.swagger.io/validator", configs: {}, custom: {}, diff --git a/src/plugins/topbar/topbar.jsx b/src/plugins/topbar/topbar.jsx index 11b5c7eb..087b3c93 100644 --- a/src/plugins/topbar/topbar.jsx +++ b/src/plugins/topbar/topbar.jsx @@ -6,6 +6,11 @@ import Logo from "./logo_small.png" export default class Topbar extends React.Component { + static propTypes = { + onFilterChange: PropTypes.func.isRequired, + filter: PropTypes.string.isRequired + } + constructor(props, context) { super(props, context) this.state = { url: props.specSelectors.url(), selectedIndex: 0 } @@ -80,6 +85,11 @@ export default class Topbar extends React.Component { } } + onFilterChange =(e) => { + let {target: {value}} = e + this.props.onFilterChange(value) + } + render() { let { getComponent, specSelectors, getConfigs } = this.props const Button = getComponent("Button") @@ -87,6 +97,7 @@ export default class Topbar extends React.Component { let isLoading = specSelectors.loadingStatus() === "loading" let isFailed = specSelectors.loadingStatus() === "failed" + let filter = this.props.filter let inputStyle = {} if(isFailed) inputStyle.color = "red" @@ -124,6 +135,10 @@ export default class Topbar extends React.Component { Swagger UX swagger + { + filter === null || filter === false ? null : + + }
    {control}
    diff --git a/src/standalone/layout.jsx b/src/standalone/layout.jsx index 20ca50d1..783b9a1c 100644 --- a/src/standalone/layout.jsx +++ b/src/standalone/layout.jsx @@ -10,7 +10,23 @@ export default class StandaloneLayout extends React.Component { specSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired + getComponent: PropTypes.func.isRequired, + getConfigs: PropTypes.func.isRequired + } + + constructor(props) { + super(props) + + this.handleFilterChange = this.handleFilterChange.bind(this) + + let { getConfigs } = this.props + let { filter } = getConfigs() + + this.state = { filter: filter } + } + + handleFilterChange(filter) { + this.setState({ filter: filter }) } render() { @@ -24,12 +40,14 @@ export default class StandaloneLayout extends React.Component { const BaseLayout = getComponent("BaseLayout", true) const OnlineValidatorBadge = getComponent("onlineValidatorBadge", true) + const filter = this.state.filter + const loadingStatus = specSelectors.loadingStatus() return ( - { Topbar ? : null } + { Topbar ? : null } { loadingStatus === "loading" &&

    Loading...

    @@ -45,7 +63,7 @@ export default class StandaloneLayout extends React.Component {

    Failed to load config.

    } - { !loadingStatus || loadingStatus === "success" && } + { !loadingStatus || loadingStatus === "success" && } From fe200f86167b42343ad784436267dc7a3ef2d119 Mon Sep 17 00:00:00 2001 From: Minasokoni Date: Fri, 7 Jul 2017 15:01:58 -0700 Subject: [PATCH 10/39] styling updates --- src/style/_layout.scss | 48 ++++++++++++++++++++++++------------------ src/style/_topbar.scss | 8 ++++++- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/style/_layout.scss b/src/style/_layout.scss index 955e4d54..78e09249 100644 --- a/src/style/_layout.scss +++ b/src/style/_layout.scss @@ -45,6 +45,7 @@ body .opblock-tag { display: flex; + align-items: center; padding: 10px 20px 10px 10px; @@ -53,8 +54,6 @@ body border-bottom: 1px solid rgba(#3b4151, .3); - align-items: center; - &:hover { background: rgba(#000,.02); @@ -106,9 +105,10 @@ body font-size: 14px; font-weight: normal; + flex: 1; + padding: 0 10px; - flex: 1; @include text_body(); } } @@ -134,6 +134,8 @@ body transition: all .5s; } + + .opblock { margin: 0 0 15px 0; @@ -154,24 +156,23 @@ body .opblock-section-header { display: flex; + align-items: center; padding: 8px 20px; background: rgba(#fff,.8); box-shadow: 0 1px 2px rgba(#000,.1); - align-items: center; - label { font-size: 12px; font-weight: bold; display: flex; + align-items: center; margin: 0; - align-items: center; @include text_headline(); span @@ -184,9 +185,10 @@ body { font-size: 14px; + flex: 1; + margin: 0; - flex: 1; @include text_headline(); } } @@ -215,11 +217,11 @@ body font-size: 16px; display: flex; + align-items: center; padding: 0 10px; @include text_code(); - align-items: center; .view-line-link { @@ -258,18 +260,18 @@ body font-size: 13px; flex: 1; + @include text_body(); } .opblock-summary { display: flex; + align-items: center; padding: 5px; cursor: pointer; - - align-items: center; } &.opblock-post @@ -316,12 +318,12 @@ body .opblock-schemes { - padding: 8px 20px; + padding: 8px 20px; - .schemes-title - { - padding: 0 10px 0 0; - } + .schemes-title + { + padding: 0 10px 0 0; + } } } @@ -498,13 +500,11 @@ body margin: 0; padding: 10px; - + white-space: pre-wrap; word-wrap: break-word; word-break: break-all; word-break: break-word; hyphens: auto; - white-space: pre-wrap; - border-radius: 4px; background: #41444e; @@ -533,10 +533,9 @@ body .schemes { display: flex; - align-items: center; - > label + > label { font-size: 12px; font-weight: bold; @@ -624,3 +623,12 @@ body opacity: 0; } } + + +section +{ + h3 + { + @include text_headline(); + } +} diff --git a/src/style/_topbar.scss b/src/style/_topbar.scss index 4bded694..b1427c78 100644 --- a/src/style/_topbar.scss +++ b/src/style/_topbar.scss @@ -29,6 +29,12 @@ padding: 0 10px; } } + .operation-filter-input + { + border: 2px solid #547f00; + border-right: none; + border-radius: 4px 0 0 4px; + } .download-url-wrapper { @@ -43,7 +49,7 @@ margin: 0; border: 2px solid #547f00; - border-radius: 4px 0 0 4px; + border-radius: 0 0 0 0; outline: none; } From 6beaaca6e6fd6511558b0978d5355bb9d2afbcd7 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Mon, 10 Jul 2017 19:46:32 -0600 Subject: [PATCH 11/39] Fixes #3361 - Check for null and undefined values in validateParam --- src/core/utils.js | 46 +++++++++++++++++++++++++--------------------- test/core/utils.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/core/utils.js b/src/core/utils.js index 448a8e9c..ae9a6320 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -228,13 +228,13 @@ export function highlight (el) { var reset = function(el) { var text = el.textContent, - pos = 0, // current position + pos = 0, // current position next1 = text[0], // next character - chr = 1, // current character - prev1, // previous character - prev2, // the one before the previous - token = // current token content - el.innerHTML = "", // (and cleaning the node) + chr = 1, // current character + prev1, // previous character + prev2, // the one before the previous + token = // current token content + el.innerHTML = "", // (and cleaning the node) // current token type: // 0: anything else (whitespaces / newlines) @@ -274,11 +274,11 @@ export function highlight (el) { (tokenType > 8 && chr == "\n") || [ // finalize conditions for other token types // 0: whitespaces - /\S/[test](chr), // merged together + /\S/[test](chr), // merged together // 1: operators - 1, // consist of a single character + 1, // consist of a single character // 2: braces - 1, // consist of a single character + 1, // consist of a single character // 3: (key)word !/[$\w]/[test](chr), // 4: regex @@ -341,12 +341,12 @@ export function highlight (el) { // condition) tokenType = 11 while (![ - 1, // 0: whitespace + 1, // 0: whitespace // 1: operator or braces - /[\/{}[(\-+*=<>:;|\\.,?!&@~]/[test](chr), // eslint-disable-line no-useless-escape - /[\])]/[test](chr), // 2: closing brace - /[$\w]/[test](chr), // 3: (key)word - chr == "/" && // 4: regex + /[\/{}[(\-+*=<>:;|\\.,?!&@~]/[test](chr), // eslint-disable-line no-useless-escape + /[\])]/[test](chr), // 2: closing brace + /[$\w]/[test](chr), // 3: (key)word + chr == "/" && // 4: regex // previous token was an // opening brace or an // operator (otherwise @@ -355,13 +355,13 @@ export function highlight (el) { // workaround for xml // closing tags prev1 != "<", - chr == "\"", // 5: string with " - chr == "'", // 6: string with ' + chr == "\"", // 5: string with " + chr == "'", // 6: string with ' // 7: xml comment chr+next1+text[pos+1]+text[pos+2] == "