fix: nested class name support
This commit is contained in:
@ -4,32 +4,18 @@ import io.bkbn.kompendium.core.attribute.KompendiumAttributes
|
||||
import io.bkbn.kompendium.core.metadata.DeleteInfo
|
||||
import io.bkbn.kompendium.core.metadata.GetInfo
|
||||
import io.bkbn.kompendium.core.metadata.HeadInfo
|
||||
import io.bkbn.kompendium.core.metadata.MethodInfo
|
||||
import io.bkbn.kompendium.core.metadata.MethodInfoWithRequest
|
||||
import io.bkbn.kompendium.core.metadata.OptionsInfo
|
||||
import io.bkbn.kompendium.core.metadata.PatchInfo
|
||||
import io.bkbn.kompendium.core.metadata.PostInfo
|
||||
import io.bkbn.kompendium.core.metadata.PutInfo
|
||||
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
||||
import io.bkbn.kompendium.core.util.Helpers.addToSpec
|
||||
import io.bkbn.kompendium.core.util.Helpers.getReferenceSlug
|
||||
import io.bkbn.kompendium.core.util.Helpers.getSimpleSlug
|
||||
import io.bkbn.kompendium.core.util.SpecConfig
|
||||
import io.bkbn.kompendium.json.schema.SchemaGenerator
|
||||
import io.bkbn.kompendium.json.schema.definition.ReferenceDefinition
|
||||
import io.bkbn.kompendium.oas.OpenApiSpec
|
||||
import io.bkbn.kompendium.oas.path.Path
|
||||
import io.bkbn.kompendium.oas.path.PathOperation
|
||||
import io.bkbn.kompendium.oas.payload.MediaType
|
||||
import io.bkbn.kompendium.oas.payload.Parameter
|
||||
import io.bkbn.kompendium.oas.payload.Request
|
||||
import io.bkbn.kompendium.oas.payload.Response
|
||||
import io.ktor.server.application.ApplicationCallPipeline
|
||||
import io.ktor.server.application.Hook
|
||||
import io.ktor.server.application.createRouteScopedPlugin
|
||||
import io.ktor.server.routing.Route
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
object NotarizedRoute {
|
||||
|
||||
|
@ -10,9 +10,10 @@ import io.bkbn.kompendium.core.metadata.PatchInfo
|
||||
import io.bkbn.kompendium.core.metadata.PostInfo
|
||||
import io.bkbn.kompendium.core.metadata.PutInfo
|
||||
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
||||
import io.bkbn.kompendium.core.plugin.NotarizedRoute
|
||||
import io.bkbn.kompendium.json.schema.SchemaGenerator
|
||||
import io.bkbn.kompendium.json.schema.definition.ReferenceDefinition
|
||||
import io.bkbn.kompendium.json.schema.util.Helpers.getReferenceSlug
|
||||
import io.bkbn.kompendium.json.schema.util.Helpers.getSimpleSlug
|
||||
import io.bkbn.kompendium.oas.OpenApiSpec
|
||||
import io.bkbn.kompendium.oas.path.Path
|
||||
import io.bkbn.kompendium.oas.path.PathOperation
|
||||
@ -24,28 +25,6 @@ import kotlin.reflect.KType
|
||||
|
||||
object Helpers {
|
||||
|
||||
private const val COMPONENT_SLUG = "#/components/schemas"
|
||||
|
||||
fun KType.getSimpleSlug(): String = when {
|
||||
this.arguments.isNotEmpty() -> genericNameAdapter(this, classifier as KClass<*>)
|
||||
else -> (classifier as KClass<*>).simpleName ?: error("Could not determine simple name for $this")
|
||||
}
|
||||
|
||||
fun KType.getReferenceSlug(): String = when {
|
||||
arguments.isNotEmpty() -> "$COMPONENT_SLUG/${genericNameAdapter(this, classifier as KClass<*>)}"
|
||||
else -> "$COMPONENT_SLUG/${(classifier as KClass<*>).simpleName}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts a class with type parameters into a reference friendly string
|
||||
*/
|
||||
private fun genericNameAdapter(type: KType, clazz: KClass<*>): String {
|
||||
val classNames = type.arguments
|
||||
.map { it.type?.classifier as KClass<*> }
|
||||
.map { it.simpleName }
|
||||
return classNames.joinToString(separator = "-", prefix = "${clazz.simpleName}-")
|
||||
}
|
||||
|
||||
fun MethodInfo.addToSpec(path: Path, spec: OpenApiSpec, config: SpecConfig) {
|
||||
SchemaGenerator.fromTypeOrUnit(this.response.responseType, spec.components.schemas)?.let { schema ->
|
||||
spec.components.schemas[this.response.responseType.getSimpleSlug()] = schema
|
||||
|
@ -20,6 +20,7 @@ import io.bkbn.kompendium.core.util.TestModules.multipleExceptions
|
||||
import io.bkbn.kompendium.core.util.TestModules.nestedGenericCollection
|
||||
import io.bkbn.kompendium.core.util.TestModules.nestedGenericMultipleParamsCollection
|
||||
import io.bkbn.kompendium.core.util.TestModules.nestedGenericResponse
|
||||
import io.bkbn.kompendium.core.util.TestModules.nestedTypeName
|
||||
import io.bkbn.kompendium.core.util.TestModules.nonRequiredParam
|
||||
import io.bkbn.kompendium.core.util.TestModules.polymorphicException
|
||||
import io.bkbn.kompendium.core.util.TestModules.notarizedHead
|
||||
@ -200,6 +201,9 @@ class KompendiumTest : DescribeSpec({
|
||||
it("Can have a nullable reference without impacting base type") {
|
||||
openApiTestAllSerializers("T0041__nullable_reference.json") { nullableReference() }
|
||||
}
|
||||
it("Can handle nested type names") {
|
||||
openApiTestAllSerializers("T0044__nested_type_name.json") { nestedTypeName() }
|
||||
}
|
||||
}
|
||||
describe("Constraints") {
|
||||
// TODO Assess strategies here
|
||||
|
@ -12,6 +12,7 @@ import io.bkbn.kompendium.core.fixtures.Foosy
|
||||
import io.bkbn.kompendium.core.fixtures.Gibbity
|
||||
import io.bkbn.kompendium.core.fixtures.ManyThings
|
||||
import io.bkbn.kompendium.core.fixtures.MultiNestedGenerics
|
||||
import io.bkbn.kompendium.core.fixtures.Nested
|
||||
import io.bkbn.kompendium.core.fixtures.NullableEnum
|
||||
import io.bkbn.kompendium.core.fixtures.NullableField
|
||||
import io.bkbn.kompendium.core.fixtures.Page
|
||||
@ -599,6 +600,8 @@ object TestModules {
|
||||
)
|
||||
)
|
||||
|
||||
fun Routing.nestedTypeName() = basicGetGenerator<Nested.Response>()
|
||||
|
||||
fun Routing.simpleRecursive() = basicGetGenerator<ColumnSchema>()
|
||||
|
||||
private inline fun <reified T> Routing.basicGetGenerator(
|
||||
|
72
core/src/test/resources/T0044__nested_type_name.json
Normal file
72
core/src/test/resources/T0044__nested_type_name.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
|
||||
"info": {
|
||||
"title": "Test API",
|
||||
"version": "1.33.7",
|
||||
"description": "An amazing, fully-ish 😉 generated API spec",
|
||||
"termsOfService": "https://example.com",
|
||||
"contact": {
|
||||
"name": "Homer Simpson",
|
||||
"url": "https://gph.is/1NPUDiM",
|
||||
"email": "chunkylover53@aol.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://myawesomeapi.com",
|
||||
"description": "Production instance of my API"
|
||||
},
|
||||
{
|
||||
"url": "https://staging.myawesomeapi.com",
|
||||
"description": "Where the fun stuff happens"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/": {
|
||||
"get": {
|
||||
"tags": [],
|
||||
"summary": "Great Summary!",
|
||||
"description": "testing more",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A Successful Endeavor",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NestedResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": false
|
||||
},
|
||||
"parameters": []
|
||||
}
|
||||
},
|
||||
"webhooks": {},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"NestedResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"idk": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"idk"
|
||||
]
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
@ -141,3 +141,8 @@ data class ManyThings(
|
||||
|
||||
data class Foosy<T, K>(val test: T, val otherThing: List<K>)
|
||||
data class Barzo<G>(val result: G)
|
||||
|
||||
object Nested {
|
||||
@Serializable
|
||||
data class Response(val idk: Boolean)
|
||||
}
|
||||
|
@ -9,21 +9,26 @@ object Helpers {
|
||||
|
||||
fun KType.getSimpleSlug(): String = when {
|
||||
this.arguments.isNotEmpty() -> genericNameAdapter(this, classifier as KClass<*>)
|
||||
else -> (classifier as KClass<*>).simpleName ?: error("Could not determine simple name for $this")
|
||||
else -> (classifier as KClass<*>).kompendiumSlug() ?: error("Could not determine simple name for $this")
|
||||
}
|
||||
|
||||
fun KType.getReferenceSlug(): String = when {
|
||||
arguments.isNotEmpty() -> "$COMPONENT_SLUG/${genericNameAdapter(this, classifier as KClass<*>)}"
|
||||
else -> "$COMPONENT_SLUG/${(classifier as KClass<*>).simpleName}"
|
||||
else -> "$COMPONENT_SLUG/${(classifier as KClass<*>).kompendiumSlug()}"
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
private fun KClass<*>.kompendiumSlug(): String? {
|
||||
if (java.packageName == "java.lang") return simpleName
|
||||
if (java.packageName == "java.util") return simpleName
|
||||
val pkg = java.packageName
|
||||
return qualifiedName?.replace(pkg, "")?.replace(".", "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts a class with type parameters into a reference friendly string
|
||||
*/
|
||||
private fun genericNameAdapter(type: KType, clazz: KClass<*>): String {
|
||||
val classNames = type.arguments
|
||||
.map { it.type?.classifier as KClass<*> }
|
||||
.map { it.simpleName }
|
||||
return classNames.joinToString(separator = "-", prefix = "${clazz.simpleName}-")
|
||||
.map { it.kompendiumSlug() }
|
||||
return classNames.joinToString(separator = "-", prefix = "${clazz.kompendiumSlug()}-")
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user