diff --git a/internal-processors/message-element-processor/build.gradle.kts b/internal-processors/message-element-processor/build.gradle.kts
new file mode 100644
index 00000000..be27cc4d
--- /dev/null
+++ b/internal-processors/message-element-processor/build.gradle.kts
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-kook.
+ *
+ * simbot-component-kook 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.
+ *
+ * simbot-component-kook 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
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with simbot-component-kook,
+ * If not, see .
+ */
+
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+}
+
+kotlin {
+ jvmToolchain(11)
+ compilerOptions {
+ javaParameters = true
+ jvmTarget.set(JvmTarget.JVM_11)
+ }
+}
+
+configJavaCompileWithModule()
+
+dependencies {
+ api(libs.ksp)
+ api(libs.kotlinPoet.ksp)
+ testImplementation(kotlin("test-junit5"))
+}
+
+tasks.getByName("test") {
+ useJUnitPlatform()
+}
+
diff --git a/internal-processors/message-element-processor/src/main/kotlin/kook/internal/processors/msgelement/MessageElementProcessor.kt b/internal-processors/message-element-processor/src/main/kotlin/kook/internal/processors/msgelement/MessageElementProcessor.kt
new file mode 100644
index 00000000..6007900b
--- /dev/null
+++ b/internal-processors/message-element-processor/src/main/kotlin/kook/internal/processors/msgelement/MessageElementProcessor.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-kook.
+ *
+ * simbot-component-kook 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.
+ *
+ * simbot-component-kook 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
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with simbot-component-kook,
+ * If not, see .
+ */
+
+package kook.internal.processors.msgelement
+
+import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.isAbstract
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.Modifier
+import com.squareup.kotlinpoet.*
+import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
+import com.squareup.kotlinpoet.ksp.toClassName
+import com.squareup.kotlinpoet.ksp.writeTo
+import java.time.Instant
+import java.time.ZoneOffset
+
+
+private const val BASE_ELEMENT_CLASS_PACKAGE = "love.forte.simbot.component.kook.message"
+private const val BASE_ELEMENT_CLASS_SIMPLE_NAME = "KookMessageElement"
+
+private const val BASE_ELEMENT_CLASS_NAME =
+ "$BASE_ELEMENT_CLASS_PACKAGE.$BASE_ELEMENT_CLASS_SIMPLE_NAME"
+
+private val BaseElementClassName =
+ ClassName(BASE_ELEMENT_CLASS_PACKAGE, BASE_ELEMENT_CLASS_SIMPLE_NAME)
+
+private const val KTX_SERIALIZABLE_ANNOTATION_PACKAGE = "kotlinx.serialization"
+private const val KTX_SERIALIZABLE_ANNOTATION_SIMPLE_NAME = "Serializable"
+private const val KTX_SERIALIZABLE_ANNOTATION_NAME =
+ "$KTX_SERIALIZABLE_ANNOTATION_PACKAGE.$KTX_SERIALIZABLE_ANNOTATION_SIMPLE_NAME"
+
+private val PolymorphicModuleBuilderClassName =
+ ClassName("kotlinx.serialization.modules", "PolymorphicModuleBuilder")
+
+private const val OUTPUT_PACKAGE = "love.forte.simbot.component.kook.message"
+private const val OUTPUT_FILE = "IncludeKookMessageElements.generated"
+private const val OUTPUT_FUN_NAME = "includeKookMessageElements"
+
+/**
+ *
+ * @author ForteScarlet
+ */
+class MessageElementProcessor(environment: SymbolProcessorEnvironment) : SymbolProcessor {
+ private val codeGenerator = environment.codeGenerator
+ private val elementDeclarations = mutableListOf()
+
+ override fun finish() {
+ val newFun = resolve(elementDeclarations)
+
+ val fileSpec = FileSpec.Companion.builder(
+ OUTPUT_PACKAGE, OUTPUT_FILE
+ )
+ .addFunction(newFun)
+ .addFileComment("\nAuto-Generated at ${Instant.now().atOffset(ZoneOffset.ofHours(8))}\n")
+ .build()
+
+ fileSpec.writeTo(
+ codeGenerator = codeGenerator,
+ aggregating = true,
+ originatingKSFiles = buildList {
+ for (impl in elementDeclarations) {
+ impl.containingFile?.also { add(it) }
+ }
+ }
+ )
+ }
+
+ override fun process(resolver: Resolver): List {
+ val baseClass = resolver.getClassDeclarationByName(
+ BASE_ELEMENT_CLASS_NAME
+ ) ?: error("Base class $BASE_ELEMENT_CLASS_NAME not found")
+
+ val baseClassStarType = baseClass.asStarProjectedType()
+
+ resolver
+ .getSymbolsWithAnnotation(KTX_SERIALIZABLE_ANNOTATION_NAME)
+ .filterIsInstance()
+ .filter { declaration ->
+ // 是 base class 的子类
+ baseClassStarType.isAssignableFrom(declaration.asStarProjectedType())
+ }
+ .filter { declaration ->
+ // 不是抽象的、不是sealed的可序列化类
+ !declaration.isAbstract() && !declaration.modifiers.contains(Modifier.SEALED)
+ }
+ .toCollection(elementDeclarations)
+
+ return emptyList()
+ }
+
+ /**
+ * 生成函数:
+ *
+ * ```kotlin
+ * internal fun PolymorphicModuleBuilder.includeKookMessageElements() {
+ * subclass(KookAsset::class, KookAsset.serializer())
+ * // ...
+ * }
+ * ```
+ */
+ private fun resolve(declarations: List): FunSpec {
+ val receiverType = PolymorphicModuleBuilderClassName.parameterizedBy(BaseElementClassName)
+// val optAnnotation =
+ val optAnnotation = AnnotationSpec.builder(ClassName("kotlin", "OptIn"))
+ .addMember(
+ "%T::class, %T::class",
+ ClassName("love.forte.simbot.annotations", "ExperimentalSimbotAPI"),
+ ClassName("love.forte.simbot.kook", "ExperimentalKookApi")
+ )
+ .build()
+
+ val internalAPIAnnotation = ClassName("love.forte.simbot.kook", "InternalKookApi")
+
+ return FunSpec.builder(OUTPUT_FUN_NAME).apply {
+ modifiers.add(KModifier.INTERNAL)
+ receiver(receiverType)
+ addAnnotation(optAnnotation)
+ addAnnotation(internalAPIAnnotation)
+
+ for (declaration in declarations) {
+ val className = declaration.toClassName()
+ addCode("subclass(%T::class, %T.serializer())\n", className, className)
+ }
+ }.build()
+ }
+}
+
diff --git a/internal-processors/message-element-processor/src/main/kotlin/kook/internal/processors/msgelement/MessageElementProcessorProvider.kt b/internal-processors/message-element-processor/src/main/kotlin/kook/internal/processors/msgelement/MessageElementProcessorProvider.kt
new file mode 100644
index 00000000..972199da
--- /dev/null
+++ b/internal-processors/message-element-processor/src/main/kotlin/kook/internal/processors/msgelement/MessageElementProcessorProvider.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-kook.
+ *
+ * simbot-component-kook 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.
+ *
+ * simbot-component-kook 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
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with simbot-component-kook,
+ * If not, see .
+ */
+
+package kook.internal.processors.msgelement
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+
+/**
+ *
+ * @author ForteScarlet
+ */
+class MessageElementProcessorProvider : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
+ MessageElementProcessor(environment)
+}
+
diff --git a/internal-processors/message-element-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/internal-processors/message-element-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
new file mode 100644
index 00000000..6bb0a159
--- /dev/null
+++ b/internal-processors/message-element-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -0,0 +1 @@
+kook.internal.processors.msgelement.MessageElementProcessorProvider
diff --git a/settings.gradle.kts b/settings.gradle.kts
index edc33e40..a61f8bac 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,24 +1,28 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
- * This file is part of simbot-component-kook.
+ * This file is part of simbot-component-kook.
*
- * simbot-component-kook 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.
+ * simbot-component-kook 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.
*
- * simbot-component-kook 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 GNU Lesser General Public License for more details.
+ * simbot-component-kook 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
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public License along with simbot-component-kook,
- * If not, see .
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with simbot-component-kook,
+ * If not, see .
*/
rootProject.name = "simbot-component-kook"
// internals
include(":internal-processors:api-reader")
+include(":internal-processors:message-element-processor")
include("simbot-component-kook-api")
include("simbot-component-kook-stdlib")
diff --git a/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/Kook.kt b/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/Kook.kt
index d94bab92..e97af2f9 100644
--- a/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/Kook.kt
+++ b/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/Kook.kt
@@ -1,18 +1,21 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
- * This file is part of simbot-component-kook.
+ * This file is part of simbot-component-kook.
*
- * simbot-component-kook 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.
+ * simbot-component-kook 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.
*
- * simbot-component-kook 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 GNU Lesser General Public License for more details.
+ * simbot-component-kook 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
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public License along with simbot-component-kook,
- * If not, see .
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with simbot-component-kook,
+ * If not, see .
*/
package love.forte.simbot.kook
@@ -82,6 +85,7 @@ public object Kook {
useArrayPolymorphism = false
// see https://github.com/kaiheila/api-docs/issues/174
explicitNulls = false
+ coerceInputValues = true
}
}
diff --git a/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/messages/MessageDetails.kt b/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/messages/MessageDetails.kt
index d5d7a609..fbd75151 100644
--- a/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/messages/MessageDetails.kt
+++ b/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/messages/MessageDetails.kt
@@ -1,24 +1,30 @@
/*
- * Copyright (c) 2021-2023. ForteScarlet.
+ * Copyright (c) 2021-2024. ForteScarlet.
*
- * This file is part of simbot-component-kook.
+ * This file is part of simbot-component-kook.
*
- * simbot-component-kook 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.
+ * simbot-component-kook 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.
*
- * simbot-component-kook 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 GNU Lesser General Public License for more details.
+ * simbot-component-kook 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
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public License along with simbot-component-kook,
- * If not, see .
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with simbot-component-kook,
+ * If not, see .
*/
package love.forte.simbot.kook.messages
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.JsonObject
+import love.forte.simbot.kook.Kook
import love.forte.simbot.kook.api.ApiResultType
import love.forte.simbot.kook.objects.*
@@ -168,16 +174,33 @@ public data class ChannelMessageDetails(
*/
@Serializable
public data class DirectMessageDetails(
- override val id: String,
- override val type: Int,
- @SerialName("author_id") override val authorId: String,
- override val content: String,
- override val embeds: List