refactor(oas31): concentrate OpenAPI 3.1.0 code to separate plugin (#8475)

Refs #8474
This commit is contained in:
Vladimír Gorej
2023-03-16 12:05:19 +01:00
committed by GitHub
parent ceccb218d3
commit 8b274414ab
35 changed files with 929 additions and 699 deletions

View File

@@ -1,41 +1,53 @@
/**
* @prettier
*/
import { OrderedMap, Map, List } from "immutable"
import { isOAS3 as isOAS3Helper } from "./helpers"
import { getDefaultRequestBodyValue } from "./components/request-body"
import { stringify } from "../../utils"
// Helpers
function onlyOAS3(selector) {
return (...args) => (system) => {
const spec = system.getSystem().specSelectors.specJson()
if(isOAS3Helper(spec)) {
return selector(...args)
} else {
return null
return (...args) =>
(system) => {
if (system.getSystem().specSelectors.isOAS3()) {
return selector(...args)
} else {
return null
}
}
}
}
function validateRequestBodyIsRequired(selector) {
return (...args) => (system) => {
const specJson = system.getSystem().specSelectors.specJson()
const argsList = [...args]
// expect argsList[0] = state
let pathMethod = argsList[1] || []
let isOas3RequestBodyRequired = specJson.getIn(["paths", ...pathMethod, "requestBody", "required"])
return (...args) =>
(system) => {
const specJson = system.getSystem().specSelectors.specJson()
const argsList = [...args]
// expect argsList[0] = state
let pathMethod = argsList[1] || []
let isOas3RequestBodyRequired = specJson.getIn([
"paths",
...pathMethod,
"requestBody",
"required",
])
if (isOas3RequestBodyRequired) {
return selector(...args)
} else {
// validation pass b/c not required
return true
if (isOas3RequestBodyRequired) {
return selector(...args)
} else {
// validation pass b/c not required
return true
}
}
}
}
const validateRequestBodyValueExists = (state, 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
if (!oas3RequestBodyValue) {
return false
@@ -44,68 +56,85 @@ const validateRequestBodyValueExists = (state, pathMethod) => {
return true
}
export const selectedServer = onlyOAS3((state, namespace) => {
const path = namespace ? [namespace, "selectedServer"] : ["selectedServer"]
return state.getIn(path) || ""
}
)
const path = namespace ? [namespace, "selectedServer"] : ["selectedServer"]
return state.getIn(path) || ""
})
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) => {
return state.getIn(["requestData", path, method, "retainBodyValue"]) || false
}
)
return state.getIn(["requestData", path, method, "retainBodyValue"]) || false
})
export const selectDefaultRequestBodyValue = (state, path, method) => (system) => {
const {oas3Selectors, specSelectors} = system.getSystem()
const spec = specSelectors.specJson()
if(isOAS3Helper(spec)) {
const currentMediaType = oas3Selectors.requestContentType(path, method)
if (currentMediaType) {
return getDefaultRequestBodyValue(
specSelectors.specResolvedSubtree(["paths", path, method, "requestBody"]),
currentMediaType,
oas3Selectors.activeExamplesMember(
path, method,
"requestBody",
"requestBody",
export const selectDefaultRequestBodyValue =
(state, path, method) => (system) => {
const { oas3Selectors, specSelectors } = system.getSystem()
if (specSelectors.isOAS3()) {
const currentMediaType = oas3Selectors.requestContentType(path, method)
if (currentMediaType) {
return getDefaultRequestBodyValue(
specSelectors.specResolvedSubtree([
"paths",
path,
method,
"requestBody",
]),
currentMediaType,
oas3Selectors.activeExamplesMember(
path,
method,
"requestBody",
"requestBody"
)
)
)
}
}
return null
}
return null
}
export const hasUserEditedBody = (state, path, method) => (system) => {
const {oas3Selectors, specSelectors} = system.getSystem()
const spec = specSelectors.specJson()
if(isOAS3Helper(spec)) {
const { oas3Selectors, specSelectors } = system.getSystem()
if (specSelectors.isOAS3()) {
let userHasEditedBody = false
const currentMediaType = oas3Selectors.requestContentType(path, method)
let userEditedRequestBody = oas3Selectors.requestBodyValue(path, method)
if (Map.isMap(userEditedRequestBody)) {
// 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)
}
if (currentMediaType) {
const currentMediaTypeDefaultBodyValue = getDefaultRequestBodyValue(
specSelectors.specResolvedSubtree(["paths", path, method, "requestBody"]),
specSelectors.specResolvedSubtree([
"paths",
path,
method,
"requestBody",
]),
currentMediaType,
oas3Selectors.activeExamplesMember(
path, method,
"requestBody",
path,
method,
"requestBody",
"requestBody"
)
)
userHasEditedBody = !!userEditedRequestBody && userEditedRequestBody !== currentMediaTypeDefaultBodyValue
userHasEditedBody =
!!userEditedRequestBody &&
userEditedRequestBody !== currentMediaTypeDefaultBodyValue
}
return userHasEditedBody
} else {
@@ -114,106 +143,114 @@ export const hasUserEditedBody = (state, path, method) => (system) => {
}
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) => {
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) => {
return state.getIn(["examples", path, method, type, name, "activeExample"]) || null
export const activeExamplesMember = onlyOAS3(
(state, path, method, type, name) => {
return (
state.getIn(["examples", path, method, type, name, "activeExample"]) ||
null
)
}
)
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) => {
return state.getIn(["requestData", path, method, "responseContentType"]) || null
}
)
return (
state.getIn(["requestData", path, method, "responseContentType"]) || null
)
})
export const serverVariableValue = onlyOAS3((state, locationData, key) => {
let path
let path
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if(typeof locationData !== "string") {
const { server, namespace } = locationData
if(namespace) {
path = [namespace, "serverVariableValues", server, key]
} else {
path = ["serverVariableValues", server, key]
}
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if (typeof locationData !== "string") {
const { server, namespace } = locationData
if (namespace) {
path = [namespace, "serverVariableValues", server, key]
} else {
const server = locationData
path = ["serverVariableValues", server, key]
}
return state.getIn(path) || null
} else {
const server = locationData
path = ["serverVariableValues", server, key]
}
)
return state.getIn(path) || null
})
export const serverVariables = onlyOAS3((state, locationData) => {
let path
let path
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if(typeof locationData !== "string") {
const { server, namespace } = locationData
if(namespace) {
path = [namespace, "serverVariableValues", server]
} else {
path = ["serverVariableValues", server]
}
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if (typeof locationData !== "string") {
const { server, namespace } = locationData
if (namespace) {
path = [namespace, "serverVariableValues", server]
} else {
const server = locationData
path = ["serverVariableValues", server]
}
return state.getIn(path) || OrderedMap()
} else {
const server = locationData
path = ["serverVariableValues", server]
}
)
return state.getIn(path) || OrderedMap()
})
export const serverEffectiveValue = onlyOAS3((state, locationData) => {
var varValues, serverValue
var varValues, serverValue
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if(typeof locationData !== "string") {
const { server, namespace } = locationData
serverValue = server
if(namespace) {
varValues = state.getIn([namespace, "serverVariableValues", serverValue])
} else {
varValues = state.getIn(["serverVariableValues", serverValue])
}
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if (typeof locationData !== "string") {
const { server, namespace } = locationData
serverValue = server
if (namespace) {
varValues = state.getIn([namespace, "serverVariableValues", serverValue])
} else {
serverValue = locationData
varValues = state.getIn(["serverVariableValues", serverValue])
}
varValues = varValues || OrderedMap()
let str = serverValue
varValues.map((val, key) => {
str = str.replace(new RegExp(`{${key}}`, "g"), val)
})
return str
} else {
serverValue = locationData
varValues = state.getIn(["serverVariableValues", serverValue])
}
)
varValues = varValues || OrderedMap()
let str = serverValue
varValues.map((val, key) => {
str = str.replace(new RegExp(`{${key}}`, "g"), val)
})
return str
})
export const validateBeforeExecute = validateRequestBodyIsRequired(
(state, pathMethod) => validateRequestBodyValueExists(state, pathMethod)
)
export const validateShallowRequired = (state, { oas3RequiredRequestBodyContentType, oas3RequestContentType, oas3RequestBodyValue} ) => {
export const validateShallowRequired = (
state,
{
oas3RequiredRequestBodyContentType,
oas3RequestContentType,
oas3RequestBodyValue,
}
) => {
let missingRequiredKeys = []
// context: json => String; urlencoded, form-data => Map
if (!Map.isMap(oas3RequestBodyValue)) {
@@ -221,16 +258,19 @@ export const validateShallowRequired = (state, { oas3RequiredRequestBodyContentT
}
let requiredKeys = []
// Cycle through list of possible contentTypes for matching contentType and defined requiredKeys
Object.keys(oas3RequiredRequestBodyContentType.requestContentType).forEach((contentType) => {
if (contentType === oas3RequestContentType) {
let contentTypeVal = oas3RequiredRequestBodyContentType.requestContentType[contentType]
contentTypeVal.forEach((requiredKey) => {
if (requiredKeys.indexOf(requiredKey) < 0 ) {
requiredKeys.push(requiredKey)
}
})
Object.keys(oas3RequiredRequestBodyContentType.requestContentType).forEach(
(contentType) => {
if (contentType === oas3RequestContentType) {
let contentTypeVal =
oas3RequiredRequestBodyContentType.requestContentType[contentType]
contentTypeVal.forEach((requiredKey) => {
if (requiredKeys.indexOf(requiredKey) < 0) {
requiredKeys.push(requiredKey)
}
})
}
}
})
)
requiredKeys.forEach((key) => {
let requiredKeyValue = oas3RequestBodyValue.getIn([key, "value"])
if (!requiredKeyValue) {