Skip to content

Commit

Permalink
Merge pull request #35 from AntonButov/bridge-core
Browse files Browse the repository at this point in the history
bridge-core
  • Loading branch information
AntonButov authored Dec 14, 2024
2 parents b76b8b7 + 2b7b7a9 commit b9c1bc5
Show file tree
Hide file tree
Showing 15 changed files with 248 additions and 56 deletions.
1 change: 0 additions & 1 deletion bridge/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ version = "1.0-SNAPSHOT"

dependencies {
implementation(platform(libs.openai.kotlin.bom))

implementation (libs.openai.kotlin)
runtimeOnly (libs.ktor)

Expand Down
27 changes: 27 additions & 0 deletions bridge/src/test/kotlin/BridgeCoreTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import com.code.factory.Bridge
import com.code.factory.BridgeImpl
import com.code.factory.OpenAiService
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.mockk.coEvery
import io.mockk.mockk

class BridgeCoreTest: StringSpec({

lateinit var bridge: Bridge
lateinit var openAi: OpenAiService

beforeTest {
openAi = mockk(relaxed = true)
coEvery { openAi.getCode(any(), any()) } returns "AiCode"
bridge = BridgeImpl(
openAi = openAi
)
}

"when InterfaceFinder find interfaces bridge should to request code resolver for resolve id" {
val code = bridge.getCode("some code", "interface")
code shouldBe "AiCode"
}

})
1 change: 1 addition & 0 deletions ksp-processor/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ version = "0.0.1"

dependencies {
implementation(project(":utils"))
implementation(project(":writer"))
implementation(project(":bridge"))

implementation(kotlin("stdlib"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.code.factory

import com.code.factory.usescases.visitors.Visitor
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSDeclaration
import kotlin.sequences.forEach

interface AllDeclarationFinder {
fun getAllDeclaration(resolver: Resolver) : List<KSDeclaration>
}

internal class AllDeclarationFinderImpl : AllDeclarationFinder {
override fun getAllDeclaration(resolver: Resolver): List<KSDeclaration> {
return buildSet<KSDeclaration> {
resolver.getAllFiles().forEach {
it.accept(
visitor = Visitor {
add(it)
},
data = ""
)
}
}.filter {
it.qualifiedName?.asString() != "kotlin.Any"
}.filter {
it.qualifiedName?.asString() != "kotlin.Unit"
}
}
}

fun allDeclarationFinder(): AllDeclarationFinder = AllDeclarationFinderImpl()
17 changes: 17 additions & 0 deletions ksp-processor/src/main/kotlin/com/code/factory/CodeResolver.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.code.factory

import com.google.devtools.ksp.symbol.KSDeclaration

interface CodeResolver {
fun getCodeString(vararg declaration: KSDeclaration): String
}

internal class CodeResolverImpl: CodeResolver {
override fun getCodeString(vararg declaration: KSDeclaration): String {
return ""
}

}

fun codeResolver(): CodeResolver =
CodeResolverImpl()
28 changes: 28 additions & 0 deletions ksp-processor/src/main/kotlin/com/code/factory/InterfaceFinder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.code.factory

import com.code.factory.usescases.getClassKind
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSClassDeclaration

interface InterfaceFinder {
fun getInterfacesWithOutImplementation(resolver: Resolver): Sequence<KSClassDeclaration>
}

internal class InterfaceFinderImpl() : InterfaceFinder {
override fun getInterfacesWithOutImplementation(resolver: Resolver): Sequence<KSClassDeclaration> {
val interfaces = resolver.getClassKind(ClassKind.INTERFACE)
val classes = resolver.getClassKind(ClassKind.CLASS)

return interfaces.filter { interfaceItem ->
classes.none { classItem ->
classItem.superTypes.any { superType ->
superType.resolve().declaration.qualifiedName?.asString() ==
interfaceItem.qualifiedName?.asString()
}
}
}
}
}

fun interfaceFinder(): InterfaceFinder = InterfaceFinderImpl()
41 changes: 34 additions & 7 deletions ksp-processor/src/main/kotlin/com/code/factory/ksp/KspProcessor.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
package com.code.factory.ksp

import com.code.factory.AllDeclarationFinder
import com.code.factory.Bridge
import com.code.factory.CodeResolver
import com.code.factory.InterfaceFinder
import com.code.factory.Writer
import com.code.factory.allDeclarationFinder
import com.code.factory.bridge
import com.code.factory.codeResolver
import com.code.factory.interfaceFinder
import com.code.factory.writer
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSVisitorVoid
import kotlinx.coroutines.runBlocking

class KspProcessor(
val codeGenerator: CodeGenerator,
val logger: KSPLogger,
val bridge: Bridge
val writer: Writer,
val allDeclarationFinder: AllDeclarationFinder,
val interfaceFinder: InterfaceFinder,
val codeResolver: CodeResolver,
val bridge: Bridge,
) : SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
val context = "context"
val typesForCoding = "types"
runBlocking {
bridge.getCode(context,typesForCoding)
val allDeclarations = allDeclarationFinder.getAllDeclaration(resolver)
val context = codeResolver.getCodeString(*allDeclarations.toTypedArray())
val interfaceWithOutImplementation = interfaceFinder.getInterfacesWithOutImplementation(resolver).toList().firstOrNull() // todo only one yet
interfaceWithOutImplementation?.let {
val stringCode = bridge.getCode(context, interfaceWithOutImplementation.toString())
writer.write(stringCode, interfaceWithOutImplementation)
}
}
return emptyList()
}
Expand All @@ -25,8 +40,20 @@ class KspProcessor(
}
}

fun kspProcessorProvider(bridge: Bridge = bridge()) = object: SymbolProcessorProvider {
fun kspProcessorProvider(
bridge: Bridge = bridge(),
allDeclarationFinder: AllDeclarationFinder = allDeclarationFinder(),
interfaceFinder: InterfaceFinder = interfaceFinder(),
codeResolver: CodeResolver = codeResolver()
) = object : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return KspProcessor(environment.codeGenerator, environment.logger, bridge)
return KspProcessor(
logger = environment.logger,
writer = writer(),
allDeclarationFinder = allDeclarationFinder,
interfaceFinder = interfaceFinder,
codeResolver = codeResolver,
bridge = bridge
)
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
package com.code.factory.usescases

import com.code.factory.usescases.visitors.Visitor
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.*

fun Resolver.getInterfacesWithOutImplementation(): Sequence<KSClassDeclaration> {
val interfaces = getClassKind(ClassKind.INTERFACE)
val classes = getClassKind(ClassKind.CLASS)

return interfaces.filter { interfaceItem ->
classes.none { classItem ->
classItem.superTypes.any { superType ->
superType.resolve().declaration.qualifiedName?.asString() ==
interfaceItem.qualifiedName?.asString()
}
}
}
}
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSDeclaration

@Throws
fun Resolver.getClassDeclarationByNames(names: List<String>): List<KSDeclaration> =
Expand All @@ -29,20 +16,3 @@ fun Resolver.getClassKind(classKind: ClassKind): Sequence<KSClassDeclaration> =
file.declarations.filterIsInstance<KSClassDeclaration>()
.filter { it.classKind == classKind }
}

fun Resolver.getAllDeclarations(): List<KSDeclaration> {
return buildSet<KSDeclaration> {
getAllFiles().forEach {
it.accept(
visitor = Visitor {
add(it)
},
data = ""
)
}
}.filter {
it.qualifiedName?.asString() != "kotlin.Any"
}.filter {
it.qualifiedName?.asString() != "kotlin.Unit"
}
}
15 changes: 9 additions & 6 deletions ksp-processor/src/test/kotlin/FindInterfacesTest.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import com.code.factory.Bridge
import com.code.factory.ksp.KspProcessor
import com.code.factory.interfaceFinder
import com.code.factory.ksp.kspProcessorProvider
import com.code.factory.usescases.getInterfacesWithOutImplementation
import com.tschuchort.compiletesting.KotlinCompilation
import io.mockk.mockk
import utils.compilation
Expand Down Expand Up @@ -41,7 +40,7 @@ class FindInterfacesTest {
}
}
interface TwoInterface {
interface InterfaceWithOutImplementation {
fun one()
}
Expand All @@ -50,11 +49,15 @@ class FindInterfacesTest {
@Test
fun `should find two interfaces`() {
compilationForAssertations(testSource) {
val interfaceNames = getInterfacesWithOutImplementation().map {
val interfaceFinder = interfaceFinder()
val interfaceNames = interfaceFinder.getInterfacesWithOutImplementation(this).map {
it.qualifiedName!!.getShortName()
}.toList()
assertEquals(listOf("TwoInterface"), interfaceNames)
assertEquals("somePackage", getInterfacesWithOutImplementation().first().packageName.getShortName())
assertEquals(listOf("InterfaceWithOutImplementation"), interfaceNames)
assertEquals(
"somePackage",
interfaceFinder.getInterfacesWithOutImplementation(this).first().packageName.getShortName()
)
}
}
}
4 changes: 2 additions & 2 deletions ksp-processor/src/test/kotlin/FindTypesTest.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import com.code.factory.usescases.getAllDeclarations
import com.code.factory.AllDeclarationFinderImpl
import utils.compilationForAssertations
import kotlin.test.Test
import kotlin.test.assertEquals
Expand All @@ -21,7 +21,7 @@ class FindTypesTest {
""".trimIndent()

compilationForAssertations(typeASource, mainCode) {
assertEquals(listOf("A"), getAllDeclarations().map { it.toString() })
assertEquals(listOf("A"), AllDeclarationFinderImpl().getAllDeclaration(this).map { it.toString() })
}
}

Expand Down
61 changes: 54 additions & 7 deletions ksp-processor/src/test/kotlin/KspProcessorTest.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,67 @@
import com.code.factory.AllDeclarationFinder
import com.code.factory.Bridge
import com.code.factory.CodeResolver
import com.code.factory.InterfaceFinder
import com.code.factory.ksp.KspProcessor
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSDeclaration
import io.kotest.core.spec.style.StringSpec
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk

class KspProcessorTest : StringSpec({

"should call bridge get code" {
val bridge: Bridge = mockk(relaxed = true)
KspProcessor(
codeGenerator = mockk(relaxed = true),
lateinit var bridge: Bridge
lateinit var kspProcessor: KspProcessor
lateinit var codeResolver: CodeResolver
lateinit var allDeclarationFinder: AllDeclarationFinder
lateinit var interfaceFinder : InterfaceFinder
lateinit var resolver: Resolver
lateinit var types: Sequence<KSClassDeclaration>
lateinit var declarations: List<KSDeclaration>

beforeTest {
bridge = mockk(relaxed = true)
allDeclarationFinder = mockk()
resolver = mockk(relaxed = true)
declarations = listOf()
every {
allDeclarationFinder.getAllDeclaration(resolver)
} returns declarations
codeResolver = mockk(relaxed = true)
every {
codeResolver.getCodeString(*declarations.toTypedArray())
} returns "code context"
interfaceFinder = mockk(relaxed = true)
kspProcessor = KspProcessor(
logger = mockk(relaxed = true),
bridge = bridge
).process(mockk(relaxed = true))
writer = mockk(relaxed = true),
allDeclarationFinder = mockk(relaxed = true),
interfaceFinder = interfaceFinder,
codeResolver = codeResolver,
bridge = bridge,
)
types = sequenceOf(mockk(relaxed = true))
every {
interfaceFinder.getInterfacesWithOutImplementation(resolver)
} returns types
}

"should call InterfaceFinder for getting a types." {
kspProcessor.process(resolver)
coVerify { interfaceFinder.getInterfacesWithOutImplementation(resolver) }
}

"should call CodeResolver for getting a code." {
kspProcessor.process(resolver)
coVerify { codeResolver.getCodeString(*declarations.toTypedArray()) }
}

coVerify { bridge.getCode(any(), any()) }
"should call bridge get code" {
kspProcessor.process(resolver)
coVerify { bridge.getCode("code context", any()) }
}

})
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ include("bridge")
include("gradle-plugin")
include("ksp-processor")
include("utils")
include("writer")
23 changes: 23 additions & 0 deletions writer/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
kotlin("jvm")
}

group = "com.code.factory"
version = "unspecified"

repositories {
mavenCentral()
}

dependencies {
implementation(libs.kotlin.kspApi)

testImplementation(kotlin("test"))
}

tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(21)
}
Loading

0 comments on commit b9c1bc5

Please sign in to comment.