feat: expose plugins and presets on SwaggerUI global symbol (#9189)
Part of this commit is also: - complete plugins consolidation - complete presets consolidation - build system consolidation Refs #9188
This commit is contained in:
1
src/core/assets/rolling-load.svg
Normal file
1
src/core/assets/rolling-load.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="200px" height="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-rolling" style="background-image: none; background-position: initial initial; background-repeat: initial initial;"><circle cx="50" cy="50" fill="none" ng-attr-stroke="{{config.color}}" ng-attr-stroke-width="{{config.width}}" ng-attr-r="{{config.radius}}" ng-attr-stroke-dasharray="{{config.dasharray}}" stroke="#555555" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138"><animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animateTransform></circle></svg>
|
||||
|
After Width: | Height: | Size: 734 B |
@@ -1,6 +0,0 @@
|
||||
/* global ace */
|
||||
ace.define("ace/snippets/yaml",
|
||||
["require","exports","module"], function(e,t,n){ // eslint-disable-line no-unused-vars
|
||||
t.snippetText=undefined
|
||||
t.scope="yaml"
|
||||
})
|
||||
@@ -3,6 +3,8 @@ import ImmutablePureComponent from "react-immutable-pure-component"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
import RollingLoadSVG from "core/assets/rolling-load.svg"
|
||||
|
||||
const decodeRefName = uri => {
|
||||
const unescaped = uri.replace(/~1/g, "/").replace(/~0/g, "~")
|
||||
|
||||
@@ -66,7 +68,7 @@ export default class Model extends ImmutablePureComponent {
|
||||
if(!schema) {
|
||||
return <span className="model model-title">
|
||||
<span className="model-title__text">{ displayName || name }</span>
|
||||
<img src={require("core/../img/rolling-load.svg")} height={"20px"} width={"20px"} />
|
||||
<img src={RollingLoadSVG} height={"20px"} width={"20px"} />
|
||||
</span>
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { safeBuildUrl } from "core/utils/url"
|
||||
import { Iterable, List } from "immutable"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
|
||||
import RollingLoadSVG from "core/assets/rolling-load.svg"
|
||||
|
||||
export default class Operation extends PureComponent {
|
||||
static propTypes = {
|
||||
@@ -122,7 +123,7 @@ export default class Operation extends PureComponent {
|
||||
<Collapse isOpened={isShown}>
|
||||
<div className="opblock-body">
|
||||
{ (operation && operation.size) || operation === null ? null :
|
||||
<img height={"32px"} width={"32px"} src={require("core/../img/rolling-load.svg")} className="opblock-loading-animation" />
|
||||
<img height={"32px"} width={"32px"} src={RollingLoadSVG} className="opblock-loading-animation" />
|
||||
}
|
||||
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}
|
||||
{ description &&
|
||||
@@ -140,7 +141,7 @@ export default class Operation extends PureComponent {
|
||||
{externalDocs.description &&
|
||||
<span className="opblock-external-docs__description">
|
||||
<Markdown source={ externalDocs.description } />
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
<Link target="_blank" className="opblock-external-docs__link" href={sanitizeUrl(externalDocsUrl)}>{externalDocsUrl}</Link>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import PropTypes from "prop-types"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
import win from "core/window"
|
||||
import { getExtensions, getCommonExtensions, numberToString, stringify, isEmptyValue } from "core/utils"
|
||||
import getParameterSchema from "../../helpers/get-parameter-schema.js"
|
||||
import getParameterSchema from "core/utils/get-parameter-schema.js"
|
||||
|
||||
export default class ParameterRow extends Component {
|
||||
static propTypes = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { fromJS, Iterable } from "immutable"
|
||||
import PropTypes from "prop-types"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
import { defaultStatusCode, getAcceptControllingResponse } from "core/utils"
|
||||
import createHtmlReadyId from "../../helpers/create-html-ready-id"
|
||||
import createHtmlReadyId from "core/utils/create-html-ready-id"
|
||||
|
||||
export default class Responses extends React.Component {
|
||||
static propTypes = {
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
import deepExtend from "deep-extend"
|
||||
|
||||
import System from "./system"
|
||||
// presets
|
||||
import BasePreset from "./presets/base"
|
||||
import ApisPreset from "./presets/apis"
|
||||
import AllPlugins from "./plugins/all"
|
||||
// plugins
|
||||
import AuthPlugin from "./plugins/auth/"
|
||||
import ConfigsPlugin from "./plugins/configs"
|
||||
import DeepLinkingPlugin from "./plugins/deep-linking"
|
||||
import ErrPlugin from "./plugins/err"
|
||||
import FilterPlugin from "./plugins/filter"
|
||||
import IconsPlugin from "./plugins/icons"
|
||||
import JSONSchema202012Plugin from "./plugins/json-schema-2020-12"
|
||||
import LayoutPlugin from "./plugins/layout"
|
||||
import LogsPlugin from "./plugins/logs"
|
||||
import OpenAPI30Plugin from "./plugins/oas3"
|
||||
import OpenAPI31Plugin from "./plugins/oas3"
|
||||
import OnCompletePlugin from "./plugins/on-complete"
|
||||
import RequestSnippetsPlugin from "./plugins/request-snippets"
|
||||
import SamplesPlugin from "./plugins/samples"
|
||||
import SpecPlugin from "./plugins/spec"
|
||||
import SwaggerClientPlugin from "./plugins/swagger-client"
|
||||
import UtilPlugin from "./plugins/util"
|
||||
import ViewPlugin from "./plugins/view"
|
||||
import DownloadUrlPlugin from "./plugins/download-url"
|
||||
import SafeRenderPlugin from "./plugins/safe-render"
|
||||
|
||||
import { parseSearch } from "./utils"
|
||||
import win from "./window"
|
||||
|
||||
@@ -216,10 +239,30 @@ export default function SwaggerUI(opts) {
|
||||
return system
|
||||
}
|
||||
|
||||
// Add presets
|
||||
SwaggerUI.presets = {
|
||||
base: BasePreset,
|
||||
apis: ApisPreset,
|
||||
}
|
||||
|
||||
// All Plugins
|
||||
SwaggerUI.plugins = AllPlugins
|
||||
SwaggerUI.plugins = {
|
||||
Auth: AuthPlugin,
|
||||
Configs: ConfigsPlugin,
|
||||
DeepLining: DeepLinkingPlugin,
|
||||
Err: ErrPlugin,
|
||||
Filter: FilterPlugin,
|
||||
Icons: IconsPlugin,
|
||||
JSONSchema202012: JSONSchema202012Plugin,
|
||||
Layout: LayoutPlugin,
|
||||
Logs: LogsPlugin,
|
||||
OpenAPI30: OpenAPI30Plugin,
|
||||
OpenAPI31: OpenAPI31Plugin,
|
||||
OnComplete: OnCompletePlugin,
|
||||
RequestSnippets: RequestSnippetsPlugin,
|
||||
Samples: SamplesPlugin,
|
||||
Spec: SpecPlugin,
|
||||
SwaggerClient: SwaggerClientPlugin,
|
||||
Util: UtilPlugin,
|
||||
View: ViewPlugin,
|
||||
DownloadUrl: DownloadUrlPlugin,
|
||||
SafeRender: SafeRenderPlugin,
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { pascalCaseFilename } from "core/utils"
|
||||
import SafeRender from "core/plugins/safe-render"
|
||||
|
||||
const request = require.context(".", true, /\.jsx?$/)
|
||||
|
||||
const allPlugins = {}
|
||||
|
||||
export default allPlugins
|
||||
|
||||
request.keys().forEach( function( key ){
|
||||
if( key === "./index.js" ) {
|
||||
return
|
||||
}
|
||||
|
||||
// if( key.slice(2).indexOf("/") > -1) {
|
||||
// // skip files in subdirs
|
||||
// return
|
||||
// }
|
||||
|
||||
let mod = request(key)
|
||||
allPlugins[pascalCaseFilename(key)] = mod.default ? mod.default : mod
|
||||
})
|
||||
|
||||
allPlugins.SafeRender = SafeRender
|
||||
@@ -1,110 +0,0 @@
|
||||
import { createSelector } from "reselect"
|
||||
import { Map } from "immutable"
|
||||
import win from "../window"
|
||||
|
||||
export default function downloadUrlPlugin (toolbox) {
|
||||
let { fn } = toolbox
|
||||
|
||||
const actions = {
|
||||
download: (url)=> ({ errActions, specSelectors, specActions, getConfigs }) => {
|
||||
let { fetch } = fn
|
||||
const config = getConfigs()
|
||||
url = url || specSelectors.url()
|
||||
specActions.updateLoadingStatus("loading")
|
||||
errActions.clear({source: "fetch"})
|
||||
fetch({
|
||||
url,
|
||||
loadSpec: true,
|
||||
requestInterceptor: config.requestInterceptor || (a => a),
|
||||
responseInterceptor: config.responseInterceptor || (a => a),
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
"Accept": "application/json,*/*"
|
||||
}
|
||||
}).then(next,next)
|
||||
|
||||
function next(res) {
|
||||
if(res instanceof Error || res.status >= 400) {
|
||||
specActions.updateLoadingStatus("failed")
|
||||
errActions.newThrownErr(Object.assign( new Error((res.message || res.statusText) + " " + url), {source: "fetch"}))
|
||||
// Check if the failure was possibly due to CORS or mixed content
|
||||
if (!res.status && res instanceof Error) checkPossibleFailReasons()
|
||||
return
|
||||
}
|
||||
specActions.updateLoadingStatus("success")
|
||||
specActions.updateSpec(res.text)
|
||||
if(specSelectors.url() !== url) {
|
||||
specActions.updateUrl(url)
|
||||
}
|
||||
}
|
||||
|
||||
function checkPossibleFailReasons() {
|
||||
try {
|
||||
let specUrl
|
||||
|
||||
if("URL" in win ) {
|
||||
specUrl = new URL(url)
|
||||
} else {
|
||||
// legacy browser, use <a href> to parse the URL
|
||||
specUrl = document.createElement("a")
|
||||
specUrl.href = url
|
||||
}
|
||||
|
||||
if(specUrl.protocol !== "https:" && win.location.protocol === "https:") {
|
||||
const error = Object.assign(
|
||||
new Error(`Possible mixed-content issue? The page was loaded over https:// but a ${specUrl.protocol}// URL was specified. Check that you are not attempting to load mixed content.`),
|
||||
{source: "fetch"}
|
||||
)
|
||||
errActions.newThrownErr(error)
|
||||
return
|
||||
}
|
||||
if(specUrl.origin !== win.location.origin) {
|
||||
const error = Object.assign(
|
||||
new Error(`Possible cross-origin (CORS) issue? The URL origin (${specUrl.origin}) does not match the page (${win.location.origin}). Check the server returns the correct 'Access-Control-Allow-*' headers.`),
|
||||
{source: "fetch"}
|
||||
)
|
||||
errActions.newThrownErr(error)
|
||||
}
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
updateLoadingStatus: (status) => {
|
||||
let enums = [null, "loading", "failed", "success", "failedConfig"]
|
||||
if(enums.indexOf(status) === -1) {
|
||||
console.error(`Error: ${status} is not one of ${JSON.stringify(enums)}`)
|
||||
}
|
||||
|
||||
return {
|
||||
type: "spec_update_loading_status",
|
||||
payload: status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let reducers = {
|
||||
"spec_update_loading_status": (state, action) => {
|
||||
return (typeof action.payload === "string")
|
||||
? state.set("loadingStatus", action.payload)
|
||||
: state
|
||||
}
|
||||
}
|
||||
|
||||
let selectors = {
|
||||
loadingStatus: createSelector(
|
||||
state => {
|
||||
return state || Map()
|
||||
},
|
||||
spec => spec.get("loadingStatus") || null
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
statePlugins: {
|
||||
spec: { actions, reducers, selectors }
|
||||
}
|
||||
}
|
||||
}
|
||||
126
src/core/plugins/download-url/index.js
Normal file
126
src/core/plugins/download-url/index.js
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import { createSelector } from "reselect"
|
||||
import { Map } from "immutable"
|
||||
import win from "core/window"
|
||||
|
||||
export default function downloadUrlPlugin(toolbox) {
|
||||
let { fn } = toolbox
|
||||
|
||||
const actions = {
|
||||
download:
|
||||
(url) =>
|
||||
({ errActions, specSelectors, specActions, getConfigs }) => {
|
||||
let { fetch } = fn
|
||||
const config = getConfigs()
|
||||
url = url || specSelectors.url()
|
||||
specActions.updateLoadingStatus("loading")
|
||||
errActions.clear({ source: "fetch" })
|
||||
fetch({
|
||||
url,
|
||||
loadSpec: true,
|
||||
requestInterceptor: config.requestInterceptor || ((a) => a),
|
||||
responseInterceptor: config.responseInterceptor || ((a) => a),
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
Accept: "application/json,*/*",
|
||||
},
|
||||
}).then(next, next)
|
||||
|
||||
function next(res) {
|
||||
if (res instanceof Error || res.status >= 400) {
|
||||
specActions.updateLoadingStatus("failed")
|
||||
errActions.newThrownErr(
|
||||
Object.assign(
|
||||
new Error((res.message || res.statusText) + " " + url),
|
||||
{ source: "fetch" }
|
||||
)
|
||||
)
|
||||
// Check if the failure was possibly due to CORS or mixed content
|
||||
if (!res.status && res instanceof Error) checkPossibleFailReasons()
|
||||
return
|
||||
}
|
||||
specActions.updateLoadingStatus("success")
|
||||
specActions.updateSpec(res.text)
|
||||
if (specSelectors.url() !== url) {
|
||||
specActions.updateUrl(url)
|
||||
}
|
||||
}
|
||||
|
||||
function checkPossibleFailReasons() {
|
||||
try {
|
||||
let specUrl
|
||||
|
||||
if ("URL" in win) {
|
||||
specUrl = new URL(url)
|
||||
} else {
|
||||
// legacy browser, use <a href> to parse the URL
|
||||
specUrl = document.createElement("a")
|
||||
specUrl.href = url
|
||||
}
|
||||
|
||||
if (
|
||||
specUrl.protocol !== "https:" &&
|
||||
win.location.protocol === "https:"
|
||||
) {
|
||||
const error = Object.assign(
|
||||
new Error(
|
||||
`Possible mixed-content issue? The page was loaded over https:// but a ${specUrl.protocol}// URL was specified. Check that you are not attempting to load mixed content.`
|
||||
),
|
||||
{ source: "fetch" }
|
||||
)
|
||||
errActions.newThrownErr(error)
|
||||
return
|
||||
}
|
||||
if (specUrl.origin !== win.location.origin) {
|
||||
const error = Object.assign(
|
||||
new Error(
|
||||
`Possible cross-origin (CORS) issue? The URL origin (${specUrl.origin}) does not match the page (${win.location.origin}). Check the server returns the correct 'Access-Control-Allow-*' headers.`
|
||||
),
|
||||
{ source: "fetch" }
|
||||
)
|
||||
errActions.newThrownErr(error)
|
||||
}
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateLoadingStatus: (status) => {
|
||||
let enums = [null, "loading", "failed", "success", "failedConfig"]
|
||||
if (enums.indexOf(status) === -1) {
|
||||
console.error(`Error: ${status} is not one of ${JSON.stringify(enums)}`)
|
||||
}
|
||||
|
||||
return {
|
||||
type: "spec_update_loading_status",
|
||||
payload: status,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let reducers = {
|
||||
spec_update_loading_status: (state, action) => {
|
||||
return typeof action.payload === "string"
|
||||
? state.set("loadingStatus", action.payload)
|
||||
: state
|
||||
},
|
||||
}
|
||||
|
||||
let selectors = {
|
||||
loadingStatus: createSelector(
|
||||
(state) => {
|
||||
return state || Map()
|
||||
},
|
||||
(spec) => spec.get("loadingStatus") || null
|
||||
),
|
||||
}
|
||||
|
||||
return {
|
||||
statePlugins: {
|
||||
spec: { actions, reducers, selectors },
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import isEmpty from "lodash/isEmpty"
|
||||
import isPlainObject from "lodash/isPlainObject"
|
||||
|
||||
import { objectify, normalizeArray } from "core/utils"
|
||||
import memoizeN from "../../../../../helpers/memoizeN"
|
||||
import memoizeN from "core/utils/memoizeN"
|
||||
import typeMap from "./types/index"
|
||||
import { getType } from "./core/type"
|
||||
import { typeCast } from "./core/utils"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { OrderedMap, Map, List } from "immutable"
|
||||
import { createSelector } from "reselect"
|
||||
|
||||
import { getDefaultRequestBodyValue } from "./components/request-body"
|
||||
import { stringify } from "../../utils"
|
||||
import { stringify } from "core/utils"
|
||||
|
||||
// Helpers
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import win from "../../window"
|
||||
import { Map } from "immutable"
|
||||
import win from "../../window"
|
||||
|
||||
|
||||
/**
|
||||
* if duplicate key name existed from FormData entries,
|
||||
|
||||
@@ -2,8 +2,7 @@ import XML from "xml"
|
||||
import RandExp from "randexp"
|
||||
import isEmpty from "lodash/isEmpty"
|
||||
import { objectify, isFunc, normalizeArray, deeplyStripKey } from "core/utils"
|
||||
|
||||
import memoizeN from "../../../../helpers/memoizeN"
|
||||
import memoizeN from "core/utils/memoizeN"
|
||||
|
||||
const generateStringFromRegex = (pattern) => {
|
||||
try {
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import reducers from "./reducers"
|
||||
import * as actions from "./actions"
|
||||
import * as selectors from "./selectors"
|
||||
import * as wrapActions from "./wrap-actions"
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
statePlugins: {
|
||||
spec: {
|
||||
wrapActions,
|
||||
reducers,
|
||||
actions,
|
||||
selectors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const SpecPlugin = () => ({
|
||||
statePlugins: {
|
||||
spec: {
|
||||
wrapActions: { ...wrapActions },
|
||||
reducers: { ...reducers },
|
||||
actions: { ...actions },
|
||||
selectors: { ...selectors },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default SpecPlugin
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fromJS, List } from "immutable"
|
||||
import { fromJSOrdered, validateParam, paramToValue } from "core/utils"
|
||||
import win from "../../window"
|
||||
import { fromJSOrdered, validateParam, paramToValue, paramToIdentifier } from "core/utils"
|
||||
import win from "core/window"
|
||||
|
||||
// selector-in-reducer is suboptimal, but `operationWithMeta` is more of a helper
|
||||
import {
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
CLEAR_VALIDATE_PARAMS,
|
||||
SET_SCHEME
|
||||
} from "./actions"
|
||||
import { paramToIdentifier } from "../../utils"
|
||||
|
||||
export default {
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { createSelector } from "reselect"
|
||||
import { sorters } from "core/utils"
|
||||
import { sorters, paramToIdentifier } from "core/utils"
|
||||
import { fromJS, Set, Map, OrderedMap, List } from "immutable"
|
||||
import { paramToIdentifier } from "../../utils"
|
||||
|
||||
const DEFAULT_TAG = "default"
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { memoize } from "core/utils"
|
||||
|
||||
import memoizeN from "core/utils/memoizeN"
|
||||
import { getComponent, render, withMappedContainer } from "./root-injects"
|
||||
import { getDisplayName } from "./fn"
|
||||
import memoizeN from "../../../helpers/memoizeN"
|
||||
|
||||
const memoizeForGetComponent = (fn) => {
|
||||
const resolver = (...args) => JSON.stringify(args)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import BasePreset from "./base"
|
||||
import OAS3Plugin from "../plugins/oas3"
|
||||
import OAS31Plugin from "../plugins/oas31"
|
||||
import JSONSchema202012Plugin from "../plugins/json-schema-2020-12"
|
||||
|
||||
export default function PresetApis() {
|
||||
return [BasePreset, OAS3Plugin, JSONSchema202012Plugin, OAS31Plugin]
|
||||
}
|
||||
11
src/core/presets/apis/index.js
Normal file
11
src/core/presets/apis/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import BasePreset from "core/presets/base"
|
||||
import OpenAPI30Plugin from "core/plugins/oas3"
|
||||
import OpenAPI31Plugin from "core/plugins/oas31"
|
||||
import JSONSchema202012Plugin from "core/plugins/json-schema-2020-12"
|
||||
|
||||
export default function PresetApis() {
|
||||
return [BasePreset, OpenAPI30Plugin, JSONSchema202012Plugin, OpenAPI31Plugin]
|
||||
}
|
||||
49
src/core/presets/base/index.js
Normal file
49
src/core/presets/base/index.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import AuthPlugin from "core/plugins/auth/"
|
||||
import ConfigsPlugin from "core/plugins/configs"
|
||||
import DeepLinkingPlugin from "core/plugins/deep-linking"
|
||||
import ErrPlugin from "core/plugins/err"
|
||||
import FilterPlugin from "core/plugins/filter"
|
||||
import IconsPlugin from "core/plugins/icons"
|
||||
import LayoutPlugin from "core/plugins/layout"
|
||||
import LogsPlugin from "core/plugins/logs"
|
||||
import OnCompletePlugin from "core/plugins/on-complete"
|
||||
import RequestSnippetsPlugin from "core/plugins/request-snippets"
|
||||
import SamplesPlugin from "core/plugins/samples"
|
||||
import SpecPlugin from "core/plugins/spec"
|
||||
import SwaggerClientPlugin from "core/plugins/swagger-client"
|
||||
import UtilPlugin from "core/plugins/util"
|
||||
import ViewPlugin from "core/plugins/view"
|
||||
import DownloadUrlPlugin from "core/plugins/download-url"
|
||||
import SafeRenderPlugin from "core/plugins/safe-render"
|
||||
// ad-hoc plugins
|
||||
import CoreComponentsPlugin from "core/presets/base/plugins/core-components"
|
||||
import FormComponentsPlugin from "core/presets/base/plugins/form-components"
|
||||
import JSONSchemaComponentsPlugin from "core/presets/base/plugins/json-schema-components"
|
||||
|
||||
const BasePreset = () => [
|
||||
ConfigsPlugin,
|
||||
UtilPlugin,
|
||||
LogsPlugin,
|
||||
ViewPlugin,
|
||||
SpecPlugin,
|
||||
ErrPlugin,
|
||||
IconsPlugin,
|
||||
LayoutPlugin,
|
||||
SamplesPlugin,
|
||||
CoreComponentsPlugin,
|
||||
FormComponentsPlugin,
|
||||
SwaggerClientPlugin,
|
||||
JSONSchemaComponentsPlugin,
|
||||
AuthPlugin,
|
||||
DownloadUrlPlugin,
|
||||
DeepLinkingPlugin,
|
||||
FilterPlugin,
|
||||
OnCompletePlugin,
|
||||
RequestSnippetsPlugin,
|
||||
SafeRenderPlugin(),
|
||||
]
|
||||
|
||||
export default BasePreset
|
||||
@@ -1,26 +1,6 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import err from "core/plugins/err"
|
||||
import layout from "core/plugins/layout"
|
||||
import spec from "core/plugins/spec"
|
||||
import view from "core/plugins/view"
|
||||
import samples from "core/plugins/samples"
|
||||
import requestSnippets from "core/plugins/request-snippets"
|
||||
import logs from "core/plugins/logs"
|
||||
import swaggerJs from "core/plugins/swagger-js"
|
||||
import auth from "core/plugins/auth"
|
||||
import util from "core/plugins/util"
|
||||
import downloadUrlPlugin from "core/plugins/download-url"
|
||||
import configsPlugin from "core/plugins/configs"
|
||||
import deepLinkingPlugin from "core/plugins/deep-linking"
|
||||
import filter from "core/plugins/filter"
|
||||
import onComplete from "core/plugins/on-complete"
|
||||
import safeRender from "core/plugins/safe-render"
|
||||
import iconsPlugin from "core/plugins/icons"
|
||||
|
||||
import OperationContainer from "core/containers/OperationContainer"
|
||||
|
||||
import App from "core/components/app"
|
||||
import AuthorizationPopup from "core/components/auth/authorization-popup"
|
||||
import AuthorizeBtn from "core/components/auth/authorize-btn"
|
||||
@@ -41,6 +21,7 @@ import OnlineValidatorBadge from "core/components/online-validator-badge"
|
||||
import Operations from "core/components/operations"
|
||||
import OperationTag from "core/components/operation-tag"
|
||||
import Operation from "core/components/operation"
|
||||
import OperationContainer from "core/containers/OperationContainer"
|
||||
import OperationSummary from "core/components/operation-summary"
|
||||
import OperationSummaryMethod from "core/components/operation-summary-method"
|
||||
import OperationSummaryPath from "core/components/operation-summary-path"
|
||||
@@ -91,116 +72,83 @@ import DeepLink from "core/components/deep-link"
|
||||
import SvgAssets from "core/components/svg-assets"
|
||||
import Markdown from "core/components/providers/markdown"
|
||||
import BaseLayout from "core/components/layouts/base"
|
||||
import * as LayoutUtils from "core/components/layout-utils"
|
||||
import * as JsonSchemaComponents from "core/json-schema-components"
|
||||
|
||||
export default function () {
|
||||
let coreComponents = {
|
||||
components: {
|
||||
App,
|
||||
authorizationPopup: AuthorizationPopup,
|
||||
authorizeBtn: AuthorizeBtn,
|
||||
AuthorizeBtnContainer,
|
||||
authorizeOperationBtn: AuthorizeOperationBtn,
|
||||
auths: Auths,
|
||||
AuthItem: AuthItem,
|
||||
authError: AuthError,
|
||||
oauth2: Oauth2,
|
||||
apiKeyAuth: ApiKeyAuth,
|
||||
basicAuth: BasicAuth,
|
||||
clear: Clear,
|
||||
liveResponse: LiveResponse,
|
||||
InitializedInput,
|
||||
info: Info,
|
||||
InfoContainer,
|
||||
InfoUrl,
|
||||
InfoBasePath,
|
||||
Contact,
|
||||
License,
|
||||
JumpToPath,
|
||||
CopyToClipboardBtn,
|
||||
onlineValidatorBadge: OnlineValidatorBadge,
|
||||
operations: Operations,
|
||||
operation: Operation,
|
||||
OperationSummary,
|
||||
OperationSummaryMethod,
|
||||
OperationSummaryPath,
|
||||
highlightCode: HighlightCode,
|
||||
responses: Responses,
|
||||
response: Response,
|
||||
ResponseExtension: ResponseExtension,
|
||||
responseBody: ResponseBody,
|
||||
parameters: Parameters,
|
||||
parameterRow: ParameterRow,
|
||||
execute: Execute,
|
||||
headers: Headers,
|
||||
errors: Errors,
|
||||
contentType: ContentType,
|
||||
overview: Overview,
|
||||
footer: Footer,
|
||||
FilterContainer,
|
||||
ParamBody: ParamBody,
|
||||
curl: Curl,
|
||||
schemes: Schemes,
|
||||
SchemesContainer,
|
||||
modelExample: ModelExample,
|
||||
ModelWrapper,
|
||||
ModelCollapse,
|
||||
Model,
|
||||
Models,
|
||||
EnumModel,
|
||||
ObjectModel,
|
||||
ArrayModel,
|
||||
PrimitiveModel,
|
||||
Property,
|
||||
TryItOutButton,
|
||||
Markdown,
|
||||
BaseLayout,
|
||||
VersionPragmaFilter,
|
||||
VersionStamp,
|
||||
OpenAPIVersion,
|
||||
OperationExt,
|
||||
OperationExtRow,
|
||||
ParameterExt,
|
||||
ParameterIncludeEmpty,
|
||||
OperationTag,
|
||||
OperationContainer,
|
||||
DeepLink,
|
||||
SvgAssets,
|
||||
Example,
|
||||
ExamplesSelect,
|
||||
ExamplesSelectValueRetainer,
|
||||
},
|
||||
}
|
||||
const CoreComponentsPlugin = () => ({
|
||||
components: {
|
||||
App,
|
||||
authorizationPopup: AuthorizationPopup,
|
||||
authorizeBtn: AuthorizeBtn,
|
||||
AuthorizeBtnContainer,
|
||||
authorizeOperationBtn: AuthorizeOperationBtn,
|
||||
auths: Auths,
|
||||
AuthItem: AuthItem,
|
||||
authError: AuthError,
|
||||
oauth2: Oauth2,
|
||||
apiKeyAuth: ApiKeyAuth,
|
||||
basicAuth: BasicAuth,
|
||||
clear: Clear,
|
||||
liveResponse: LiveResponse,
|
||||
InitializedInput,
|
||||
info: Info,
|
||||
InfoContainer,
|
||||
InfoUrl,
|
||||
InfoBasePath,
|
||||
Contact,
|
||||
License,
|
||||
JumpToPath,
|
||||
CopyToClipboardBtn,
|
||||
onlineValidatorBadge: OnlineValidatorBadge,
|
||||
operations: Operations,
|
||||
operation: Operation,
|
||||
OperationSummary,
|
||||
OperationSummaryMethod,
|
||||
OperationSummaryPath,
|
||||
highlightCode: HighlightCode,
|
||||
responses: Responses,
|
||||
response: Response,
|
||||
ResponseExtension: ResponseExtension,
|
||||
responseBody: ResponseBody,
|
||||
parameters: Parameters,
|
||||
parameterRow: ParameterRow,
|
||||
execute: Execute,
|
||||
headers: Headers,
|
||||
errors: Errors,
|
||||
contentType: ContentType,
|
||||
overview: Overview,
|
||||
footer: Footer,
|
||||
FilterContainer,
|
||||
ParamBody: ParamBody,
|
||||
curl: Curl,
|
||||
schemes: Schemes,
|
||||
SchemesContainer,
|
||||
modelExample: ModelExample,
|
||||
ModelWrapper,
|
||||
ModelCollapse,
|
||||
Model,
|
||||
Models,
|
||||
EnumModel,
|
||||
ObjectModel,
|
||||
ArrayModel,
|
||||
PrimitiveModel,
|
||||
Property,
|
||||
TryItOutButton,
|
||||
Markdown,
|
||||
BaseLayout,
|
||||
VersionPragmaFilter,
|
||||
VersionStamp,
|
||||
OperationExt,
|
||||
OperationExtRow,
|
||||
ParameterExt,
|
||||
ParameterIncludeEmpty,
|
||||
OperationTag,
|
||||
OperationContainer,
|
||||
OpenAPIVersion,
|
||||
DeepLink,
|
||||
SvgAssets,
|
||||
Example,
|
||||
ExamplesSelect,
|
||||
ExamplesSelectValueRetainer,
|
||||
},
|
||||
})
|
||||
|
||||
let formComponents = {
|
||||
components: LayoutUtils,
|
||||
}
|
||||
|
||||
let jsonSchemaComponents = {
|
||||
components: JsonSchemaComponents,
|
||||
}
|
||||
|
||||
return [
|
||||
configsPlugin,
|
||||
util,
|
||||
logs,
|
||||
view,
|
||||
spec,
|
||||
err,
|
||||
layout,
|
||||
samples,
|
||||
coreComponents,
|
||||
formComponents,
|
||||
swaggerJs,
|
||||
jsonSchemaComponents,
|
||||
auth,
|
||||
downloadUrlPlugin,
|
||||
deepLinkingPlugin,
|
||||
filter,
|
||||
onComplete,
|
||||
requestSnippets,
|
||||
iconsPlugin,
|
||||
safeRender(),
|
||||
]
|
||||
}
|
||||
export default CoreComponentsPlugin
|
||||
10
src/core/presets/base/plugins/form-components/index.js
Normal file
10
src/core/presets/base/plugins/form-components/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import * as LayoutUtils from "core/components/layout-utils"
|
||||
|
||||
const FormComponentsPlugin = () => ({
|
||||
components: { ...LayoutUtils },
|
||||
})
|
||||
|
||||
export default FormComponentsPlugin
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
import * as JSONSchemaComponents from "core/components/json-schema-components"
|
||||
|
||||
const JSONSchemaComponentsPlugin = () => ({
|
||||
components: { ...JSONSchemaComponents },
|
||||
})
|
||||
|
||||
export default JSONSchemaComponentsPlugin
|
||||
@@ -1,16 +0,0 @@
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
// Takes a list and proptype, and returns a PropType.shape({ [item]: propType })
|
||||
const mapListToPropTypeShape = (list, propType) => PropTypes.shape(
|
||||
list.reduce((shape, propName) => {
|
||||
shape[propName] = propType
|
||||
return shape
|
||||
}, {}))
|
||||
|
||||
|
||||
export const arrayOrString = PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.string),
|
||||
PropTypes.string,
|
||||
])
|
||||
|
||||
export const objectWithFuncs = list => mapListToPropTypeShape(list, PropTypes.func.isRequired)
|
||||
@@ -5,7 +5,7 @@ import deepExtend from "deep-extend"
|
||||
import { combineReducers } from "redux-immutable"
|
||||
import { serializeError } from "serialize-error"
|
||||
import merge from "lodash/merge"
|
||||
import { NEW_THROWN_ERR } from "corePlugins/err/actions"
|
||||
import { NEW_THROWN_ERR } from "core/plugins/err/actions"
|
||||
import win from "core/window"
|
||||
|
||||
import { systemThunkMiddleware, isFn, objMap, objReduce, isObject, isArray, isFunc } from "core/utils"
|
||||
|
||||
10
src/core/utils/create-html-ready-id.js
Normal file
10
src/core/utils/create-html-ready-id.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Replace invalid characters from a string to create an html-ready ID
|
||||
*
|
||||
* @param {string} id A string that may contain invalid characters for the HTML ID attribute
|
||||
* @param {string} [replacement=_] The string to replace invalid characters with; "_" by default
|
||||
* @return {string} Information about the parameter schema
|
||||
*/
|
||||
export default function createHtmlReadyId(id, replacement = "_") {
|
||||
return id.replace(/[^\w-]/g, replacement)
|
||||
}
|
||||
92
src/core/utils/get-parameter-schema.js
Normal file
92
src/core/utils/get-parameter-schema.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @prettier
|
||||
*/
|
||||
|
||||
import Im from "immutable"
|
||||
|
||||
const swagger2SchemaKeys = Im.Set.of(
|
||||
"type",
|
||||
"format",
|
||||
"items",
|
||||
"default",
|
||||
"maximum",
|
||||
"exclusiveMaximum",
|
||||
"minimum",
|
||||
"exclusiveMinimum",
|
||||
"maxLength",
|
||||
"minLength",
|
||||
"pattern",
|
||||
"maxItems",
|
||||
"minItems",
|
||||
"uniqueItems",
|
||||
"enum",
|
||||
"multipleOf"
|
||||
)
|
||||
|
||||
/**
|
||||
* @typedef {Object} ParameterSchemaDescriptor
|
||||
* @property {Immutable.Map} schema - the parameter schema
|
||||
* @property {string|null} parameterContentMediaType - the effective media type, for `content`-based OpenAPI 3.0 Parameters, or `null` otherwise
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the effective schema value for a parameter, or an empty Immutable.Map if
|
||||
* no suitable schema can be found.
|
||||
*
|
||||
* Supports OpenAPI 3.0 `Parameter.content` priority -- since a Parameter Object
|
||||
* cannot have both `schema` and `content`, this function ignores `schema` when
|
||||
* `content` is present.
|
||||
*
|
||||
* @param {Immutable.Map} parameter The parameter to identify a schema for
|
||||
* @param {object} config
|
||||
* @param {boolean} config.isOAS3 Whether the parameter is from an OpenAPI 2.0
|
||||
* or OpenAPI 3.0 definition
|
||||
* @return {ParameterSchemaDescriptor} Information about the parameter schema
|
||||
*/
|
||||
export default function getParameterSchema(parameter, { isOAS3 } = {}) {
|
||||
// Return empty Map if `parameter` isn't a Map
|
||||
if (!Im.Map.isMap(parameter)) {
|
||||
return {
|
||||
schema: Im.Map(),
|
||||
parameterContentMediaType: null,
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOAS3) {
|
||||
// Swagger 2.0
|
||||
if (parameter.get("in") === "body") {
|
||||
return {
|
||||
schema: parameter.get("schema", Im.Map()),
|
||||
parameterContentMediaType: null,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
schema: parameter.filter((v, k) => swagger2SchemaKeys.includes(k)),
|
||||
parameterContentMediaType: null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we've reached here, the parameter is OpenAPI 3.0
|
||||
|
||||
if (parameter.get("content")) {
|
||||
const parameterContentMediaTypes = parameter
|
||||
.get("content", Im.Map({}))
|
||||
.keySeq()
|
||||
|
||||
const parameterContentMediaType = parameterContentMediaTypes.first()
|
||||
|
||||
return {
|
||||
schema: parameter.getIn(
|
||||
["content", parameterContentMediaType, "schema"],
|
||||
Im.Map()
|
||||
),
|
||||
parameterContentMediaType,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
schema: parameter.get("schema") ? parameter.get("schema", Im.Map()): Im.Map(),
|
||||
parameterContentMediaType: null,
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,12 @@ import find from "lodash/find"
|
||||
import some from "lodash/some"
|
||||
import eq from "lodash/eq"
|
||||
import isFunction from "lodash/isFunction"
|
||||
import win from "./window"
|
||||
import cssEscape from "css.escape"
|
||||
import getParameterSchema from "../helpers/get-parameter-schema"
|
||||
import randomBytes from "randombytes"
|
||||
import shaJs from "sha.js"
|
||||
import win from "core/window"
|
||||
import getParameterSchema from "core/utils/get-parameter-schema"
|
||||
|
||||
|
||||
const DEFAULT_RESPONSE_KEY = "default"
|
||||
|
||||
@@ -117,11 +118,11 @@ export function createObjWithHashedKeys (fdObj) {
|
||||
}
|
||||
|
||||
export function bindToState(obj, state) {
|
||||
var newObj = {}
|
||||
Object.keys(obj)
|
||||
.filter(key => typeof obj[key] === "function")
|
||||
.forEach(key => newObj[key] = obj[key].bind(null, state))
|
||||
return newObj
|
||||
var newObj = {}
|
||||
Object.keys(obj)
|
||||
.filter(key => typeof obj[key] === "function")
|
||||
.forEach(key => newObj[key] = obj[key].bind(null, state))
|
||||
return newObj
|
||||
}
|
||||
|
||||
export function normalizeArray(arr) {
|
||||
@@ -344,21 +345,21 @@ export const validateString = ( val ) => {
|
||||
}
|
||||
|
||||
export const validateDateTime = (val) => {
|
||||
if (isNaN(Date.parse(val))) {
|
||||
return "Value must be a DateTime"
|
||||
}
|
||||
if (isNaN(Date.parse(val))) {
|
||||
return "Value must be a DateTime"
|
||||
}
|
||||
}
|
||||
|
||||
export const validateGuid = (val) => {
|
||||
val = val.toString().toLowerCase()
|
||||
if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}[)}]?$/.test(val)) {
|
||||
return "Value must be a Guid"
|
||||
}
|
||||
val = val.toString().toLowerCase()
|
||||
if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}[)}]?$/.test(val)) {
|
||||
return "Value must be a Guid"
|
||||
}
|
||||
}
|
||||
|
||||
export const validateMaxLength = (val, max) => {
|
||||
if (val.length > max) {
|
||||
return `Value must be no longer than ${max} character${max !== 1 ? "s" : ""}`
|
||||
return `Value must be no longer than ${max} character${max !== 1 ? "s" : ""}`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +387,7 @@ export const validateUniqueItems = (val, uniqueItems) => {
|
||||
|
||||
export const validateMinItems = (val, min) => {
|
||||
if (!val && min >= 1 || val && val.length < min) {
|
||||
return `Array must contain at least ${min} item${min === 1 ? "" : "s"}`
|
||||
return `Array must contain at least ${min} item${min === 1 ? "" : "s"}`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,14 +399,14 @@ export const validateMaxItems = (val, max) => {
|
||||
|
||||
export const validateMinLength = (val, min) => {
|
||||
if (val.length < min) {
|
||||
return `Value must be at least ${min} character${min !== 1 ? "s" : ""}`
|
||||
return `Value must be at least ${min} character${min !== 1 ? "s" : ""}`
|
||||
}
|
||||
}
|
||||
|
||||
export const validatePattern = (val, rxPattern) => {
|
||||
var patt = new RegExp(rxPattern)
|
||||
if (!patt.test(val)) {
|
||||
return "Value must follow pattern " + rxPattern
|
||||
return "Value must follow pattern " + rxPattern
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,10 +824,10 @@ export function generateCodeVerifier() {
|
||||
|
||||
export function createCodeChallenge(codeVerifier) {
|
||||
return b64toB64UrlEncoded(
|
||||
shaJs("sha256")
|
||||
shaJs("sha256")
|
||||
.update(codeVerifier)
|
||||
.digest("base64")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function b64toB64UrlEncoded(str) {
|
||||
48
src/core/utils/memoizeN.js
Normal file
48
src/core/utils/memoizeN.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import memoize from "lodash/memoize"
|
||||
|
||||
/**
|
||||
* This function is extension on top of lodash.memoize.
|
||||
* It uses all the arguments of the `fn` as the cache key instead of just the first one.
|
||||
* If resolver is provided, it determines the cache key for
|
||||
* storing the result based on the arguments provided to the memoized function.
|
||||
*/
|
||||
|
||||
const shallowArrayEquals = (a) => (b) => {
|
||||
return Array.isArray(a) && Array.isArray(b)
|
||||
&& a.length === b.length
|
||||
&& a.every((val, index) => val === b[index])
|
||||
}
|
||||
|
||||
const list = (...args) => args
|
||||
|
||||
class Cache extends Map {
|
||||
delete(key) {
|
||||
const keys = Array.from(this.keys())
|
||||
const foundKey = keys.find(shallowArrayEquals(key))
|
||||
return super.delete(foundKey)
|
||||
}
|
||||
|
||||
get(key) {
|
||||
const keys = Array.from(this.keys())
|
||||
const foundKey = keys.find(shallowArrayEquals(key))
|
||||
return super.get(foundKey)
|
||||
}
|
||||
|
||||
has(key) {
|
||||
const keys = Array.from(this.keys())
|
||||
return keys.findIndex(shallowArrayEquals(key)) !== -1
|
||||
}
|
||||
}
|
||||
|
||||
const memoizeN = (fn, resolver = list) => {
|
||||
const { Cache: OriginalCache } = memoize
|
||||
memoize.Cache = Cache
|
||||
|
||||
const memoized = memoize(fn, resolver)
|
||||
|
||||
memoize.Cache = OriginalCache
|
||||
|
||||
return memoized
|
||||
}
|
||||
|
||||
export default memoizeN
|
||||
Reference in New Issue
Block a user