diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/plugin/NotarizedRoute.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/plugin/NotarizedRoute.kt index 4b6c1c792..4a3df5477 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/plugin/NotarizedRoute.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/plugin/NotarizedRoute.kt @@ -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 { diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt index 897fe3b0c..7a3e61ec8 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt @@ -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 diff --git a/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt b/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt index 448291dbe..4245e766b 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt @@ -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 diff --git a/core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt b/core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt index e2d936254..710a23ca0 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt @@ -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() + fun Routing.simpleRecursive() = basicGetGenerator() private inline fun Routing.basicGetGenerator( diff --git a/core/src/test/resources/T0044__nested_type_name.json b/core/src/test/resources/T0044__nested_type_name.json new file mode 100644 index 000000000..e27eb3825 --- /dev/null +++ b/core/src/test/resources/T0044__nested_type_name.json @@ -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": [] +} diff --git a/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt b/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt index cf5dcd6fa..b831f1f2e 100644 --- a/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt +++ b/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt @@ -141,3 +141,8 @@ data class ManyThings( data class Foosy(val test: T, val otherThing: List) data class Barzo(val result: G) + +object Nested { + @Serializable + data class Response(val idk: Boolean) +} diff --git a/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/util/Helpers.kt b/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/util/Helpers.kt index 252c9f1fc..f0c0e19eb 100644 --- a/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/util/Helpers.kt +++ b/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/util/Helpers.kt @@ -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()}-") } }