diff --git a/build.gradle.kts b/build.gradle.kts index 6c3a40cd..24f192b7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,11 +1,15 @@ -import co.anitrend.support.query.builder.buildSrc.plugins.resolver.handleDependencySelection -import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask +// Top-level build file where you can add configuration options common to all sub-projects/modules. +import org.jetbrains.dokka.gradle.DokkaMultiModuleTask plugins { - id("com.github.ben-manes.versions") + id("org.jetbrains.dokka") } buildscript { + repositories { + google() + mavenCentral() + } dependencies { classpath(libs.android.gradle.plugin) classpath(libs.jetbrains.kotlin.gradle) @@ -28,17 +32,7 @@ tasks { } } -tasks.named( - "dependencyUpdates", - DependencyUpdatesTask::class.java -).configure { - checkForGradleUpdate = false - outputFormatter = "json" - outputDir = "build/dependencyUpdates" - reportfileName = "report" - resolutionStrategy { - componentSelection { - all { handleDependencySelection() } - } - } -} \ No newline at end of file +tasks.withType(DokkaMultiModuleTask::class.java) { + outputDirectory.set(rootProject.file("dokka-docs")) + failOnWarning.set(false) +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index cc34ac8e..76e1b471 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,7 +1,6 @@ plugins { `kotlin-dsl` `maven-publish` - `version-catalog` } repositories { @@ -25,9 +24,6 @@ dependencies { /* Depend on the dokka plugin, since we want to access it in our plugin */ implementation(libs.jetbrains.dokka.gradle) - /** Dependency management */ - implementation(libs.gradle.versions) - /** Spotless */ implementation(libs.spotless.gradle) diff --git a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/module/Modules.kt b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/module/Modules.kt index d263fdea..6a2f37e7 100644 --- a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/module/Modules.kt +++ b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/module/Modules.kt @@ -16,7 +16,8 @@ internal object Modules { } enum class Processor(override val id: String) : Module { - Kapt("processor") + Kapt("processor"), + Ksp("processor") } enum class Common(override val id: String) : Module { diff --git a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectConfiguration.kt b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectConfiguration.kt index 66edce4b..71b29c50 100644 --- a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectConfiguration.kt +++ b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectConfiguration.kt @@ -1,17 +1,18 @@ package co.anitrend.support.query.builder.buildSrc.plugins.components -import co.anitrend.support.query.builder.buildSrc.extension.* import co.anitrend.support.query.builder.buildSrc.extension.baseAppExtension import co.anitrend.support.query.builder.buildSrc.extension.baseExtension +import co.anitrend.support.query.builder.buildSrc.extension.isSampleModule +import co.anitrend.support.query.builder.buildSrc.extension.props import com.android.build.gradle.internal.dsl.DefaultConfig import org.gradle.api.JavaVersion import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.dsl.KotlinCompile +import org.gradle.api.tasks.testing.Test +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile import java.io.File - -@Suppress("UnstableApiUsage") private fun DefaultConfig.applyAdditionalConfiguration(project: Project) { if (project.isSampleModule()) { applicationId = "co.anitrend.support.query.builder.sample" @@ -93,18 +94,22 @@ internal fun Project.configureAndroid(): Unit = baseExtension().run { targetCompatibility = JavaVersion.VERSION_17 } - tasks.withType(KotlinCompile::class.java) { + tasks.withType(KotlinCompilationTask::class.java) { val compilerArgumentOptions = emptyList() - kotlinOptions { - allWarningsAsErrors = false - freeCompilerArgs = compilerArgumentOptions + compilerOptions { + allWarningsAsErrors.set(false) + freeCompilerArgs.addAll(compilerArgumentOptions) } } + tasks.withType(Test::class.java) { + useJUnitPlatform() + } + tasks.withType(KotlinJvmCompile::class.java) { - kotlinOptions { - jvmTarget = "17" + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) } } } diff --git a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectPlugins.kt b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectPlugins.kt index 6b24c361..3e7c383f 100644 --- a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectPlugins.kt +++ b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectPlugins.kt @@ -1,10 +1,10 @@ package co.anitrend.support.query.builder.buildSrc.plugins.components +import co.anitrend.support.query.builder.buildSrc.extension.isKotlinLibraryGroup +import co.anitrend.support.query.builder.buildSrc.extension.isProcessorModule +import co.anitrend.support.query.builder.buildSrc.extension.isSampleModule import org.gradle.api.Project import org.gradle.api.plugins.PluginContainer -import co.anitrend.support.query.builder.buildSrc.extension.isSampleModule -import co.anitrend.support.query.builder.buildSrc.extension.isProcessorModule -import co.anitrend.support.query.builder.buildSrc.extension.isKotlinLibraryGroup private fun addAndroidPlugin(project: Project, pluginContainer: PluginContainer) { when { @@ -29,13 +29,14 @@ private fun addKotlinAndroidPlugin(project: Project, pluginContainer: PluginCont } private fun addAnnotationProcessor(project: Project, pluginContainer: PluginContainer) { - if (project.isSampleModule() || project.isProcessorModule()) + if (project.isSampleModule() || project.isProcessorModule()) { pluginContainer.apply("kotlin-kapt") + } } internal fun Project.configurePlugins() { addAndroidPlugin(project, plugins) addKotlinAndroidPlugin(project, plugins) - addAnnotationProcessor(project, plugins) + //addAnnotationProcessor(project, plugins) } diff --git a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectProperties.kt b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectProperties.kt index ebf38568..16112d25 100644 --- a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectProperties.kt +++ b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/components/ProjectProperties.kt @@ -10,11 +10,11 @@ enum class PropertyTypes(val key: String) { VERSION("version"), } -class PropertiesReader(project: Project) { +class PropertiesReader(project: Project, path: String = "gradle/version.properties") { private val properties = Properties(2) init { - val releaseFile = File(project.rootDir, "gradle/version.properties") + val releaseFile = File(project.rootDir, path) if (!releaseFile.exists()) { project.logger.error("Release file cannot be found in path: $releaseFile") } @@ -28,4 +28,4 @@ class PropertiesReader(project: Project) { return properties.getProperty(type.key) ?: throw IllegalStateException("$type properties were not initialized") } -} \ No newline at end of file +} diff --git a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/resolver/ConfigurationResolver.kt b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/resolver/ConfigurationResolver.kt index 305d4662..d5c96399 100644 --- a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/resolver/ConfigurationResolver.kt +++ b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/resolver/ConfigurationResolver.kt @@ -1,14 +1 @@ package co.anitrend.support.query.builder.buildSrc.plugins.resolver - -import com.github.benmanes.gradle.versions.updates.resolutionstrategy.ComponentSelectionWithCurrent - -fun ComponentSelectionWithCurrent.handleDependencySelection() { - val reject = listOf("preview", "m", "rc", "alpha", "beta") - .map { qualifier -> - val pattern = "(?i).*[.-]$qualifier[.\\d-]*" - Regex(pattern, RegexOption.IGNORE_CASE) - } - .any { it.matches(candidate.version) } - if (reject) - reject("$candidate version does not fit acceptance criteria") -} \ No newline at end of file diff --git a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/strategy/DependencyStrategy.kt b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/strategy/DependencyStrategy.kt index 99b9a218..ef717dfc 100644 --- a/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/strategy/DependencyStrategy.kt +++ b/buildSrc/src/main/java/co/anitrend/support/query/builder/buildSrc/plugins/strategy/DependencyStrategy.kt @@ -1,6 +1,9 @@ package co.anitrend.support.query.builder.buildSrc.plugins.strategy -import co.anitrend.support.query.builder.buildSrc.extension.* +import co.anitrend.support.query.builder.buildSrc.extension.implementation +import co.anitrend.support.query.builder.buildSrc.extension.isSampleModule +import co.anitrend.support.query.builder.buildSrc.extension.libs +import co.anitrend.support.query.builder.buildSrc.extension.test import org.gradle.api.Project import org.gradle.api.artifacts.dsl.DependencyHandler @@ -12,13 +15,14 @@ internal class DependencyStrategy(private val project: Project) { test(project.libs.junit) test(project.libs.mockk) + test(project.libs.jetbrains.kotlin.test) } private fun DependencyHandler.applyLifeCycleDependencies() { implementation(project.libs.androidx.lifecycle.extensions) - implementation(project.libs.androidx.lifecycle.runTimeKtx) - implementation(project.libs.androidx.lifecycle.liveDataKtx) - implementation(project.libs.androidx.lifecycle.liveDataCoreKtx) + implementation(project.libs.androidx.lifecycle.runTime.ktx) + implementation(project.libs.androidx.lifecycle.liveData.ktx) + implementation(project.libs.androidx.lifecycle.liveDataCore.ktx) } fun applyDependenciesOn(handler: DependencyHandler) { diff --git a/core-ext/build.gradle.kts b/core-ext/build.gradle.kts index e67a393b..f649a113 100644 --- a/core-ext/build.gradle.kts +++ b/core-ext/build.gradle.kts @@ -13,5 +13,5 @@ tasks.withType { dependencies { implementation(project(":core")) - implementation(libs.androidx.sqliteKtx) + implementation(libs.androidx.sqlite.ktx) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93e58160..ad74a109 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -ktlint = "1.1.1" +ktlint = "1.5.0" gradle-plugin = "8.10.1" @@ -19,33 +19,40 @@ io-mockk = "1.14.2" spek2-spek = "2.0.19" +google-devtools-ksp = "2.0.0-1.0.22" [plugins] android-junit5 = { id = "de.mannodermaus.android-junit5", version = "1.12.2.0" } +google-devtools-ksp = { id = "com.google.devtools.ksp", version.ref = "google-devtools-ksp" } + [libraries] -timber = "com.jakewharton.timber:timber:5.0.1" -junit = "junit:junit:4.13.2" +timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" } +junit = { module ="junit:junit", version = "4.13.2" } android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "gradle-plugin" } -androidx-activityKtx = "androidx.activity:activity-ktx:1.10.1" +androidx-activity = { module = "androidx.activity:activity", version = "1.10.1" } +androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version = "1.10.1" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } androidx-appcompatResources = { module = "androidx.appcompat:appcompat-resources", version.ref = "androidx-appcompat" } androidx-constraintLayout = "androidx.constraintlayout:constraintlayout:2.2.1" -androidx-fragmentKtx = "androidx.fragment:fragment-ktx:1.8.7" +androidx-fragment = { module = "androidx.fragment:fragment", version = "1.8.7" } +androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version = "1.8.7" } -androidx-lifecycle-extensions = "androidx.lifecycle:lifecycle-extensions:2.2.0" -androidx-lifecycle-runTimeKtx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } -androidx-lifecycle-liveDataKtx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } -androidx-lifecycle-liveDataCoreKtx = { module = "androidx.lifecycle:lifecycle-livedata-core-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-extensions = { module = "androidx.lifecycle:lifecycle-extensions", version = "2.2.0" } +androidx-lifecycle-runTime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-liveData-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-liveDataCore-ktx = { module = "androidx.lifecycle:lifecycle-livedata-core-ktx", version.ref = "androidx-lifecycle" } -androidx-navigation-fragmentKtx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" } -androidx-navigation-uiKtx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" } +androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" } +androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment", version.ref = "androidx-navigation" } +androidx-navigation-ui = { module = "androidx.navigation:navigation-ui", version.ref = "androidx-navigation" } +androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" } androidx-room-common = { module = "androidx.room:room-common", version.ref = "androidx-room" } @@ -53,15 +60,13 @@ androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = " androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" } androidx-sqlite = { module = "androidx.sqlite:sqlite", version.ref = "androidx-sqlite" } -androidx-sqliteKtx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "androidx-sqlite" } +androidx-sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "androidx-sqlite" } androidx-test-core = { module = "androidx.test:core", version = "1.6.1" } -androidx-test-coreKtx = { module = "androidx.test:core-ktx", version = "1.6.1" } +androidx-test-core-ktx = { module = "androidx.test:core-ktx", version = "1.6.1" } androidx-test-runner = { module = "androidx.test:runner", version = "1.6.2" } androidx-test-rules = { module = "androidx.test:rules", version = "1.6.1" } -androidx-junitKtx = { module = "androidx.test.ext:junit-ktx", version.ref = "androidx-test-ext" } - google-auto-service = "com.google.auto.service:auto-service:1.1.1" google-android-material = "com.google.android.material:material:1.12.0" @@ -69,21 +74,22 @@ jetbrains-dokka-gradle = { module = "org.jetbrains.dokka:dokka-gradle-plugin", v jetbrains-kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "jetbrains-kotlin" } jetbrains-kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "jetbrains-kotlin" } jetbrains-kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "jetbrains-kotlin" } +jetbrains-kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "jetbrains-kotlin" } mockk = { module = "io.mockk:mockk", version.ref = "io-mockk" } mockk-android = { module = "io.mockk:mockk-android", version.ref = "io-mockk" } -gradle-versions = "com.github.ben-manes:gradle-versions-plugin:0.52.0" +spotless-gradle = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "7.0.2" } -spotless-gradle = "com.diffplug.spotless:spotless-plugin-gradle:7.0.4" +spotless-gradle = "com.diffplug.spotless:spotless-plugin-gradle:7.0.3" +pintrest-ktlint = { module = "com.pinterest:ktlint", version.ref = "ktlint" } squareup-kotlinpoet = "com.squareup:kotlinpoet:2.2.0" -tschuchortdev-kotlin-compile-testing = "com.github.tschuchortdev:kotlin-compile-testing:1.6.0" +google-devtools-ksp-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "google-devtools-ksp" } +kotlin-compile-testing-ksp = { module = "com.github.tschuchortdev:kotlin-compile-testing-ksp", version = "1.6.0" } gradle-plugins-android-junit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.12.2.0" spek2-spek-dsl-jvm = { module = "org.spekframework.spek2:spek-dsl-jvm", version.ref = "spek2-spek" } spek2-spek-runner-junit5 = { module = "org.spekframework.spek2:spek-runner-junit5", version.ref = "spek2-spek" } - -pintrest-ktlint = { module = "com.pinterest:ktlint", version.ref = "ktlint" } diff --git a/processor/build.gradle.kts b/processor/build.gradle.kts index 0842e824..31185134 100644 --- a/processor/build.gradle.kts +++ b/processor/build.gradle.kts @@ -1,21 +1,23 @@ plugins { id("co.anitrend.support.query.builder.plugin") + alias(libs.plugins.google.devtools.ksp) } -tasks.withType { - dependsOn(":annotations:classesJar") -} +dependencies { + implementation(project(":annotations")) -tasks.withType { - dependsOn(":processor:classesJar") -} + api(libs.squareup.kotlinpoet) + compileOnly(libs.androidx.room.common) + implementation(libs.google.devtools.ksp.api) -dependencies { - compileOnly(libs.google.auto.service) - kapt(libs.google.auto.service) + testImplementation(libs.jetbrains.kotlin.test) + testImplementation(libs.kotlin.compile.testing.ksp) +} - api(libs.squareup.kotlinpoet) - compileOnly(libs.androidx.room.common) +tasks.withType(Test::class.java) { + dependsOn(":annotations:classesJar") +} - implementation(project(":annotations")) +tasks.test { + useJUnitPlatform() } diff --git a/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/EntitySchemaProcessor.kt b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/EntitySchemaProcessor.kt index e3443faf..76923480 100644 --- a/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/EntitySchemaProcessor.kt +++ b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/EntitySchemaProcessor.kt @@ -20,36 +20,27 @@ import androidx.room.ColumnInfo import androidx.room.Embedded import androidx.room.Entity import co.anitrend.support.query.builder.annotation.EntitySchema -import co.anitrend.support.query.builder.processor.extensions.createCandidate -import co.anitrend.support.query.builder.processor.factory.ClassFactory -import co.anitrend.support.query.builder.processor.logger.CoreLogger -import co.anitrend.support.query.builder.processor.logger.contract.ILogger -import com.google.auto.service.AutoService -import javax.annotation.processing.AbstractProcessor -import javax.annotation.processing.ProcessingEnvironment -import javax.annotation.processing.Processor -import javax.annotation.processing.RoundEnvironment -import javax.lang.model.SourceVersion -import javax.lang.model.element.TypeElement -import javax.lang.model.util.Elements -import javax.lang.model.util.Types +import co.anitrend.support.query.builder.processor.codegen.EntitySchemaCodeGenerator +import com.google.devtools.ksp.processing.CodeGenerator +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSClassDeclaration -@AutoService(Processor::class) -class EntitySchemaProcessor : AbstractProcessor() { +class EntitySchemaProcessor( + codeGenerator: CodeGenerator, + private val logger: KSPLogger, + private val options: Map, +) : SymbolProcessor { - private lateinit var logger: ILogger - private lateinit var types: Types - private lateinit var elements: Elements + private val navParamCodeGenerator = + EntitySchemaCodeGenerator( + codeGenerator = codeGenerator, + logger = logger, + ) - override fun init(processingEnv: ProcessingEnvironment) { - super.init(processingEnv) - logger = CoreLogger(processingEnv.messager) - types = processingEnv.typeUtils - elements = processingEnv.elementUtils - logger.lineBreakWithSeparatorCharacter() - } - - override fun getSupportedAnnotationTypes() = setOf( + private fun getSupportedAnnotationTypes() = setOf( EntitySchema::class.java.canonicalName, ColumnInfo::class.java.canonicalName, Embedded::class.java.canonicalName, @@ -57,23 +48,24 @@ class EntitySchemaProcessor : AbstractProcessor() { ) /** - * If [EntitySchema] has any overrides we'd specify them here + * Called by Kotlin Symbol Processing to run the processing task. + * + * @param resolver provides [SymbolProcessor] with access to compiler details such as Symbols. + * @return A list of deferred symbols that the processor can't process. Only symbols that can't be processed at this round should be returned. Symbols in compiled code (libraries) are always valid and are ignored if returned in the deferral list. */ - override fun getSupportedOptions() = emptySet() + override fun process(resolver: Resolver): List { + val schema = requireNotNull(EntitySchema::class.qualifiedName) + + val schemaSymbols = resolver.getSymbolsWithAnnotation(schema) + .filterIsInstance() + + logger.logging("Available candidates: [${schemaSymbols.joinToString(separator = ", ")}]") - override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported() + schemaSymbols + .groupBy { it.parentDeclaration?.qualifiedName?.asString() } + .map(transform = Map.Entry>::value) + .forEach(action = navParamCodeGenerator::invoke) - override fun process( - annotations: MutableSet, - roundEnvironment: RoundEnvironment, - ): Boolean { - val elementItems = roundEnvironment.getElementsAnnotatedWith( - EntitySchema::class.java, - ).map { element -> element.createCandidate(types, logger, roundEnvironment) } - if (elementItems.isNotEmpty()) { - logger.debug("Available candidates: [${elementItems.joinToString(separator = ", ")}]") - ClassFactory(processingEnv, elements, logger).generateUsing(elementItems) - } - return true + return emptyList() } } diff --git a/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/EntitySchemaCodeGenerator.kt b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/EntitySchemaCodeGenerator.kt new file mode 100644 index 00000000..f2e27f4c --- /dev/null +++ b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/EntitySchemaCodeGenerator.kt @@ -0,0 +1,22 @@ +package co.anitrend.support.query.builder.processor.codegen + +import co.anitrend.support.query.builder.processor.codegen.contract.ICodeGenerator +import co.anitrend.support.query.builder.processor.model.KSCandidate +import com.google.devtools.ksp.processing.CodeGenerator +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.symbol.KSClassDeclaration + +class EntitySchemaCodeGenerator( + private val codeGenerator: CodeGenerator, + private val logger: KSPLogger, +) : ICodeGenerator { + override fun invoke(classes: List) { + val candidates = classes.map { + KSCandidate( + classDeclaration = it, + logger = logger + ) + } + + } +} diff --git a/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/contract/ICodeGenerator.kt b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/contract/ICodeGenerator.kt new file mode 100644 index 00000000..67c55124 --- /dev/null +++ b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/contract/ICodeGenerator.kt @@ -0,0 +1,7 @@ +package co.anitrend.support.query.builder.processor.codegen.contract + +import com.google.devtools.ksp.symbol.KSClassDeclaration + +interface ICodeGenerator { + operator fun invoke(classes: List) +} diff --git a/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/extension/CodeAnalyserExtension.kt b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/extension/CodeAnalyserExtension.kt new file mode 100644 index 00000000..59adf931 --- /dev/null +++ b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/codegen/extension/CodeAnalyserExtension.kt @@ -0,0 +1,6 @@ +package co.anitrend.support.query.builder.processor.codegen.extension + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSValueArgument + +fun KSClassDeclaration.annotationArgOf(block: (KSValueArgument) -> Boolean) = annotations.flatMap { it.arguments }.first(block) diff --git a/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/model/KSCandidate.kt b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/model/KSCandidate.kt new file mode 100644 index 00000000..a5adb7b3 --- /dev/null +++ b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/model/KSCandidate.kt @@ -0,0 +1,56 @@ +package co.anitrend.support.query.builder.processor.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import co.anitrend.support.query.builder.processor.model.column.ColumnItem +import co.anitrend.support.query.builder.processor.model.core.Item +import co.anitrend.support.query.builder.processor.model.embed.EmbedItem +import co.anitrend.support.query.builder.processor.model.table.TableItem +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.symbol.KSClassDeclaration + +internal class KSCandidate( + private val classDeclaration: KSClassDeclaration, + private val logger: KSPLogger +) { + val packageName: String = classDeclaration.packageName.asString() + val className: String = classDeclaration.simpleName.asString() + val fileName: String = "${className}Schema" + + private fun getColumns(): List { + val fieldColumns = classDeclaration.annotations.filter { + it.shortName.getQualifier() == ColumnInfo::class.java.simpleName + } + return fieldColumns.map { fieldColumn -> + val columnName = fieldColumn.arguments.find { argument -> + argument.name?.getShortName() == ColumnInfo::name.name + }?.value as String + ColumnItem( + name = columnName, + fieldName = fieldColumn.shortName.asString() + ) + }.toList() + } + + private fun getEmbedded(): List { + return emptyList() + } + + fun getTable(): Item { + val entity = classDeclaration.annotations.find { + it.shortName.getQualifier() == Entity::class.qualifiedName + } + + val tableName = entity?.arguments?.find { + it.name?.getShortName() == Entity::tableName.name + }?.value as String + + return TableItem( + name = tableName, + columns = getColumns(), + embedded = getEmbedded(), + ) + } + + override fun toString(): String = classDeclaration.simpleName.asString() +} diff --git a/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/provider/EntitySchemaProcessorProvider.kt b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/provider/EntitySchemaProcessorProvider.kt new file mode 100644 index 00000000..4dd3f4e2 --- /dev/null +++ b/processor/src/main/kotlin/co/anitrend/support/query/builder/processor/provider/EntitySchemaProcessorProvider.kt @@ -0,0 +1,16 @@ +package co.anitrend.support.query.builder.processor.provider + +import co.anitrend.support.query.builder.processor.EntitySchemaProcessor +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.processing.SymbolProcessorProvider + +class EntitySchemaProcessorProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { + return EntitySchemaProcessor( + codeGenerator = environment.codeGenerator, + logger = environment.logger, + options = environment.options, + ) + } +} diff --git a/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 00000000..8f189d6f --- /dev/null +++ b/processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +co.anitrend.support.query.builder.processor.EntitySchemaProcessor diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 58a5373e..840cbddc 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("co.anitrend.support.query.builder.plugin") + alias(libs.plugins.google.devtools.ksp) } android { @@ -11,24 +12,28 @@ tasks.withType { } dependencies { - implementation(libs.androidx.activityKtx) - implementation(libs.androidx.fragmentKtx) + implementation(libs.androidx.activity) + implementation(libs.androidx.activity.ktx) + implementation(libs.androidx.fragment) + implementation(libs.androidx.fragment.ktx) implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompatResources) implementation(libs.androidx.constraintLayout) - implementation(libs.androidx.navigation.fragmentKtx) - implementation(libs.androidx.navigation.uiKtx) + implementation(libs.androidx.navigation.fragment) + implementation(libs.androidx.navigation.fragment.ktx) + implementation(libs.androidx.navigation.ui) + implementation(libs.androidx.navigation.ui.ktx) implementation(libs.google.android.material) implementation(libs.androidx.room.ktx) implementation(libs.androidx.room.runtime) - kapt(libs.androidx.room.compiler) + ksp(libs.androidx.room.compiler) - androidTestImplementation(libs.androidx.test.coreKtx) + androidTestImplementation(libs.androidx.test.core.ktx) androidTestImplementation(libs.androidx.test.rules) androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.mockk.android) @@ -36,5 +41,5 @@ dependencies { implementation(project(":annotations")) implementation(project(":core")) implementation(project(":core-ext")) - kapt(project(":processor")) + ksp(project(":processor")) }