Skip to content

Commit e9a7752

Browse files
authored
Merge pull request #61 from ForteScarlet/optimise-annotation-excludes
Optimising the default annotation copy configuration: exclude the `kotlin.optIn` by default, and exclude both `@JvmAsync` and `@JvmBlocking` on the JVM platform
2 parents ad56893 + 2d80835 commit e9a7752

File tree

11 files changed

+309
-51
lines changed

11 files changed

+309
-51
lines changed

README.md

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,6 @@ plugin {
494494
id("love.forte.plugin.suspend-transform") version "$VERSION"
495495
}
496496

497-
498497
suspendTransform {
499498
// enabled suspend transform plugin
500499
enabled = true
@@ -543,6 +542,138 @@ suspendTransform {
543542
}
544543
```
545544

545+
For example, you want to use a single annotation to do the work of `@JvmAsync`, `@JvmBlocking`, and `@JsPromise`:
546+
547+
```kotlin
548+
// Your JVM transform functions
549+
// e.g. com.example.Transforms.jvm.kt
550+
551+
@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN)
552+
fun <T> runInBlocking(block: suspend () -> T): T {
553+
// run the `block` in blocking
554+
runBlocking { block() }
555+
}
556+
557+
@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN)
558+
public fun <T> runInAsync(block: suspend () -> T, scope: CoroutineScope? = null): CompletableFuture<T> {
559+
// run the `block` in async
560+
val scope0 = scope ?: GlobalScope
561+
return scope0.future { block() }
562+
563+
/*
564+
the `scope` is the `block`'s container:
565+
```
566+
interface Container {
567+
@JvmAsync
568+
suspend fun run()
569+
👇 compiled
570+
571+
fun runAsync() = runInAsync(block = { run() }, scope = this as? CoroutineScope)
572+
}
573+
```
574+
*/
575+
}
576+
577+
// Your JS transform function
578+
// e.g. com.example.Transforms.js.kt
579+
@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN)
580+
fun <T> runInPromise(block: suspend () -> T, scope: CoroutineScope? = null): T {
581+
val scope0 = scope ?: GlobalScope
582+
return scope0.promise { block() }
583+
}
584+
```
585+
586+
Create your annotation:
587+
588+
```kotlin
589+
// Your single annotation
590+
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
591+
@Retention(AnnotationRetention.BINARY)
592+
public annotation class SuspendTrans(
593+
val blockingBaseName: String = "",
594+
val blockingSuffix: String = "Blocking",
595+
val blockingAsProperty: Boolean = false,
596+
597+
val asyncBaseName: String = "",
598+
val asyncSuffix: String = "Async",
599+
val asyncAsProperty: Boolean = false,
600+
601+
val reserveBaseName: String = "",
602+
val reserveSuffix: String = "Reserve",
603+
val reserveAsProperty: Boolean = false,
604+
)
605+
```
606+
607+
Then, config your build script:
608+
609+
```kotlin
610+
// The annotation type
611+
val suspendTransMarkAnnotationClassInfo = ClassInfo("love.forte.simbot.suspendrunner", "SuspendTrans")
612+
613+
// The mark annotations
614+
val jvmSuspendTransMarkAnnotationForBlocking = MarkAnnotation(
615+
suspendTransMarkAnnotationClassInfo,
616+
baseNameProperty = "blockingBaseName",
617+
suffixProperty = "blockingSuffix",
618+
asPropertyProperty = "blockingAsProperty",
619+
defaultSuffix = SuspendTransformConfiguration.jvmBlockingAnnotationInfo.defaultSuffix,
620+
)
621+
val jvmSuspendTransMarkAnnotationForAsync = MarkAnnotation(
622+
suspendTransMarkAnnotationClassInfo,
623+
baseNameProperty = "asyncBaseName",
624+
suffixProperty = "asyncSuffix",
625+
asPropertyProperty = "asyncAsProperty",
626+
defaultSuffix = SuspendTransformConfiguration.jvmAsyncAnnotationInfo.defaultSuffix,
627+
)
628+
val jsSuspendTransMarkAnnotationForPromise = MarkAnnotation(
629+
suspendTransMarkAnnotationClassInfo,
630+
baseNameProperty = "jsPromiseBaseName",
631+
suffixProperty = "jsPromiseSuffix",
632+
asPropertyProperty = "jsPromiseAsProperty",
633+
defaultSuffix = "Async",
634+
)
635+
636+
// The transformers
637+
val suspendTransTransformerForJvmBlocking: Transformer = jvmBlockingTransformer.copy(
638+
markAnnotation = jvmSuspendTransMarkAnnotationForBlocking,
639+
copyAnnotationExcludes = SuspendTransformConfiguration.jvmBlockingTransformer.copyAnnotationExcludes +
640+
jvmSuspendTransMarkAnnotationForBlocking.classInfo
641+
)
642+
643+
val suspendTransTransformerForJvmAsync: Transformer = jvmAsyncTransformer.copy(
644+
markAnnotation = jvmSuspendTransMarkAnnotationForAsync,
645+
copyAnnotationExcludes = SuspendTransformConfiguration.jvmAsyncTransformer.copyAnnotationExcludes +
646+
jvmSuspendTransMarkAnnotationForAsync.classInfo
647+
)
648+
649+
val suspendTransTransformerForJsPromise: Transformer = jsPromiseTransformer.copy(
650+
markAnnotation = jvmSuspendTransMarkAnnotationForReserve,
651+
copyAnnotationExcludes = jsPromiseTransformer.copyAnnotationExcludes +
652+
jsSuspendTransMarkAnnotationForPromise.classInfo,
653+
)
654+
655+
// The above section can also be considered to be defined in `buildSrc`.
656+
657+
suspendTransform {
658+
// disable, use the runtime and the annotation by yourself
659+
includeRuntime = false
660+
includeAnnotation = false
661+
662+
addJvmTransformers(
663+
suspendTransTransformerForJvmBlocking,
664+
suspendTransTransformerForJvmAsync
665+
)
666+
addJsTransformers(
667+
suspendTransTransformerForJsPromise
668+
)
669+
}
670+
```
671+
672+
673+
## Use Cases
674+
675+
- [Simple Robot Frameworks](https://github.com/simple-robot/simpler-robot) (Fully customized)
676+
546677

547678
## License
548679

README_CN.md

Lines changed: 131 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -543,9 +543,137 @@ suspendTransform {
543543
}
544544
```
545545

