Skip to content

Repository files navigation

genkit

Base compartida para procesadores de anotaciones/símbolos con arquitectura hexagonal. Extrae, una sola vez, la parte de un processor que no es específica del dominio y que se reescribe (con bugs sutiles) en cada uno: modelo neutral de tipos, resolución de tipos, diagnósticos que acumulan, y un contrato de emisión neutral. Con dos frontends sobre el mismo modelo:

  • kspkit — frontend KSP (Kotlin Symbol Processing).
  • aptkit — frontend APT (javac annotation processing, para clases Java).

El nombre es deliberado: genkit-* es agnóstico del frontend. Un consumidor de solo-Java (vía aptkit) nunca depende de un artefacto llamado "ksp", y viceversa.

La usan kaudit y kvalid, y kmapx para su modelo de tipos.

Documentación (reutilizar genkit)

Para construir tu propio processor sobre genkit:

  • Crea tu processor — el flujo completo con un ejemplo mínimo (anotación → dominio → emisor → processor KSP) + cómo testear sin compilar.
  • Modelo y puertos — referencia de genkit-model (TypeRef, ClassModel, AnnotationArg…) y genkit-ports (TypeResolver, DiagnosticReporter, CodeWriter) + los dobles en memoria.
  • Frontends (KSP / APT) — cablear kspkit (Kotlin) y aptkit (Java), y la paridad entre ambos.
  • Sitio (MkDocs Material): mkdocs serve. Ejemplos completos: kaudit y kvalid.

Estado

v0.1 (io.github.kuroxbyte:genkit-*, kspkit, aptkit; Apache-2.0). 23 tests en verde (unidad + compile-testing real con kctfork KSP2 y javac ToolProvider). Probado por tres consumidores: la "prueba de fuego" — kvalid reutilizó los puertos de kaudit sin deformarlos.

Filosofía

Separar dominio (puro, testeable sin compilar) de infraestructura (KSP, APT, Poet):

  • El dominio de una librería depende solo de genkit-model y genkit-ports.
  • Un adaptador de entrada (kspkit para KSP, aptkit para APT) traduce sus símbolos a un modelo neutral: ningún KSNode ni javax.lang.model.Element sobrevive a la frontera.
  • La salida es un contrato neutral (GeneratedFile, texto); KotlinPoet/JavaPoet viven aislados en genkit-emit.

El pago: un adaptador K2 futuro (plugin de compilador) reutilizaría el 100% del dominio; y el dominio se testea con dobles en memoria → suites de cientos de casos en milisegundos.

Módulos

Módulo Rol Dependencias
genkit-model Modelo neutral: TypeRef/TypeKind, ClassModel/PropertyModel/…, AnnotationModel/AnnotationArg, SourceRef. Agnóstico del frontend. CERO
genkit-ports Puertos: TypeResolver, DiagnosticReporter, CodeWriter + GeneratedFile. Dobles en memoria vía test-fixtures. model
genkit-emit Puentes FileSpec.toGeneratedFile() (KotlinPoet) y JavaFile.toGeneratedFile() (JavaPoet). Aísla los toolkits de emisión. ports, KotlinPoet, JavaPoet
kspkit Frontend KSP: KspTranslator (KSP→modelo), KspTypeResolver, KspDiagnosticReporter (sobre KSPLogger), KspCodeWriter (sobre CodeGenerator), puente SourceRef↔KSNode. model, ports, KSP
aptkit Frontend APT (Java): AptTranslator (javax.lang.model→modelo, records + POJOs), AptTypeResolver, AptDiagnosticReporter (sobre Messager), AptCodeWriter (sobre Filer). model, ports, JDK

Puertos

interface TypeResolver {
    fun resolve(ref: TypeRef): ClassModel?
    fun isAnnotatedWith(ref: TypeRef, fqName: String): Boolean
}
interface DiagnosticReporter {          // acumula, no aborta al primer error
    fun error(code: String, message: String, at: SourceRef? = null)
    fun warn(code: String, message: String, at: SourceRef? = null)
    fun hasErrors(): Boolean
}
fun interface CodeWriter { fun write(file: GeneratedFile, origins: Set<SourceRef>) }
data class GeneratedFile(val packageName: String, val fileName: String, val content: String)

DiagnosticReporter usa códigos como String: cada librería define su propio espacio (kaudit.key.nullable, size.max). Los dobles en memoria se consumen con testImplementation(testFixtures("io.github.kuroxbyte:genkit-ports")).

Regla de aislamiento (doble candado)

*-core de cada librería (y genkit-model/genkit-ports) no compilan con dependencia a KSP ni Poet:

  1. Gradle — no se declara la dependencia.
  2. Konsist — un test de arquitectura falla si algún archivo importa com.google.devtools.ksp o com.squareup.kotlinpoet.

Consumir

// settings.gradle.kts del consumidor
includeBuild("../genkit")          // dev: substitución por proyecto

// build.gradle.kts del *-core (solo el modelo neutral)
dependencies {
    api("io.github.kuroxbyte:genkit-model:0.1.0")
    api("io.github.kuroxbyte:genkit-ports:0.1.0")
    testImplementation(testFixtures("io.github.kuroxbyte:genkit-ports:0.1.0"))
}
// el *-processor (KSP) añade io.github.kuroxbyte:kspkit
// la variante *-apt (Java)  añade io.github.kuroxbyte:aptkit

En release se usa la versión publicada; genkit se publica antes que sus consumidores.

Compilar desde el fuente

./gradlew build

Requisitos: JDK 17+.

About

Base hexagonal para construir tu propio processor de anotaciones/símbolos (KSP + APT) sobre un modelo neutral de tipos.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages