mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-06-29 21:07:33 +00:00
commit
0d825cf424
|
@ -1,5 +1,14 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.16.12
|
||||||
|
|
||||||
|
* `Repos`:
|
||||||
|
* `Exposed`:
|
||||||
|
* `CommonExposedRepo.selectByIds` uses `foldRight` by default instead of raw foreach
|
||||||
|
* `Koin`:
|
||||||
|
* `Generator`:
|
||||||
|
* Module has been created
|
||||||
|
|
||||||
## 0.16.11
|
## 0.16.11
|
||||||
|
|
||||||
* `LanguageCodes`:
|
* `LanguageCodes`:
|
||||||
|
|
|
@ -9,6 +9,7 @@ buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath libs.buildscript.kt.gradle
|
classpath libs.buildscript.kt.gradle
|
||||||
classpath libs.buildscript.kt.serialization
|
classpath libs.buildscript.kt.serialization
|
||||||
|
classpath libs.buildscript.kt.ksp
|
||||||
classpath libs.buildscript.jb.dokka
|
classpath libs.buildscript.jb.dokka
|
||||||
classpath libs.buildscript.gh.release
|
classpath libs.buildscript.gh.release
|
||||||
classpath libs.buildscript.android.gradle
|
classpath libs.buildscript.android.gradle
|
||||||
|
|
|
@ -29,6 +29,6 @@ allprojects {
|
||||||
defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
|
defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
|
||||||
|
|
||||||
publishGradlePath = "${rootProject.projectDir.absolutePath}/publish.gradle"
|
publishGradlePath = "${rootProject.projectDir.absolutePath}/publish.gradle"
|
||||||
publishMavenPath = "${rootProject.projectDir.absolutePath}/maven.publish.gradle"
|
publishJvmOnlyPath = "${rootProject.projectDir.absolutePath}/jvm.publish.gradle"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.16.11
|
version=0.16.12
|
||||||
android_code_version=179
|
android_code_version=180
|
||||||
|
|
|
@ -19,6 +19,9 @@ gh-release = "2.4.1"
|
||||||
|
|
||||||
koin = "3.3.2"
|
koin = "3.3.2"
|
||||||
|
|
||||||
|
ksp = "1.7.20-1.0.8"
|
||||||
|
kotlin-poet = "1.12.0"
|
||||||
|
|
||||||
android-gradle = "7.3.0"
|
android-gradle = "7.3.0"
|
||||||
dexcount = "3.1.0"
|
dexcount = "3.1.0"
|
||||||
|
|
||||||
|
@ -83,9 +86,16 @@ android-test-junit = { module = "androidx.test.ext:junit", version.ref = "androi
|
||||||
kt-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "kt" }
|
kt-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "kt" }
|
||||||
kt-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kt" }
|
kt-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kt" }
|
||||||
|
|
||||||
|
# ksp dependencies
|
||||||
|
|
||||||
|
kotlin-poet = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin-poet" }
|
||||||
|
ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
|
||||||
|
|
||||||
|
# Buildscript
|
||||||
|
|
||||||
buildscript-kt-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kt" }
|
buildscript-kt-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kt" }
|
||||||
buildscript-kt-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kt" }
|
buildscript-kt-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kt" }
|
||||||
|
buildscript-kt-ksp = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin", version.ref = "ksp" }
|
||||||
buildscript-jb-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "jb-dokka" }
|
buildscript-jb-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "jb-dokka" }
|
||||||
buildscript-gh-release = { module = "com.github.breadmoirai:github-release", version.ref = "gh-release" }
|
buildscript-gh-release = { module = "com.github.breadmoirai:github-release", version.ref = "gh-release" }
|
||||||
buildscript-android-gradle = { module = "com.android.tools.build:gradle", version.ref = "android-gradle" }
|
buildscript-android-gradle = { module = "com.android.tools.build:gradle", version.ref = "android-gradle" }
|
||||||
|
|
118
jvm.publish.gradle
Normal file
118
jvm.publish.gradle
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
|
task javadocJar(type: Jar) {
|
||||||
|
from javadoc
|
||||||
|
classifier = 'javadoc'
|
||||||
|
}
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
classifier = 'sources'
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
|
||||||
|
artifact javadocJar
|
||||||
|
artifact sourcesJar
|
||||||
|
|
||||||
|
pom {
|
||||||
|
resolveStrategy = Closure.DELEGATE_FIRST
|
||||||
|
|
||||||
|
description = "It is set of projects with micro tools for avoiding of routines coding"
|
||||||
|
name = "${project.name}"
|
||||||
|
url = "https://github.com/InsanusMokrassar/MicroUtils/"
|
||||||
|
|
||||||
|
scm {
|
||||||
|
developerConnection = "scm:git:[fetch=]https://github.com/InsanusMokrassar/MicroUtils.git[push=]https://github.com/InsanusMokrassar/MicroUtils.git"
|
||||||
|
url = "https://github.com/InsanusMokrassar/MicroUtils.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
|
||||||
|
developer {
|
||||||
|
id = "InsanusMokrassar"
|
||||||
|
name = "Aleksei Ovsiannikov"
|
||||||
|
email = "ovsyannikov.alexey95@gmail.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
developer {
|
||||||
|
id = "000Sanya"
|
||||||
|
name = "Syrov Aleksandr"
|
||||||
|
email = "000sanya.000sanya@gmail.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
|
||||||
|
license {
|
||||||
|
name = "Apache Software License 2.0"
|
||||||
|
url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
|
||||||
|
maven {
|
||||||
|
name = "GithubPackages"
|
||||||
|
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||||
|
|
||||||
|
credentials {
|
||||||
|
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
||||||
|
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
|
||||||
|
maven {
|
||||||
|
name = "Gitea"
|
||||||
|
url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
|
||||||
|
|
||||||
|
credentials(HttpHeaderCredentials) {
|
||||||
|
name = "Authorization"
|
||||||
|
value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
|
||||||
|
}
|
||||||
|
|
||||||
|
authentication {
|
||||||
|
header(HttpHeaderAuthentication)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||||
|
maven {
|
||||||
|
name = "sonatype"
|
||||||
|
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
|
||||||
|
|
||||||
|
credentials {
|
||||||
|
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||||
|
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.hasProperty("signing.gnupg.keyName")) {
|
||||||
|
apply plugin: 'signing'
|
||||||
|
|
||||||
|
signing {
|
||||||
|
useGpgCmd()
|
||||||
|
|
||||||
|
sign publishing.publications
|
||||||
|
}
|
||||||
|
|
||||||
|
task signAll {
|
||||||
|
tasks.withType(Sign).forEach {
|
||||||
|
dependsOn(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
jvm.publish.kpsb
Normal file
1
jvm.publish.kpsb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"Gitea","url":"https://git.inmo.dev/api/packages/InsanusMokrassar/maven","credsType":{"type":"dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository.CredentialsType.HttpHeaderCredentials","headerName":"Authorization","headerValueProperty":"GITEA_TOKEN"}},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}
|
100
koin/generator/README.md
Normal file
100
koin/generator/README.md
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
# Koin generator
|
||||||
|
|
||||||
|
It is Kotlin Symbol Processing generator for `Koin` module in `MicroUtils`.
|
||||||
|
|
||||||
|
1. [What may do this generator](#what-may-do-this-generator)
|
||||||
|
2. [How to add generator](#how-to-add-generator)
|
||||||
|
|
||||||
|
## What may do this generator
|
||||||
|
|
||||||
|
Let's imagine you want to have shortcuts in koin, to get something easily:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val koin: Koin// some initialization
|
||||||
|
|
||||||
|
val someUrl = koin.serverUrl
|
||||||
|
```
|
||||||
|
|
||||||
|
So, in that case you may mark containing file with next annotation (in the beginning of file):
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@file:GenerateKoinDefinition("serverUrl", String::class, nullable = false)
|
||||||
|
```
|
||||||
|
|
||||||
|
If file is called like `Sample.kt`, will be generated file `GeneratedDefinitionsSample.kt` with next content:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
public val Scope.serverUrl: String
|
||||||
|
get() = get(named("serverUrl"))
|
||||||
|
|
||||||
|
public val Koin.serverUrl: String
|
||||||
|
get() = get(named("serverUrl"))
|
||||||
|
|
||||||
|
public fun Module.serverUrlSingle(createdAtStart: Boolean = false,
|
||||||
|
definition: Definition<String>): KoinDefinition<String> =
|
||||||
|
single(named("serverUrl"), createdAtStart = createdAtStart, definition = definition)
|
||||||
|
|
||||||
|
public fun Module.serverUrlFactory(definition: Definition<String>):
|
||||||
|
KoinDefinition<String> = factory(named("serverUrl"), definition = definition)
|
||||||
|
```
|
||||||
|
|
||||||
|
Besides, you may use the generics:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@file:GenerateKoinDefinition("sampleInfo", Sample::class, G1::class, G2::class, nullable = false)
|
||||||
|
```
|
||||||
|
|
||||||
|
Will generate:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
public val Scope.sampleInfo: Sample<G1, G2>
|
||||||
|
get() = get(named("sampleInfo"))
|
||||||
|
|
||||||
|
public val Koin.sampleInfo: Sample<G1, G2>
|
||||||
|
get() = get(named("sampleInfo"))
|
||||||
|
|
||||||
|
public fun Module.sampleInfoSingle(createdAtStart: Boolean = false,
|
||||||
|
definition: Definition<Sample<G1, G2>>): KoinDefinition<Sample<G1, G2>> =
|
||||||
|
single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition)
|
||||||
|
|
||||||
|
public fun Module.sampleInfoFactory(definition: Definition<Sample<G1, G2>>):
|
||||||
|
KoinDefinition<Sample<G1, G2>> = factory(named("sampleInfo"), definition = definition)
|
||||||
|
```
|
||||||
|
|
||||||
|
In case you wish not to generate single:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@file:GenerateKoinDefinition("sampleInfo", Sample::class, G1::class, G2::class, nullable = false, generateSingle = false)
|
||||||
|
```
|
||||||
|
|
||||||
|
And you will take next code:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
public val Scope.sampleInfo: Sample<G1, G2>
|
||||||
|
get() = get(named("sampleInfo"))
|
||||||
|
|
||||||
|
public val Koin.sampleInfo: Sample<G1, G2>
|
||||||
|
get() = get(named("sampleInfo"))
|
||||||
|
|
||||||
|
public fun Module.sampleInfoFactory(definition: Definition<Sample<G1, G2>>):
|
||||||
|
KoinDefinition<Sample<G1, G2>> = factory(named("sampleInfo"), definition = definition)
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to add generator
|
||||||
|
|
||||||
|
**Note: $ksp_version in the samples above is equal to supported `ksp` version presented in `/gradle/libs.versions.toml` of project**
|
||||||
|
|
||||||
|
**Note: $microutils_version in the version of MicroUtils library in your project**
|
||||||
|
|
||||||
|
1. Add `classpath` in `build.gradle` (`classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp_version"`)
|
||||||
|
2. Add plugin to the plugins list of your module: `id "com.google.devtools.ksp"`
|
||||||
|
3. In `dependencies` block add to the required target/compile the dependency `dev.inmo:micro_utils.koin.generator:$microutils_version`:
|
||||||
|
```groovy
|
||||||
|
dependencies {
|
||||||
|
add("kspCommonMainMetadata", "dev.inmo:micro_utils.koin.generator:$microutils_version") // will work in commonMain of your multiplatform module
|
||||||
|
add("kspJvm", "dev.inmo:micro_utils.koin.generator:$microutils_version") // will work in main of your JVM module
|
||||||
|
}
|
||||||
|
|
||||||
|
ksp { // this generator do not require any arguments and we should left `ksp` empty
|
||||||
|
}
|
||||||
|
```
|
15
koin/generator/build.gradle
Normal file
15
koin/generator/build.gradle
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.jvm"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$publishJvmOnlyPath"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api project(":micro_utils.koin")
|
||||||
|
api libs.kotlin.poet
|
||||||
|
api libs.ksp
|
||||||
|
}
|
178
koin/generator/src/main/kotlin/Processor.kt
Normal file
178
koin/generator/src/main/kotlin/Processor.kt
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
package dev.inmo.micro_utils.koin.generator
|
||||||
|
|
||||||
|
import com.google.devtools.ksp.KSTypeNotPresentException
|
||||||
|
import com.google.devtools.ksp.KSTypesNotPresentException
|
||||||
|
import com.google.devtools.ksp.KspExperimental
|
||||||
|
import com.google.devtools.ksp.getAnnotationsByType
|
||||||
|
import com.google.devtools.ksp.processing.CodeGenerator
|
||||||
|
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.KSFile
|
||||||
|
import com.squareup.kotlinpoet.ClassName
|
||||||
|
import com.squareup.kotlinpoet.FileSpec
|
||||||
|
import com.squareup.kotlinpoet.FunSpec
|
||||||
|
import com.squareup.kotlinpoet.ParameterSpec
|
||||||
|
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
|
||||||
|
import com.squareup.kotlinpoet.PropertySpec
|
||||||
|
import com.squareup.kotlinpoet.asTypeName
|
||||||
|
import com.squareup.kotlinpoet.ksp.toClassName
|
||||||
|
import com.squareup.kotlinpoet.ksp.toTypeName
|
||||||
|
import com.squareup.kotlinpoet.ksp.writeTo
|
||||||
|
import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
import org.koin.core.scope.Scope
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class Processor(
|
||||||
|
private val codeGenerator: CodeGenerator
|
||||||
|
) : SymbolProcessor {
|
||||||
|
private val definitionClassName = ClassName("org.koin.core.definition", "Definition")
|
||||||
|
private val koinDefinitionClassName = ClassName("org.koin.core.definition", "KoinDefinition")
|
||||||
|
|
||||||
|
@OptIn(KspExperimental::class)
|
||||||
|
override fun process(resolver: Resolver): List<KSAnnotated> {
|
||||||
|
resolver.getSymbolsWithAnnotation(
|
||||||
|
GenerateKoinDefinition::class.qualifiedName!!
|
||||||
|
).filterIsInstance<KSFile>().forEach { ksFile ->
|
||||||
|
FileSpec.builder(
|
||||||
|
ksFile.packageName.asString(),
|
||||||
|
"GeneratedDefinitions${ksFile.fileName.removeSuffix(".kt")}"
|
||||||
|
).apply {
|
||||||
|
addFileComment(
|
||||||
|
"""
|
||||||
|
THIS CODE HAVE BEEN GENERATED AUTOMATICALLY
|
||||||
|
TO REGENERATE IT JUST DELETE FILE
|
||||||
|
ORIGINAL FILE: ${ksFile.fileName}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
ksFile.getAnnotationsByType(GenerateKoinDefinition::class).forEach {
|
||||||
|
val type = runCatching {
|
||||||
|
it.type.asTypeName()
|
||||||
|
}.getOrElse { e ->
|
||||||
|
if (e is KSTypeNotPresentException) {
|
||||||
|
e.ksType.toClassName()
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val targetType = runCatching {
|
||||||
|
type.parameterizedBy(*(it.typeArgs.takeIf { it.isNotEmpty() } ?.map { it.asTypeName() } ?.toTypedArray() ?: return@runCatching type))
|
||||||
|
}.getOrElse { e ->
|
||||||
|
when (e) {
|
||||||
|
is KSTypeNotPresentException -> e.ksType.toClassName()
|
||||||
|
}
|
||||||
|
if (e is KSTypesNotPresentException) {
|
||||||
|
type.parameterizedBy(*e.ksTypes.map { it.toTypeName() }.toTypedArray())
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}.copy(
|
||||||
|
nullable = it.nullable
|
||||||
|
)
|
||||||
|
fun addGetterProperty(
|
||||||
|
receiver: KClass<*>
|
||||||
|
) {
|
||||||
|
addProperty(
|
||||||
|
PropertySpec.builder(
|
||||||
|
it.name,
|
||||||
|
targetType,
|
||||||
|
).apply {
|
||||||
|
addKdoc(
|
||||||
|
"""
|
||||||
|
@return Definition by key "${it.name}"
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
getter(
|
||||||
|
FunSpec.getterBuilder().apply {
|
||||||
|
addCode(
|
||||||
|
"return " + (if (it.nullable) {
|
||||||
|
"getOrNull"
|
||||||
|
} else {
|
||||||
|
"get"
|
||||||
|
}) + "(named(\"${it.name}\"))"
|
||||||
|
)
|
||||||
|
}.build()
|
||||||
|
)
|
||||||
|
receiver(receiver)
|
||||||
|
}.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
addGetterProperty(Scope::class)
|
||||||
|
addGetterProperty(Koin::class)
|
||||||
|
|
||||||
|
if (it.generateSingle) {
|
||||||
|
addFunction(
|
||||||
|
FunSpec.builder("${it.name}Single").apply {
|
||||||
|
addKdoc(
|
||||||
|
"""
|
||||||
|
Will register [definition] with [org.koin.core.module.Module.single] and key "${it.name}"
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
receiver(Module::class)
|
||||||
|
addParameter(
|
||||||
|
ParameterSpec.builder(
|
||||||
|
"createdAtStart",
|
||||||
|
Boolean::class
|
||||||
|
).apply {
|
||||||
|
defaultValue("false")
|
||||||
|
}.build()
|
||||||
|
)
|
||||||
|
addParameter(
|
||||||
|
ParameterSpec.builder(
|
||||||
|
"definition",
|
||||||
|
definitionClassName.parameterizedBy(targetType.copy(nullable = false))
|
||||||
|
).build()
|
||||||
|
)
|
||||||
|
returns(koinDefinitionClassName.parameterizedBy(targetType.copy(nullable = false)))
|
||||||
|
addCode(
|
||||||
|
"return single(named(\"${it.name}\"), createdAtStart = createdAtStart, definition = definition)"
|
||||||
|
)
|
||||||
|
}.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.generateFactory) {
|
||||||
|
addFunction(
|
||||||
|
FunSpec.builder("${it.name}Factory").apply {
|
||||||
|
addKdoc(
|
||||||
|
"""
|
||||||
|
Will register [definition] with [org.koin.core.module.Module.factory] and key "${it.name}"
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
receiver(Module::class)
|
||||||
|
addParameter(
|
||||||
|
ParameterSpec.builder(
|
||||||
|
"definition",
|
||||||
|
definitionClassName.parameterizedBy(targetType.copy(nullable = false))
|
||||||
|
).build()
|
||||||
|
)
|
||||||
|
returns(koinDefinitionClassName.parameterizedBy(targetType.copy(nullable = false)))
|
||||||
|
addCode(
|
||||||
|
"return factory(named(\"${it.name}\"), definition = definition)"
|
||||||
|
)
|
||||||
|
}.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
addImport("org.koin.core.qualifier", "named")
|
||||||
|
}
|
||||||
|
}.build().let {
|
||||||
|
File(
|
||||||
|
File(ksFile.filePath).parent,
|
||||||
|
"GeneratedDefinitions${ksFile.fileName}"
|
||||||
|
).takeIf { !it.exists() } ?.apply {
|
||||||
|
parentFile.mkdirs()
|
||||||
|
|
||||||
|
writer().use { writer ->
|
||||||
|
it.writeTo(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
11
koin/generator/src/main/kotlin/Provider.kt
Normal file
11
koin/generator/src/main/kotlin/Provider.kt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package dev.inmo.micro_utils.koin.generator
|
||||||
|
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessor
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessorProvider
|
||||||
|
|
||||||
|
class Provider : SymbolProcessorProvider {
|
||||||
|
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = Processor(
|
||||||
|
environment.codeGenerator
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
dev.inmo.micro_utils.koin.generator.Provider
|
27
koin/generator/test/build.gradle
Normal file
27
koin/generator/test/build.gradle
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
id "com.google.devtools.ksp"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api project(":micro_utils.koin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
add("kspCommonMainMetadata", project(":micro_utils.koin.generator"))
|
||||||
|
}
|
||||||
|
|
||||||
|
ksp {
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// THIS CODE HAVE BEEN GENERATED AUTOMATICALLY
|
||||||
|
// TO REGENERATE IT JUST DELETE FILE
|
||||||
|
// ORIGINAL FILE: Test.kt
|
||||||
|
package dev.inmo.micro_utils.koin.generator.test
|
||||||
|
|
||||||
|
import kotlin.Boolean
|
||||||
|
import kotlin.String
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.definition.Definition
|
||||||
|
import org.koin.core.definition.KoinDefinition
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
import org.koin.core.qualifier.named
|
||||||
|
import org.koin.core.scope.Scope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Definition by key "sampleInfo"
|
||||||
|
*/
|
||||||
|
public val Scope.sampleInfo: Test<String>
|
||||||
|
get() = get(named("sampleInfo"))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Definition by key "sampleInfo"
|
||||||
|
*/
|
||||||
|
public val Koin.sampleInfo: Test<String>
|
||||||
|
get() = get(named("sampleInfo"))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will register [definition] with [org.koin.core.module.Module.single] and key "sampleInfo"
|
||||||
|
*/
|
||||||
|
public fun Module.sampleInfoSingle(createdAtStart: Boolean = false,
|
||||||
|
definition: Definition<Test<String>>): KoinDefinition<Test<String>> =
|
||||||
|
single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will register [definition] with [org.koin.core.module.Module.factory] and key "sampleInfo"
|
||||||
|
*/
|
||||||
|
public fun Module.sampleInfoFactory(definition: Definition<Test<String>>):
|
||||||
|
KoinDefinition<Test<String>> = factory(named("sampleInfo"), definition = definition)
|
13
koin/generator/test/src/commonMain/kotlin/Test.kt
Normal file
13
koin/generator/test/src/commonMain/kotlin/Test.kt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
@file:GenerateKoinDefinition("sampleInfo", Test::class, String::class, nullable = false)
|
||||||
|
package dev.inmo.micro_utils.koin.generator.test
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition
|
||||||
|
import org.koin.core.Koin
|
||||||
|
|
||||||
|
class Test<T>(
|
||||||
|
koin: Koin
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
koin.sampleInfo
|
||||||
|
}
|
||||||
|
}
|
1
koin/generator/test/src/main/AndroidManifest.xml
Normal file
1
koin/generator/test/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="dev.inmo.micro_utils.koin.generator.test"/>
|
|
@ -0,0 +1,28 @@
|
||||||
|
package dev.inmo.micro_utils.koin.annotations
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this annotation to mark files near to which generator should place generated extensions for koin [org.koin.core.scope.Scope]
|
||||||
|
* and [org.koin.core.Koin]
|
||||||
|
*
|
||||||
|
* @param name Name for definitions. This name will be available as extension for [org.koin.core.scope.Scope] and [org.koin.core.Koin]
|
||||||
|
* @param type Type of extensions. It is base star-typed class
|
||||||
|
* @param typeArgs Generic types for [type]. For example, if [type] == `Something::class` and [typeArgs] == `G1::class,
|
||||||
|
* G2::class`, the result type will be `Something<G1, G2>`
|
||||||
|
* @param nullable In case when true, extension will not throw error when definition has not been registered in koin
|
||||||
|
* @param generateSingle Generate definition factory with [org.koin.core.module.Module.single]. You will be able to use
|
||||||
|
* the extension [org.koin.core.module.Module].[name]Single(createdAtStart/* default false */) { /* your definition */ }
|
||||||
|
* @param generateFactory Generate definition factory with [org.koin.core.module.Module.factory]. You will be able to use
|
||||||
|
* the extension [org.koin.core.module.Module].[name]Factory { /* your definition */ }
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FILE)
|
||||||
|
@Repeatable
|
||||||
|
annotation class GenerateKoinDefinition(
|
||||||
|
val name: String,
|
||||||
|
val type: KClass<*>,
|
||||||
|
vararg val typeArgs: KClass<*>,
|
||||||
|
val nullable: Boolean = true,
|
||||||
|
val generateSingle: Boolean = true,
|
||||||
|
val generateFactory: Boolean = true
|
||||||
|
)
|
|
@ -7,15 +7,9 @@ interface CommonExposedRepo<IdType, ObjectType> : ExposedRepo {
|
||||||
val ResultRow.asId: IdType
|
val ResultRow.asId: IdType
|
||||||
val selectById: ISqlExpressionBuilder.(IdType) -> Op<Boolean>
|
val selectById: ISqlExpressionBuilder.(IdType) -> Op<Boolean>
|
||||||
val selectByIds: ISqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
|
val selectByIds: ISqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
|
||||||
get() = { list ->
|
get() = {
|
||||||
if (list.isEmpty()) {
|
it.foldRight<IdType, Op<Boolean>?>(null) { id, acc ->
|
||||||
Op.FALSE
|
acc ?.or(selectById(id)) ?: selectById(id)
|
||||||
} else {
|
} ?: Op.FALSE
|
||||||
var op = selectById(list.first())
|
|
||||||
(1 until list.size).forEach {
|
|
||||||
op = op.or(selectById(list[it]))
|
|
||||||
}
|
|
||||||
op
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ String[] includes = [
|
||||||
":safe_wrapper",
|
":safe_wrapper",
|
||||||
":crypto",
|
":crypto",
|
||||||
":koin",
|
":koin",
|
||||||
|
":koin:generator",
|
||||||
|
":koin:generator:test",
|
||||||
":selector:common",
|
":selector:common",
|
||||||
":pagination:common",
|
":pagination:common",
|
||||||
":pagination:exposed",
|
":pagination:exposed",
|
||||||
|
|
|
@ -39,14 +39,18 @@ object StartLauncherPlugin : StartPlugin {
|
||||||
|
|
||||||
includes(
|
includes(
|
||||||
config.plugins.mapNotNull {
|
config.plugins.mapNotNull {
|
||||||
|
val pluginName = it::class.simpleName ?: it.toString()
|
||||||
runCatching {
|
runCatching {
|
||||||
|
logger.i { "Start koin module registration for $pluginName" }
|
||||||
module {
|
module {
|
||||||
with(it) {
|
with(it) {
|
||||||
setupDI(rawJsonObject)
|
setupDI(rawJsonObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onFailure { e ->
|
}.onFailure { e ->
|
||||||
logger.w("Unable to load DI part of $it", e)
|
logger.w("Unable to register koin module of $pluginName", e)
|
||||||
|
}.onSuccess {
|
||||||
|
logger.i("Successfully registered koin module of $pluginName")
|
||||||
}.getOrNull()
|
}.getOrNull()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -76,16 +80,17 @@ object StartLauncherPlugin : StartPlugin {
|
||||||
logger.i("Start starting of subplugins")
|
logger.i("Start starting of subplugins")
|
||||||
val scope = koin.get<CoroutineScope>()
|
val scope = koin.get<CoroutineScope>()
|
||||||
koin.get<Config>().plugins.map { plugin ->
|
koin.get<Config>().plugins.map { plugin ->
|
||||||
|
val pluginName = plugin::class.simpleName ?: plugin.toString()
|
||||||
scope.launch {
|
scope.launch {
|
||||||
runCatchingSafely {
|
runCatchingSafely {
|
||||||
logger.i("Start loading of $plugin")
|
logger.i("Start loading of $pluginName")
|
||||||
with(plugin) {
|
with(plugin) {
|
||||||
startPlugin(koin)
|
startPlugin(koin)
|
||||||
}
|
}
|
||||||
}.onFailure { e ->
|
}.onFailure { e ->
|
||||||
logger.w("Unable to start plugin $plugin", e)
|
logger.w("Unable to start plugin $pluginName", e)
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
logger.i("Complete loading of $plugin")
|
logger.i("Complete loading of $pluginName")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.joinAll()
|
}.joinAll()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user