lots of stuff, no time to s-plain (#5)
This commit is contained in:
@ -1,2 +1,3 @@
|
|||||||
kotlin 1.5.0-M2
|
kotlin 1.5.0-M2
|
||||||
java openjdk-14.0.1
|
java openjdk-14.0.1
|
||||||
|
gradle 7.0
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
## [0.0.2] - April 12th, 2021
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Beginning of an implementation. Currently, able to generate a rough outline of the API at runtime, along with generating
|
||||||
|
full data classes represented by JSON Schema.
|
||||||
|
|
||||||
## [0.0.1] - April 11th, 2021
|
## [0.0.1] - April 11th, 2021
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
52
README.md
52
README.md
@ -2,10 +2,56 @@
|
|||||||
|
|
||||||
## What is Kompendium
|
## What is Kompendium
|
||||||
|
|
||||||
Kompendium is intended to be a non-intrusive OpenApi Specification generator for [Ktor](https://ktor.io).
|
Kompendium is intended to be a minimally invasive
|
||||||
Non-invasive meaning that users will use only Ktor native functions when implementing their API, and will supplement
|
OpenApi Specification generator for
|
||||||
with Kompendium code in order to generate the appropriate spec.
|
[Ktor](https://ktor.io).
|
||||||
|
Minimally invasive meaning that users will use only
|
||||||
|
Ktor native functions when implementing their API,
|
||||||
|
and will supplement with Kompendium code in order
|
||||||
|
to generate the appropriate spec.
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// Minimal API Example
|
||||||
|
fun Application.mainModule() {
|
||||||
|
install(ContentNegotiation) {
|
||||||
|
jackson()
|
||||||
|
}
|
||||||
|
routing {
|
||||||
|
route("/test") {
|
||||||
|
route("/{id}") {
|
||||||
|
notarizedGet(testIdGetInfo) {
|
||||||
|
call.respondText("get by id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route("/single") {
|
||||||
|
notarizedGet(testSingleGetInfo) {
|
||||||
|
call.respondText("get single")
|
||||||
|
}
|
||||||
|
notarizedPost<A, B, C>(testSinglePostInfo) {
|
||||||
|
call.respondText("test post")
|
||||||
|
}
|
||||||
|
notarizedPut<A, B, D>(testSinglePutInfo) {
|
||||||
|
call.respondText { "hey" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route("/openapi.json") {
|
||||||
|
get {
|
||||||
|
call.respond(openApiSpec.copy(
|
||||||
|
info = OpenApiSpecInfo(
|
||||||
|
title = "Test API",
|
||||||
|
version = "1.3.3.7",
|
||||||
|
description = "An amazing, fully-ish 😉 generated API spec"
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-7.1-20210328220041+0000-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -6,6 +6,7 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
implementation(libs.bundles.ktor)
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
||||||
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.0")
|
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.0")
|
||||||
|
@ -1,12 +1,128 @@
|
|||||||
package org.leafygreens.kompendium
|
package org.leafygreens.kompendium
|
||||||
|
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpec
|
import io.ktor.application.ApplicationCall
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecInfo
|
import io.ktor.http.HttpMethod
|
||||||
|
import io.ktor.routing.Route
|
||||||
|
import io.ktor.routing.createRouteFromPath
|
||||||
|
import io.ktor.routing.method
|
||||||
|
import io.ktor.util.pipeline.PipelineInterceptor
|
||||||
|
import java.lang.reflect.ParameterizedType
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.full.findAnnotation
|
||||||
|
import kotlin.reflect.full.memberProperties
|
||||||
|
import kotlin.reflect.jvm.javaField
|
||||||
|
import org.leafygreens.kompendium.annotations.KompendiumField
|
||||||
|
import org.leafygreens.kompendium.annotations.KompendiumInternal
|
||||||
|
import org.leafygreens.kompendium.models.oas.ArraySchema
|
||||||
|
import org.leafygreens.kompendium.models.oas.FormatSchema
|
||||||
|
import org.leafygreens.kompendium.models.oas.ObjectSchema
|
||||||
|
import org.leafygreens.kompendium.models.oas.OpenApiSpec
|
||||||
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecComponentSchema
|
||||||
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo
|
||||||
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItem
|
||||||
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItemOperation
|
||||||
|
import org.leafygreens.kompendium.models.oas.SimpleSchema
|
||||||
|
import org.leafygreens.kompendium.models.meta.MethodInfo
|
||||||
|
import org.leafygreens.kompendium.util.Helpers.calculatePath
|
||||||
|
import org.leafygreens.kompendium.util.Helpers.putPairIfAbsent
|
||||||
|
|
||||||
class Kompendium {
|
object Kompendium {
|
||||||
val spec = OpenApiSpec(
|
val openApiSpec = OpenApiSpec(
|
||||||
info = OpenApiSpecInfo(),
|
info = OpenApiSpecInfo(),
|
||||||
servers = mutableListOf(),
|
servers = mutableListOf(),
|
||||||
paths = mutableMapOf()
|
paths = mutableMapOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun Route.notarizedGet(info: MethodInfo, body: PipelineInterceptor<Unit, ApplicationCall>): Route {
|
||||||
|
val path = calculatePath()
|
||||||
|
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
|
||||||
|
openApiSpec.paths[path]?.get = OpenApiSpecPathItemOperation(
|
||||||
|
summary = info.summary,
|
||||||
|
description = info.description,
|
||||||
|
tags = info.tags
|
||||||
|
)
|
||||||
|
return method(HttpMethod.Get) { handle(body) }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified TQ : Any, reified TP : Any, reified TR : Any> Route.notarizedPost(
|
||||||
|
info: MethodInfo,
|
||||||
|
noinline body: PipelineInterceptor<Unit, ApplicationCall>
|
||||||
|
): Route = generateComponentSchemas<TQ, TP, TR>(info, body) { i, b ->
|
||||||
|
val path = calculatePath()
|
||||||
|
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
|
||||||
|
openApiSpec.paths[path]?.post = OpenApiSpecPathItemOperation(
|
||||||
|
summary = i.summary,
|
||||||
|
description = i.description,
|
||||||
|
tags = i.tags
|
||||||
|
)
|
||||||
|
return method(HttpMethod.Post) { handle(b) }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified TQ : Any, reified TP : Any, reified TR : Any> Route.notarizedPut(
|
||||||
|
info: MethodInfo,
|
||||||
|
noinline body: PipelineInterceptor<Unit, ApplicationCall>,
|
||||||
|
): Route = generateComponentSchemas<TQ, TP, TR>(info, body) { i, b ->
|
||||||
|
val path = calculatePath()
|
||||||
|
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
|
||||||
|
openApiSpec.paths[path]?.put = OpenApiSpecPathItemOperation(
|
||||||
|
summary = i.summary,
|
||||||
|
description = i.description,
|
||||||
|
tags = i.tags
|
||||||
|
)
|
||||||
|
return method(HttpMethod.Put) { handle(b) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(KompendiumInternal::class)
|
||||||
|
inline fun <reified TQ : Any, reified TP : Any, reified TR : Any> generateComponentSchemas(
|
||||||
|
info: MethodInfo,
|
||||||
|
noinline body: PipelineInterceptor<Unit, ApplicationCall>,
|
||||||
|
block: (MethodInfo, PipelineInterceptor<Unit, ApplicationCall>) -> Route
|
||||||
|
): Route {
|
||||||
|
openApiSpec.components.schemas.putPairIfAbsent(objectSchemaPair(TQ::class))
|
||||||
|
openApiSpec.components.schemas.putPairIfAbsent(objectSchemaPair(TR::class))
|
||||||
|
openApiSpec.components.schemas.putPairIfAbsent(objectSchemaPair(TP::class))
|
||||||
|
return block.invoke(info, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
@KompendiumInternal
|
||||||
|
// TODO Investigate a caching mechanism to reduce overhead... then just reference once created
|
||||||
|
fun objectSchemaPair(clazz: KClass<*>): Pair<String, ObjectSchema> {
|
||||||
|
val o = objectSchema(clazz)
|
||||||
|
return Pair(clazz.qualifiedName!!, o)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun objectSchema(clazz: KClass<*>): ObjectSchema =
|
||||||
|
ObjectSchema(properties = clazz.memberProperties.associate { prop ->
|
||||||
|
val field = prop.javaField?.type?.kotlin
|
||||||
|
val anny = prop.findAnnotation<KompendiumField>()
|
||||||
|
val schema = when (field) {
|
||||||
|
List::class -> listFieldSchema(prop)
|
||||||
|
else -> fieldToSchema(field as KClass<*>)
|
||||||
|
}
|
||||||
|
|
||||||
|
val name = anny?.let {
|
||||||
|
anny.name
|
||||||
|
} ?: prop.name
|
||||||
|
|
||||||
|
Pair(name, schema)
|
||||||
|
})
|
||||||
|
|
||||||
|
private fun listFieldSchema(prop: KProperty<*>): ArraySchema {
|
||||||
|
val listType = ((prop.javaField?.genericType
|
||||||
|
as ParameterizedType).actualTypeArguments.first()
|
||||||
|
as Class<*>).kotlin
|
||||||
|
return ArraySchema(fieldToSchema(listType))
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(KompendiumInternal::class)
|
||||||
|
private fun fieldToSchema(field: KClass<*>): OpenApiSpecComponentSchema = when (field) {
|
||||||
|
Int::class -> FormatSchema("int32", "integer")
|
||||||
|
Long::class -> FormatSchema("int64", "integer")
|
||||||
|
Double::class -> FormatSchema("double", "number")
|
||||||
|
Float::class -> FormatSchema("float", "number")
|
||||||
|
String::class -> SimpleSchema("string")
|
||||||
|
Boolean::class -> SimpleSchema("boolean")
|
||||||
|
else -> objectSchema(field)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package org.leafygreens.kompendium.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Target(AnnotationTarget.PROPERTY)
|
||||||
|
annotation class KompendiumField(val name: String)
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.leafygreens.kompendium.annotations
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
@RequiresOptIn(
|
||||||
|
level = RequiresOptIn.Level.WARNING,
|
||||||
|
message = "This API internal to Kompendium and should not be used. It could be removed or changed without notice."
|
||||||
|
)
|
||||||
|
@Experimental(level = Experimental.Level.WARNING)
|
||||||
|
@Target(
|
||||||
|
AnnotationTarget.CLASS,
|
||||||
|
AnnotationTarget.TYPEALIAS,
|
||||||
|
AnnotationTarget.FUNCTION,
|
||||||
|
AnnotationTarget.PROPERTY,
|
||||||
|
AnnotationTarget.FIELD,
|
||||||
|
AnnotationTarget.CONSTRUCTOR,
|
||||||
|
AnnotationTarget.PROPERTY_SETTER
|
||||||
|
)
|
||||||
|
annotation class KompendiumInternal
|
@ -1,14 +0,0 @@
|
|||||||
package org.leafygreens.kompendium.models
|
|
||||||
|
|
||||||
data class OpenApiSpec(
|
|
||||||
val openapi: String = "3.0.3",
|
|
||||||
val info: OpenApiSpecInfo? = null,
|
|
||||||
// TODO Needs to default to server object with url of `/`
|
|
||||||
val servers: MutableList<OpenApiSpecServer>? = null,
|
|
||||||
val paths: MutableMap<String, OpenApiSpecPathItem>? = null,
|
|
||||||
val components: OpenApiSpecComponents? = null,
|
|
||||||
// todo needs to reference objects in the components -> security scheme 🤔
|
|
||||||
val security: List<Map<String, List<String>>>? = null,
|
|
||||||
val tags: List<OpenApiSpecTag>? = null,
|
|
||||||
val externalDocs: OpenApiSpecExternalDocumentation? = null
|
|
||||||
)
|
|
@ -1,6 +0,0 @@
|
|||||||
package org.leafygreens.kompendium.models
|
|
||||||
|
|
||||||
// TODO I *think* the only thing I need here is the security https://swagger.io/specification/#components-object
|
|
||||||
data class OpenApiSpecComponents(
|
|
||||||
val securitySchemes: Map<String, OpenApiSpecSchema>
|
|
||||||
)
|
|
@ -1,16 +0,0 @@
|
|||||||
package org.leafygreens.kompendium.models
|
|
||||||
|
|
||||||
data class OpenApiSpecPathItem(
|
|
||||||
val summary: String? = null,
|
|
||||||
val description: String? = null,
|
|
||||||
val get: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val put: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val post: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val delete: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val options: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val head: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val patch: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val trace: OpenApiSpecPathItemOperation? = null,
|
|
||||||
val servers: List<OpenApiSpecServer>? = null,
|
|
||||||
val parameters: List<OpenApiSpecReferencable>? = null
|
|
||||||
)
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.leafygreens.kompendium.models
|
|
||||||
|
|
||||||
data class OpenApiSpecPathItemOperation(
|
|
||||||
val tags: Set<String> = emptySet(),
|
|
||||||
val summary: String? = null,
|
|
||||||
val description: String? = null,
|
|
||||||
val externalDocs: OpenApiSpecExternalDocumentation? = null,
|
|
||||||
val operationId: String? = null,
|
|
||||||
val parameters: List<OpenApiSpecReferencable>? = null,
|
|
||||||
val requestBody: OpenApiSpecReferencable? = null,
|
|
||||||
// TODO How to enforce `default` requirement 🧐
|
|
||||||
val responses: Map<String, OpenApiSpecReferencable>? = null,
|
|
||||||
val callbacks: Map<String, OpenApiSpecReferencable>? = null,
|
|
||||||
val deprecated: Boolean = false,
|
|
||||||
// todo big yikes... also needs to reference objects in the security scheme 🤔
|
|
||||||
val security: List<Map<String, List<String>>>? = null,
|
|
||||||
val servers: List<OpenApiSpecServer>? = null,
|
|
||||||
val `x-codegen-request-body-name`: String? = null
|
|
||||||
)
|
|
@ -0,0 +1,3 @@
|
|||||||
|
package org.leafygreens.kompendium.models.meta
|
||||||
|
|
||||||
|
data class MethodInfo(val summary: String, val description: String? = null, val tags: Set<String> = emptySet())
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
|
data class OpenApiSpec(
|
||||||
|
val openapi: String = "3.0.3",
|
||||||
|
val info: OpenApiSpecInfo,
|
||||||
|
// TODO Needs to default to server object with url of `/`
|
||||||
|
val servers: MutableList<OpenApiSpecServer> = mutableListOf(),
|
||||||
|
val paths: MutableMap<String, OpenApiSpecPathItem> = mutableMapOf(),
|
||||||
|
val components: OpenApiSpecComponents = OpenApiSpecComponents(),
|
||||||
|
// todo needs to reference objects in the components -> security scheme 🤔
|
||||||
|
val security: MutableList<Map<String, List<String>>> = mutableListOf(),
|
||||||
|
val tags: MutableList<OpenApiSpecTag> = mutableListOf(),
|
||||||
|
val externalDocs: OpenApiSpecExternalDocumentation? = null
|
||||||
|
)
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
|
// TODO Enum for type?
|
||||||
|
sealed class OpenApiSpecComponentSchema(open val type: String)
|
||||||
|
|
||||||
|
data class ObjectSchema(
|
||||||
|
val properties: Map<String, OpenApiSpecComponentSchema>
|
||||||
|
) : OpenApiSpecComponentSchema("object")
|
||||||
|
|
||||||
|
data class SimpleSchema(override val type: String) : OpenApiSpecComponentSchema(type)
|
||||||
|
|
||||||
|
data class FormatSchema(val format: String, override val type: String) : OpenApiSpecComponentSchema(type)
|
||||||
|
|
||||||
|
data class ArraySchema(val items: OpenApiSpecComponentSchema) : OpenApiSpecComponentSchema("array")
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
|
// TODO I *think* the only thing I need here is the security https://swagger.io/specification/#components-object
|
||||||
|
data class OpenApiSpecComponents(
|
||||||
|
val schemas: MutableMap<String, OpenApiSpecComponentSchema> = mutableMapOf(),
|
||||||
|
val securitySchemes: MutableMap<String, OpenApiSpecSchema> = mutableMapOf()
|
||||||
|
)
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
data class OpenApiSpecLink(
|
data class OpenApiSpecLink(
|
||||||
val operationRef: String?, // todo mutually exclusive with operationId
|
val operationRef: String?, // todo mutually exclusive with operationId
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
// TODO Oof -> https://swagger.io/specification/#media-type-object
|
// TODO Oof -> https://swagger.io/specification/#media-type-object
|
||||||
data class OpenApiSpecMediaType(
|
data class OpenApiSpecMediaType(
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
data class OpenApiSpecOAuthFlows(
|
data class OpenApiSpecOAuthFlows(
|
||||||
val implicit: OpenApiSpecOAuthFlow?,
|
val implicit: OpenApiSpecOAuthFlow?,
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
|
data class OpenApiSpecPathItem(
|
||||||
|
var get: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var put: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var post: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var delete: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var options: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var head: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var patch: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var trace: OpenApiSpecPathItemOperation? = null,
|
||||||
|
var servers: List<OpenApiSpecServer>? = null,
|
||||||
|
var parameters: List<OpenApiSpecReferencable>? = null
|
||||||
|
)
|
@ -0,0 +1,19 @@
|
|||||||
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
|
data class OpenApiSpecPathItemOperation(
|
||||||
|
var tags: Set<String> = emptySet(),
|
||||||
|
var summary: String? = null,
|
||||||
|
var description: String? = null,
|
||||||
|
var externalDocs: OpenApiSpecExternalDocumentation? = null,
|
||||||
|
var operationId: String? = null,
|
||||||
|
var parameters: List<OpenApiSpecReferencable>? = null,
|
||||||
|
var requestBody: OpenApiSpecReferencable? = null,
|
||||||
|
// TODO How to enforce `default` requirement 🧐
|
||||||
|
var responses: Map<String, OpenApiSpecReferencable>? = null,
|
||||||
|
var callbacks: Map<String, OpenApiSpecReferencable>? = null,
|
||||||
|
var deprecated: Boolean = false,
|
||||||
|
// todo big yikes... also needs to reference objects in the security scheme 🤔
|
||||||
|
var security: List<Map<String, List<String>>>? = null,
|
||||||
|
var servers: List<OpenApiSpecServer>? = null,
|
||||||
|
var `x-codegen-request-body-name`: String? = null
|
||||||
|
)
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
sealed class OpenApiSpecReferencable
|
sealed class OpenApiSpecReferencable
|
||||||
|
|
||||||
@ -9,10 +9,10 @@ data class OpenApiSpecCallback(
|
|||||||
) : OpenApiSpecReferencable()
|
) : OpenApiSpecReferencable()
|
||||||
|
|
||||||
data class OpenApiSpecResponse(
|
data class OpenApiSpecResponse(
|
||||||
val description: String? = null,
|
val description: String? = null,
|
||||||
val headers: Map<String, OpenApiSpecReferencable>? = null,
|
val headers: Map<String, OpenApiSpecReferencable>? = null,
|
||||||
val content: Map<String, OpenApiSpecMediaType>? = null,
|
val content: Map<String, OpenApiSpecMediaType>? = null,
|
||||||
val links: Map<String, OpenApiSpecReferencable>? = null
|
val links: Map<String, OpenApiSpecReferencable>? = null
|
||||||
) : OpenApiSpecReferencable()
|
) : OpenApiSpecReferencable()
|
||||||
|
|
||||||
data class OpenApiSpecHeader(
|
data class OpenApiSpecHeader(
|
||||||
@ -34,7 +34,7 @@ data class OpenApiSpecParameter(
|
|||||||
) : OpenApiSpecReferencable()
|
) : OpenApiSpecReferencable()
|
||||||
|
|
||||||
data class OpenApiSpecRequest(
|
data class OpenApiSpecRequest(
|
||||||
val description: String?,
|
val description: String?,
|
||||||
val content: Map<String, OpenApiSpecMediaType>,
|
val content: Map<String, OpenApiSpecMediaType>,
|
||||||
val required: Boolean = false
|
val required: Boolean = false
|
||||||
) : OpenApiSpecReferencable()
|
) : OpenApiSpecReferencable()
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
sealed class OpenApiSpecSchema
|
sealed class OpenApiSpecSchema
|
||||||
|
|
||||||
@ -21,11 +21,11 @@ data class OpenApiSpecSchemaRef(
|
|||||||
) : OpenApiSpecSchema()
|
) : OpenApiSpecSchema()
|
||||||
|
|
||||||
data class OpenApiSpecSchemaSecurity(
|
data class OpenApiSpecSchemaSecurity(
|
||||||
val type: String? = null, // TODO Enum? "apiKey", "http", "oauth2", "openIdConnect"
|
val type: String? = null, // TODO Enum? "apiKey", "http", "oauth2", "openIdConnect"
|
||||||
val name: String? = null,
|
val name: String? = null,
|
||||||
val `in`: String? = null,
|
val `in`: String? = null,
|
||||||
val scheme: String? = null,
|
val scheme: String? = null,
|
||||||
val flows: OpenApiSpecOAuthFlows? = null,
|
val flows: OpenApiSpecOAuthFlows? = null,
|
||||||
val bearerFormat: String? = null,
|
val bearerFormat: String? = null,
|
||||||
val description: String? = null,
|
val description: String? = null,
|
||||||
) : OpenApiSpecSchema()
|
) : OpenApiSpecSchema()
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
data class OpenApiSpecServerVariable(
|
data class OpenApiSpecServerVariable(
|
||||||
val `enum`: Set<String>, // todo enforce not empty
|
val `enum`: Set<String>, // todo enforce not empty
|
@ -1,4 +1,4 @@
|
|||||||
package org.leafygreens.kompendium.models
|
package org.leafygreens.kompendium.models.oas
|
||||||
|
|
||||||
data class OpenApiSpecTag(
|
data class OpenApiSpecTag(
|
||||||
val name: String,
|
val name: String,
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.leafygreens.kompendium.util
|
||||||
|
|
||||||
|
import io.ktor.routing.PathSegmentConstantRouteSelector
|
||||||
|
import io.ktor.routing.PathSegmentParameterRouteSelector
|
||||||
|
import io.ktor.routing.RootRouteSelector
|
||||||
|
import io.ktor.routing.Route
|
||||||
|
import io.ktor.util.InternalAPI
|
||||||
|
|
||||||
|
object Helpers {
|
||||||
|
|
||||||
|
@OptIn(InternalAPI::class)
|
||||||
|
fun Route.calculatePath(tail: String = ""): String = when (selector) {
|
||||||
|
is RootRouteSelector -> tail
|
||||||
|
is PathSegmentParameterRouteSelector -> parent?.calculatePath("/$selector$tail") ?: "/{$selector}$tail"
|
||||||
|
is PathSegmentConstantRouteSelector -> parent?.calculatePath("/$selector$tail") ?: "/$selector$tail"
|
||||||
|
else -> error("unknown selector type $selector")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K, V> MutableMap<K, V>.putPairIfAbsent(pair: Pair<K, V>) = putIfAbsent(pair.first, pair.second)
|
||||||
|
|
||||||
|
}
|
@ -7,8 +7,7 @@ internal class KompendiumTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Kompendium can be instantiated with no details`() {
|
fun `Kompendium can be instantiated with no details`() {
|
||||||
val kompendium = Kompendium()
|
assertEquals(Kompendium.openApiSpec.openapi, "3.0.3", "Kompendium has a default spec version of 3.0.3")
|
||||||
assertEquals(kompendium.spec.openapi, "3.0.3", "Kompendium has a default spec version of 3.0.3")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,26 +2,26 @@ package org.leafygreens.kompendium.util
|
|||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpec
|
import org.leafygreens.kompendium.models.oas.OpenApiSpec
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecComponents
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecComponents
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecExternalDocumentation
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecExternalDocumentation
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecInfo
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecInfoContact
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfoContact
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecInfoLicense
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfoLicense
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecMediaType
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecMediaType
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecOAuthFlow
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecOAuthFlow
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecOAuthFlows
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecOAuthFlows
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecParameter
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecParameter
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecPathItem
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItem
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecPathItemOperation
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItemOperation
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecRequest
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecRequest
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecResponse
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecResponse
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecSchemaArray
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaArray
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecSchemaRef
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaRef
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecSchemaSecurity
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaSecurity
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecSchemaString
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaString
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecServer
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecServer
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecTag
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecTag
|
||||||
|
|
||||||
object TestData {
|
object TestData {
|
||||||
fun getFileSnapshot(fileName: String): String {
|
fun getFileSnapshot(fileName: String): String {
|
||||||
@ -61,7 +61,7 @@ object TestData {
|
|||||||
url = URI("http://petstore.swagger.io/v2")
|
url = URI("http://petstore.swagger.io/v2")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
tags = listOf(
|
tags = mutableListOf(
|
||||||
OpenApiSpecTag(
|
OpenApiSpecTag(
|
||||||
name = "pet",
|
name = "pet",
|
||||||
description = "Everything about your Pets",
|
description = "Everything about your Pets",
|
||||||
@ -201,7 +201,7 @@ object TestData {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
components = OpenApiSpecComponents(
|
components = OpenApiSpecComponents(
|
||||||
securitySchemes = mapOf(
|
securitySchemes = mutableMapOf(
|
||||||
"petstore_auth" to OpenApiSpecSchemaSecurity(
|
"petstore_auth" to OpenApiSpecSchemaSecurity(
|
||||||
type = "oauth2",
|
type = "oauth2",
|
||||||
flows = OpenApiSpecOAuthFlows(
|
flows = OpenApiSpecOAuthFlows(
|
||||||
@ -219,7 +219,8 @@ object TestData {
|
|||||||
name = "api_key",
|
name = "api_key",
|
||||||
`in` = "header"
|
`in` = "header"
|
||||||
)
|
)
|
||||||
)
|
),
|
||||||
|
schemas = mutableMapOf()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components" : {
|
"components" : {
|
||||||
|
"schemas" : { },
|
||||||
"securitySchemes" : {
|
"securitySchemes" : {
|
||||||
"petstore_auth" : {
|
"petstore_auth" : {
|
||||||
"type" : "oauth2",
|
"type" : "oauth2",
|
||||||
@ -173,6 +174,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"security" : [ ],
|
||||||
"tags" : [ {
|
"tags" : [ {
|
||||||
"name" : "pet",
|
"name" : "pet",
|
||||||
"description" : "Everything about your Pets",
|
"description" : "Everything about your Pets",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("kapt")
|
|
||||||
application
|
application
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8,7 +7,6 @@ dependencies {
|
|||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
|
||||||
implementation(projects.kompendiumCore)
|
implementation(projects.kompendiumCore)
|
||||||
kapt(projects.kompendiumProcessor)
|
|
||||||
|
|
||||||
implementation(libs.bundles.ktor)
|
implementation(libs.bundles.ktor)
|
||||||
implementation(libs.bundles.logging)
|
implementation(libs.bundles.logging)
|
||||||
|
@ -2,47 +2,85 @@ package org.leafygreens.kompendium.playground
|
|||||||
|
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
import io.ktor.application.install
|
||||||
|
import io.ktor.features.ContentNegotiation
|
||||||
|
import io.ktor.jackson.jackson
|
||||||
|
import io.ktor.response.respond
|
||||||
import io.ktor.response.respondText
|
import io.ktor.response.respondText
|
||||||
import io.ktor.routing.get
|
import io.ktor.routing.get
|
||||||
import io.ktor.routing.route
|
import io.ktor.routing.route
|
||||||
import io.ktor.routing.routing
|
import io.ktor.routing.routing
|
||||||
import io.ktor.server.engine.embeddedServer
|
import io.ktor.server.engine.embeddedServer
|
||||||
import io.ktor.server.netty.Netty
|
import io.ktor.server.netty.Netty
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumContact
|
import org.leafygreens.kompendium.Kompendium.notarizedGet
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumInfo
|
import org.leafygreens.kompendium.Kompendium.notarizedPost
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumLicense
|
import org.leafygreens.kompendium.Kompendium.notarizedPut
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumModule
|
import org.leafygreens.kompendium.Kompendium.openApiSpec
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumServers
|
import org.leafygreens.kompendium.annotations.KompendiumField
|
||||||
|
import org.leafygreens.kompendium.models.meta.MethodInfo
|
||||||
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo
|
||||||
|
import org.leafygreens.kompendium.playground.KompendiumTOC.testIdGetInfo
|
||||||
|
import org.leafygreens.kompendium.playground.KompendiumTOC.testSingleGetInfo
|
||||||
|
import org.leafygreens.kompendium.playground.KompendiumTOC.testSinglePostInfo
|
||||||
|
import org.leafygreens.kompendium.playground.KompendiumTOC.testSinglePutInfo
|
||||||
|
|
||||||
@KompendiumInfo(
|
|
||||||
title = "Test API",
|
|
||||||
version = "0.0.1",
|
|
||||||
description = "An API for testing"
|
|
||||||
)
|
|
||||||
@KompendiumContact(
|
|
||||||
name = "Homer Simpson",
|
|
||||||
url = "https://en.wikipedia.org/wiki/The_Simpsons",
|
|
||||||
email = "chunkylover53@aol.com"
|
|
||||||
)
|
|
||||||
@KompendiumLicense(
|
|
||||||
name = "DOH",
|
|
||||||
url = "https://opensource.org/licenses/DOH"
|
|
||||||
)
|
|
||||||
@KompendiumServers(urls = [ "https://thesimpsonsquoteapi.glitch.me/quotes" ])
|
|
||||||
fun main() {
|
fun main() {
|
||||||
embeddedServer(
|
embeddedServer(
|
||||||
Netty,
|
Netty,
|
||||||
port = 8080,
|
port = 8081,
|
||||||
module = Application::mainModule
|
module = Application::mainModule
|
||||||
).start(wait = true)
|
).start(wait = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@KompendiumModule
|
data class A(val a: String, val aa: Int, val aaa: List<Long>)
|
||||||
|
data class B(
|
||||||
|
@KompendiumField(name = "AYY")
|
||||||
|
val a: A,
|
||||||
|
val b: Double,
|
||||||
|
)
|
||||||
|
data class C(val c: String)
|
||||||
|
|
||||||
|
data class D(val a: A, val b: B, val c: C)
|
||||||
|
|
||||||
|
object KompendiumTOC {
|
||||||
|
val testIdGetInfo = MethodInfo("Get Test", "Test for getting", tags = setOf("test", "example", "get"))
|
||||||
|
val testSingleGetInfo = MethodInfo("Another get test", "testing more")
|
||||||
|
val testSinglePostInfo = MethodInfo("Test post endpoint", "Post your tests here!")
|
||||||
|
val testSinglePutInfo = MethodInfo("Test put endpoint", "Put your tests here!")
|
||||||
|
}
|
||||||
|
|
||||||
fun Application.mainModule() {
|
fun Application.mainModule() {
|
||||||
|
install(ContentNegotiation) {
|
||||||
|
jackson()
|
||||||
|
}
|
||||||
routing {
|
routing {
|
||||||
route("/") {
|
route("/test") {
|
||||||
|
route("/{id}") {
|
||||||
|
notarizedGet(testIdGetInfo) {
|
||||||
|
call.respondText("get by id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route("/single") {
|
||||||
|
notarizedGet(testSingleGetInfo) {
|
||||||
|
call.respondText("get single")
|
||||||
|
}
|
||||||
|
notarizedPost<A, B, C>(testSinglePostInfo) {
|
||||||
|
call.respondText("test post")
|
||||||
|
}
|
||||||
|
notarizedPut<A, B, D>(testSinglePutInfo) {
|
||||||
|
call.respondText { "hey" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route("/openapi.json") {
|
||||||
get {
|
get {
|
||||||
call.respondText("hi")
|
call.respond(openApiSpec.copy(
|
||||||
|
info = OpenApiSpecInfo(
|
||||||
|
title = "Test API",
|
||||||
|
version = "1.3.3.7",
|
||||||
|
description = "An amazing, fully-ish 😉 generated API spec"
|
||||||
|
)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
plugins {
|
|
||||||
kotlin("kapt")
|
|
||||||
`java-library`
|
|
||||||
`maven-publish`
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
|
||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
|
||||||
implementation(projects.kompendiumCore)
|
|
||||||
implementation("com.google.auto.service:auto-service:1.0")
|
|
||||||
kapt("com.google.auto.service:auto-service:1.0")
|
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
|
||||||
}
|
|
||||||
//
|
|
||||||
//publishing {
|
|
||||||
// repositories {
|
|
||||||
// maven {
|
|
||||||
// name = "GithubPackages"
|
|
||||||
// url = uri("https://maven.pkg.github.com/lg-backbone/kompendium")
|
|
||||||
// credentials {
|
|
||||||
// username = System.getenv("GITHUB_ACTOR")
|
|
||||||
// password = System.getenv("GITHUB_TOKEN")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// publications {
|
|
||||||
// create<MavenPublication>("kompendium") {
|
|
||||||
// from(components["kotlin"])
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
@ -1,112 +0,0 @@
|
|||||||
package org.leafygreens.kompendium.processor
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService
|
|
||||||
import java.net.URI
|
|
||||||
import javax.annotation.processing.AbstractProcessor
|
|
||||||
import javax.annotation.processing.Processor
|
|
||||||
import javax.annotation.processing.RoundEnvironment
|
|
||||||
import javax.annotation.processing.SupportedSourceVersion
|
|
||||||
import javax.lang.model.SourceVersion
|
|
||||||
import javax.lang.model.element.TypeElement
|
|
||||||
import org.leafygreens.kompendium.Kompendium
|
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumContact
|
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumInfo
|
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumLicense
|
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumModule
|
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumServers
|
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecInfoContact
|
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecInfoLicense
|
|
||||||
import org.leafygreens.kompendium.models.OpenApiSpecServer
|
|
||||||
|
|
||||||
@AutoService(Processor::class)
|
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
|
||||||
class KompendiumProcessor : AbstractProcessor() {
|
|
||||||
|
|
||||||
private val kompendium = Kompendium()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val KAPT_KOTLIN_GENERATED_OPTION_NAME = "kapt.kotlin.generated"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSupportedAnnotationTypes(): MutableSet<String> {
|
|
||||||
return mutableSetOf(
|
|
||||||
KompendiumInfo::class.java.canonicalName,
|
|
||||||
KompendiumContact::class.java.canonicalName,
|
|
||||||
KompendiumLicense::class.java.canonicalName,
|
|
||||||
KompendiumServers::class.java.canonicalName,
|
|
||||||
KompendiumModule::class.java.canonicalName
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Throw error if more than 1 info, contact, etc.?
|
|
||||||
override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment?): Boolean {
|
|
||||||
roundEnv?.getElementsAnnotatedWith(KompendiumInfo::class.java)?.forEach {
|
|
||||||
val info = it.getAnnotation(KompendiumInfo::class.java)
|
|
||||||
processKompendiumInfo(info)
|
|
||||||
}
|
|
||||||
roundEnv?.getElementsAnnotatedWith(KompendiumContact::class.java)?.forEach {
|
|
||||||
val contact = it.getAnnotation(KompendiumContact::class.java)
|
|
||||||
processKompendiumContact(contact)
|
|
||||||
}
|
|
||||||
roundEnv?.getElementsAnnotatedWith(KompendiumLicense::class.java)?.forEach {
|
|
||||||
val license = it.getAnnotation(KompendiumLicense::class.java)
|
|
||||||
processKompendiumLicense(license)
|
|
||||||
}
|
|
||||||
roundEnv?.getElementsAnnotatedWith(KompendiumServers::class.java)?.forEach {
|
|
||||||
val servers = it.getAnnotation(KompendiumServers::class.java)
|
|
||||||
processKompendiumServers(servers)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processKompendiumInfo(info: KompendiumInfo) {
|
|
||||||
kompendium.spec.info?.apply {
|
|
||||||
this.title = info.title
|
|
||||||
this.version = info.version
|
|
||||||
info.description.blankToNull()?.let { desc ->
|
|
||||||
this.description = desc
|
|
||||||
}
|
|
||||||
info.termsOfService.blankToNull()?.let { tos ->
|
|
||||||
this.termsOfService = URI(tos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processKompendiumContact(contact: KompendiumContact) {
|
|
||||||
kompendium.spec.info?.apply {
|
|
||||||
this.contact = OpenApiSpecInfoContact(
|
|
||||||
name = contact.name
|
|
||||||
).apply {
|
|
||||||
contact.url.blankToNull()?.let { url ->
|
|
||||||
this.url = URI(url)
|
|
||||||
}
|
|
||||||
contact.email.blankToNull()?.let { email ->
|
|
||||||
this.email = email
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processKompendiumLicense(license: KompendiumLicense) {
|
|
||||||
kompendium.spec.info?.apply {
|
|
||||||
this.license = OpenApiSpecInfoLicense(
|
|
||||||
name = license.name
|
|
||||||
).apply {
|
|
||||||
license.url.blankToNull()?.let { url ->
|
|
||||||
this.url = URI(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processKompendiumServers(servers: KompendiumServers) {
|
|
||||||
servers.urls.forEach { url ->
|
|
||||||
kompendium.spec.servers?.add(OpenApiSpecServer(URI(url)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.blankToNull(): String? = ifBlank {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
rootProject.name = "kompendium"
|
rootProject.name = "kompendium"
|
||||||
include("kompendium-core")
|
include("kompendium-core")
|
||||||
include("kompendium-processor")
|
|
||||||
include("kompendium-playground")
|
include("kompendium-playground")
|
||||||
|
|
||||||
// Feature Previews
|
// Feature Previews
|
||||||
|
Reference in New Issue
Block a user