Added Swagger

This commit is contained in:
2020-06-10 08:25:21 +02:00
parent 5c6f37eaf7
commit af76cbca87
257 changed files with 48861 additions and 12 deletions
@@ -0,0 +1,21 @@
import keywordMap from "./keyword-map"
import getKeywordsForPath from "./get-keywords-for-path"
export default function getCompletions(editor, session, pos, prefix, cb, ctx, system) {
const { fn: { getPathForPosition }, specSelectors } = system
const { isOAS3 } = specSelectors
if(isOAS3 && !isOAS3()) {
// isOAS3 selector exists, and returns false
return cb(null, null)
}
const { AST } = ctx
var editorValue = editor.getValue()
const path = getPathForPosition({ pos, prefix, editorValue, AST})
const suggestions = getKeywordsForPath({ system, path, keywordMap })
cb(null, suggestions)
}
@@ -0,0 +1,176 @@
import isArray from "lodash/isArray"
import isObject from "lodash/isObject"
import mapValues from "lodash/mapValues"
import isPlainObject from "lodash/isPlainObject"
import toArray from "lodash/toArray"
import isString from "lodash/isString"
import get from "lodash/get"
export default function getKeywordsForPath({ system, path, keywordMap}) {
keywordMap = Object.assign({}, keywordMap)
// is getting path was not successful stop here and return no candidates
if (!isArray(path)) {
return [
{
name: "array",
value: " ",
score: 300,
meta: "Couldn't load suggestions"
}
]
}
if(path[path.length - 2] === "tags" && path.length > 2) {
// 'path.length > 2' excludes top-level 'tags'
return system.specSelectors.tags().map(tag => ({
score: 0,
meta: "local",
value: tag.get("name"),
})).toJS()
}
let reversePath = path.slice(0).reverse()
if(reversePath[1] === "security" && isNumeric(reversePath[0])) {
// **.security[x]
return system.specSelectors.securityDefinitions().keySeq().map(sec => ({
score: 0,
meta: "local",
caption: sec,
snippet: `${sec}: []`
})).toJS()
}
if(reversePath[0] === "security") {
// **.security:
return system.specSelectors.securityDefinitions().keySeq().map(sec => ({
score: 0,
meta: "local",
caption: sec,
snippet: `\n- ${sec}: []`
})).toJS()
}
// traverse down the keywordMap for each key in the path until there is
// no key in the path
var key = path.shift()
while (key && isObject(keywordMap)) {
keywordMap = getChild(keywordMap, key)
key = path.shift()
}
// if no keywordMap was found after the traversal return no candidates
if (!isObject(keywordMap)) {
return []
}
// if keywordMap is an array of strings, return the array as list of
// suggestions
if (isArray(keywordMap) && keywordMap.every(isString)) {
return keywordMap.map(constructAceCompletion.bind(null, "value"))
}
// If keywordMap is describing an array unwrap the inner map so we can
// suggest for array items
if (isArray(keywordMap)) {
if(isArray(keywordMap[0])) {
return keywordMap[0].map(item => {
return {
name: "array",
value: "- " + item,
score: 300,
meta: "array item"
}
})
} else {
return [{
name: "array",
value: "- ",
score: 300,
meta: "array item"
}]
}
}
// if keywordMap is not an object at this point return no candidates
if (!isObject(keywordMap)) {
return []
}
// for each key in keywordMap map construct a completion candidate and
// return the array
return suggestionFromSchema(keywordMap)
}
function getChild(object, key) {
var keys = Object.keys(object)
var regex
var isArrayAccess = /^\d+$/.test(key)
if(isArrayAccess && isArray(object)) {
return object[0]
}
for (var i = 0; i < keys.length; i++) {
let childVal = object[keys[i]]
if (!childVal) {
return null
}
regex = new RegExp(childVal.__regex || keys[i])
if (regex.test(key) && childVal) {
if(typeof childVal === "object" && !isArray(childVal)) {
return Object.assign({}, childVal)
} else {
return childVal
}
}
}
}
function suggestionFromSchema(map) {
const res = toArray(mapValues(map, (val, key) => {
const keyword = get(val, "__value", key)
const meta = isPlainObject(val) ? "object" : "keyword"
return constructAceCompletion(meta, keyword)
}))
return res
}
function constructAceCompletion(meta, keyword) {
if(keyword.slice(0, 2) === "__") {
return {}
}
// Give keywords, that extra colon
let snippet
switch(meta) {
case "keyword":
snippet = `${keyword}: `
break
case "object":
snippet = `${keyword}:\n `
break
default:
snippet = keyword
}
// snippet's treat `$` as special characters
snippet = snippet.replace("$", "\\$")
return {
snippet,
caption: keyword,
score: 300,
meta,
}
}
function isNumeric(obj) {
return !isNaN(obj)
}
@@ -0,0 +1,11 @@
import * as wrapActions from "./wrap-actions"
export default function EditorAutosuggestOAS3KeywordsPlugin() {
return {
statePlugins: {
editor: {
wrapActions,
}
}
}
}
@@ -0,0 +1,20 @@
import {
ExternalDocumentation,
Info,
SecurityRequirement,
Server,
Tag,
Components,
Paths
} from "./oas3-objects.js"
export default {
openapi: String,
info: Info,
servers: [Server],
paths: Paths,
components: Components,
security: [SecurityRequirement],
tags: [Tag],
externalDocs: ExternalDocumentation
}
@@ -0,0 +1,331 @@
// Adapted from OAS 3.0.0-rc2
// comma dangles in this file = cleaner diffs
/*eslint comma-dangle: ["error", "always-multiline"]*/
// anyOf and combine are the same for now.
// they are seperated for semantics, and for possible future improvement
const anyOf = (...objs) => objs ? Object.assign({}, ...objs) : {}
const stringEnum = (arr) => arr
const Any = null
export const ExternalDocumentation = {
description: String,
url: String,
}
export const Contact = {
name: String,
url: String,
email: String,
}
export const License = {
name: String,
url: String,
}
export const Info = {
title: String,
description: String,
termsOfService: String,
contact: Contact,
license: License,
version: String,
}
export const ServerVariable = {
enum: [String],
default: String,
description: String,
}
export const XML = {
name: String,
namespace: String,
prefix: String,
attribute: Boolean,
wrapped: Boolean,
}
export const OAuthFlow = {
authorizationUrl: String,
tokenUrl: String,
refreshUrl: String,
scopes: {
".": String,
},
}
export const Reference = {
"$ref": String,
}
export const Example = {
summary: String,
description: String,
value: Any,
externalValue: String,
}
export const SecurityRequirement = {
".": [String],
}
export const Server = {
url: String,
description: String,
variables: {
".": ServerVariable,
},
}
export const Link = {
operationRef: String,
operationId: String,
parameters: {
".": Any,
},
requestBody: Any,
description: String,
server: Server,
}
export const Schema = {
// Lifted from JSONSchema
title: String,
multipleOf: String,
maximum: String,
exclusiveMaximum: String,
minimum: String,
exclusiveMinimum: String,
maxLength: String,
minLength: String,
pattern: RegExp,
maxItems: String,
minItems: String,
uniqueItems: Boolean,
maxProperties: String,
minProperties: String,
required: Boolean,
enum: String,
// Adapted from JSONSchema
type: String,
get allOf () { return this },
get oneOf () { return this },
get anyOf () { return this },
get not () { return this },
get items () { return this },
get properties () {
return {
".": this,
}
},
get additionalProperties () { return this },
description: String,
format: String,
default: Any,
nullable: Boolean,
readOnly: Boolean,
writeOnly: Boolean,
xml: XML,
externalDocs: ExternalDocumentation,
example: Any,
deprecated: Boolean,
}
export const Encoding = {
contentType: String,
headers: {
".": undefined,
},
style: stringEnum(["matrix", "label", "form", "simple", "spaceDelimited", "pipeDelimited", "deepObject"]),
explode: Boolean,
allowReserved: Boolean,
}
export const MediaType = {
schema: anyOf(Schema, Reference),
example: Any,
examples: {
".": anyOf(Example, Reference),
},
encoding: {
".": Encoding,
},
}
export const Parameter = {
name: String,
in: stringEnum(["query", "header", "path", "cookie"]),
description: String,
required: Boolean,
deprecated: Boolean,
allowEmptyValue: Boolean,
style: stringEnum(["matrix", "label", "form", "simple", "spaceDelimited", "pipeDelimited", "deepObject"]),
explode: String,
allowReserved: Boolean,
schema: anyOf(Schema, Reference),
example: Any,
examples: {
".": anyOf(Example, Reference),
},
content: {
".": MediaType,
},
}
export const Header = {
description: String,
required: Boolean,
deprecated: Boolean,
allowEmptyValue: Boolean,
style: stringEnum(["matrix", "label", "form", "simple", "spaceDelimited", "pipeDelimited", "deepObject"]),
explode: String,
allowReserved: Boolean,
schema: anyOf(Schema, Reference),
example: Any,
examples: {
".": anyOf(Example, Reference),
},
content: {
".": MediaType,
},
}
export const RequestBody = {
description: String,
content: {
".": MediaType,
},
}
export const Response = {
description: String,
headers: {
".": anyOf(Header, Reference),
},
content: {
".": MediaType,
},
links: {
".": anyOf(Link, Reference),
},
}
export const Responses = {
default: anyOf(Response, Reference),
"\\d\\d\\d|\\d\\dX|\\dXX": anyOf(Response, Reference),
}
export const Callback = {
// ".": PathItem,
}
export const Tag = {
name: String,
description: String,
externalDocs: ExternalDocumentation,
}
export const OAuthFlows = {
implicit: OAuthFlow,
password: OAuthFlow,
clientCredentials: OAuthFlow,
authorizationCode: OAuthFlow,
}
export const SecurityScheme = {
type: String,
description: String,
name: String,
in: String,
scheme: String,
bearerFormat: String,
flows: OAuthFlows,
openIdConnectUrl: String,
}
const ComponentFixedFieldRegex = "^[a-zA-Z0-9\.\-_]+$"
export const Components = {
schemas: {
[ComponentFixedFieldRegex]: anyOf(Schema, Reference),
},
responses: {
[ComponentFixedFieldRegex]: anyOf(Response, Reference),
},
parameters: {
[ComponentFixedFieldRegex]: anyOf(Parameter, Reference),
},
examples: {
[ComponentFixedFieldRegex]: anyOf(Example, Reference),
},
requestBodies: {
[ComponentFixedFieldRegex]: anyOf(RequestBody, Reference),
},
headers: {
[ComponentFixedFieldRegex]: anyOf(Header, Reference),
},
securitySchemes: {
[ComponentFixedFieldRegex]: anyOf(SecurityScheme, Reference),
},
links: {
[ComponentFixedFieldRegex]: anyOf(Link, Reference),
},
callbacks: {
get [ComponentFixedFieldRegex]() { return anyOf(Callback, Reference) },
},
}
export const Operation = {
tags: [String],
summary: String,
description: String,
externalDocs: ExternalDocumentation,
operationId: String,
parameters: [anyOf(Parameter, Reference)],
requestBody: anyOf(RequestBody, Reference),
responses: Responses,
get callbacks() {
return {
".": anyOf(Callback, Reference),
}
},
deprecated: Boolean,
security: [SecurityRequirement],
servers: [Server],
}
export const Discriminator = {
propertyName: String,
mapping: {
".": String,
},
}
export const PathItem = anyOf(Reference, {
summary: String,
description: String,
get: Operation,
put: Operation,
post: Operation,
delete: Operation,
options: Operation,
head: Operation,
patch: Operation,
trace: Operation,
servers: Server,
parameters: anyOf(Parameter, Reference),
})
export const Paths = {
"/.": PathItem,
}
// solves `PathItem -> Operation -> Callback -> PathItem` circular reference
Callback["."] = PathItem
// solves `Encoding -> Header -> MediaType -> Encoding` circular reference
Encoding.headers["."] = Header
@@ -0,0 +1,11 @@
import getCompletions from "./get-completions"
// Add an autosuggest completer
export const addAutosuggestionCompleters = (ori, system) => (context) => {
return ori(context).concat([{
getCompletions(...args) {
// Add `context`, then `system` as the last args
return getCompletions(...args, context, system)
}
}])
}