Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@

import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import util.kotlinVersionParsed
import util.libs

plugins {
alias(libs.plugins.serialization) apply false
alias(libs.plugins.kotlinx.rpc) apply false
alias(libs.plugins.atomicfu) apply false
alias(libs.plugins.conventions.kover)
alias(libs.plugins.conventions.gradle.doctor)
alias(libs.plugins.binary.compatibility.validator)

if (libs.versions.atomicfu.get() >= "0.24.0") {
alias(libs.plugins.atomicfu.new)
} else {
alias(libs.plugins.atomicfu.old)
}
}

// useful for dependencies introspection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform

interface VersionSpecificApi {
fun isJs(platform: TargetPlatform?): Boolean
fun isWasm(platform: TargetPlatform?): Boolean

fun referenceClass(context: IrPluginContext, packageName: String, name: String): IrClassSymbol?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ internal class RPCIrContext(
return pluginContext.platform.isNative()
}

fun isWasmTarget(): Boolean {
return versionSpecificApi.isWasm(pluginContext.platform)
}

val functions = Functions()

inner class Functions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1209,10 +1209,10 @@ internal class RPCStubGenerator(
}
}

// Associated object annotation works on JS and Native platforms.
// Associated object annotation works on JS, WASM, and Native platforms.
// See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/find-associated-object.html
private fun addAssociatedObjectAnnotationIfPossible() {
if (ctx.isJsTarget() || ctx.isNativeTarget()) {
if (ctx.isJsTarget() || ctx.isNativeTarget() || ctx.isWasmTarget()) {
addAssociatedObjectAnnotation()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isJs
import org.jetbrains.kotlin.platform.isWasm

object VersionSpecificApiImpl : VersionSpecificApi {
override fun isJs(platform: TargetPlatform?): Boolean {
return platform.isJs()
}

override fun isWasm(platform: TargetPlatform?): Boolean {
return platform.isWasm()
}

override var IrFieldBuilder.isFinalVS: Boolean
get() = isFinal
set(value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ object VersionSpecificApiImpl : VersionSpecificApi {
override fun isJs(platform: TargetPlatform?): Boolean {
return platform.isJs()
}

override fun isWasm(platform: TargetPlatform?): Boolean = false

override var IrFieldBuilder.isFinalVS: Boolean
get() = undefinedAPI()
set(_) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ object VersionSpecificApiImpl : VersionSpecificApi {
override fun isJs(platform: TargetPlatform?): Boolean {
return platform.isJs()
}

override fun isWasm(platform: TargetPlatform?): Boolean = false

override var IrFieldBuilder.isFinalVS: Boolean
get() = undefinedAPI()
set(_) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ object VersionSpecificApiImpl : VersionSpecificApi {
override fun isJs(platform: TargetPlatform?): Boolean {
return platform.isJs()
}

override fun isWasm(platform: TargetPlatform?): Boolean = false

override var IrFieldBuilder.isFinalVS: Boolean
get() = undefinedAPI()
set(_) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ object VersionSpecificApiImpl : VersionSpecificApi {
return platform.isJs()
}

override fun isWasm(platform: TargetPlatform?): Boolean = false

override var IrFieldBuilder.isFinalVS: Boolean
get() = modality == Modality.FINAL
set(value) {
Expand Down
15 changes: 14 additions & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

import util.applyAtomicfuPlugin

/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

plugins {
alias(libs.plugins.conventions.kmp)
alias(libs.plugins.atomicfu)
}

applyAtomicfuPlugin()

kotlin {
sourceSets {
commonMain {
Expand All @@ -24,5 +31,11 @@ kotlin {
implementation(libs.kotlin.js.wrappers)
}
}

wasmJsMain {
dependencies {
implementation(libs.kotlinx.browser)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("detekt.MatchingDeclarationName")

package kotlinx.rpc.internal

import kotlinx.rpc.internal.utils.InternalRPCApi
import kotlin.reflect.KClass

@InternalRPCApi
public actual val KClass<*>.qualifiedClassNameOrNull: String?
get() = toString()

@InternalRPCApi
public actual val KClass<*>.typeName: String?
get() = qualifiedClassNameOrNull
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("detekt.MatchingDeclarationName")

package kotlinx.rpc.internal

import kotlinx.rpc.RPC
import kotlinx.rpc.internal.utils.InternalRPCApi
import kotlin.reflect.AssociatedObjectKey
import kotlin.reflect.ExperimentalAssociatedObjects
import kotlin.reflect.KClass
import kotlin.reflect.findAssociatedObject

@InternalRPCApi
@AssociatedObjectKey
@OptIn(ExperimentalAssociatedObjects::class)
@Target(AnnotationTarget.CLASS)
public annotation class WithRPCStubObject(
@Suppress("unused")
val stub: KClass<out RPCStubObject<out RPC>>
)

@OptIn(ExperimentalAssociatedObjects::class)
@InternalRPCApi
public actual fun <R : Any> findRPCStubProvider(kClass: KClass<*>, resultKClass: KClass<R>): R {
val associatedObject = kClass.findAssociatedObject<WithRPCStubObject>()
?: internalError("Unable to find $kClass associated object")

if (resultKClass.isInstance(associatedObject)) {
@Suppress("UNCHECKED_CAST")
return associatedObject as R
}

internalError(
"Located associated object is not of desired type $resultKClass, " +
"instead found $associatedObject of class " +
(associatedObject::class.qualifiedClassNameOrNull ?: associatedObject::class)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("detekt.MatchingDeclarationName")

package kotlinx.rpc.internal

import kotlinx.rpc.internal.utils.InternalRPCApi
import kotlin.reflect.KClass

@InternalRPCApi
public actual val KClass<*>.qualifiedClassNameOrNull: String?
get() = toString()

@InternalRPCApi
public actual val KClass<*>.typeName: String?
get() = qualifiedClassNameOrNull
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("detekt.MatchingDeclarationName")

package kotlinx.rpc.internal

import kotlinx.rpc.RPC
import kotlinx.rpc.internal.utils.InternalRPCApi
import kotlin.reflect.AssociatedObjectKey
import kotlin.reflect.ExperimentalAssociatedObjects
import kotlin.reflect.KClass
import kotlin.reflect.findAssociatedObject

@InternalRPCApi
@AssociatedObjectKey
@OptIn(ExperimentalAssociatedObjects::class)
@Target(AnnotationTarget.CLASS)
public annotation class WithRPCStubObject(
@Suppress("unused")
val stub: KClass<out RPCStubObject<out RPC>>
)

@OptIn(ExperimentalAssociatedObjects::class)
@InternalRPCApi
public actual fun <R : Any> findRPCStubProvider(kClass: KClass<*>, resultKClass: KClass<R>): R {
val associatedObject = kClass.findAssociatedObject<WithRPCStubObject>()
?: internalError("Unable to find $kClass associated object")

if (resultKClass.isInstance(associatedObject)) {
@Suppress("UNCHECKED_CAST")
return associatedObject as R
}

internalError(
"Located associated object is not of desired type $resultKClass, " +
"instead found $associatedObject of class " +
(associatedObject::class.qualifiedClassNameOrNull ?: associatedObject::class)
)
}
58 changes: 33 additions & 25 deletions gradle-conventions-settings/src/main/kotlin/util/JsTarget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,53 @@

package util

import org.gradle.api.Project
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.getting
import org.gradle.kotlin.dsl.invoke
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import java.io.File

fun Project.configureJs() {
configureJsTasks()
fun ProjectKotlinConfig.configureJsAndWasmJs() {
if (!js) {
return
}

kotlin {
js(IR) {
configureJsAndWasmJsTasks()
}

sourceSets {
jsTest {
dependencies {
implementation(npm("puppeteer", "*"))
}
val jsTest by getting {
puppeteer()
}
}
}
}

private fun Project.configureJsTasks() {
kotlin {
js(IR) {
nodejs {
testTask {
useMocha {
timeout = "10000"
}
}
}
fun KotlinSourceSet.puppeteer() {
dependencies {
implementation(npm("puppeteer", "*"))
}
}

browser {
testTask {
useKarma {
useChromeHeadless()
useConfigDirectory(File(project.rootProject.projectDir, "karma"))
}
}
fun KotlinJsTargetDsl.configureJsAndWasmJsTasks() {
nodejs {
testTask {
useMocha {
timeout = "10000"
}
}
}

binaries.library()
(this as KotlinJsIrTarget).whenBrowserConfigured {
testTask {
useKarma {
useChromeHeadless()
useConfigDirectory(File(project.rootProject.projectDir, "karma"))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.gradle.api.Project
import kotlin.reflect.KProperty

class OptionalProperty(private val target: Project) {
operator fun getValue(thisRef: Any, property: KProperty<*>): Boolean {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return getValue("kotlinx.rpc.${property.name}")
}

Expand Down
Loading