All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.http4k.connect.plugin.Http4kConnectActionVisitor.kt Maven / Gradle / Ivy
package org.http4k.connect.plugin
import com.google.devtools.ksp.getAllSuperTypes
import com.google.devtools.ksp.getConstructors
import com.google.devtools.ksp.symbol.ClassKind.OBJECT
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSNode
import com.google.devtools.ksp.visitor.KSEmptyVisitor
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.ParameterSpec
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.asClassName
import com.squareup.kotlinpoet.asTypeName
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.toTypeName
import dev.forkhandles.result4k.Result4k
import org.http4k.connect.PagedAction
import org.http4k.connect.RemoteFailure
import java.util.Locale
class Http4kConnectActionVisitor(private val log: (Any?) -> Unit) :
KSEmptyVisitor>() {
override fun visitClassDeclaration(
classDeclaration: KSClassDeclaration,
data: KSClassDeclaration
): Sequence {
log("Processing " + classDeclaration.asStarProjectedType().declaration.qualifiedName!!.asString())
return classDeclaration.getConstructors().flatMap { ctr ->
listOfNotNull(
generateActionExtension(classDeclaration, data, ctr),
classDeclaration.takeIf {
it.getAllSuperTypes().map { it.toClassName().canonicalName }
.contains(PagedAction::class.qualifiedName)
}
?.let { generateActionPagination(classDeclaration, data, ctr) }
)
}
}
override fun defaultHandler(node: KSNode, data: KSClassDeclaration) = error("unsupported")
}
private fun generateActionPagination(
actionClass: KSClassDeclaration,
clientClazz: KSClassDeclaration,
ctr: KSFunctionDeclaration
) = generateExtensionFunction(
actionClass, clientClazz, ctr, "Paginated",
CodeBlock.of(
"return org.http4k.connect.paginated(::invoke, %T(${ctr.parameters.joinToString(", ") { it.name!!.asString() }}))",
actionClass.asType(emptyList()).toTypeName()
),
Sequence::class.asClassName().parameterizedBy(
Result4k::class.asClassName().parameterizedBy(
(actionClass.getAllFunctions()
.first { it.simpleName.getShortName() == "toResult" }
.returnType!!.resolve().arguments[0].type!!.resolve().declaration as KSClassDeclaration)
.getAllProperties().first { it.simpleName.getShortName() == "items" }.type.toTypeName(),
RemoteFailure::class.asTypeName()
)
)
)
private fun generateActionExtension(
actionClass: KSClassDeclaration,
clientClazz: KSClassDeclaration,
ctr: KSFunctionDeclaration
) = generateExtensionFunction(
actionClass, clientClazz, ctr, "",
CodeBlock.of(
when (actionClass.classKind) {
OBJECT -> "return invoke(%T)"
else -> "return invoke(%T(${ctr.parameters.joinToString(", ") { it.name!!.asString() }}))"
},
actionClass.asType(emptyList()).toTypeName()
),
actionClass.getAllFunctions()
.first { it.simpleName.getShortName() == "toResult" }.returnType!!.toTypeName()
)
private fun generateExtensionFunction(
actionClazz: KSClassDeclaration,
adapterClazz: KSClassDeclaration,
ctr: KSFunctionDeclaration,
suffix: String,
codeBlock: CodeBlock,
returnType: TypeName
): FunSpec {
val baseFunction = FunSpec.builder(
actionClazz.simpleName.asString().replaceFirstChar { it.lowercase(Locale.getDefault()) } + suffix)
.addKdoc("@see ${actionClazz.qualifiedName!!.asString().replace('/', '.')}")
.receiver(adapterClazz.toClassName())
.returns(returnType)
.addCode(codeBlock)
ctr.parameters.forEach {
val base = ParameterSpec.builder(it.name!!.asString(), it.type.toTypeName())
with(it.type.resolve()) {
if (isMarkedNullable) base.defaultValue(CodeBlock.of("null"))
else if (it.hasDefault) {
if (starProjection().toString() == "Map<*, *>") base.defaultValue(CodeBlock.of("emptyMap()"))
else if (starProjection().toString() == "List<*>") base.defaultValue(CodeBlock.of("emptyList()"))
else if (starProjection().toString() == "Set<*>") base.defaultValue(CodeBlock.of("emptySet()"))
else {
}
} else {
}
}
baseFunction.addParameter(base.build())
}
return baseFunction.build()
}