308 lines
8.3 KiB
JavaScript
308 lines
8.3 KiB
JavaScript
/**
|
|
* @prettier
|
|
*/
|
|
import { OrderedMap, Map, List } from "immutable"
|
|
import constant from "lodash/constant"
|
|
|
|
import { getDefaultRequestBodyValue } from "./components/request-body"
|
|
import { stringify } from "core/utils"
|
|
|
|
// Helpers
|
|
|
|
const onlyOAS3 =
|
|
(selector) =>
|
|
(state, ...args) =>
|
|
(system) => {
|
|
if (system.getSystem().specSelectors.isOAS3()) {
|
|
const selectedValue = selector(state, ...args)
|
|
return typeof selectedValue === "function"
|
|
? selectedValue(system)
|
|
: selectedValue
|
|
} 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",
|
|
])
|
|
|
|
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",
|
|
])
|
|
// context: bodyValue can be a String, or a Map
|
|
if (!oas3RequestBodyValue) {
|
|
return false
|
|
}
|
|
// validation pass if String is not empty, or if Map exists
|
|
return true
|
|
}
|
|
|
|
export const selectedServer = onlyOAS3((state, namespace) => {
|
|
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
|
|
})
|
|
|
|
export const shouldRetainRequestBodyValue = onlyOAS3((state, path, method) => {
|
|
return state.getIn(["requestData", path, method, "retainBodyValue"]) || false
|
|
})
|
|
|
|
export const selectDefaultRequestBodyValue =
|
|
(state, path, method) => (system) => {
|
|
const { oas3Selectors, specSelectors, fn } = 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"
|
|
),
|
|
fn
|
|
)
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
export const hasUserEditedBody = onlyOAS3((state, path, method) => (system) => {
|
|
const { oas3Selectors, specSelectors, fn } = system
|
|
|
|
let userHasEditedBody = false
|
|
const currentMediaType = oas3Selectors.requestContentType(path, method)
|
|
let userEditedRequestBody = oas3Selectors.requestBodyValue(path, method)
|
|
const requestBody = specSelectors.specResolvedSubtree([
|
|
"paths",
|
|
path,
|
|
method,
|
|
"requestBody",
|
|
])
|
|
|
|
/**
|
|
* The only request body that can currently be edited is for Path Items that are direct values of OpenAPI.paths.
|
|
* Path Item contained within the Callback Object or OpenAPI.webhooks (OpenAPI 3.1.0) have `Try it out`
|
|
* disabled and thus body cannot be edited.
|
|
*/
|
|
if (!requestBody) {
|
|
return false
|
|
}
|
|
|
|
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()
|
|
)
|
|
}
|
|
if (List.isList(userEditedRequestBody)) {
|
|
userEditedRequestBody = stringify(userEditedRequestBody)
|
|
}
|
|
|
|
if (currentMediaType) {
|
|
const currentMediaTypeDefaultBodyValue = getDefaultRequestBodyValue(
|
|
requestBody,
|
|
currentMediaType,
|
|
oas3Selectors.activeExamplesMember(
|
|
path,
|
|
method,
|
|
"requestBody",
|
|
"requestBody"
|
|
),
|
|
fn
|
|
)
|
|
userHasEditedBody =
|
|
!!userEditedRequestBody &&
|
|
userEditedRequestBody !== currentMediaTypeDefaultBodyValue
|
|
}
|
|
return userHasEditedBody
|
|
})
|
|
|
|
export const requestBodyInclusionSetting = onlyOAS3((state, path, method) => {
|
|
return state.getIn(["requestData", path, method, "bodyInclusion"]) || Map()
|
|
})
|
|
|
|
export const requestBodyErrors = onlyOAS3((state, path, method) => {
|
|
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 requestContentType = onlyOAS3((state, path, method) => {
|
|
return (
|
|
state.getIn(["requestData", path, method, "requestContentType"]) || null
|
|
)
|
|
})
|
|
|
|
export const responseContentType = onlyOAS3((state, path, method) => {
|
|
return (
|
|
state.getIn(["requestData", path, method, "responseContentType"]) || null
|
|
)
|
|
})
|
|
|
|
export const serverVariableValue = onlyOAS3((state, locationData, key) => {
|
|
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]
|
|
}
|
|
} else {
|
|
const server = locationData
|
|
path = ["serverVariableValues", server, key]
|
|
}
|
|
|
|
return state.getIn(path) || null
|
|
})
|
|
|
|
export const serverVariables = onlyOAS3((state, locationData) => {
|
|
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]
|
|
}
|
|
} else {
|
|
const server = locationData
|
|
path = ["serverVariableValues", server]
|
|
}
|
|
|
|
return state.getIn(path) || OrderedMap()
|
|
})
|
|
|
|
export const serverEffectiveValue = onlyOAS3((state, locationData) => {
|
|
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])
|
|
}
|
|
} 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,
|
|
}
|
|
) => {
|
|
let missingRequiredKeys = []
|
|
// context: json => String; urlencoded, form-data => Map
|
|
if (!Map.isMap(oas3RequestBodyValue)) {
|
|
return missingRequiredKeys
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
)
|
|
requiredKeys.forEach((key) => {
|
|
let requiredKeyValue = oas3RequestBodyValue.getIn([key, "value"])
|
|
if (!requiredKeyValue) {
|
|
missingRequiredKeys.push(key)
|
|
}
|
|
})
|
|
return missingRequiredKeys
|
|
}
|
|
|
|
export const validOperationMethods = constant([
|
|
"get",
|
|
"put",
|
|
"post",
|
|
"delete",
|
|
"options",
|
|
"head",
|
|
"patch",
|
|
"trace",
|
|
])
|