Skip to content

Commit

Permalink
Merge pull request #918 from simple-robot/processor-and-power-assert
Browse files Browse the repository at this point in the history
feat: 新增一个新的组 love.forte.simbot.processor, 以及其中一个新的用于组件开发的ksp处理器 simbot-processor-message-element-polymorphic-include
  • Loading branch information
ForteScarlet authored Aug 13, 2024
2 parents 176d3b6 + 38d1c16 commit 73cf588
Show file tree
Hide file tree
Showing 14 changed files with 511 additions and 15 deletions.
1 change: 1 addition & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ val kotlinVersion: String = libs.versions.kotlin.get()
dependencies {
implementation(kotlin("gradle-plugin", kotlinVersion))
implementation(kotlin("serialization", kotlinVersion))
implementation(kotlin("power-assert", kotlinVersion))
implementation(libs.bundles.dokka)

// see https://github.com/gradle-nexus/publish-plugin
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/P.kt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ sealed class P(override val group: String) : ProjectDetail() {
const val GROUP_QUANTCAT = "love.forte.simbot.quantcat"
const val GROUP_EXTENSION = "love.forte.simbot.extension"
const val GROUP_BENCHMARK = "love.forte.simbot.benchmark"
const val GROUP_PROCESSOR = "love.forte.simbot.processor"

// const val COMPONENT_GROUP = "love.forte.simbot.component"
const val DESCRIPTION = "Simple Robot,一个通用的bot风格事件调度框架,以灵活的统一标准来编写bot应用。"
Expand Down
3 changes: 3 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ include(":internal-processors:interface-uml-processor")
// gradle
include(":simbot-gradles:simbot-gradle-suspendtransforms")

// processors
include("simbot-processors:simbot-processor-message-element-polymorphic-include")

include(":simbot-commons:simbot-common-annotations")
include(":simbot-commons:simbot-common-collection")
include(":simbot-commons:simbot-common-streamable")
Expand Down
15 changes: 15 additions & 0 deletions simbot-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*
*/

import com.google.devtools.ksp.gradle.KspTaskMetadata
import love.forte.gradle.common.kotlin.multiplatform.applyTier1
import love.forte.gradle.common.kotlin.multiplatform.applyTier2
import love.forte.gradle.common.kotlin.multiplatform.applyTier3
Expand Down Expand Up @@ -136,6 +137,7 @@ kotlin {
dependencies {
// add("kspJvm", libs.suspend.reversal.processor)
add("kspJvm", project(":internal-processors:interface-uml-processor"))
add("kspCommonMainMetadata", project(":simbot-processors:simbot-processor-message-element-polymorphic-include"))
}

ksp {
Expand All @@ -145,6 +147,19 @@ ksp {
// arg("simbot.internal.processor.uml.target", "love.forte.simbot.definition.Actor")
arg("simbot.internal.processor.uml.output", rootDir.resolve("generated-docs/event-uml.md").absolutePath)
// arg("simbot.internal.processor.uml.output", rootDir.resolve("generated-docs/actor-uml.md").absolutePath)

// simbot-processor-message-element-polymorphic-include
arg("simbot.processor.message-element-polymorphic-include.localOnly", "true")
arg("simbot.processor.message-element-polymorphic-include.outputPackage", "love.forte.simbot.message")
arg("simbot.processor.message-element-polymorphic-include.visibility", "internal")
}

kotlin.sourceSets.commonMain {
// solves all implicit dependency trouble and IDEs source code detection
// see https://github.com/google/ksp/issues/963#issuecomment-1894144639
tasks.withType<KspTaskMetadata> {
kotlin.srcDir(destinationDirectory.file("kotlin"))
}
}

// BuildConfig for the current version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.PolymorphicModuleBuilder
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import love.forte.simbot.message.MessagesBuilder.Companion.create
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
Expand Down Expand Up @@ -95,19 +94,7 @@ public sealed interface Messages : Message, Iterable<Message.Element> {
@get:JvmName("standardSerializersModule")
public val standardSerializersModule: SerializersModule = SerializersModule {
polymorphic(Message.Element::class) {
subclass(Text.serializer())
subclass(At.serializer())
subclass(AtAll.serializer())
// images
subclass(OfflineByteArrayImage.serializer())
subclass(SimpleOfflineResourceImage.serializer())
subclass(RemoteIDImage.serializer())

subclass(Emoji.serializer())
subclass(Face.serializer())
subclass(MessageIdReference.serializer())


includeMessageElementPolymorphic()
resolvePlatformStandardSerializers()
}
}
Expand Down
26 changes: 26 additions & 0 deletions simbot-processors/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024. ForteScarlet.
*
* Project https://github.com/simple-robot/simpler-robot
* Email ForteScarlet@163.com
*
* This file is part of the Simple Robot Library (Alias: simple-robot, simbot, etc.).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

subprojects {
group = P.GROUP_PROCESSOR
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Message element polymorphic include

为所有 `Message.Element` (或某个指定子类) 生成一个注册多态序列化信息的聚合函数的 KSP 处理器,
常用于组件开发等场景。

```kotlin
// 生成类似于如下的API
internal fun PolymorphicModuleBuilder<Message.Element>.includeElements() {
subclass(...)
subclass(...)
subclass(...)
}

```

会寻找指定的类型的所有**非抽象****非接口**、且标记了 `kotlinx.serialization.Serializable` 注解的子类。

可选配置项:

```kotlin
// 选项参数以 `simbot.processor.message-element-polymorphic-include` 开头
ksp {
// 是否启用
arg("simbot.processor.message-element-polymorphic-include.enable", "true")
arg("simbot.processor.message-element-polymorphic-include.localOnly", "false")
arg("simbot.processor.message-element-polymorphic-include.baseClass", "love.forte.simbot.message.Message.Element")
arg("simbot.processor.message-element-polymorphic-include.visibility", "internal") // 默认 internal 可选: public, internal
arg("simbot.processor.message-element-polymorphic-include.generateFunName", "includeMessageElementPolymorphic")
arg("simbot.processor.message-element-polymorphic-include.outputPackage", "love.forte.simbot.message") // 默认为 null,如果不提供(不是空字符串哦)则与 baseClass 同包
arg("simbot.processor.message-element-polymorphic-include.outputFileName", "MessageElementPolymorphicInclude.generated")
arg("simbot.processor.message-element-polymorphic-include.outputFileJvmName", "") // 默认 null
arg("simbot.processor.message-element-polymorphic-include.outputFileJvmMultifile", "false") // 默认 false
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
public class love/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration {
public static final field CONFIG_PREFIX Ljava/lang/String;
public static final field Companion Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration$Companion;
public fun <init> ()V
public synthetic fun <init> (ILjava/lang/String;ZZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLkotlinx/serialization/internal/SerializationConstructorMarker;)V
public fun getBaseClass ()Ljava/lang/String;
public fun getEnable ()Z
public fun getGenerateFunName ()Ljava/lang/String;
public fun getLocalOnly ()Z
public fun getOutputFileJvmMultifile ()Z
public fun getOutputFileJvmName ()Ljava/lang/String;
public fun getOutputFileName ()Ljava/lang/String;
public fun getOutputPackage ()Ljava/lang/String;
public fun getVisibility ()Ljava/lang/String;
public fun setBaseClass (Ljava/lang/String;)V
public fun setEnable (Z)V
public fun setGenerateFunName (Ljava/lang/String;)V
public fun setLocalOnly (Z)V
public fun setOutputFileJvmMultifile (Z)V
public fun setOutputFileJvmName (Ljava/lang/String;)V
public fun setOutputFileName (Ljava/lang/String;)V
public fun setOutputPackage (Ljava/lang/String;)V
public fun setVisibility (Ljava/lang/String;)V
public fun visibilityValue ()Lcom/squareup/kotlinpoet/KModifier;
public static final synthetic fun write$Self (Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
}

public synthetic class love/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration$$serializer;
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration;
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class love/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}

public class love/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeProcessor : com/google/devtools/ksp/processing/SymbolProcessor {
protected field baseKSClassDeclaration Lcom/google/devtools/ksp/symbol/KSClassDeclaration;
public fun <init> (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration;)V
protected fun createFile ()Lcom/squareup/kotlinpoet/FileSpec;
protected fun createFileBuilder ()Lcom/squareup/kotlinpoet/FileSpec$Builder;
public fun finish ()V
protected fun getBaseKSClassDeclaration ()Lcom/google/devtools/ksp/symbol/KSClassDeclaration;
protected fun getGenerateFunName ()Ljava/lang/String;
protected fun getOutputFileJvmMultifile ()Z
protected fun getOutputFileJvmName ()Ljava/lang/String;
protected fun getOutputFileName ()Ljava/lang/String;
protected fun getOutputPackage ()Ljava/lang/String;
protected fun getTargetClasses ()Ljava/util/List;
protected fun getVisibility ()Lcom/squareup/kotlinpoet/KModifier;
protected fun getVisitor ()Lcom/google/devtools/ksp/symbol/KSVisitor;
protected fun isLocalOnly ()Z
public fun process (Lcom/google/devtools/ksp/processing/Resolver;)Ljava/util/List;
protected fun setBaseKSClassDeclaration (Lcom/google/devtools/ksp/symbol/KSClassDeclaration;)V
protected fun useInFile (Lcom/squareup/kotlinpoet/FileSpec$Builder;)V
protected fun write (Lcom/squareup/kotlinpoet/FileSpec;)V
}

protected class love/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeProcessor$Visitor : com/google/devtools/ksp/symbol/KSVisitorVoid {
public fun <init> (Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeProcessor;)V
public synthetic fun visitClassDeclaration (Lcom/google/devtools/ksp/symbol/KSClassDeclaration;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitClassDeclaration (Lcom/google/devtools/ksp/symbol/KSClassDeclaration;Lkotlin/Unit;)V
}

public class love/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeProcessorProvider : com/google/devtools/ksp/processing/SymbolProcessorProvider {
public fun <init> ()V
public fun create (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;)Lcom/google/devtools/ksp/processing/SymbolProcessor;
protected fun readConfiguration (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;)Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeConfiguration;
}

public final class love/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeProcessorProvider$EmptySymbolProcessor : com/google/devtools/ksp/processing/SymbolProcessor {
public static final field INSTANCE Llove/forte/simbot/processor/message/element/polymorphic/include/MessageElementPolymorphicIncludeProcessorProvider$EmptySymbolProcessor;
public fun process (Lcom/google/devtools/ksp/processing/Resolver;)Ljava/util/List;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024. ForteScarlet.
*
* Project https://github.com/simple-robot/simpler-robot
* Email ForteScarlet@163.com
*
* This file is part of the Simple Robot Library (Alias: simple-robot, simbot, etc.).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

plugins {
kotlin("jvm")
id("simbot.dokka-module-configuration")
kotlin("plugin.serialization")
}

configJavaCompileWithModule()
apply(plugin = "simbot-jvm-maven-publish")

kotlin {
explicitApi()
configKotlinJvm(JVMConstants.KT_JVM_TARGET_VALUE)
}

dependencies {
implementation(libs.ksp)
implementation(libs.kotlinPoet.ksp)
implementation(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.properties)
}

tasks.getByName<Test>("test") {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2024. ForteScarlet.
*
* Project https://github.com/simple-robot/simpler-robot
* Email ForteScarlet@163.com
*
* This file is part of the Simple Robot Library (Alias: simple-robot, simbot, etc.).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

package love.forte.simbot.processor.message.element.polymorphic.include

import com.squareup.kotlinpoet.KModifier
import kotlinx.serialization.Serializable


/**
* configurations for [MessageElementPolymorphicIncludeProcessor].
*
* @author ForteScarlet
*/
@Serializable
public open class MessageElementPolymorphicIncludeConfiguration {
public open var baseClass: String = "love.forte.simbot.message.Message.Element"
public open var enable: Boolean = true
public open var localOnly: Boolean = false
public open var visibility: String = "internal"
public open var generateFunName: String = "includeMessageElementPolymorphic"
public open var outputPackage: String? = null
public open var outputFileName: String = "MessageElementPolymorphicInclude.generated"
public open var outputFileJvmName: String? = null
public open var outputFileJvmMultifile: Boolean = false

public open fun visibilityValue(): KModifier {
return when {
visibility.equals("internal", ignoreCase = true) -> KModifier.INTERNAL
visibility.equals("public", ignoreCase = true) -> KModifier.PUBLIC
else -> throw IllegalArgumentException("Unknown visibility: $visibility, not in ['internal', 'public']")
}
}

public companion object {
public const val CONFIG_PREFIX: String = "simbot.processor.message-element-polymorphic-include"

}
}

Loading

0 comments on commit 73cf588

Please sign in to comment.