546-
## 友情连接
547-
[Kotlin Suspend Interface reversal](https://github.com/ForteScarlet/kotlin-suspend-interface-reversal)
548-
: 基于 KSP,为包含挂起函数的接口或抽象类生成与平台兼容的扩展类型。
546+
举个例子,你想要使用一个单独的注解就完成`@JvmAsync`, `@JvmBlocking`, and `@JsPromise`的工作:
547+
548+
549+
```kotlin
550+
// 你在JVM平台上的转化函数
551+
// 比如 com.example.Transforms.jvm.kt
552+
553+
@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN)
554+
fun <T> runInBlocking(block: suspend () -> T): T {
555+
// run the `block` in blocking
556+
runBlocking { block() }
557+
}
558+
559+
@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN)
560+
public fun <T> runInAsync(block: suspend () -> T, scope: CoroutineScope? = null): CompletableFuture<T> {
561+
// run the `block` in async
562+
val scope0 = scope ?: GlobalScope
563+
return scope0.future { block() }
564+
565+
/*
566+
`scope` 是 `block`'s 所处的容器:
567+
```
568+
interface Container {
569+
@JvmAsync
570+
suspend fun run()
571+
👇 compiled
572+
573+
fun runAsync() = runInAsync(block = { run() }, scope = this as? CoroutineScope)
574+
}
575+
```
576+
*/
577+
}
578+
579+
// 你JS平台上的转化函数
580+
// 比如 com.example.Transforms.js.kt
581+
@Deprecated("Just used by compiler", level = DeprecationLevel.HIDDEN)
582+
fun <T> runInPromise(block: suspend () -> T, scope: CoroutineScope? = null): T {
583+
val scope0 = scope ?: GlobalScope
584+
return scope0.promise { block() }
585+
}
586+
```
587+
588+
创建你的注解:
589+
590+
```kotlin
591+
// Your single annotation
592+
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
593+
@Retention(AnnotationRetention.BINARY)
594+
public annotation class SuspendTrans(
595+
val blockingBaseName: String = "",
596+
val blockingSuffix: String = "Blocking",
597+
val blockingAsProperty: Boolean = false,
598+
599+
val asyncBaseName: String = "",
600+
val asyncSuffix: String = "Async",
601+
val asyncAsProperty: Boolean = false,
602+
603+
val reserveBaseName: String = "",
604+
val reserveSuffix: String = "Reserve",
605+
val reserveAsProperty: Boolean = false,
606+
)
607+
```
608+
609+
然后,配置你的构建脚本
610+
611+
```kotlin
612+
// 注解类型
613+
val suspendTransMarkAnnotationClassInfo = ClassInfo("love.forte.simbot.suspendrunner", "SuspendTrans")
614+
615+
// 标记注解定义
616+
val jvmSuspendTransMarkAnnotationForBlocking = MarkAnnotation(
617+
suspendTransMarkAnnotationClassInfo,
618+
baseNameProperty = "blockingBaseName",
619+
suffixProperty = "blockingSuffix",
620+
asPropertyProperty = "blockingAsProperty",
621+
defaultSuffix = SuspendTransformConfiguration.jvmBlockingAnnotationInfo.defaultSuffix,
622+
)
623+
val jvmSuspendTransMarkAnnotationForAsync = MarkAnnotation(
624+
suspendTransMarkAnnotationClassInfo,
625+
baseNameProperty = "asyncBaseName",
626+
suffixProperty = "asyncSuffix",
627+
asPropertyProperty = "asyncAsProperty",
628+
defaultSuffix = SuspendTransformConfiguration.jvmAsyncAnnotationInfo.defaultSuffix,
629+
)
630+
val jsSuspendTransMarkAnnotationForPromise = MarkAnnotation(
631+
suspendTransMarkAnnotationClassInfo,
632+
baseNameProperty = "jsPromiseBaseName",
633+
suffixProperty = "jsPromiseSuffix",
634+
asPropertyProperty = "jsPromiseAsProperty",
635+
defaultSuffix = "Async",
636+
)
637+
638+
// 转化函数定义
639+
val suspendTransTransformerForJvmBlocking: Transformer = jvmBlockingTransformer.copy(
640+
markAnnotation = jvmSuspendTransMarkAnnotationForBlocking,
641+
copyAnnotationExcludes = SuspendTransformConfiguration.jvmBlockingTransformer.copyAnnotationExcludes +
642+
jvmSuspendTransMarkAnnotationForBlocking.classInfo
643+
)
644+
645+
val suspendTransTransformerForJvmAsync: Transformer = jvmAsyncTransformer.copy(
646+
markAnnotation = jvmSuspendTransMarkAnnotationForAsync,
647+
copyAnnotationExcludes = SuspendTransformConfiguration.jvmAsyncTransformer.copyAnnotationExcludes +
648+
jvmSuspendTransMarkAnnotationForAsync.classInfo
649+
)
650+
651+
val suspendTransTransformerForJsPromise: Transformer = jsPromiseTransformer.copy(
652+
markAnnotation = jvmSuspendTransMarkAnnotationForReserve,
653+
copyAnnotationExcludes = jsPromiseTransformer.copyAnnotationExcludes +
654+
jsSuspendTransMarkAnnotationForPromise.classInfo,
655+
)
656+
657+
// 上面这些东西也可以考虑在 `buildSrc` 中定义。
658+
659+
suspendTransform {
660+
// 关闭它们,并使用你自己自定义的 runtime 和 annotation
661+
includeRuntime = false
662+
includeAnnotation = false
663+
664+
addJvmTransformers(
665+
suspendTransTransformerForJvmBlocking,
666+
suspendTransTransformerForJvmAsync
667+
)
668+
addJsTransformers(
669+
suspendTransTransformerForJsPromise
670+
)
671+
}
672+
```
673+
674+
## 应用案例
675+
676+
- [Simple Robot 框架](https://github.com/simple-robot/simpler-robot) (完全定制化)
549677

550678
## 开源协议
551679

compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/SuspendTransformConfiguration.kt

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,12 @@ open class SuspendTransformConfiguration {
221221
@JvmStatic
222222
val jvmSyntheticClassInfo = ClassInfo("kotlin.jvm", "JvmSynthetic")
223223

224+
@JvmStatic
225+
val kotlinOptInClassInfo = ClassInfo("kotlin", "OptIn")
226+
224227
@JvmStatic
225228
val jvmApi4JAnnotationClassInfo = ClassInfo("love.forte.plugin.suspendtrans.annotation", "Api4J")
226-
//endregion
227229

228-
//region JVM blocking defaults
229230

230231
@JvmStatic
231232
val jvmBlockingMarkAnnotationClassInfo = ClassInfo("love.forte.plugin.suspendtrans.annotation", "JvmBlocking")
@@ -240,6 +241,21 @@ open class SuspendTransformConfiguration {
240241
JVM_RUN_IN_BLOCKING_FUNCTION_FUNCTION_NAME,
241242
)
242243

244+
@JvmStatic
245+
val jvmAsyncMarkAnnotationClassInfo = ClassInfo("love.forte.plugin.suspendtrans.annotation", "JvmAsync")
246+
247+
@JvmStatic
248+
val jvmAsyncAnnotationInfo = MarkAnnotation(jvmAsyncMarkAnnotationClassInfo, defaultSuffix = "Async")
249+
250+
@JvmStatic
251+
val jvmAsyncTransformFunction = FunctionInfo(
252+
JVM_RUN_IN_ASYNC_FUNCTION_PACKAGE_NAME,
253+
JVM_RUN_IN_ASYNC_FUNCTION_CLASS_NAME,
254+
JVM_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME,
255+
)
256+
//endregion
257+
258+
//region JVM blocking defaults
243259
@JvmStatic
244260
val jvmBlockingTransformer = Transformer(
245261
markAnnotation = jvmBlockingAnnotationInfo,
@@ -248,7 +264,12 @@ open class SuspendTransformConfiguration {
248264
transformReturnTypeGeneric = false,
249265
originFunctionIncludeAnnotations = listOf(IncludeAnnotation(jvmSyntheticClassInfo)),
250266
copyAnnotationsToSyntheticFunction = true,
251-
copyAnnotationExcludes = listOf(jvmSyntheticClassInfo, jvmBlockingAnnotationInfo.classInfo),
267+
copyAnnotationExcludes = listOf(
268+
jvmSyntheticClassInfo,
269+
jvmBlockingMarkAnnotationClassInfo,
270+
jvmAsyncMarkAnnotationClassInfo,
271+
kotlinOptInClassInfo,
272+
),
252273
syntheticFunctionIncludeAnnotations = listOf(
253274
IncludeAnnotation(jvmApi4JAnnotationClassInfo)
254275
.apply { includeProperty = true }
@@ -257,18 +278,6 @@ open class SuspendTransformConfiguration {
257278
//endregion
258279

259280
//region JVM async defaults
260-
@JvmStatic
261-
val jvmAsyncMarkAnnotationClassInfo = ClassInfo("love.forte.plugin.suspendtrans.annotation", "JvmAsync")
262-
263-
@JvmStatic
264-
val jvmAsyncAnnotationInfo = MarkAnnotation(jvmAsyncMarkAnnotationClassInfo, defaultSuffix = "Async")
265-
266-
@JvmStatic
267-
val jvmAsyncTransformFunction = FunctionInfo(
268-
JVM_RUN_IN_ASYNC_FUNCTION_PACKAGE_NAME,
269-
JVM_RUN_IN_ASYNC_FUNCTION_CLASS_NAME,
270-
JVM_RUN_IN_ASYNC_FUNCTION_FUNCTION_NAME,
271-
)
272281

273282
@JvmStatic
274283
val jvmAsyncTransformer = Transformer(
@@ -278,7 +287,12 @@ open class SuspendTransformConfiguration {
278287
transformReturnTypeGeneric = true,
279288
originFunctionIncludeAnnotations = listOf(IncludeAnnotation(jvmSyntheticClassInfo)),
280289
copyAnnotationsToSyntheticFunction = true,
281-
copyAnnotationExcludes = listOf(jvmSyntheticClassInfo, jvmAsyncAnnotationInfo.classInfo),
290+
copyAnnotationExcludes = listOf(
291+
jvmSyntheticClassInfo,
292+
jvmBlockingMarkAnnotationClassInfo,
293+
jvmAsyncMarkAnnotationClassInfo,
294+
kotlinOptInClassInfo,
295+
),
282296
syntheticFunctionIncludeAnnotations = listOf(
283297
IncludeAnnotation(jvmApi4JAnnotationClassInfo).apply {
284298
includeProperty = true
@@ -312,7 +326,10 @@ open class SuspendTransformConfiguration {
312326
transformReturnTypeGeneric = true,
313327
originFunctionIncludeAnnotations = listOf(),
314328
copyAnnotationsToSyntheticFunction = true,
315-
copyAnnotationExcludes = listOf(jsAsyncAnnotationInfo.classInfo),
329+
copyAnnotationExcludes = listOf(
330+
jsAsyncMarkAnnotationClassInfo,
331+
kotlinOptInClassInfo,
332+
),
316333
syntheticFunctionIncludeAnnotations = listOf(
317334
IncludeAnnotation(jsApi4JsAnnotationInfo).apply {
318335
includeProperty = true

0 commit comments

Comments
 (0)