330 lines
8.2 KiB
JavaScript
330 lines
8.2 KiB
JavaScript
import { createSelector } from "reselect"
|
|
import { sorters } from "core/utils"
|
|
import { fromJS, Set, Map, List } from "immutable"
|
|
|
|
const DEFAULT_TAG = "default"
|
|
|
|
const OPERATION_METHODS = ["get", "put", "post", "delete", "options", "head", "patch"]
|
|
|
|
const state = state => {
|
|
return state || Map()
|
|
}
|
|
|
|
export const lastError = createSelector(
|
|
state,
|
|
spec => spec.get("lastError")
|
|
)
|
|
|
|
export const url = createSelector(
|
|
state,
|
|
spec => spec.get("url")
|
|
)
|
|
|
|
export const specStr = createSelector(
|
|
state,
|
|
spec => spec.get("spec") || ""
|
|
)
|
|
|
|
export const specSource = createSelector(
|
|
state,
|
|
spec => spec.get("specSource") || "not-editor"
|
|
)
|
|
|
|
export const specJson = createSelector(
|
|
state,
|
|
spec => spec.get("json", Map())
|
|
)
|
|
|
|
export const specResolved = createSelector(
|
|
state,
|
|
spec => spec.get("resolved", Map())
|
|
)
|
|
|
|
// Default Spec ( as an object )
|
|
export const spec = state => {
|
|
let res = specResolved(state)
|
|
return res
|
|
}
|
|
|
|
export const info = createSelector(
|
|
spec,
|
|
spec => returnSelfOrNewMap(spec && spec.get("info"))
|
|
)
|
|
|
|
export const externalDocs = createSelector(
|
|
spec,
|
|
spec => returnSelfOrNewMap(spec && spec.get("externalDocs"))
|
|
)
|
|
|
|
export const version = createSelector(
|
|
info,
|
|
info => info && info.get("version")
|
|
)
|
|
|
|
export const semver = createSelector(
|
|
version,
|
|
version => /v?([0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(version).slice(1)
|
|
)
|
|
|
|
export const paths = createSelector(
|
|
spec,
|
|
spec => spec.get("paths")
|
|
)
|
|
|
|
export const operations = createSelector(
|
|
paths,
|
|
paths => {
|
|
if(!paths || paths.size < 1)
|
|
return List()
|
|
|
|
let list = List()
|
|
|
|
if(!paths || !paths.forEach) {
|
|
return List()
|
|
}
|
|
|
|
paths.forEach((path, pathName) => {
|
|
if(!path || !path.forEach) {
|
|
return {}
|
|
}
|
|
path.forEach((operation, method) => {
|
|
if(OPERATION_METHODS.indexOf(method) === -1) {
|
|
return
|
|
}
|
|
list = list.push(fromJS({
|
|
path: pathName,
|
|
method,
|
|
operation,
|
|
id: `${method}-${pathName}`
|
|
}))
|
|
})
|
|
})
|
|
|
|
return list
|
|
}
|
|
)
|
|
|
|
export const consumes = createSelector(
|
|
spec,
|
|
spec => Set(spec.get("consumes"))
|
|
)
|
|
|
|
export const produces = createSelector(
|
|
spec,
|
|
spec => Set(spec.get("produces"))
|
|
)
|
|
|
|
export const security = createSelector(
|
|
spec,
|
|
spec => spec.get("security", List())
|
|
)
|
|
|
|
export const securityDefinitions = createSelector(
|
|
spec,
|
|
spec => spec.get("securityDefinitions")
|
|
)
|
|
|
|
|
|
export const findDefinition = ( state, name ) => {
|
|
return specResolved(state).getIn(["definitions", name], null)
|
|
}
|
|
|
|
export const definitions = createSelector(
|
|
spec,
|
|
spec => spec.get("definitions") || Map()
|
|
)
|
|
|
|
export const basePath = createSelector(
|
|
spec,
|
|
spec => spec.get("basePath")
|
|
)
|
|
|
|
export const host = createSelector(
|
|
spec,
|
|
spec => spec.get("host")
|
|
)
|
|
|
|
export const schemes = createSelector(
|
|
spec,
|
|
spec => spec.get("schemes", Map())
|
|
)
|
|
|
|
export const operationsWithRootInherited = createSelector(
|
|
operations,
|
|
consumes,
|
|
produces,
|
|
(operations, consumes, produces) => {
|
|
return operations.map( ops => ops.update("operation", op => {
|
|
if(op) {
|
|
if(!Map.isMap(op)) { return }
|
|
return op.withMutations( op => {
|
|
if ( !op.get("consumes") ) {
|
|
op.update("consumes", a => Set(a).merge(consumes))
|
|
}
|
|
if ( !op.get("produces") ) {
|
|
op.update("produces", a => Set(a).merge(produces))
|
|
}
|
|
return op
|
|
})
|
|
} else {
|
|
// return something with Immutable methods
|
|
return Map()
|
|
}
|
|
|
|
}))
|
|
}
|
|
)
|
|
|
|
export const tags = createSelector(
|
|
spec,
|
|
json => json.get("tags", List())
|
|
)
|
|
|
|
export const tagDetails = (state, tag) => {
|
|
let currentTags = tags(state) || List()
|
|
return currentTags.filter(Map.isMap).find(t => t.get("name") === tag, Map())
|
|
}
|
|
|
|
export const operationsWithTags = createSelector(
|
|
operationsWithRootInherited,
|
|
operations => {
|
|
return operations.reduce( (taggedMap, op) => {
|
|
let tags = Set(op.getIn(["operation","tags"]))
|
|
if(tags.count() < 1)
|
|
return taggedMap.update(DEFAULT_TAG, List(), ar => ar.push(op))
|
|
return tags.reduce( (res, tag) => res.update(tag, List(), (ar) => ar.push(op)), taggedMap )
|
|
}, Map())
|
|
}
|
|
)
|
|
|
|
export const taggedOperations = (state) => ({ getConfigs }) => {
|
|
let { apisSorter, operationsSorter } = getConfigs();
|
|
|
|
return operationsWithTags(state)
|
|
.sort((operationA, operationB) => {
|
|
let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]);
|
|
return (!sortFn ? null : sortFn(operationA, operationB));
|
|
})
|
|
.map((ops, tag) => {
|
|
let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ]);
|
|
let operations = (!sortFn ? ops : ops.sort(sortFn));
|
|
|
|
return Map({ tagDetails: tagDetails(state, tag), operations: operations });
|
|
});
|
|
};
|
|
|
|
export const responses = createSelector(
|
|
state,
|
|
state => state.get( "responses", Map() )
|
|
)
|
|
|
|
export const requests = createSelector(
|
|
state,
|
|
state => state.get( "requests", Map() )
|
|
)
|
|
|
|
export const responseFor = (state, path, method) => {
|
|
return responses(state).getIn([path, method], null)
|
|
}
|
|
|
|
export const requestFor = (state, path, method) => {
|
|
return requests(state).getIn([path, method], null)
|
|
}
|
|
|
|
export const allowTryItOutFor = () => {
|
|
// This is just a hook for now.
|
|
return true
|
|
}
|
|
|
|
// Get the parameter value by parameter name
|
|
export function getParameter(state, pathMethod, name) {
|
|
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
|
return params.filter( (p) => {
|
|
return Map.isMap(p) && p.get("name") === name
|
|
}).first()
|
|
}
|
|
|
|
export const hasHost = createSelector(
|
|
spec,
|
|
spec => {
|
|
const host = spec.get("host")
|
|
return typeof host === "string" && host.length > 0 && host[0] !== "/"
|
|
}
|
|
)
|
|
|
|
// Get the parameter values, that the user filled out
|
|
export function parameterValues(state, pathMethod, isXml) {
|
|
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
|
return params.reduce( (hash, p) => {
|
|
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
|
|
return hash.set(p.get("name"), value)
|
|
}, fromJS({}))
|
|
}
|
|
|
|
// True if any parameter includes `in: ?`
|
|
export function parametersIncludeIn(parameters, inValue="") {
|
|
if(List.isList(parameters)) {
|
|
return parameters.some( p => Map.isMap(p) && p.get("in") === inValue )
|
|
}
|
|
}
|
|
|
|
// True if any parameter includes `type: ?`
|
|
export function parametersIncludeType(parameters, typeValue="") {
|
|
if(List.isList(parameters)) {
|
|
return parameters.some( p => Map.isMap(p) && p.get("type") === typeValue )
|
|
}
|
|
}
|
|
|
|
// Get the consumes/produces value that the user selected
|
|
export function contentTypeValues(state, pathMethod) {
|
|
let op = spec(state).getIn(["paths", ...pathMethod], fromJS({}))
|
|
const parameters = op.get("parameters") || new List()
|
|
const requestContentType = (
|
|
parametersIncludeType(parameters, "file") ? "multipart/form-data"
|
|
: parametersIncludeIn(parameters, "formData") ? "application/x-www-form-urlencoded"
|
|
: op.get("consumes_value")
|
|
)
|
|
|
|
|
|
return fromJS({
|
|
requestContentType,
|
|
responseContentType: op.get("produces_value")
|
|
})
|
|
}
|
|
|
|
// Get the consumes/produces by path
|
|
export function operationConsumes(state, pathMethod) {
|
|
return spec(state).getIn(["paths", ...pathMethod, "consumes"], fromJS({}))
|
|
}
|
|
|
|
export const operationScheme = ( state, path, method ) => {
|
|
let url = state.get("url")
|
|
let matchResult = url.match(/^([a-z][a-z0-9+\-.]*):/)
|
|
let urlScheme = Array.isArray(matchResult) ? matchResult[1] : null
|
|
|
|
return state.getIn(["scheme", path, method]) || state.getIn(["scheme", "_defaultScheme"]) || urlScheme || ""
|
|
}
|
|
|
|
export const canExecuteScheme = ( state, path, method ) => {
|
|
return ["http", "https"].indexOf(operationScheme(state, path, method)) > -1
|
|
}
|
|
|
|
export const validateBeforeExecute = ( state, pathMethod ) => {
|
|
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
|
let isValid = true
|
|
|
|
params.forEach( (p) => {
|
|
let errors = p.get("errors")
|
|
if ( errors && errors.count() ) {
|
|
isValid = false
|
|
}
|
|
})
|
|
|
|
return isValid
|
|
}
|
|
|
|
function returnSelfOrNewMap(obj) {
|
|
// returns obj if obj is an Immutable map, else returns a new Map
|
|
return Map.isMap(obj) ? obj : new Map()
|
|
}
|