Skip to content

Commit

Permalink
Merge pull request #766 from InsanusMokrassar/8.1.0
Browse files Browse the repository at this point in the history
8.1.0
  • Loading branch information
InsanusMokrassar authored Jun 19, 2023
2 parents 9c98411 + cf46139 commit 6f512a1
Show file tree
Hide file tree
Showing 14 changed files with 86 additions and 470 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# TelegramBotAPI changelog

## 8.1.0

**PARTIALLY BREAKING CHANGES: Exclude `.*Impl` classcasts from `ClassCastsNew`**

* `Version`:
* `MicroUtils`: `0.19.2` -> `0.19.4`
* `Utils`:
* Add deep links formatting for internal `tg://` prefix (thanks to [@klimatov](https://github.com/klimatov))
* Exclude `.*Impl` classcasts from `ClassCastsNew`

## 8.0.1

* `Version`:
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ kotlin.incremental=true
kotlin.incremental.js=true

library_group=dev.inmo
library_version=8.0.1
library_version=8.1.0
6 changes: 3 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]

kotlin = "1.8.21"
kotlin = "1.8.22"
kotlin-serialization = "1.5.1"
kotlin-coroutines = "1.6.4"

Expand All @@ -10,10 +10,10 @@ korlibs = "4.0.3"
uuid = "0.7.1"
ktor = "2.3.1"

ksp = "1.8.21-1.0.11"
ksp = "1.8.22-1.0.11"
kotlin-poet = "1.14.2"

microutils = "0.19.2"
microutils = "0.19.4"

github-release-plugin = "2.4.1"
dokka = "1.8.20"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import dev.inmo.tgbotapi.types.chat.User
*
* @see FromUser
*/
@ClassCastsIncluded
@ClassCastsIncluded(excludeRegex = ".*Impl")
interface WithUser {
val user: User
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import kotlinx.serialization.Serializable

@Serializable(InlineQueryResultSerializer::class)
@ClassCastsIncluded
@ClassCastsIncluded(excludeRegex = ".*Impl")
interface InlineQueryResult {
val type: String
val id: InlineQueryIdentifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ sealed interface AbleToAddInAttachmentMenuChat : Chat {
}

@Serializable(PreviewChatSerializer::class)
@ClassCastsIncluded
@ClassCastsIncluded(excludeRegex = ".*Impl")
sealed interface Chat {
val id: IdChatIdentifier
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package dev.inmo.tgbotapi.types.chat
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObject

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use ExtendedChannelChat due")
data class ExtendedChannelChatImpl(
@SerialName(idField)
override val id: ChatId,
Expand All @@ -33,6 +35,7 @@ data class ExtendedChannelChatImpl(
) : ExtendedChannelChat

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use ExtendedGroupChat due")
data class ExtendedGroupChatImpl(
@SerialName(idField)
override val id: ChatId,
Expand All @@ -54,6 +57,7 @@ data class ExtendedGroupChatImpl(
) : ExtendedGroupChat

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use ExtendedPrivateChat due")
data class ExtendedPrivateChatImpl(
@SerialName(idField)
override val id: UserId,
Expand All @@ -80,6 +84,7 @@ data class ExtendedPrivateChatImpl(
typealias ExtendedUser = ExtendedPrivateChatImpl

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use ExtendedSupergroupChat due")
data class ExtendedSupergroupChatImpl(
@SerialName(idField)
override val id: ChatId,
Expand Down Expand Up @@ -121,6 +126,7 @@ data class ExtendedSupergroupChatImpl(
) : ExtendedSupergroupChat

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use ExtendedForumChat due")
data class ExtendedForumChatImpl(
@SerialName(idField)
override val id: IdChatIdentifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import dev.inmo.micro_utils.language_codes.IetfLanguageCode
import dev.inmo.micro_utils.language_codes.IetfLanguageCodeSerializer
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.abstracts.WithOptionalLanguageCode
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use GroupChat due")
data class GroupChatImpl(
@SerialName(idField)
override val id: ChatId,
Expand All @@ -16,6 +18,7 @@ data class GroupChatImpl(
) : GroupChat

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use PrivateChat due")
data class PrivateChatImpl(
@SerialName(idField)
override val id: UserId,
Expand All @@ -28,6 +31,7 @@ data class PrivateChatImpl(
) : PrivateChat

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use SupergroupChat due")
data class SupergroupChatImpl(
@SerialName(idField)
override val id: ChatId,
Expand All @@ -38,6 +42,7 @@ data class SupergroupChatImpl(
) : SupergroupChat

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use ForumChat due")
data class ForumChatImpl(
@SerialName(idField)
override val id: IdChatIdentifier,
Expand All @@ -48,6 +53,7 @@ data class ForumChatImpl(
) : ForumChat

@Serializable
@RiskFeature("This class is a subject of changes. It is better to use ChannelChat due")
data class ChannelChatImpl(
@SerialName(idField)
override val id: ChatId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

@ClassCastsIncluded
@ClassCastsIncluded(excludeRegex = ".*Impl")
interface Message : WithChat {
val messageId: MessageId
val date: DateTime
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package dev.inmo.tgbotapi.utils.internal

import dev.inmo.tgbotapi.utils.RiskFeature

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
@RiskFeature("It is internal API in tgbotapi.core and should not be used outside")
annotation class ClassCastsIncluded(val typesRegex: String = "", val excludeRegex: String = "")

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
internal annotation class ClassCastsIncluded
@RiskFeature("It is internal API in tgbotapi.core and should not be used outside")
annotation class ClassCastsExcluded
1 change: 1 addition & 0 deletions tgbotapi.ksp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ repositories {
dependencies {
implementation libs.kotlin.poet
implementation libs.ksp
implementation project(":tgbotapi.core")
}
46 changes: 41 additions & 5 deletions tgbotapi.ksp/src/main/kotlin/TelegramBotAPISymbolProcessor.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package dev.inmo.tgbotapi.ksp.processor

import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getAllSuperTypes
import com.google.devtools.ksp.getAnnotationsByType
import com.google.devtools.ksp.isAnnotationPresent
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.asClassName
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.writeTo
import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.internal.ClassCastsExcluded
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import java.io.File

class TelegramBotAPISymbolProcessor(
Expand All @@ -15,24 +24,51 @@ class TelegramBotAPISymbolProcessor(
private val outputFile: String = "Output",
private val outputFolder: String? = null
) : SymbolProcessor {
private val classCastsIncludedClassName = ClassCastsIncluded::class.asClassName()
@OptIn(KspExperimental::class, RiskFeature::class)
override fun process(resolver: Resolver): List<KSAnnotated> {
val classes = resolver.getSymbolsWithAnnotation("dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded").filterIsInstance<KSClassDeclaration>()
val classes = resolver.getSymbolsWithAnnotation(classCastsIncludedClassName.canonicalName).filterIsInstance<KSClassDeclaration>()
val classesRegexes: Map<KSClassDeclaration, Pair<Regex?, Regex?>> = classes.mapNotNull {
it to (it.getAnnotationsByType(ClassCastsIncluded::class).firstNotNullOfOrNull {
it.typesRegex.takeIf { it.isNotEmpty() } ?.let(::Regex) to it.excludeRegex.takeIf { it.isNotEmpty() } ?.let(::Regex)
} ?: return@mapNotNull null)
}.toMap()
val classesSubtypes = mutableMapOf<KSClassDeclaration, MutableSet<KSClassDeclaration>>()

resolver.getAllFiles().forEach {
it.declarations.forEach { potentialSubtype ->
if (potentialSubtype is KSClassDeclaration) {
if (
potentialSubtype is KSClassDeclaration
&& potentialSubtype.isAnnotationPresent(ClassCastsExcluded::class).not()
) {
val allSupertypes = potentialSubtype.getAllSuperTypes().map { it.declaration }
classes.forEach {
if (it in allSupertypes) {
classesSubtypes.getOrPut(it) { mutableSetOf() }.add(potentialSubtype)

for (currentClass in classes) {
val regexes = classesRegexes[currentClass]
val simpleName = potentialSubtype.simpleName.getShortName()
when {
currentClass !in allSupertypes
|| regexes ?.first ?.matches(simpleName) == false
|| regexes ?.second ?.matches(simpleName) == true -> continue
else -> {
classesSubtypes.getOrPut(currentClass) { mutableSetOf() }.add(potentialSubtype)
}
}
}
}
}
}
fun fillWithSealeds(source: KSClassDeclaration, current: KSClassDeclaration = source) {
val regexes = classesRegexes[source]
current.getSealedSubclasses().forEach {
val simpleName = it.simpleName.getShortName()
if (
regexes ?.first ?.matches(simpleName) == false
|| regexes ?.second ?.matches(simpleName) == true
|| it.isAnnotationPresent(ClassCastsExcluded::class)
) {
return@forEach
}
classesSubtypes.getOrPut(source) { mutableSetOf() }.add(it)
fillWithSealeds(source, it)
}
Expand Down
Loading

0 comments on commit 6f512a1

Please sign in to comment.