Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: OpenAPI 3.1 support #8367

Merged
merged 30 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c70a4c0
fix(oas3-request-body): add Im prototype check
tim-lai Dec 1, 2022
6f6a4f3
feat(oas31): webhooks component and selectors
tim-lai Nov 29, 2022
565857e
feat(oas31): new info and license fields plus wrappable License compo…
tim-lai Dec 15, 2022
049fb54
feat(webhooks): move position in baseLayout and render null case
tim-lai Dec 16, 2022
d756346
feat(oas31): new oas3.x predicates
tim-lai Jan 23, 2023
b7f6245
feat(oas31): new selector `selectIsOpenAPI31`
tim-lai Jan 25, 2023
f4300e1
feat(oas31): License component with `selectIsOpenAPI31`
tim-lai Jan 25, 2023
1eb9e2c
test(oas31): cypress tests for License component
tim-lai Jan 26, 2023
ba530be
test(oas31): add anchor target safety check for License object
tim-lai Jan 26, 2023
4f17657
feat(oas3): export Contact component
tim-lai Jan 26, 2023
fde3c3a
feat(oas31): wrap Info component for summary field
tim-lai Jan 26, 2023
fc6ba1d
test(oas31): cypress tests for Info wrapped component
tim-lai Jan 26, 2023
5ba8799
chore(oas31) cleanup test fixtures
tim-lai Jan 26, 2023
27de43a
feat(oas31): add selectIsOpenAPI31 to BaseLayout for Webhooks
tim-lai Jan 26, 2023
054b1d1
refactor(oas31): webhooks cleanup
tim-lai Jan 26, 2023
1c5b651
test(oas31): cypress tests for Webhook component
tim-lai Jan 26, 2023
ab8d4cd
feat(deps): swagger-cllient with apidom
tim-lai Jan 27, 2023
e188971
fix(oas31): import Contact into Base preset
tim-lai Jan 27, 2023
4524014
test(oas2): temp skip of enum-boolean e2e assertion
tim-lai Jan 27, 2023
a67e5d8
chore(deps): update package-lock
tim-lai Jan 27, 2023
65c5e73
fix(oas31): isOAS3 helper missing args
tim-lai Jan 30, 2023
96957a6
test(jest): add import for License component
tim-lai Jan 30, 2023
7c9782a
chore(build): increase allowable build size
tim-lai Jan 30, 2023
b2041d7
test(oas2): restore enum-boolean e2e assertion
tim-lai Jan 30, 2023
b290a5b
chore(deps): bump swagger-client to v3.19.0-alpha.4
tim-lai Feb 3, 2023
d26263a
Merge branch 'master' of github.com:swagger-api/swagger-ui into HEAD
tim-lai Feb 3, 2023
b9d8668
chore(deps): bump http-cache-semantics from 4.1.0 to 4.1.1 (#8368)
dependabot[bot] Feb 3, 2023
718924b
chore(deps): bump json5 and babel-plugin-module-resolver (#8369)
dependabot[bot] Feb 3, 2023
df840cb
chore(deps): add package overrides
tim-lai Feb 3, 2023
3c8d9f8
Merge branch 'master' of github.com:swagger-api/swagger-ui into feat/…
tim-lai Feb 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1,065 changes: 927 additions & 138 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"deps-license": "license-checker --production --csv --out $npm_package_config_deps_check_dir/licenses.csv && license-checker --development --csv --out $npm_package_config_deps_check_dir/licenses-dev.csv",
"deps-size": "webpack -p --config webpack/bundle.babel.js --json | webpack-bundle-size-analyzer >| $npm_package_config_deps_check_dir/sizes.txt",
"deps-check": "run-s deps-license deps-size",
"link:apidom": "npm link @swagger-api/apidom-core @swagger-api/apidom-reference @swagger-api/apidom-ns-openapi-3-1 @swagger-api/apidom-ns-openapi-3-0 @swagger-api/apidom-ns-json-schema-draft-4 @swagger-api/apidom-json-pointer",
"lint": "eslint --ext \".js,.jsx\" src test dev-helpers flavors",
"lint-errors": "eslint --quiet --ext \".js,.jsx\" src test dev-helpers flavors",
"lint-fix": "eslint --ext \".js,.jsx\" src test dev-helpers flavors --fix",
Expand Down Expand Up @@ -94,7 +95,7 @@
"reselect": "^4.1.5",
"serialize-error": "^8.1.0",
"sha.js": "^2.4.11",
"swagger-client": "^3.18.5",
"swagger-client": "=3.19.0-alpha.4",
"url-parse": "^1.5.8",
"xml": "=1.0.1",
"xml-but-prettier": "^1.0.1",
Expand Down Expand Up @@ -122,7 +123,7 @@
"autoprefixer": "^10.4.12",
"babel-loader": "^8.2.3",
"babel-plugin-lodash": "=3.3.4",
"babel-plugin-module-resolver": "=4.1.0",
"babel-plugin-module-resolver": "=5.0.0",
"babel-plugin-transform-react-remove-prop-types": "=0.4.24",
"body-parser": "^1.19.0",
"buffer": "^6.0.3",
Expand Down Expand Up @@ -187,6 +188,13 @@
"webpack-node-externals": "=3.0.0",
"webpack-stats-plugin": "=1.0.3"
},
"overrides": {
"swagger-client": {
"@swagger-api/apidom-reference": {
"axios": "npm:-@0.0.1"
}
}
},
"config": {
"deps_check_dir": ".deps_check"
}
Expand Down
6 changes: 3 additions & 3 deletions src/core/components/info.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class InfoBasePath extends React.Component {
}


class Contact extends React.Component {
export class Contact extends React.Component {
static propTypes = {
data: PropTypes.object,
getComponent: PropTypes.func.isRequired,
Expand Down Expand Up @@ -53,7 +53,7 @@ class Contact extends React.Component {
}
}

class License extends React.Component {
export class License extends React.Component {
static propTypes = {
license: PropTypes.object,
getComponent: PropTypes.func.isRequired,
Expand All @@ -64,7 +64,6 @@ class License extends React.Component {

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})
Expand Down Expand Up @@ -125,6 +124,7 @@ export default class Info extends React.Component {
const VersionStamp = getComponent("VersionStamp")
const InfoUrl = getComponent("InfoUrl")
const InfoBasePath = getComponent("InfoBasePath")
const License = getComponent("License")

return (
<div className="info">
Expand Down
9 changes: 9 additions & 0 deletions src/core/components/layouts/base.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default class BaseLayout extends React.Component {
let VersionPragmaFilter = getComponent("VersionPragmaFilter")
let Operations = getComponent("operations", true)
let Models = getComponent("Models", true)
let Webhooks = getComponent("Webhooks", true)
let Row = getComponent("Row")
let Col = getComponent("Col")
let Errors = getComponent("errors", true)
Expand All @@ -30,6 +31,7 @@ export default class BaseLayout extends React.Component {
const FilterContainer = getComponent("FilterContainer", true)
let isSwagger2 = specSelectors.isSwagger2()
let isOAS3 = specSelectors.isOAS3()
const isOpenAPI31 = specSelectors.selectIsOpenAPI31()

const isSpecEmpty = !specSelectors.specStr()

Expand Down Expand Up @@ -112,6 +114,13 @@ export default class BaseLayout extends React.Component {
<Operations/>
</Col>
</Row>
{ isOpenAPI31 &&
<Row className="webhooks-container">
<Col mobile={12} desktop={12} >
<Webhooks />
</Col>
</Row>
}
<Row>
<Col mobile={12} desktop={12} >
<Models/>
Expand Down
4 changes: 3 additions & 1 deletion src/core/plugins/oas3/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ServersContainer from "./servers-container"
import RequestBodyEditor from "./request-body-editor"
import HttpAuth from "./http-auth"
import OperationServers from "./operation-servers"
import Webhooks from "./webhooks"

export default {
Callbacks,
Expand All @@ -15,5 +16,6 @@ export default {
ServersContainer,
RequestBodyEditor,
OperationServers,
operationLink: OperationLink
operationLink: OperationLink,
Webhooks
}
10 changes: 5 additions & 5 deletions src/core/plugins/oas3/components/request-body.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { getCommonExtensions, getSampleSchema, stringify, isEmptyValue } from "c
import { getKnownSyntaxHighlighterLanguage } from "core/utils/jsonParse"

export const getDefaultRequestBodyValue = (requestBody, mediaType, activeExamplesKey) => {
const mediaTypeValue = requestBody.getIn(["content", mediaType])
const schema = mediaTypeValue.get("schema").toJS()
const mediaTypeValue = requestBody?.getIn(["content", mediaType])
const schema = mediaTypeValue?.get("schema").toJS()

const hasExamplesKey = mediaTypeValue.get("examples") !== undefined
const exampleSchema = mediaTypeValue.get("example")
const hasExamplesKey = mediaTypeValue?.get("examples") !== undefined
const exampleSchema = mediaTypeValue?.get("example")
const mediaTypeExample = hasExamplesKey
? mediaTypeValue.getIn([
? mediaTypeValue?.getIn([
"examples",
activeExamplesKey,
"value"
Expand Down
60 changes: 60 additions & 0 deletions src/core/plugins/oas3/components/webhooks.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// OpenAPI 3.1 feature
import React from "react"
import PropTypes from "prop-types"
import { fromJS } from "immutable"
import ImPropTypes from "react-immutable-proptypes"

// Todo: nice to have: similar to operation-tags, could have an expand/collapse button
// to show/hide all webhook items
const Webhooks = (props) => {
const { specSelectors, getComponent, specPath } = props

const webhooksPathItems = specSelectors.selectWebhooks() // OrderedMap
if (!webhooksPathItems || webhooksPathItems?.size < 1) {
return null
}
const OperationContainer = getComponent("OperationContainer", true)

const pathItemsElements = webhooksPathItems.entrySeq().map(([pathItemName, pathItem], i) => {
const operationsElements = pathItem.entrySeq().map(([operationMethod, operation], j) => {
const op = fromJS({
operation
})
// using defaultProps for `specPath`; may want to remove from props
// and/or if extract to separate PathItem component, allow for use
// with both OAS3.1 "webhooks" and "components.pathItems" features
return <OperationContainer
{...props}
op={op}
key={`${pathItemName}--${operationMethod}--${j}`}
tag={""}
method={operationMethod}
path={pathItemName}
specPath={specPath.push("webhooks", pathItemName, operationMethod)}
allowTryItOut={false}
/>
})
return <div key={`${pathItemName}-${i}`}>
{operationsElements}
</div>
})

return (
<div className="webhooks">
<h2>Webhooks</h2>
{pathItemsElements}
</div>
)
}

Webhooks.propTypes = {
specSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
specPath: ImPropTypes.list,
}

Webhooks.defaultProps = {
specPath: fromJS([])
}

export default Webhooks
23 changes: 17 additions & 6 deletions src/core/plugins/oas3/helpers.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import React from "react"

export function isOAS3(jsSpec) {
export function isOpenAPI30(jsSpec) {
const oasVersion = jsSpec.get("openapi")
if(typeof oasVersion !== "string") {
if (typeof oasVersion !== "string") {
return false
}
return oasVersion.startsWith("3.0.") && oasVersion.length > 4
}

// we gate against `3.1` because we want to explicitly opt into supporting it
// at some point in the future -- KS, 7/2018
export function isOpenAPI31(jsSpec) {
const oasVersion = jsSpec.get("openapi")
if (typeof oasVersion !== "string") {
return false
}
return oasVersion.startsWith("3.1.") && oasVersion.length > 4
}

// starts with, but is not `3.0.` exactly
return oasVersion.startsWith("3.0.") && 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) {
Expand Down
24 changes: 23 additions & 1 deletion src/core/plugins/oas3/spec-extensions/selectors.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { createSelector } from "reselect"
import { Map } from "immutable"
import { isOAS3 as isOAS3Helper, isSwagger2 as isSwagger2Helper } from "../helpers"
import { isOAS3 as isOAS3Helper, isOpenAPI31 as isOpenAPI31Helper, isSwagger2 as isSwagger2Helper } from "../helpers"


// Helpers

// 1/2023: as of now, more accurately, isAnyOAS3
function onlyOAS3(selector) {
return () => (system, ...args) => {
const spec = system.getSystem().specSelectors.specJson()
Expand All @@ -16,6 +17,17 @@ function onlyOAS3(selector) {
}
}

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()
}
Expand Down Expand Up @@ -48,3 +60,13 @@ export const isSwagger2 = (ori, system) => () => {
const spec = system.getSystem().specSelectors.specJson()
return isSwagger2Helper(spec)
}

export const selectIsOpenAPI31 = (ori, system) => () => {
const spec = system.getSystem().specSelectors.specJson()
return isOpenAPI31Helper(spec)
}

export const selectWebhooks = isOpenAPI31(createSelector(
spec,
spec => spec.getIn(["webhooks"]) || Map()
))
26 changes: 24 additions & 2 deletions src/core/plugins/oas3/spec-extensions/wrap-selectors.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createSelector } from "reselect"
import { specJsonWithResolvedSubtrees } from "../../spec/selectors"
import { Map } from "immutable"
import { isOAS3 as isOAS3Helper, isSwagger2 as isSwagger2Helper } from "../helpers"
import { isOAS3 as isOAS3Helper, isOpenAPI31 as isOpenAPI31Helper, isSwagger2 as isSwagger2Helper } from "../helpers"


// Helpers

// 1/2023: as of now, more accurately, isAnyOAS3
function onlyOAS3(selector) {
return (ori, system) => (...args) => {
const spec = system.getSystem().specSelectors.specJson()
Expand All @@ -17,6 +17,17 @@ function onlyOAS3(selector) {
}
}

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()
}
Expand Down Expand Up @@ -83,3 +94,14 @@ 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 changes: 4 additions & 0 deletions src/core/plugins/oas3/wrap-components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import VersionStamp from "./version-stamp"
import OnlineValidatorBadge from "./online-validator-badge"
import Model from "./model"
import JsonSchema_string from "./json-schema-string"
import License from "./license"
import info from "./info"

export default {
Markdown,
Expand All @@ -12,4 +14,6 @@ export default {
VersionStamp,
model: Model,
onlineValidatorBadge: OnlineValidatorBadge,
License,
info,
}