refactor(oas31): concentrate OpenAPI 3.1.0 code to separate plugin (#8475)
Refs #8474
This commit is contained in:
45
src/core/components/contact.jsx
Normal file
45
src/core/components/contact.jsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import { safeBuildUrl } from "core/utils/url"
|
||||||
|
import { sanitizeUrl } from "core/utils"
|
||||||
|
|
||||||
|
class Contact extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
data: PropTypes.object,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
selectedServer: PropTypes.string,
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { data, getComponent, selectedServer, url: specUrl } = this.props
|
||||||
|
const name = data.get("name", "the developer")
|
||||||
|
const url = safeBuildUrl(data.get("url"), specUrl, { selectedServer })
|
||||||
|
const email = data.get("email")
|
||||||
|
|
||||||
|
const Link = getComponent("Link")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="info__contact">
|
||||||
|
{url && (
|
||||||
|
<div>
|
||||||
|
<Link href={sanitizeUrl(url)} target="_blank">
|
||||||
|
{name} - Website
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{email && (
|
||||||
|
<Link href={sanitizeUrl(`mailto:${email}`)}>
|
||||||
|
{url ? `Send email to ${name}` : `Contact ${name}`}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Contact
|
||||||
@@ -1,102 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import ImPropTypes from "react-immutable-proptypes"
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
import { sanitizeUrl } from "core/utils"
|
import { sanitizeUrl } from "core/utils"
|
||||||
import { safeBuildUrl } from "core/utils/url"
|
import { safeBuildUrl } from "core/utils/url"
|
||||||
|
|
||||||
|
|
||||||
export class InfoBasePath extends React.Component {
|
export class InfoBasePath extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
host: PropTypes.string,
|
host: PropTypes.string,
|
||||||
basePath: PropTypes.string
|
basePath: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { host, basePath } = this.props
|
const { host, basePath } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<pre className="base-url">
|
<pre className="base-url">
|
||||||
[ Base URL: {host}{basePath} ]
|
[ Base URL: {host}
|
||||||
|
{basePath} ]
|
||||||
</pre>
|
</pre>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class Contact extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
data: PropTypes.object,
|
|
||||||
getComponent: PropTypes.func.isRequired,
|
|
||||||
specSelectors: PropTypes.object.isRequired,
|
|
||||||
selectedServer: PropTypes.string,
|
|
||||||
url: PropTypes.string.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
render(){
|
|
||||||
let { data, getComponent, selectedServer, url: specUrl} = this.props
|
|
||||||
let name = data.get("name") || "the developer"
|
|
||||||
let url = safeBuildUrl(data.get("url"), specUrl, {selectedServer})
|
|
||||||
let email = data.get("email")
|
|
||||||
|
|
||||||
const Link = getComponent("Link")
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="info__contact">
|
|
||||||
{ url && <div><Link href={ sanitizeUrl(url) } target="_blank">{ name } - Website</Link></div> }
|
|
||||||
{ email &&
|
|
||||||
<Link href={sanitizeUrl(`mailto:${email}`)}>
|
|
||||||
{ url ? `Send email to ${name}` : `Contact ${name}`}
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class License extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
license: PropTypes.object,
|
|
||||||
getComponent: PropTypes.func.isRequired,
|
|
||||||
specSelectors: PropTypes.object.isRequired,
|
|
||||||
selectedServer: PropTypes.string,
|
|
||||||
url: PropTypes.string.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
render(){
|
|
||||||
let { license, getComponent, selectedServer, url: specUrl } = this.props
|
|
||||||
const Link = getComponent("Link")
|
|
||||||
let name = license.get("name") || "License"
|
|
||||||
let url = safeBuildUrl(license.get("url"), specUrl, {selectedServer})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="info__license">
|
|
||||||
{
|
|
||||||
url ? <Link target="_blank" href={ sanitizeUrl(url) }>{ name }</Link>
|
|
||||||
: <span>{ name }</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class InfoUrl extends React.PureComponent {
|
export class InfoUrl extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired
|
getComponent: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { url, getComponent } = this.props
|
const { url, getComponent } = this.props
|
||||||
|
|
||||||
const Link = getComponent("Link")
|
const Link = getComponent("Link")
|
||||||
|
|
||||||
return <Link target="_blank" href={ sanitizeUrl(url) }><span className="url"> { url }</span></Link>
|
return (
|
||||||
|
<Link target="_blank" href={sanitizeUrl(url)}>
|
||||||
|
<span className="url"> {url}</span>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Info extends React.Component {
|
class Info extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
title: PropTypes.any,
|
||||||
|
description: PropTypes.any,
|
||||||
|
version: PropTypes.any,
|
||||||
info: PropTypes.object,
|
info: PropTypes.object,
|
||||||
url: PropTypes.string,
|
url: PropTypes.string,
|
||||||
host: PropTypes.string,
|
host: PropTypes.string,
|
||||||
@@ -108,16 +59,32 @@ export default class Info extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { info, url, host, basePath, getComponent, externalDocs, selectedServer, url: specUrl } = this.props
|
const {
|
||||||
let version = info.get("version")
|
info,
|
||||||
let description = info.get("description")
|
url,
|
||||||
let title = info.get("title")
|
host,
|
||||||
let termsOfServiceUrl = safeBuildUrl(info.get("termsOfService"), specUrl, {selectedServer})
|
basePath,
|
||||||
let contact = info.get("contact")
|
getComponent,
|
||||||
let license = info.get("license")
|
externalDocs,
|
||||||
let rawExternalDocsUrl = externalDocs && externalDocs.get("url")
|
selectedServer,
|
||||||
let externalDocsUrl = safeBuildUrl(rawExternalDocsUrl, specUrl, {selectedServer})
|
url: specUrl,
|
||||||
let externalDocsDescription = externalDocs && externalDocs.get("description")
|
} = this.props
|
||||||
|
const version = info.get("version")
|
||||||
|
const description = info.get("description")
|
||||||
|
const title = info.get("title")
|
||||||
|
const termsOfServiceUrl = safeBuildUrl(
|
||||||
|
info.get("termsOfService"),
|
||||||
|
specUrl,
|
||||||
|
{ selectedServer }
|
||||||
|
)
|
||||||
|
const contactData = info.get("contact")
|
||||||
|
const licenseData = info.get("license")
|
||||||
|
const rawExternalDocsUrl = externalDocs && externalDocs.get("url")
|
||||||
|
const externalDocsUrl = safeBuildUrl(rawExternalDocsUrl, specUrl, {
|
||||||
|
selectedServer,
|
||||||
|
})
|
||||||
|
const externalDocsDescription =
|
||||||
|
externalDocs && externalDocs.get("description")
|
||||||
|
|
||||||
const Markdown = getComponent("Markdown", true)
|
const Markdown = getComponent("Markdown", true)
|
||||||
const Link = getComponent("Link")
|
const Link = getComponent("Link")
|
||||||
@@ -125,42 +92,61 @@ export default class Info extends React.Component {
|
|||||||
const InfoUrl = getComponent("InfoUrl")
|
const InfoUrl = getComponent("InfoUrl")
|
||||||
const InfoBasePath = getComponent("InfoBasePath")
|
const InfoBasePath = getComponent("InfoBasePath")
|
||||||
const License = getComponent("License")
|
const License = getComponent("License")
|
||||||
|
const Contact = getComponent("Contact")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="info">
|
<div className="info">
|
||||||
<hgroup className="main">
|
<hgroup className="main">
|
||||||
<h2 className="title" >{ title }
|
<h2 className="title">
|
||||||
{ version && <VersionStamp version={version}></VersionStamp> }
|
{title}
|
||||||
|
{version && <VersionStamp version={version}></VersionStamp>}
|
||||||
</h2>
|
</h2>
|
||||||
{ host || basePath ? <InfoBasePath host={ host } basePath={ basePath } /> : null }
|
{host || basePath ? (
|
||||||
{ url && <InfoUrl getComponent={getComponent} url={url} /> }
|
<InfoBasePath host={host} basePath={basePath} />
|
||||||
|
) : null}
|
||||||
|
{url && <InfoUrl getComponent={getComponent} url={url} />}
|
||||||
</hgroup>
|
</hgroup>
|
||||||
|
|
||||||
<div className="description">
|
<div className="description">
|
||||||
<Markdown source={ description } />
|
<Markdown source={description} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{termsOfServiceUrl && (
|
||||||
termsOfServiceUrl && <div className="info__tos">
|
<div className="info__tos">
|
||||||
<Link target="_blank" href={ sanitizeUrl(termsOfServiceUrl) }>Terms of service</Link>
|
<Link target="_blank" href={sanitizeUrl(termsOfServiceUrl)}>
|
||||||
|
Terms of service
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
|
|
||||||
{contact && contact.size ? <Contact getComponent={getComponent} data={ contact } selectedServer={selectedServer} url={url} /> : null }
|
|
||||||
{license && license.size ? <License getComponent={getComponent} license={ license } selectedServer={selectedServer} url={url}/> : null }
|
|
||||||
{ externalDocsUrl ?
|
|
||||||
<Link className="info__extdocs" target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</Link>
|
|
||||||
: null }
|
|
||||||
|
|
||||||
|
{contactData?.size > 0 && (
|
||||||
|
<Contact
|
||||||
|
getComponent={getComponent}
|
||||||
|
data={contactData}
|
||||||
|
selectedServer={selectedServer}
|
||||||
|
url={url}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{licenseData?.size > 0 && (
|
||||||
|
<License
|
||||||
|
getComponent={getComponent}
|
||||||
|
license={licenseData}
|
||||||
|
selectedServer={selectedServer}
|
||||||
|
url={url}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{externalDocsUrl ? (
|
||||||
|
<Link
|
||||||
|
className="info__extdocs"
|
||||||
|
target="_blank"
|
||||||
|
href={sanitizeUrl(externalDocsUrl)}
|
||||||
|
>
|
||||||
|
{externalDocsDescription || externalDocsUrl}
|
||||||
|
</Link>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Info.propTypes = {
|
export default Info
|
||||||
title: PropTypes.any,
|
|
||||||
description: PropTypes.any,
|
|
||||||
version: PropTypes.any,
|
|
||||||
url: PropTypes.string
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,37 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
export default class BaseLayout extends React.Component {
|
export default class BaseLayout extends React.Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
errSelectors: PropTypes.object.isRequired,
|
errSelectors: PropTypes.object.isRequired,
|
||||||
errActions: PropTypes.object.isRequired,
|
errActions: PropTypes.object.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
oas3Selectors: PropTypes.object.isRequired,
|
oas3Selectors: PropTypes.object.isRequired,
|
||||||
oas3Actions: PropTypes.object.isRequired,
|
oas3Actions: PropTypes.object.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired
|
getComponent: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let {errSelectors, specSelectors, getComponent} = this.props
|
const { errSelectors, specSelectors, getComponent } = this.props
|
||||||
|
|
||||||
let SvgAssets = getComponent("SvgAssets")
|
const SvgAssets = getComponent("SvgAssets")
|
||||||
let InfoContainer = getComponent("InfoContainer", true)
|
const InfoContainer = getComponent("InfoContainer", true)
|
||||||
let VersionPragmaFilter = getComponent("VersionPragmaFilter")
|
const VersionPragmaFilter = getComponent("VersionPragmaFilter")
|
||||||
let Operations = getComponent("operations", true)
|
const Operations = getComponent("operations", true)
|
||||||
let Models = getComponent("Models", true)
|
const Models = getComponent("Models", true)
|
||||||
let Webhooks = getComponent("Webhooks", true)
|
const Webhooks = getComponent("Webhooks", true)
|
||||||
let Row = getComponent("Row")
|
const Row = getComponent("Row")
|
||||||
let Col = getComponent("Col")
|
const Col = getComponent("Col")
|
||||||
let Errors = getComponent("errors", true)
|
const Errors = getComponent("errors", true)
|
||||||
|
|
||||||
const ServersContainer = getComponent("ServersContainer", true)
|
const ServersContainer = getComponent("ServersContainer", true)
|
||||||
const SchemesContainer = getComponent("SchemesContainer", true)
|
const SchemesContainer = getComponent("SchemesContainer", true)
|
||||||
const AuthorizeBtnContainer = getComponent("AuthorizeBtnContainer", true)
|
const AuthorizeBtnContainer = getComponent("AuthorizeBtnContainer", true)
|
||||||
const FilterContainer = getComponent("FilterContainer", true)
|
const FilterContainer = getComponent("FilterContainer", true)
|
||||||
let isSwagger2 = specSelectors.isSwagger2()
|
const isSwagger2 = specSelectors.isSwagger2()
|
||||||
let isOAS3 = specSelectors.isOAS3()
|
const isOAS3 = specSelectors.isOAS3()
|
||||||
const isOpenAPI31 = specSelectors.selectIsOpenAPI31()
|
const isOAS31 = specSelectors.isOAS31()
|
||||||
|
|
||||||
const isSpecEmpty = !specSelectors.specStr()
|
const isSpecEmpty = !specSelectors.specStr()
|
||||||
|
|
||||||
@@ -39,44 +41,50 @@ export default class BaseLayout extends React.Component {
|
|||||||
|
|
||||||
let loadingMessage = null
|
let loadingMessage = null
|
||||||
|
|
||||||
if(loadingStatus === "loading") {
|
if (loadingStatus === "loading") {
|
||||||
loadingMessage = <div className="info">
|
loadingMessage = (
|
||||||
<div className="loading-container">
|
<div className="info">
|
||||||
<div className="loading"></div>
|
<div className="loading-container">
|
||||||
|
<div className="loading"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(loadingStatus === "failed") {
|
if (loadingStatus === "failed") {
|
||||||
loadingMessage = <div className="info">
|
loadingMessage = (
|
||||||
<div className="loading-container">
|
<div className="info">
|
||||||
<h4 className="title">Failed to load API definition.</h4>
|
<div className="loading-container">
|
||||||
<Errors />
|
<h4 className="title">Failed to load API definition.</h4>
|
||||||
|
<Errors />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadingStatus === "failedConfig") {
|
if (loadingStatus === "failedConfig") {
|
||||||
const lastErr = errSelectors.lastError()
|
const lastErr = errSelectors.lastError()
|
||||||
const lastErrMsg = lastErr ? lastErr.get("message") : ""
|
const lastErrMsg = lastErr ? lastErr.get("message") : ""
|
||||||
loadingMessage = <div className="info failed-config">
|
loadingMessage = (
|
||||||
<div className="loading-container">
|
<div className="info failed-config">
|
||||||
<h4 className="title">Failed to load remote configuration.</h4>
|
<div className="loading-container">
|
||||||
<p>{lastErrMsg}</p>
|
<h4 className="title">Failed to load remote configuration.</h4>
|
||||||
|
<p>{lastErrMsg}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!loadingMessage && isSpecEmpty) {
|
if (!loadingMessage && isSpecEmpty) {
|
||||||
loadingMessage = <h4>No API definition provided.</h4>
|
loadingMessage = <h4>No API definition provided.</h4>
|
||||||
}
|
}
|
||||||
|
|
||||||
if(loadingMessage) {
|
if (loadingMessage) {
|
||||||
return <div className="swagger-ui">
|
return (
|
||||||
<div className="loading-container">
|
<div className="swagger-ui">
|
||||||
{loadingMessage}
|
<div className="loading-container">{loadingMessage}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const servers = specSelectors.servers()
|
const servers = specSelectors.servers()
|
||||||
@@ -87,43 +95,47 @@ export default class BaseLayout extends React.Component {
|
|||||||
const hasSecurityDefinitions = !!specSelectors.securityDefinitions()
|
const hasSecurityDefinitions = !!specSelectors.securityDefinitions()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='swagger-ui'>
|
<div className="swagger-ui">
|
||||||
<SvgAssets />
|
<SvgAssets />
|
||||||
<VersionPragmaFilter isSwagger2={isSwagger2} isOAS3={isOAS3} alsoShow={<Errors/>}>
|
<VersionPragmaFilter
|
||||||
<Errors/>
|
isSwagger2={isSwagger2}
|
||||||
|
isOAS3={isOAS3}
|
||||||
|
alsoShow={<Errors />}
|
||||||
|
>
|
||||||
|
<Errors />
|
||||||
<Row className="information-container">
|
<Row className="information-container">
|
||||||
<Col mobile={12}>
|
<Col mobile={12}>
|
||||||
<InfoContainer/>
|
<InfoContainer />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{hasServers || hasSchemes || hasSecurityDefinitions ? (
|
{hasServers || hasSchemes || hasSecurityDefinitions ? (
|
||||||
<div className="scheme-container">
|
<div className="scheme-container">
|
||||||
<Col className="schemes wrapper" mobile={12}>
|
<Col className="schemes wrapper" mobile={12}>
|
||||||
{hasServers ? (<ServersContainer />) : null}
|
{hasServers ? <ServersContainer /> : null}
|
||||||
{hasSchemes ? (<SchemesContainer />) : null}
|
{hasSchemes ? <SchemesContainer /> : null}
|
||||||
{hasSecurityDefinitions ? (<AuthorizeBtnContainer />) : null}
|
{hasSecurityDefinitions ? <AuthorizeBtnContainer /> : null}
|
||||||
</Col>
|
</Col>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<FilterContainer/>
|
<FilterContainer />
|
||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col mobile={12} desktop={12} >
|
<Col mobile={12} desktop={12}>
|
||||||
<Operations/>
|
<Operations />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{ isOpenAPI31 &&
|
{isOAS31 && (
|
||||||
<Row className="webhooks-container">
|
<Row className="webhooks-container">
|
||||||
<Col mobile={12} desktop={12} >
|
<Col mobile={12} desktop={12}>
|
||||||
<Webhooks />
|
<Webhooks />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
}
|
)}
|
||||||
<Row>
|
<Row>
|
||||||
<Col mobile={12} desktop={12} >
|
<Col mobile={12} desktop={12}>
|
||||||
<Models/>
|
<Models />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</VersionPragmaFilter>
|
</VersionPragmaFilter>
|
||||||
|
|||||||
41
src/core/components/license.jsx
Normal file
41
src/core/components/license.jsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import { safeBuildUrl } from "core/utils/url"
|
||||||
|
import { sanitizeUrl } from "core/utils"
|
||||||
|
|
||||||
|
class License extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
license: PropTypes.object,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
selectedServer: PropTypes.string,
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { license, getComponent, selectedServer, url: specUrl } = this.props
|
||||||
|
const name = license.get("name", "License")
|
||||||
|
const url = safeBuildUrl(license.get("url"), specUrl, { selectedServer })
|
||||||
|
|
||||||
|
const Link = getComponent("Link")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="info__license">
|
||||||
|
{url ? (
|
||||||
|
<div className="info__license__url">
|
||||||
|
<Link target="_blank" href={sanitizeUrl(url)}>
|
||||||
|
{name}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span>{name}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default License
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { createSelector } from "reselect"
|
import { createSelector } from "reselect"
|
||||||
import { List, Map, fromJS } from "immutable"
|
import { List, Map, fromJS } from "immutable"
|
||||||
import { isOAS3 as isOAS3Helper } from "../helpers"
|
|
||||||
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
@@ -9,8 +8,7 @@ const state = state => state
|
|||||||
|
|
||||||
function onlyOAS3(selector) {
|
function onlyOAS3(selector) {
|
||||||
return (ori, system) => (...args) => {
|
return (ori, system) => (...args) => {
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
if(system.getSystem().specSelectors.isOAS3()) {
|
||||||
if(isOAS3Helper(spec)) {
|
|
||||||
// Pass the spec plugin state to Reselect to trigger on securityDefinitions update
|
// Pass the spec plugin state to Reselect to trigger on securityDefinitions update
|
||||||
let resolvedSchemes = system.getState().getIn(["spec", "resolvedSubtrees",
|
let resolvedSchemes = system.getState().getIn(["spec", "resolvedSubtrees",
|
||||||
"components", "securitySchemes"])
|
"components", "securitySchemes"])
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import ServersContainer from "./servers-container"
|
|||||||
import RequestBodyEditor from "./request-body-editor"
|
import RequestBodyEditor from "./request-body-editor"
|
||||||
import HttpAuth from "./http-auth"
|
import HttpAuth from "./http-auth"
|
||||||
import OperationServers from "./operation-servers"
|
import OperationServers from "./operation-servers"
|
||||||
import Webhooks from "./webhooks"
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Callbacks,
|
Callbacks,
|
||||||
@@ -17,5 +16,4 @@ export default {
|
|||||||
RequestBodyEditor,
|
RequestBodyEditor,
|
||||||
OperationServers,
|
OperationServers,
|
||||||
operationLink: OperationLink,
|
operationLink: OperationLink,
|
||||||
Webhooks
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export function isOpenAPI30(jsSpec) {
|
export function isOAS30(jsSpec) {
|
||||||
const oasVersion = jsSpec.get("openapi")
|
const oasVersion = jsSpec.get("openapi")
|
||||||
if (typeof oasVersion !== "string") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return oasVersion.startsWith("3.0.") && oasVersion.length > 4
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOpenAPI31(jsSpec) {
|
return (
|
||||||
const oasVersion = jsSpec.get("openapi")
|
typeof oasVersion === "string" &&
|
||||||
if (typeof oasVersion !== "string") {
|
/^3\.0\.([0123])(?:-rc[012])?$/.test(oasVersion)
|
||||||
return false
|
)
|
||||||
}
|
|
||||||
return oasVersion.startsWith("3.1.") && oasVersion.length > 4
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOAS3(jsSpec) {
|
|
||||||
const oasVersion = jsSpec.get("openapi")
|
|
||||||
if(typeof oasVersion !== "string") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return isOpenAPI30(jsSpec) || isOpenAPI31(jsSpec)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSwagger2(jsSpec) {
|
export function isSwagger2(jsSpec) {
|
||||||
const swaggerVersion = jsSpec.get("swagger")
|
const swaggerVersion = jsSpec.get("swagger")
|
||||||
if(typeof swaggerVersion !== "string") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return swaggerVersion.startsWith("2.0")
|
return typeof swaggerVersion === "string" && swaggerVersion === "2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OAS3ComponentWrapFactory(Component) {
|
export function OAS3ComponentWrapFactory(Component) {
|
||||||
return (Ori, system) => (props) => {
|
return (Ori, system) => (props) => {
|
||||||
if(system && system.specSelectors && system.specSelectors.specJson) {
|
if (typeof system.specSelectors?.isOAS3 === "function") {
|
||||||
const spec = system.specSelectors.specJson()
|
if (system.specSelectors.isOAS3()) {
|
||||||
|
|
||||||
if(isOAS3(spec)) {
|
|
||||||
return <Component {...props} {...system} Ori={Ori}></Component>
|
return <Component {...props} {...system} Ori={Ori}></Component>
|
||||||
} else {
|
} else {
|
||||||
return <Ori {...props}></Ori>
|
return <Ori {...props}></Ori>
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
// import reducers from "./reducers"
|
/**
|
||||||
// import * as actions from "./actions"
|
* @prettier
|
||||||
|
*/
|
||||||
import * as specWrapSelectors from "./spec-extensions/wrap-selectors"
|
import * as specWrapSelectors from "./spec-extensions/wrap-selectors"
|
||||||
import * as authWrapSelectors from "./auth-extensions/wrap-selectors"
|
import * as authWrapSelectors from "./auth-extensions/wrap-selectors"
|
||||||
import * as specSelectors from "./spec-extensions/selectors"
|
import * as specSelectors from "./spec-extensions/selectors"
|
||||||
import components from "./components"
|
import components from "./components"
|
||||||
import wrapComponents from "./wrap-components"
|
import wrapComponents from "./wrap-components"
|
||||||
import * as oas3Actions from "./actions"
|
import * as actions from "./actions"
|
||||||
import * as oas3Selectors from "./selectors"
|
import * as selectors from "./selectors"
|
||||||
import oas3Reducers from "./reducers"
|
import reducers from "./reducers"
|
||||||
|
|
||||||
export default function() {
|
export default function () {
|
||||||
return {
|
return {
|
||||||
components,
|
components,
|
||||||
wrapComponents,
|
wrapComponents,
|
||||||
statePlugins: {
|
statePlugins: {
|
||||||
spec: {
|
spec: {
|
||||||
wrapSelectors: specWrapSelectors,
|
wrapSelectors: specWrapSelectors,
|
||||||
selectors: specSelectors
|
selectors: specSelectors,
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
wrapSelectors: authWrapSelectors
|
wrapSelectors: authWrapSelectors,
|
||||||
},
|
},
|
||||||
oas3: {
|
oas3: {
|
||||||
actions: oas3Actions,
|
actions,
|
||||||
reducers: oas3Reducers,
|
reducers,
|
||||||
selectors: oas3Selectors,
|
selectors,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
import { OrderedMap, Map, List } from "immutable"
|
import { OrderedMap, Map, List } from "immutable"
|
||||||
import { isOAS3 as isOAS3Helper } from "./helpers"
|
|
||||||
import { getDefaultRequestBodyValue } from "./components/request-body"
|
import { getDefaultRequestBodyValue } from "./components/request-body"
|
||||||
import { stringify } from "../../utils"
|
import { stringify } from "../../utils"
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
function onlyOAS3(selector) {
|
function onlyOAS3(selector) {
|
||||||
return (...args) => (system) => {
|
return (...args) =>
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
(system) => {
|
||||||
if(isOAS3Helper(spec)) {
|
if (system.getSystem().specSelectors.isOAS3()) {
|
||||||
return selector(...args)
|
return selector(...args)
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateRequestBodyIsRequired(selector) {
|
function validateRequestBodyIsRequired(selector) {
|
||||||
return (...args) => (system) => {
|
return (...args) =>
|
||||||
const specJson = system.getSystem().specSelectors.specJson()
|
(system) => {
|
||||||
const argsList = [...args]
|
const specJson = system.getSystem().specSelectors.specJson()
|
||||||
// expect argsList[0] = state
|
const argsList = [...args]
|
||||||
let pathMethod = argsList[1] || []
|
// expect argsList[0] = state
|
||||||
let isOas3RequestBodyRequired = specJson.getIn(["paths", ...pathMethod, "requestBody", "required"])
|
let pathMethod = argsList[1] || []
|
||||||
|
let isOas3RequestBodyRequired = specJson.getIn([
|
||||||
|
"paths",
|
||||||
|
...pathMethod,
|
||||||
|
"requestBody",
|
||||||
|
"required",
|
||||||
|
])
|
||||||
|
|
||||||
if (isOas3RequestBodyRequired) {
|
if (isOas3RequestBodyRequired) {
|
||||||
return selector(...args)
|
return selector(...args)
|
||||||
} else {
|
} else {
|
||||||
// validation pass b/c not required
|
// validation pass b/c not required
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateRequestBodyValueExists = (state, pathMethod) => {
|
const validateRequestBodyValueExists = (state, pathMethod) => {
|
||||||
pathMethod = pathMethod || []
|
pathMethod = pathMethod || []
|
||||||
let oas3RequestBodyValue = state.getIn(["requestData", ...pathMethod, "bodyValue"])
|
let oas3RequestBodyValue = state.getIn([
|
||||||
|
"requestData",
|
||||||
|
...pathMethod,
|
||||||
|
"bodyValue",
|
||||||
|
])
|
||||||
// context: bodyValue can be a String, or a Map
|
// context: bodyValue can be a String, or a Map
|
||||||
if (!oas3RequestBodyValue) {
|
if (!oas3RequestBodyValue) {
|
||||||
return false
|
return false
|
||||||
@@ -44,68 +56,85 @@ const validateRequestBodyValueExists = (state, pathMethod) => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const selectedServer = onlyOAS3((state, namespace) => {
|
export const selectedServer = onlyOAS3((state, namespace) => {
|
||||||
const path = namespace ? [namespace, "selectedServer"] : ["selectedServer"]
|
const path = namespace ? [namespace, "selectedServer"] : ["selectedServer"]
|
||||||
return state.getIn(path) || ""
|
return state.getIn(path) || ""
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
export const requestBodyValue = onlyOAS3((state, path, method) => {
|
export const requestBodyValue = onlyOAS3((state, path, method) => {
|
||||||
return state.getIn(["requestData", path, method, "bodyValue"]) || null
|
return state.getIn(["requestData", path, method, "bodyValue"]) || null
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
export const shouldRetainRequestBodyValue = onlyOAS3((state, path, method) => {
|
export const shouldRetainRequestBodyValue = onlyOAS3((state, path, method) => {
|
||||||
return state.getIn(["requestData", path, method, "retainBodyValue"]) || false
|
return state.getIn(["requestData", path, method, "retainBodyValue"]) || false
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
export const selectDefaultRequestBodyValue = (state, path, method) => (system) => {
|
export const selectDefaultRequestBodyValue =
|
||||||
const {oas3Selectors, specSelectors} = system.getSystem()
|
(state, path, method) => (system) => {
|
||||||
const spec = specSelectors.specJson()
|
const { oas3Selectors, specSelectors } = system.getSystem()
|
||||||
if(isOAS3Helper(spec)) {
|
|
||||||
const currentMediaType = oas3Selectors.requestContentType(path, method)
|
if (specSelectors.isOAS3()) {
|
||||||
if (currentMediaType) {
|
const currentMediaType = oas3Selectors.requestContentType(path, method)
|
||||||
return getDefaultRequestBodyValue(
|
if (currentMediaType) {
|
||||||
specSelectors.specResolvedSubtree(["paths", path, method, "requestBody"]),
|
return getDefaultRequestBodyValue(
|
||||||
currentMediaType,
|
specSelectors.specResolvedSubtree([
|
||||||
oas3Selectors.activeExamplesMember(
|
"paths",
|
||||||
path, method,
|
path,
|
||||||
"requestBody",
|
method,
|
||||||
"requestBody",
|
"requestBody",
|
||||||
|
]),
|
||||||
|
currentMediaType,
|
||||||
|
oas3Selectors.activeExamplesMember(
|
||||||
|
path,
|
||||||
|
method,
|
||||||
|
"requestBody",
|
||||||
|
"requestBody"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hasUserEditedBody = (state, path, method) => (system) => {
|
export const hasUserEditedBody = (state, path, method) => (system) => {
|
||||||
const {oas3Selectors, specSelectors} = system.getSystem()
|
const { oas3Selectors, specSelectors } = system.getSystem()
|
||||||
const spec = specSelectors.specJson()
|
|
||||||
if(isOAS3Helper(spec)) {
|
if (specSelectors.isOAS3()) {
|
||||||
let userHasEditedBody = false
|
let userHasEditedBody = false
|
||||||
const currentMediaType = oas3Selectors.requestContentType(path, method)
|
const currentMediaType = oas3Selectors.requestContentType(path, method)
|
||||||
let userEditedRequestBody = oas3Selectors.requestBodyValue(path, method)
|
let userEditedRequestBody = oas3Selectors.requestBodyValue(path, method)
|
||||||
if (Map.isMap(userEditedRequestBody)) {
|
if (Map.isMap(userEditedRequestBody)) {
|
||||||
// context is not application/json media-type
|
// context is not application/json media-type
|
||||||
userEditedRequestBody = stringify(userEditedRequestBody.mapEntries((kv) => Map.isMap(kv[1]) ? [kv[0], kv[1].get("value")] : kv).toJS())
|
userEditedRequestBody = stringify(
|
||||||
|
userEditedRequestBody
|
||||||
|
.mapEntries((kv) =>
|
||||||
|
Map.isMap(kv[1]) ? [kv[0], kv[1].get("value")] : kv
|
||||||
|
)
|
||||||
|
.toJS()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if(List.isList(userEditedRequestBody)) {
|
if (List.isList(userEditedRequestBody)) {
|
||||||
userEditedRequestBody = stringify(userEditedRequestBody)
|
userEditedRequestBody = stringify(userEditedRequestBody)
|
||||||
}
|
}
|
||||||
if (currentMediaType) {
|
if (currentMediaType) {
|
||||||
const currentMediaTypeDefaultBodyValue = getDefaultRequestBodyValue(
|
const currentMediaTypeDefaultBodyValue = getDefaultRequestBodyValue(
|
||||||
specSelectors.specResolvedSubtree(["paths", path, method, "requestBody"]),
|
specSelectors.specResolvedSubtree([
|
||||||
|
"paths",
|
||||||
|
path,
|
||||||
|
method,
|
||||||
|
"requestBody",
|
||||||
|
]),
|
||||||
currentMediaType,
|
currentMediaType,
|
||||||
oas3Selectors.activeExamplesMember(
|
oas3Selectors.activeExamplesMember(
|
||||||
path, method,
|
path,
|
||||||
"requestBody",
|
method,
|
||||||
"requestBody",
|
"requestBody",
|
||||||
|
"requestBody"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
userHasEditedBody = !!userEditedRequestBody && userEditedRequestBody !== currentMediaTypeDefaultBodyValue
|
userHasEditedBody =
|
||||||
|
!!userEditedRequestBody &&
|
||||||
|
userEditedRequestBody !== currentMediaTypeDefaultBodyValue
|
||||||
}
|
}
|
||||||
return userHasEditedBody
|
return userHasEditedBody
|
||||||
} else {
|
} else {
|
||||||
@@ -114,106 +143,114 @@ export const hasUserEditedBody = (state, path, method) => (system) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const requestBodyInclusionSetting = onlyOAS3((state, path, method) => {
|
export const requestBodyInclusionSetting = onlyOAS3((state, path, method) => {
|
||||||
return state.getIn(["requestData", path, method, "bodyInclusion"]) || Map()
|
return state.getIn(["requestData", path, method, "bodyInclusion"]) || Map()
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
export const requestBodyErrors = onlyOAS3((state, path, method) => {
|
export const requestBodyErrors = onlyOAS3((state, path, method) => {
|
||||||
return state.getIn(["requestData", path, method, "errors"]) || null
|
return state.getIn(["requestData", path, method, "errors"]) || null
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
export const activeExamplesMember = onlyOAS3((state, path, method, type, name) => {
|
export const activeExamplesMember = onlyOAS3(
|
||||||
return state.getIn(["examples", path, method, type, name, "activeExample"]) || null
|
(state, path, method, type, name) => {
|
||||||
|
return (
|
||||||
|
state.getIn(["examples", path, method, type, name, "activeExample"]) ||
|
||||||
|
null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const requestContentType = onlyOAS3((state, path, method) => {
|
export const requestContentType = onlyOAS3((state, path, method) => {
|
||||||
return state.getIn(["requestData", path, method, "requestContentType"]) || null
|
return (
|
||||||
}
|
state.getIn(["requestData", path, method, "requestContentType"]) || null
|
||||||
)
|
)
|
||||||
|
})
|
||||||
|
|
||||||
export const responseContentType = onlyOAS3((state, path, method) => {
|
export const responseContentType = onlyOAS3((state, path, method) => {
|
||||||
return state.getIn(["requestData", path, method, "responseContentType"]) || null
|
return (
|
||||||
}
|
state.getIn(["requestData", path, method, "responseContentType"]) || null
|
||||||
)
|
)
|
||||||
|
})
|
||||||
|
|
||||||
export const serverVariableValue = onlyOAS3((state, locationData, key) => {
|
export const serverVariableValue = onlyOAS3((state, locationData, key) => {
|
||||||
let path
|
let path
|
||||||
|
|
||||||
// locationData may take one of two forms, for backwards compatibility
|
// locationData may take one of two forms, for backwards compatibility
|
||||||
// Object: ({server, namespace?}) or String:(server)
|
// Object: ({server, namespace?}) or String:(server)
|
||||||
if(typeof locationData !== "string") {
|
if (typeof locationData !== "string") {
|
||||||
const { server, namespace } = locationData
|
const { server, namespace } = locationData
|
||||||
if(namespace) {
|
if (namespace) {
|
||||||
path = [namespace, "serverVariableValues", server, key]
|
path = [namespace, "serverVariableValues", server, key]
|
||||||
} else {
|
|
||||||
path = ["serverVariableValues", server, key]
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const server = locationData
|
|
||||||
path = ["serverVariableValues", server, key]
|
path = ["serverVariableValues", server, key]
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
return state.getIn(path) || null
|
const server = locationData
|
||||||
|
path = ["serverVariableValues", server, key]
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
return state.getIn(path) || null
|
||||||
|
})
|
||||||
|
|
||||||
export const serverVariables = onlyOAS3((state, locationData) => {
|
export const serverVariables = onlyOAS3((state, locationData) => {
|
||||||
let path
|
let path
|
||||||
|
|
||||||
// locationData may take one of two forms, for backwards compatibility
|
// locationData may take one of two forms, for backwards compatibility
|
||||||
// Object: ({server, namespace?}) or String:(server)
|
// Object: ({server, namespace?}) or String:(server)
|
||||||
if(typeof locationData !== "string") {
|
if (typeof locationData !== "string") {
|
||||||
const { server, namespace } = locationData
|
const { server, namespace } = locationData
|
||||||
if(namespace) {
|
if (namespace) {
|
||||||
path = [namespace, "serverVariableValues", server]
|
path = [namespace, "serverVariableValues", server]
|
||||||
} else {
|
|
||||||
path = ["serverVariableValues", server]
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const server = locationData
|
|
||||||
path = ["serverVariableValues", server]
|
path = ["serverVariableValues", server]
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
return state.getIn(path) || OrderedMap()
|
const server = locationData
|
||||||
|
path = ["serverVariableValues", server]
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
return state.getIn(path) || OrderedMap()
|
||||||
|
})
|
||||||
|
|
||||||
export const serverEffectiveValue = onlyOAS3((state, locationData) => {
|
export const serverEffectiveValue = onlyOAS3((state, locationData) => {
|
||||||
var varValues, serverValue
|
var varValues, serverValue
|
||||||
|
|
||||||
// locationData may take one of two forms, for backwards compatibility
|
// locationData may take one of two forms, for backwards compatibility
|
||||||
// Object: ({server, namespace?}) or String:(server)
|
// Object: ({server, namespace?}) or String:(server)
|
||||||
if(typeof locationData !== "string") {
|
if (typeof locationData !== "string") {
|
||||||
const { server, namespace } = locationData
|
const { server, namespace } = locationData
|
||||||
serverValue = server
|
serverValue = server
|
||||||
if(namespace) {
|
if (namespace) {
|
||||||
varValues = state.getIn([namespace, "serverVariableValues", serverValue])
|
varValues = state.getIn([namespace, "serverVariableValues", serverValue])
|
||||||
} else {
|
|
||||||
varValues = state.getIn(["serverVariableValues", serverValue])
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
serverValue = locationData
|
|
||||||
varValues = state.getIn(["serverVariableValues", serverValue])
|
varValues = state.getIn(["serverVariableValues", serverValue])
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
varValues = varValues || OrderedMap()
|
serverValue = locationData
|
||||||
let str = serverValue
|
varValues = state.getIn(["serverVariableValues", serverValue])
|
||||||
|
|
||||||
varValues.map((val, key) => {
|
|
||||||
str = str.replace(new RegExp(`{${key}}`, "g"), val)
|
|
||||||
})
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
varValues = varValues || OrderedMap()
|
||||||
|
let str = serverValue
|
||||||
|
|
||||||
|
varValues.map((val, key) => {
|
||||||
|
str = str.replace(new RegExp(`{${key}}`, "g"), val)
|
||||||
|
})
|
||||||
|
|
||||||
|
return str
|
||||||
|
})
|
||||||
|
|
||||||
export const validateBeforeExecute = validateRequestBodyIsRequired(
|
export const validateBeforeExecute = validateRequestBodyIsRequired(
|
||||||
(state, pathMethod) => validateRequestBodyValueExists(state, pathMethod)
|
(state, pathMethod) => validateRequestBodyValueExists(state, pathMethod)
|
||||||
)
|
)
|
||||||
|
|
||||||
export const validateShallowRequired = (state, { oas3RequiredRequestBodyContentType, oas3RequestContentType, oas3RequestBodyValue} ) => {
|
export const validateShallowRequired = (
|
||||||
|
state,
|
||||||
|
{
|
||||||
|
oas3RequiredRequestBodyContentType,
|
||||||
|
oas3RequestContentType,
|
||||||
|
oas3RequestBodyValue,
|
||||||
|
}
|
||||||
|
) => {
|
||||||
let missingRequiredKeys = []
|
let missingRequiredKeys = []
|
||||||
// context: json => String; urlencoded, form-data => Map
|
// context: json => String; urlencoded, form-data => Map
|
||||||
if (!Map.isMap(oas3RequestBodyValue)) {
|
if (!Map.isMap(oas3RequestBodyValue)) {
|
||||||
@@ -221,16 +258,19 @@ export const validateShallowRequired = (state, { oas3RequiredRequestBodyContentT
|
|||||||
}
|
}
|
||||||
let requiredKeys = []
|
let requiredKeys = []
|
||||||
// Cycle through list of possible contentTypes for matching contentType and defined requiredKeys
|
// Cycle through list of possible contentTypes for matching contentType and defined requiredKeys
|
||||||
Object.keys(oas3RequiredRequestBodyContentType.requestContentType).forEach((contentType) => {
|
Object.keys(oas3RequiredRequestBodyContentType.requestContentType).forEach(
|
||||||
if (contentType === oas3RequestContentType) {
|
(contentType) => {
|
||||||
let contentTypeVal = oas3RequiredRequestBodyContentType.requestContentType[contentType]
|
if (contentType === oas3RequestContentType) {
|
||||||
contentTypeVal.forEach((requiredKey) => {
|
let contentTypeVal =
|
||||||
if (requiredKeys.indexOf(requiredKey) < 0 ) {
|
oas3RequiredRequestBodyContentType.requestContentType[contentType]
|
||||||
requiredKeys.push(requiredKey)
|
contentTypeVal.forEach((requiredKey) => {
|
||||||
}
|
if (requiredKeys.indexOf(requiredKey) < 0) {
|
||||||
})
|
requiredKeys.push(requiredKey)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
requiredKeys.forEach((key) => {
|
requiredKeys.forEach((key) => {
|
||||||
let requiredKeyValue = oas3RequestBodyValue.getIn([key, "value"])
|
let requiredKeyValue = oas3RequestBodyValue.getIn([key, "value"])
|
||||||
if (!requiredKeyValue) {
|
if (!requiredKeyValue) {
|
||||||
|
|||||||
@@ -1,72 +1,39 @@
|
|||||||
import { createSelector } from "reselect"
|
|
||||||
import { Map } from "immutable"
|
import { Map } from "immutable"
|
||||||
import { isOAS3 as isOAS3Helper, isOpenAPI31 as isOpenAPI31Helper, isSwagger2 as isSwagger2Helper } from "../helpers"
|
import { isSwagger2 as isSwagger2Helper, isOAS30 as isOAS30Helper } from "../helpers"
|
||||||
|
|
||||||
|
|
||||||
// Helpers
|
/**
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
|
||||||
// 1/2023: as of now, more accurately, isAnyOAS3
|
export const isSwagger2 = () => (system) => {
|
||||||
function onlyOAS3(selector) {
|
|
||||||
return () => (system, ...args) => {
|
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
|
||||||
if(isOAS3Helper(spec)) {
|
|
||||||
return selector(...args)
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isOpenAPI31(selector) {
|
|
||||||
return () => (system, ...args) => {
|
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
|
||||||
if (isOpenAPI31Helper(spec)) {
|
|
||||||
return selector(...args)
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const state = state => {
|
|
||||||
return state || Map()
|
|
||||||
}
|
|
||||||
|
|
||||||
const specJson = createSelector(
|
|
||||||
state,
|
|
||||||
spec => spec.get("json", Map())
|
|
||||||
)
|
|
||||||
|
|
||||||
const specResolved = createSelector(
|
|
||||||
state,
|
|
||||||
spec => spec.get("resolved", Map())
|
|
||||||
)
|
|
||||||
|
|
||||||
const spec = state => {
|
|
||||||
let res = specResolved(state)
|
|
||||||
if(res.count() < 1)
|
|
||||||
res = specJson(state)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// New selectors
|
|
||||||
|
|
||||||
export const servers = onlyOAS3(createSelector(
|
|
||||||
spec,
|
|
||||||
spec => spec.getIn(["servers"]) || Map()
|
|
||||||
))
|
|
||||||
|
|
||||||
export const isSwagger2 = (ori, system) => () => {
|
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
return isSwagger2Helper(spec)
|
return isSwagger2Helper(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectIsOpenAPI31 = (ori, system) => () => {
|
export const isOAS30 = () => (system) => {
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
return isOpenAPI31Helper(spec)
|
return isOAS30Helper(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectWebhooks = isOpenAPI31(createSelector(
|
export const isOAS3 = () => (system) => {
|
||||||
spec,
|
return system.getSystem().specSelectors.isOAS30()
|
||||||
spec => spec.getIn(["webhooks"]) || Map()
|
}
|
||||||
))
|
|
||||||
|
function onlyOAS3(selector) {
|
||||||
|
return () => (system, ...args) => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
if(system.specSelectors.isOAS3(spec)) {
|
||||||
|
const result = selector(...args)
|
||||||
|
return typeof result === "function" ? result(system, ...args) : result
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const servers = onlyOAS3(() => (system) => {
|
||||||
|
const spec = system.specSelectors.specJson()
|
||||||
|
return spec.get("servers", servers.mapConst)
|
||||||
|
})
|
||||||
|
servers.mapConst = Map()
|
||||||
|
|||||||
@@ -1,107 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
import { createSelector } from "reselect"
|
import { createSelector } from "reselect"
|
||||||
import { specJsonWithResolvedSubtrees } from "../../spec/selectors"
|
import { specJsonWithResolvedSubtrees } from "../../spec/selectors"
|
||||||
import { Map } from "immutable"
|
import { Map } from "immutable"
|
||||||
import { isOAS3 as isOAS3Helper, isOpenAPI31 as isOpenAPI31Helper, isSwagger2 as isSwagger2Helper } from "../helpers"
|
|
||||||
|
|
||||||
|
/**
|
||||||
// Helpers
|
* Helpers
|
||||||
// 1/2023: as of now, more accurately, isAnyOAS3
|
*/
|
||||||
function onlyOAS3(selector) {
|
function onlyOAS3(selector) {
|
||||||
return (ori, system) => (...args) => {
|
return (ori, system) =>
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
(...args) => {
|
||||||
if(isOAS3Helper(spec)) {
|
if (system.getSystem().specSelectors.isOAS3()) {
|
||||||
return selector(...args)
|
const result = selector(...args)
|
||||||
} else {
|
return typeof result === "function" ? result(system, ...args) : result
|
||||||
return ori(...args)
|
} else {
|
||||||
|
return ori(...args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isOpenAPI31(selector) {
|
|
||||||
return (ori, system) => (...args) => {
|
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
|
||||||
if (isOpenAPI31Helper(spec)) {
|
|
||||||
return selector(...args)
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const state = state => {
|
|
||||||
return state || Map()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const nullSelector = createSelector(() => null)
|
const nullSelector = createSelector(() => null)
|
||||||
|
|
||||||
const OAS3NullSelector = onlyOAS3(nullSelector)
|
const OAS3NullSelector = onlyOAS3(nullSelector)
|
||||||
|
|
||||||
const specJson = createSelector(
|
/**
|
||||||
state,
|
* Wrappers
|
||||||
spec => spec.get("json", Map())
|
*/
|
||||||
)
|
|
||||||
|
|
||||||
const specResolved = createSelector(
|
export const definitions = onlyOAS3(() => (system) => {
|
||||||
state,
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
spec => spec.get("resolved", Map())
|
const schemas = spec.getIn(["components", "schemas"])
|
||||||
)
|
return Map.isMap(schemas) ? schemas : definitions.mapConst
|
||||||
|
})
|
||||||
|
definitions.mapConst = Map()
|
||||||
|
|
||||||
const spec = state => {
|
export const hasHost = onlyOAS3(() => (system) => {
|
||||||
let res = specResolved(state)
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
if(res.count() < 1)
|
return spec.hasIn(["servers", 0])
|
||||||
res = specJson(state)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrappers
|
|
||||||
|
|
||||||
export const definitions = onlyOAS3(createSelector(
|
|
||||||
spec,
|
|
||||||
spec => {
|
|
||||||
const res = spec.getIn(["components", "schemas"])
|
|
||||||
return Map.isMap(res) ? res : Map()
|
|
||||||
}
|
|
||||||
))
|
|
||||||
|
|
||||||
export const hasHost = onlyOAS3((state) => {
|
|
||||||
return spec(state).hasIn(["servers", 0])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const securityDefinitions = onlyOAS3(createSelector(
|
export const securityDefinitions = onlyOAS3(
|
||||||
specJsonWithResolvedSubtrees,
|
createSelector(
|
||||||
spec => spec.getIn(["components", "securitySchemes"]) || null
|
specJsonWithResolvedSubtrees,
|
||||||
))
|
(spec) => spec.getIn(["components", "securitySchemes"]) || null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
export const host = OAS3NullSelector
|
export const host = OAS3NullSelector
|
||||||
export const basePath = OAS3NullSelector
|
export const basePath = OAS3NullSelector
|
||||||
export const consumes = OAS3NullSelector
|
export const consumes = OAS3NullSelector
|
||||||
export const produces = OAS3NullSelector
|
export const produces = OAS3NullSelector
|
||||||
export const schemes = OAS3NullSelector
|
export const schemes = OAS3NullSelector
|
||||||
|
|
||||||
// New selectors
|
|
||||||
|
|
||||||
export const servers = onlyOAS3(createSelector(
|
|
||||||
spec,
|
|
||||||
spec => spec.getIn(["servers"]) || Map()
|
|
||||||
))
|
|
||||||
|
|
||||||
export const isOAS3 = (ori, system) => () => {
|
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
|
||||||
return isOAS3Helper(Map.isMap(spec) ? spec : Map())
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isSwagger2 = (ori, system) => () => {
|
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
|
||||||
return isSwagger2Helper(Map.isMap(spec) ? spec : Map())
|
|
||||||
}
|
|
||||||
|
|
||||||
export const selectIsOpenAPI31 = (ori, system) => () => {
|
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
|
||||||
return isOpenAPI31Helper(Map.isMap(spec) ? spec : Map())
|
|
||||||
}
|
|
||||||
|
|
||||||
export const selectWebhooks = isOpenAPI31(createSelector(
|
|
||||||
spec,
|
|
||||||
spec => spec.getIn(["webhooks"]) || Map()
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import VersionStamp from "./version-stamp"
|
|||||||
import OnlineValidatorBadge from "./online-validator-badge"
|
import OnlineValidatorBadge from "./online-validator-badge"
|
||||||
import Model from "./model"
|
import Model from "./model"
|
||||||
import JsonSchema_string from "./json-schema-string"
|
import JsonSchema_string from "./json-schema-string"
|
||||||
import License from "./license"
|
|
||||||
import info from "./info"
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Markdown,
|
Markdown,
|
||||||
@@ -14,6 +12,4 @@ export default {
|
|||||||
VersionStamp,
|
VersionStamp,
|
||||||
model: Model,
|
model: Model,
|
||||||
onlineValidatorBadge: OnlineValidatorBadge,
|
onlineValidatorBadge: OnlineValidatorBadge,
|
||||||
License,
|
|
||||||
info,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import ImPropTypes from "react-immutable-proptypes"
|
|
||||||
import { sanitizeUrl } from "core/utils"
|
|
||||||
import { safeBuildUrl } from "core/utils/url"
|
|
||||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
|
||||||
|
|
||||||
const Info = (props) => {
|
|
||||||
const { info, url, host, basePath, getComponent, specSelectors, externalDocs, selectedServer, url: specUrl } = props
|
|
||||||
const isOpenAPI31 = specSelectors.selectIsOpenAPI31()
|
|
||||||
const version = info.get("version")
|
|
||||||
const description = info.get("description")
|
|
||||||
const title = info.get("title")
|
|
||||||
const termsOfServiceUrl = safeBuildUrl(info.get("termsOfService"), specUrl, { selectedServer })
|
|
||||||
const contact = info.get("contact")
|
|
||||||
const license = info.get("license")
|
|
||||||
// note that ux may want to move summary to a sub-heading, as summary is a string that does not need to be Markdown
|
|
||||||
const summary = info.get("summary") // OAS3.1 field
|
|
||||||
const rawExternalDocsUrl = externalDocs && externalDocs.get("url")
|
|
||||||
const externalDocsUrl = safeBuildUrl(rawExternalDocsUrl, specUrl, { selectedServer })
|
|
||||||
const externalDocsDescription = externalDocs && externalDocs.get("description")
|
|
||||||
|
|
||||||
const Markdown = getComponent("Markdown", true)
|
|
||||||
const Link = getComponent("Link")
|
|
||||||
const VersionStamp = getComponent("VersionStamp")
|
|
||||||
const InfoUrl = getComponent("InfoUrl")
|
|
||||||
const InfoBasePath = getComponent("InfoBasePath")
|
|
||||||
const License = getComponent("License")
|
|
||||||
const Contact = getComponent("Contact")
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="info">
|
|
||||||
<hgroup className="main">
|
|
||||||
<h2 className="title" >{title}
|
|
||||||
{version && <VersionStamp version={version}></VersionStamp>}
|
|
||||||
</h2>
|
|
||||||
{host || basePath ? <InfoBasePath host={host} basePath={basePath} /> : null}
|
|
||||||
{url && <InfoUrl getComponent={getComponent} url={url} />}
|
|
||||||
</hgroup>
|
|
||||||
|
|
||||||
{
|
|
||||||
isOpenAPI31 && summary && <div className="info__summary">
|
|
||||||
<Markdown source={summary} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div className="description">
|
|
||||||
<Markdown source={description} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
|
||||||
termsOfServiceUrl && <div className="info__tos">
|
|
||||||
<Link target="_blank" href={sanitizeUrl(termsOfServiceUrl)}>Terms of service</Link>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
{contact && contact.size ? <Contact getComponent={getComponent} data={contact} selectedServer={selectedServer} url={url} /> : null}
|
|
||||||
{license && license.size ? <License getComponent={getComponent} license={license} selectedServer={selectedServer} url={url} /> : null}
|
|
||||||
{externalDocsUrl ?
|
|
||||||
<Link className="info__extdocs" target="_blank" href={sanitizeUrl(externalDocsUrl)}>{externalDocsDescription || externalDocsUrl}</Link>
|
|
||||||
: null}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Info.propTypes = {
|
|
||||||
info: PropTypes.object,
|
|
||||||
url: PropTypes.string,
|
|
||||||
host: PropTypes.string,
|
|
||||||
basePath: PropTypes.string,
|
|
||||||
externalDocs: ImPropTypes.map,
|
|
||||||
getComponent: PropTypes.func.isRequired,
|
|
||||||
specSelectors: PropTypes.object.isRequired,
|
|
||||||
oas3selectors: PropTypes.func,
|
|
||||||
selectedServer: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default OAS3ComponentWrapFactory(Info)
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import { sanitizeUrl } from "core/utils"
|
|
||||||
import { safeBuildUrl } from "core/utils/url"
|
|
||||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
|
||||||
|
|
||||||
const baseSPDXurl = "https://spdx.org/licenses"
|
|
||||||
const createSPDXurl = (identifier) => {
|
|
||||||
return `${baseSPDXurl}/${identifier}.html`
|
|
||||||
}
|
|
||||||
|
|
||||||
const License = (props) => {
|
|
||||||
const { license, getComponent, selectedServer, url: specUrl, specSelectors } = props
|
|
||||||
const Link = getComponent("Link")
|
|
||||||
const name = license.get("name") || "License"
|
|
||||||
const url = safeBuildUrl(license.get("url"), specUrl, { selectedServer })
|
|
||||||
const identifier = license.get("identifier") || "" // OAS3.1 field
|
|
||||||
const identifierUrl = createSPDXurl(identifier)
|
|
||||||
const isOpenAPI31 = specSelectors.selectIsOpenAPI31()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="info__license">
|
|
||||||
{
|
|
||||||
!isOpenAPI31 && url && <div className="info__license__url"><Link target="_blank" href={sanitizeUrl(url)}>{name}</Link></div>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
isOpenAPI31 && url && !identifier && <div className="info__license__url"><Link target="_blank" href={sanitizeUrl(url)}>{name}</Link></div>
|
|
||||||
}
|
|
||||||
{
|
|
||||||
isOpenAPI31 && identifier && !url && <div className="info__license__identifier"><Link target="_blank" href={sanitizeUrl(baseSPDXurl)}>SPDX License</Link>: <Link target="_blank" href={sanitizeUrl(identifierUrl)}>{identifier}</Link></div>
|
|
||||||
}
|
|
||||||
{/* {
|
|
||||||
isOpenAPI31 && identifier && url && <div className="info__license_error">Render Error: License.url and License.identifier are mutually exclusive fields</div>
|
|
||||||
} */}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
License.propTypes = {
|
|
||||||
license: PropTypes.shape({
|
|
||||||
get: PropTypes.func,
|
|
||||||
}),
|
|
||||||
getComponent: PropTypes.func.isRequired,
|
|
||||||
specSelectors: PropTypes.object.isRequired,
|
|
||||||
selectedServer: PropTypes.string,
|
|
||||||
url: PropTypes.string.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default OAS3ComponentWrapFactory(License)
|
|
||||||
155
src/core/plugins/oas31/components/info.jsx
Normal file
155
src/core/plugins/oas31/components/info.jsx
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
import { sanitizeUrl } from "core/utils"
|
||||||
|
import { safeBuildUrl } from "core/utils/url"
|
||||||
|
|
||||||
|
export class InfoBasePath extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
host: PropTypes.string,
|
||||||
|
basePath: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { host, basePath } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<pre className="base-url">
|
||||||
|
[ Base URL: {host}
|
||||||
|
{basePath} ]
|
||||||
|
</pre>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InfoUrl extends React.PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { url, getComponent } = this.props
|
||||||
|
const Link = getComponent("Link")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link target="_blank" href={sanitizeUrl(url)}>
|
||||||
|
<span className="url"> {url}</span>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Info extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
title: PropTypes.any,
|
||||||
|
description: PropTypes.any,
|
||||||
|
version: PropTypes.any,
|
||||||
|
info: PropTypes.object,
|
||||||
|
url: PropTypes.string,
|
||||||
|
host: PropTypes.string,
|
||||||
|
basePath: PropTypes.string,
|
||||||
|
externalDocs: ImPropTypes.map,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
oas3selectors: PropTypes.func,
|
||||||
|
selectedServer: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
info,
|
||||||
|
url,
|
||||||
|
host,
|
||||||
|
basePath,
|
||||||
|
getComponent,
|
||||||
|
externalDocs,
|
||||||
|
selectedServer,
|
||||||
|
url: specUrl,
|
||||||
|
} = this.props
|
||||||
|
const version = info.get("version")
|
||||||
|
const summary = info.get("summary")
|
||||||
|
const description = info.get("description")
|
||||||
|
const title = info.get("title")
|
||||||
|
const termsOfServiceUrl = safeBuildUrl(
|
||||||
|
info.get("termsOfService"),
|
||||||
|
specUrl,
|
||||||
|
{ selectedServer }
|
||||||
|
)
|
||||||
|
const contactData = info.get("contact")
|
||||||
|
const licenseData = info.get("license")
|
||||||
|
const rawExternalDocsUrl = externalDocs && externalDocs.get("url")
|
||||||
|
const externalDocsUrl = safeBuildUrl(rawExternalDocsUrl, specUrl, {
|
||||||
|
selectedServer,
|
||||||
|
})
|
||||||
|
const externalDocsDescription =
|
||||||
|
externalDocs && externalDocs.get("description")
|
||||||
|
|
||||||
|
const Markdown = getComponent("Markdown", true)
|
||||||
|
const Link = getComponent("Link")
|
||||||
|
const VersionStamp = getComponent("VersionStamp")
|
||||||
|
const InfoUrl = getComponent("InfoUrl")
|
||||||
|
const InfoBasePath = getComponent("InfoBasePath")
|
||||||
|
const License = getComponent("License")
|
||||||
|
const Contact = getComponent("Contact")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="info">
|
||||||
|
<hgroup className="main">
|
||||||
|
<h2 className="title">
|
||||||
|
{title}
|
||||||
|
{version && <VersionStamp version={version}></VersionStamp>}
|
||||||
|
</h2>
|
||||||
|
{host || basePath ? (
|
||||||
|
<InfoBasePath host={host} basePath={basePath} />
|
||||||
|
) : null}
|
||||||
|
{url && <InfoUrl getComponent={getComponent} url={url} />}
|
||||||
|
</hgroup>
|
||||||
|
{summary && (
|
||||||
|
<div className="info__summary">
|
||||||
|
<Markdown source={summary} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="description">
|
||||||
|
<Markdown source={description} />
|
||||||
|
</div>
|
||||||
|
{termsOfServiceUrl && (
|
||||||
|
<div className="info__tos">
|
||||||
|
<Link target="_blank" href={sanitizeUrl(termsOfServiceUrl)}>
|
||||||
|
Terms of service
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{contactData?.size > 0 && (
|
||||||
|
<Contact
|
||||||
|
getComponent={getComponent}
|
||||||
|
data={contactData}
|
||||||
|
selectedServer={selectedServer}
|
||||||
|
url={url}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{licenseData?.size > 0 && (
|
||||||
|
<License
|
||||||
|
getComponent={getComponent}
|
||||||
|
license={licenseData}
|
||||||
|
selectedServer={selectedServer}
|
||||||
|
url={url}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{externalDocsUrl ? (
|
||||||
|
<Link
|
||||||
|
className="info__extdocs"
|
||||||
|
target="_blank"
|
||||||
|
href={sanitizeUrl(externalDocsUrl)}
|
||||||
|
>
|
||||||
|
{externalDocsDescription || externalDocsUrl}
|
||||||
|
</Link>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Info
|
||||||
52
src/core/plugins/oas31/components/license.jsx
Normal file
52
src/core/plugins/oas31/components/license.jsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import { safeBuildUrl } from "core/utils/url"
|
||||||
|
import { sanitizeUrl } from "core/utils"
|
||||||
|
|
||||||
|
class License extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
license: PropTypes.object,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
selectedServer: PropTypes.string,
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { license, getComponent, selectedServer, url: specUrl } = this.props
|
||||||
|
const name = license.get("name", "License")
|
||||||
|
const url = sanitizeUrl(
|
||||||
|
safeBuildUrl(license.get("url"), specUrl, { selectedServer })
|
||||||
|
)
|
||||||
|
const identifier = license.get("identifier", "")
|
||||||
|
const spdxURL = sanitizeUrl(`https://spdx.org/licenses/${identifier}.html`)
|
||||||
|
|
||||||
|
const Link = getComponent("Link")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="info__license">
|
||||||
|
{identifier && (
|
||||||
|
<div className="info__license__url">
|
||||||
|
<Link target="_blank" href={spdxURL}>
|
||||||
|
{name}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{url && !identifier && (
|
||||||
|
<div className="info__license__url">
|
||||||
|
<Link target="_blank" href={url}>
|
||||||
|
{name}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!url && !identifier && <span>{name}</span>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default License
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// OpenAPI 3.1 feature
|
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
@@ -8,8 +7,8 @@ import ImPropTypes from "react-immutable-proptypes"
|
|||||||
// to show/hide all webhook items
|
// to show/hide all webhook items
|
||||||
const Webhooks = (props) => {
|
const Webhooks = (props) => {
|
||||||
const { specSelectors, getComponent, specPath } = props
|
const { specSelectors, getComponent, specPath } = props
|
||||||
|
|
||||||
const webhooksPathItems = specSelectors.selectWebhooks() // OrderedMap
|
const webhooksPathItems = specSelectors.webhooks()
|
||||||
if (!webhooksPathItems || webhooksPathItems?.size < 1) {
|
if (!webhooksPathItems || webhooksPathItems?.size < 1) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -21,7 +20,7 @@ const Webhooks = (props) => {
|
|||||||
operation
|
operation
|
||||||
})
|
})
|
||||||
// using defaultProps for `specPath`; may want to remove from props
|
// using defaultProps for `specPath`; may want to remove from props
|
||||||
// and/or if extract to separate PathItem component, allow for use
|
// and/or if extract to separate PathItem component, allow for use
|
||||||
// with both OAS3.1 "webhooks" and "components.pathItems" features
|
// with both OAS3.1 "webhooks" and "components.pathItems" features
|
||||||
return <OperationContainer
|
return <OperationContainer
|
||||||
{...props}
|
{...props}
|
||||||
10
src/core/plugins/oas31/helpers.js
Normal file
10
src/core/plugins/oas31/helpers.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
export const isOAS31 = (jsSpec) => {
|
||||||
|
const oasVersion = jsSpec.get("openapi")
|
||||||
|
|
||||||
|
return (
|
||||||
|
typeof oasVersion === "string" && /^3\.1\.(?:[1-9]\d*|0)$/.test(oasVersion)
|
||||||
|
)
|
||||||
|
}
|
||||||
37
src/core/plugins/oas31/index.js
Normal file
37
src/core/plugins/oas31/index.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import Webhooks from "./components/webhooks"
|
||||||
|
import License from "./components/license"
|
||||||
|
import Info from "./components/info"
|
||||||
|
import LicenseWrapper from "./wrap-components/license"
|
||||||
|
import InfoWrapper from "./wrap-components/info"
|
||||||
|
import { isOAS31, webhooks } from "./spec-extensions/selectors"
|
||||||
|
import { isOAS3 } from "./spec-extensions/wrap-selectors"
|
||||||
|
|
||||||
|
const OAS31Plugin = () => {
|
||||||
|
return {
|
||||||
|
components: {
|
||||||
|
Webhooks,
|
||||||
|
OAS31Info: Info,
|
||||||
|
OAS31License: License,
|
||||||
|
},
|
||||||
|
wrapComponents: {
|
||||||
|
License: LicenseWrapper,
|
||||||
|
info: InfoWrapper,
|
||||||
|
},
|
||||||
|
statePlugins: {
|
||||||
|
spec: {
|
||||||
|
selectors: {
|
||||||
|
isOAS31,
|
||||||
|
webhooks,
|
||||||
|
},
|
||||||
|
wrapSelectors: {
|
||||||
|
isOAS3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OAS31Plugin
|
||||||
29
src/core/plugins/oas31/spec-extensions/selectors.js
Normal file
29
src/core/plugins/oas31/spec-extensions/selectors.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import { Map } from "immutable"
|
||||||
|
|
||||||
|
import { isOAS31 as isOAS31Helper } from "../helpers"
|
||||||
|
|
||||||
|
export const isOAS31 = () => (system) => {
|
||||||
|
const spec = system.specSelectors.specJson()
|
||||||
|
return isOAS31Helper(spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onlyOAS31 =
|
||||||
|
(selector) =>
|
||||||
|
() =>
|
||||||
|
(system, ...args) => {
|
||||||
|
if (system.getSystem().specSelectors.isOAS31()) {
|
||||||
|
const result = selector(...args)
|
||||||
|
return typeof result === "function" ? result(system, ...args) : result
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const webhooks = onlyOAS31(() => (system) => {
|
||||||
|
const spec = system.specSelectors.specJson()
|
||||||
|
return spec.get("webhooks", webhooks.mapConst)
|
||||||
|
})
|
||||||
|
webhooks.mapConst = Map()
|
||||||
4
src/core/plugins/oas31/spec-extensions/wrap-selectors.js
Normal file
4
src/core/plugins/oas31/spec-extensions/wrap-selectors.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const isOAS3 = (oriSelector, system) => (state, ...args) => {
|
||||||
|
const isOAS31 = system.specSelectors.isOAS31()
|
||||||
|
return isOAS31 || oriSelector(...args)
|
||||||
|
}
|
||||||
16
src/core/plugins/oas31/wrap-components/info.jsx
Normal file
16
src/core/plugins/oas31/wrap-components/info.jsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
const InfoWrapper = (Original, system) => (props) => {
|
||||||
|
if (system.specSelectors.isOAS31()) {
|
||||||
|
const OAS31Info = system.getComponent("OAS31Info")
|
||||||
|
|
||||||
|
return <OAS31Info {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Original {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InfoWrapper
|
||||||
16
src/core/plugins/oas31/wrap-components/license.jsx
Normal file
16
src/core/plugins/oas31/wrap-components/license.jsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
const LicenseWrapper = (Original, system) => (props) => {
|
||||||
|
if (system.specSelectors.isOAS31()) {
|
||||||
|
const OAS31License = system.getComponent("OAS31License")
|
||||||
|
|
||||||
|
return <OAS31License {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Original {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LicenseWrapper
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
import BasePreset from "./base"
|
import BasePreset from "./base"
|
||||||
import OAS3Plugin from "../plugins/oas3"
|
import OAS3Plugin from "../plugins/oas3"
|
||||||
|
import OAS31Plugin from "../plugins/oas31"
|
||||||
// Just the base, for now.
|
|
||||||
|
|
||||||
export default function PresetApis() {
|
export default function PresetApis() {
|
||||||
|
return [BasePreset, OAS3Plugin, OAS31Plugin]
|
||||||
return [
|
|
||||||
BasePreset,
|
|
||||||
OAS3Plugin
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
import err from "core/plugins/err"
|
import err from "core/plugins/err"
|
||||||
import layout from "core/plugins/layout"
|
import layout from "core/plugins/layout"
|
||||||
import spec from "core/plugins/spec"
|
import spec from "core/plugins/spec"
|
||||||
@@ -57,13 +60,10 @@ import Errors from "core/components/errors"
|
|||||||
import ContentType from "core/components/content-type"
|
import ContentType from "core/components/content-type"
|
||||||
import Overview from "core/components/overview"
|
import Overview from "core/components/overview"
|
||||||
import InitializedInput from "core/components/initialized-input"
|
import InitializedInput from "core/components/initialized-input"
|
||||||
import Info, {
|
import Info, { InfoUrl, InfoBasePath } from "core/components/info"
|
||||||
InfoUrl,
|
|
||||||
InfoBasePath,
|
|
||||||
License,
|
|
||||||
Contact,
|
|
||||||
} from "core/components/info"
|
|
||||||
import InfoContainer from "core/containers/info"
|
import InfoContainer from "core/containers/info"
|
||||||
|
import Contact from "core/components/contact"
|
||||||
|
import License from "core/components/license"
|
||||||
import JumpToPath from "core/components/jump-to-path"
|
import JumpToPath from "core/components/jump-to-path"
|
||||||
import CopyToClipboardBtn from "core/components/copy-to-clipboard-btn"
|
import CopyToClipboardBtn from "core/components/copy-to-clipboard-btn"
|
||||||
import Footer from "core/components/footer"
|
import Footer from "core/components/footer"
|
||||||
@@ -87,16 +87,12 @@ import VersionPragmaFilter from "core/components/version-pragma-filter"
|
|||||||
import VersionStamp from "core/components/version-stamp"
|
import VersionStamp from "core/components/version-stamp"
|
||||||
import DeepLink from "core/components/deep-link"
|
import DeepLink from "core/components/deep-link"
|
||||||
import SvgAssets from "core/components/svg-assets"
|
import SvgAssets from "core/components/svg-assets"
|
||||||
|
|
||||||
import Markdown from "core/components/providers/markdown"
|
import Markdown from "core/components/providers/markdown"
|
||||||
|
|
||||||
import BaseLayout from "core/components/layouts/base"
|
import BaseLayout from "core/components/layouts/base"
|
||||||
|
|
||||||
import * as LayoutUtils from "core/components/layout-utils"
|
import * as LayoutUtils from "core/components/layout-utils"
|
||||||
import * as JsonSchemaComponents from "core/json-schema-components"
|
import * as JsonSchemaComponents from "core/json-schema-components"
|
||||||
|
|
||||||
export default function() {
|
export default function () {
|
||||||
|
|
||||||
let coreComponents = {
|
let coreComponents = {
|
||||||
components: {
|
components: {
|
||||||
App,
|
App,
|
||||||
@@ -115,6 +111,10 @@ export default function() {
|
|||||||
InitializedInput,
|
InitializedInput,
|
||||||
info: Info,
|
info: Info,
|
||||||
InfoContainer,
|
InfoContainer,
|
||||||
|
InfoUrl,
|
||||||
|
InfoBasePath,
|
||||||
|
Contact,
|
||||||
|
License,
|
||||||
JumpToPath,
|
JumpToPath,
|
||||||
CopyToClipboardBtn,
|
CopyToClipboardBtn,
|
||||||
onlineValidatorBadge: OnlineValidatorBadge,
|
onlineValidatorBadge: OnlineValidatorBadge,
|
||||||
@@ -163,23 +163,19 @@ export default function() {
|
|||||||
OperationTag,
|
OperationTag,
|
||||||
OperationContainer,
|
OperationContainer,
|
||||||
DeepLink,
|
DeepLink,
|
||||||
InfoUrl,
|
|
||||||
InfoBasePath,
|
|
||||||
License,
|
|
||||||
Contact,
|
|
||||||
SvgAssets,
|
SvgAssets,
|
||||||
Example,
|
Example,
|
||||||
ExamplesSelect,
|
ExamplesSelect,
|
||||||
ExamplesSelectValueRetainer,
|
ExamplesSelectValueRetainer,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let formComponents = {
|
let formComponents = {
|
||||||
components: LayoutUtils
|
components: LayoutUtils,
|
||||||
}
|
}
|
||||||
|
|
||||||
let jsonSchemaComponents = {
|
let jsonSchemaComponents = {
|
||||||
components: JsonSchemaComponents
|
components: JsonSchemaComponents,
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
swagger: 2.0.0
|
swagger: "2.0"
|
||||||
|
|
||||||
info:
|
info:
|
||||||
title: OpenAPI 2.0 Info Object
|
title: OpenAPI 2.0 Info Object
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
swagger: 2.0.0
|
swagger: "2.0"
|
||||||
info:
|
info:
|
||||||
title: OpenAPI 2.0 License with only url present
|
title: OpenAPI 2.0 License with only url present
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|||||||
@@ -5,5 +5,4 @@ info:
|
|||||||
description: This is a sample server for a pet store.
|
description: This is a sample server for a pet store.
|
||||||
license:
|
license:
|
||||||
name: Apache 2.0
|
name: Apache 2.0
|
||||||
# url: https://www.apache.org/licenses/LICENSE-2.0.html
|
identifier: Apache-2.0
|
||||||
identifier: Apache-2.0 # mutually exclusive of url; separately, for json_schema, consider const, prefix, array items can be of a different type (current assumption is all array items are the same)
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
describe("Render Info Component", () => {
|
describe("Render Info Component", () => {
|
||||||
describe("OpenAPI 2.x", () => {
|
describe("OpenAPI 2.0", () => {
|
||||||
const baseUrl = "/?url=/documents/features/info-openAPI2.yaml"
|
const baseUrl = "/?url=/documents/features/info-openAPI2.yaml"
|
||||||
|
|
||||||
it("should render Info Description", () => {
|
it("should render Info Description", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info .description")
|
.get(".info .description")
|
||||||
.should("contains.text", "This is a sample")
|
.should("contains.text", "This is a sample")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should render Info Main anchor target xss link with safe `rel` attributes", () => {
|
it("should render Info Main anchor target xss link with safe `rel` attributes", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info .main > a")
|
.get(".info .main > a")
|
||||||
@@ -16,19 +18,23 @@ describe("Render Info Component", () => {
|
|||||||
.should("have.attr", "target")
|
.should("have.attr", "target")
|
||||||
.and("equal", "_blank")
|
.and("equal", "_blank")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should not render Info Summary (an OpenAPI 3.1 field)", () => {
|
it("should not render Info Summary (an OpenAPI 3.1 field)", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__summary")
|
.get(".info__summary")
|
||||||
.should("not.exist")
|
.should("not.exist")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("OpenAPI 3.0.x", () => {
|
describe("OpenAPI 3.0.x", () => {
|
||||||
const baseUrl = "/?url=/documents/features/info-openAPI30.yaml"
|
const baseUrl = "/?url=/documents/features/info-openAPI30.yaml"
|
||||||
|
|
||||||
it("should render Info Description", () => {
|
it("should render Info Description", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info .description")
|
.get(".info .description")
|
||||||
.should("contains.text", "This is a sample")
|
.should("contains.text", "This is a sample")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should render Info Main anchor target xss link with safe `rel` attributes", () => {
|
it("should render Info Main anchor target xss link with safe `rel` attributes", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info .main > a")
|
.get(".info .main > a")
|
||||||
@@ -39,19 +45,23 @@ describe("Render Info Component", () => {
|
|||||||
.should("have.attr", "target")
|
.should("have.attr", "target")
|
||||||
.and("equal", "_blank")
|
.and("equal", "_blank")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should not render Info Summary (an OpenAPI 3.1 field)", () => {
|
it("should not render Info Summary (an OpenAPI 3.1 field)", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__summary")
|
.get(".info__summary")
|
||||||
.should("not.exist")
|
.should("not.exist")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("OpenAPI 3.1.x", () => {
|
describe("OpenAPI 3.1.x", () => {
|
||||||
const baseUrl = "/?url=/documents/features/info-openAPI31.yaml"
|
const baseUrl = "/?url=/documents/features/info-openAPI31.yaml"
|
||||||
|
|
||||||
it("should render Info Description", () => {
|
it("should render Info Description", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info .description")
|
.get(".info .description")
|
||||||
.should("contains.text", "This is a sample")
|
.should("contains.text", "This is a sample")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should render Info Main anchor target xss link with safe `rel` attributes", () => {
|
it("should render Info Main anchor target xss link with safe `rel` attributes", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info .main > a")
|
.get(".info .main > a")
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
describe("Render License Component", () => {
|
describe("Render License Component", () => {
|
||||||
describe("OpenAPI 2", () =>{
|
describe("OpenAPI 2.0", () => {
|
||||||
const baseUrl = "/?url=/documents/features/license-openAPI2.yaml"
|
const baseUrl = "/?url=/documents/features/license-openAPI2.yaml"
|
||||||
|
|
||||||
it("should render License URL", () => {
|
it("should render License URL", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license")
|
.get(".info__license")
|
||||||
.should("exist")
|
.should("exist")
|
||||||
.should("contains.text", "Apache 2.0")
|
.should("contains.text", "Apache 2.0")
|
||||||
.should("not.contains.text", "SPDX License")
|
|
||||||
.get(".info__license__identifier")
|
|
||||||
.should("not.exist")
|
|
||||||
})
|
})
|
||||||
it("should render License URL anchor target xss link with safe `rel` attributes ", () => {
|
|
||||||
|
it("should render License URL anchor target xss link with safe `rel` attributes", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license > .link")
|
.get(".info__license__url > .link")
|
||||||
.should("have.attr", "rel")
|
.should("have.attr", "rel")
|
||||||
.and("include", "noopener")
|
.and("include", "noopener")
|
||||||
.and("include", "noreferrer")
|
.and("include", "noreferrer")
|
||||||
@@ -21,18 +23,18 @@ describe("Render License Component", () => {
|
|||||||
.and("equal", "_blank")
|
.and("equal", "_blank")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("OpenAPI 3.0.x", () => {
|
describe("OpenAPI 3.0.x", () => {
|
||||||
const baseUrl = "/?url=/documents/features/license-openAPI30.yaml"
|
const baseUrl = "/?url=/documents/features/license-openAPI30.yaml"
|
||||||
|
|
||||||
it("should render License URL", () => {
|
it("should render License URL", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license__url")
|
.get(".info__license__url")
|
||||||
.should("exist")
|
.should("exist")
|
||||||
.should("contains.text", "Apache 2.0")
|
.should("contains.text", "Apache 2.0")
|
||||||
.should("not.contains.text", "SPDX License")
|
})
|
||||||
.get(".info__license__identifier")
|
|
||||||
.should("not.exist")
|
it("should render URL anchor target xss link with safe `rel` attributes", () => {
|
||||||
})
|
|
||||||
it("should render URL anchor target xss link with safe `rel` attributes ", () => {
|
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license__url > a")
|
.get(".info__license__url > a")
|
||||||
.should("have.attr", "rel")
|
.should("have.attr", "rel")
|
||||||
@@ -43,19 +45,22 @@ describe("Render License Component", () => {
|
|||||||
.and("equal", "_blank")
|
.and("equal", "_blank")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe("OpenAPI 3.1.x", () => {
|
|
||||||
describe("only URL", () => {
|
describe("OpenAPI 3.1.x", () => {
|
||||||
|
describe("given URL field", () => {
|
||||||
const baseUrl = "/?url=/documents/features/license-openAPI31-url.yaml"
|
const baseUrl = "/?url=/documents/features/license-openAPI31-url.yaml"
|
||||||
|
|
||||||
it("should render URL", () => {
|
it("should render URL", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license__url")
|
.get(".info__license__url")
|
||||||
.should("exist")
|
.should("exist")
|
||||||
.should("contains.text", "Apache 2.0")
|
.should("contains.text", "Apache 2.0")
|
||||||
.should("not.contains.text", "SPDX License")
|
.get(".info__license__url > a")
|
||||||
.get(".info__license__identifier")
|
.should("have.attr", "href")
|
||||||
.should("not.exist")
|
.and("equal", "https://www.apache.org/licenses/LICENSE-2.0.html")
|
||||||
})
|
})
|
||||||
it("should render URL anchor target xss link with safe `rel` attributes ", () => {
|
|
||||||
|
it("should render URL anchor target xss link with safe `rel` attributes", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license__url > a")
|
.get(".info__license__url > a")
|
||||||
.should("have.attr", "rel")
|
.should("have.attr", "rel")
|
||||||
@@ -66,40 +71,43 @@ describe("Render License Component", () => {
|
|||||||
.and("equal", "_blank")
|
.and("equal", "_blank")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe("only SPDX Identifier", () => {
|
|
||||||
const baseUrl = "/?url=/documents/features/license-openAPI31-identifier.yaml"
|
describe("given identifier field", () => {
|
||||||
it("should render SPDX Identifier", () => {
|
const baseUrl =
|
||||||
|
"/?url=/documents/features/license-openAPI31-identifier.yaml"
|
||||||
|
|
||||||
|
it("should render URL using identifier", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license__identifier")
|
|
||||||
.should("exist")
|
|
||||||
.should("contains.text", "Apache-2.0")
|
|
||||||
.should("contains.text", "SPDX License")
|
|
||||||
.get(".info__license__url")
|
.get(".info__license__url")
|
||||||
.should("not.exist")
|
.should("exist")
|
||||||
})
|
.should("contains.text", "Apache 2.0")
|
||||||
it("should render SPDX and Identifier anchor target xss links with safe `rel` attributes ", () => {
|
.get(".info__license__url > a")
|
||||||
|
.should("have.attr", "href")
|
||||||
|
.and("equal", "https://spdx.org/licenses/Apache-2.0.html")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should render URL anchor target xss links with safe `rel` attributes", () => {
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license__identifier > a")
|
.get(".info__license__url > a")
|
||||||
.each(($el) => {
|
.should("have.attr", "rel")
|
||||||
cy.get($el)
|
.and("include", "noopener")
|
||||||
.should("have.attr", "rel")
|
.and("include", "noreferrer")
|
||||||
.and("include", "noopener")
|
.get(".info .main > a")
|
||||||
.and("include", "noreferrer")
|
.should("have.attr", "target")
|
||||||
cy.get($el)
|
.and("equal", "_blank")
|
||||||
.should("have.attr", "target")
|
|
||||||
.and("equal", "_blank")
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("URL and SPX are mutually exclusive", () => {
|
describe("URL and SPX are mutually exclusive", () => {
|
||||||
it("should render nothing if both URL & SPDX exists", () => {
|
it("should render nothing if both URL & SPDX exists", () => {
|
||||||
const baseUrl = "/?url=/documents/features/license-openAPI31-error-both-identifier-and-url.yaml"
|
const baseUrl =
|
||||||
|
"/?url=/documents/features/license-openAPI31-error-both-identifier-and-url.yaml"
|
||||||
cy.visit(baseUrl)
|
cy.visit(baseUrl)
|
||||||
.get(".info__license__identifier")
|
.get(".info__license__identifier")
|
||||||
.should("not.exist")
|
.should("not.exist")
|
||||||
.get(".info__license__url")
|
.get(".info__license__url")
|
||||||
.should("not.exist")
|
.should("not.exist")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
import { isOAS3, isSwagger2 } from "corePlugins/oas3/helpers"
|
import { isOAS30, isSwagger2 } from "corePlugins/oas3/helpers"
|
||||||
|
|
||||||
const isOAS3Shorthand = (version) => isOAS3(fromJS({
|
const isOAS3Shorthand = (version) => isOAS30(fromJS({
|
||||||
openapi: version
|
openapi: version
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ describe("isOAS3", function () {
|
|||||||
it("should recognize valid OAS3 version values", function () {
|
it("should recognize valid OAS3 version values", function () {
|
||||||
expect(isOAS3Shorthand("3.0.0")).toEqual(true)
|
expect(isOAS3Shorthand("3.0.0")).toEqual(true)
|
||||||
expect(isOAS3Shorthand("3.0.1")).toEqual(true)
|
expect(isOAS3Shorthand("3.0.1")).toEqual(true)
|
||||||
expect(isOAS3Shorthand("3.0.11111")).toEqual(true)
|
expect(isOAS3Shorthand("3.0.11111")).toEqual(false)
|
||||||
expect(isOAS3Shorthand("3.0.0-rc0")).toEqual(true)
|
expect(isOAS3Shorthand("3.0.0-rc0")).toEqual(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ describe("isOAS3", function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should gracefully fail when `openapi` field is missing", function () {
|
it("should gracefully fail when `openapi` field is missing", function () {
|
||||||
expect(isOAS3(fromJS({
|
expect(isOAS30(fromJS({
|
||||||
openApi: "3.0.0"
|
openApi: "3.0.0"
|
||||||
}))).toEqual(false)
|
}))).toEqual(false)
|
||||||
expect(isOAS3Shorthand(null)).toEqual(false)
|
expect(isOAS3Shorthand(null)).toEqual(false)
|
||||||
@@ -41,7 +41,7 @@ describe("isOAS3", function () {
|
|||||||
describe("isSwagger2", function () {
|
describe("isSwagger2", function () {
|
||||||
it("should recognize valid Swagger 2.0 version values", function () {
|
it("should recognize valid Swagger 2.0 version values", function () {
|
||||||
expect(isSwagger2Shorthand("2.0")).toEqual(true)
|
expect(isSwagger2Shorthand("2.0")).toEqual(true)
|
||||||
expect(isSwagger2Shorthand("2.0-rc0")).toEqual(true)
|
expect(isSwagger2Shorthand("2.0-rc0")).toEqual(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should fail for invalid Swagger 2.0 version values", function () {
|
it("should fail for invalid Swagger 2.0 version values", function () {
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +90,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +127,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,7 +171,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +212,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,7 +267,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +321,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,7 +350,8 @@ describe("OAS3 plugin - state", function() {
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => {
|
specJson: () => {
|
||||||
return fromJS({ openapi: "3.0.0" })
|
return fromJS({ openapi: "3.0.0" })
|
||||||
}
|
},
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe("oas3 plugin - auth extensions - wrapSelectors", function(){
|
|||||||
specJson: () => fromJS({
|
specJson: () => fromJS({
|
||||||
openapi: "3.0.0"
|
openapi: "3.0.0"
|
||||||
}),
|
}),
|
||||||
|
isOAS3: () => true,
|
||||||
securityDefinitions: () => {
|
securityDefinitions: () => {
|
||||||
return fromJS({
|
return fromJS({
|
||||||
"oauth2AuthorizationCode": {
|
"oauth2AuthorizationCode": {
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
|
|
||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
import {
|
import { definitions } from "corePlugins/oas3/spec-extensions/wrap-selectors"
|
||||||
definitions
|
|
||||||
} from "corePlugins/oas3/spec-extensions/wrap-selectors"
|
|
||||||
|
|
||||||
describe("oas3 plugin - spec extensions - wrapSelectors", function(){
|
describe("oas3 plugin - spec extensions - wrapSelectors", function(){
|
||||||
|
|
||||||
@@ -28,6 +25,7 @@ describe("oas3 plugin - spec extensions - wrapSelectors", function(){
|
|||||||
getSystem: () => system,
|
getSystem: () => system,
|
||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => spec,
|
specJson: () => spec,
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +55,7 @@ describe("oas3 plugin - spec extensions - wrapSelectors", function(){
|
|||||||
getSystem: () => system,
|
getSystem: () => system,
|
||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => spec,
|
specJson: () => spec,
|
||||||
|
isOAS3: () => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +81,8 @@ describe("oas3 plugin - spec extensions - wrapSelectors", function(){
|
|||||||
getSystem: () => system,
|
getSystem: () => system,
|
||||||
specSelectors: {
|
specSelectors: {
|
||||||
specJson: () => spec,
|
specJson: () => spec,
|
||||||
}
|
isOAS3: () => true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { render } from "enzyme"
|
import { render } from "enzyme"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
import Info, { InfoUrl, License } from "components/info"
|
import Info, { InfoUrl } from "components/info"
|
||||||
|
import Contact from "components/contact"
|
||||||
|
import License from "components/license"
|
||||||
import { Link } from "components/layout-utils"
|
import { Link } from "components/layout-utils"
|
||||||
import Markdown from "components/providers/markdown"
|
import Markdown from "components/providers/markdown"
|
||||||
|
|
||||||
@@ -11,7 +13,8 @@ describe("<Info/> Anchor Target Safety", function(){
|
|||||||
Markdown,
|
Markdown,
|
||||||
InfoUrl,
|
InfoUrl,
|
||||||
License,
|
License,
|
||||||
Link
|
Contact,
|
||||||
|
Link,
|
||||||
}
|
}
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
getComponent: c => components[c] || dummyComponent,
|
getComponent: c => components[c] || dummyComponent,
|
||||||
|
|||||||
Reference in New Issue
Block a user