Skip to content

Commit

Permalink
Merge pull request #771 from IlyaGulya/feature/add-wasmJs-target-support
Browse files Browse the repository at this point in the history
Support wasmJs target
  • Loading branch information
CherryPerry committed Jan 11, 2024
2 parents 6849fb6 + a4fe69f commit 61cc293
Show file tree
Hide file tree
Showing 54 changed files with 419 additions and 105 deletions.
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ kotlin.code.style=official
org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true

# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with the app's APK
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true

kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.mpp.applyDefaultHierarchyTemplate=false

# For compatibility with Kotlin 1.9.0, see https://github.com/badoo/Reaktive/issues/697
Expand Down
10 changes: 3 additions & 7 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
[versions]
kotlin = "1.9.21"
kotlinx-coroutines = "1.7.3"
kotlinx-coroutines = "1.8.0-RC2"
detekt = "1.22.0"

[libraries]
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-stdlib-js = { module = "org.jetbrains.kotlin:kotlin-stdlib-js", version.ref = "kotlin" }
kotlin-stdlib-common = { module = "org.jetbrains.kotlin:kotlin-stdlib-common", version.ref = "kotlin" }

kotlin-test-common = { module = "org.jetbrains.kotlin:kotlin-test-common", version.ref = "kotlin" }
kotlin-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "kotlin" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
kotlin-test-annotations = { module = "org.jetbrains.kotlin:kotlin-test-annotations-common", version.ref = "kotlin" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-test-annotations = { module = "org.jetbrains.kotlin:kotlin-test-annotations", version.ref = "kotlin" }

kotlinx-compatibility = "org.jetbrains.kotlinx:binary-compatibility-validator:0.13.2"
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class JsPlugin : Plugin<Project> {

private fun configureJsCompilation(target: Project) {
target.extensions.configure(KotlinMultiplatformExtension::class.java) {
js(IR) {
js {
browser {
testTask {
useKarma {
Expand All @@ -31,12 +31,12 @@ class JsPlugin : Plugin<Project> {
}
sourceSets.getByName("jsMain") {
dependencies {
implementation(project.getLibrary("kotlin-stdlib-js"))
implementation(project.getLibrary("kotlin-stdlib"))
}
}
sourceSets.getByName("jsTest") {
dependencies {
implementation(project.getLibrary("kotlin-test-js"))
implementation(project.getLibrary("kotlin-test"))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ class MppConfigurationPlugin : Plugin<Project> {
target.version = target.findProperty("reaktive_version") as Any
target.extensions.configure(KotlinMultiplatformExtension::class.java) {
sourceSets {
maybeCreate("commonMain").dependencies { implementation(target.getLibrary("kotlin-stdlib-common")) }
maybeCreate("commonMain").dependencies { implementation(target.getLibrary("kotlin-stdlib")) }
maybeCreate("commonTest").dependencies {
implementation(target.getLibrary("kotlin-test-common"))
implementation(target.getLibrary("kotlin-test-annotations"))
implementation(target.getLibrary("kotlin-test"))
}
}

Expand All @@ -48,6 +47,7 @@ class MppConfigurationPlugin : Plugin<Project> {
setupAndroidTarget(project)
setupJvmTarget(project)
setupJsTarget(project)
setupWasmJsTarget(project)
setupLinuxX64Target(project)
setupIosTargets(project)

Expand Down Expand Up @@ -80,8 +80,14 @@ class MppConfigurationPlugin : Plugin<Project> {
maybeCreate("androidMain").dependsOn(getByName("jvmCommonMain"))
maybeCreate("androidUnitTest").dependsOn(getByName("jvmCommonTest"))

maybeCreate("jsMain").dependsOn(getByName("jvmJsCommonMain"))
maybeCreate("jsTest").dependsOn(getByName("jvmJsCommonTest"))
maybeCreate("jsCommonMain").dependsOn(getByName("jvmJsCommonMain"))
maybeCreate("jsCommonTest").dependsOn(getByName("jvmJsCommonTest"))

maybeCreate("jsMain").dependsOn(getByName("jsCommonMain"))
maybeCreate("jsTest").dependsOn(getByName("jsCommonTest"))

maybeCreate("wasmJsMain").dependsOn(getByName("jsCommonMain"))
maybeCreate("wasmJsTest").dependsOn(getByName("jsCommonTest"))

maybeCreate("nativeCommonMain").dependsOn(getByName("jvmNativeCommonMain"))
maybeCreate("nativeCommonTest").dependsOn(getByName("jvmNativeCommonTest"))
Expand Down Expand Up @@ -162,7 +168,7 @@ class MppConfigurationPlugin : Plugin<Project> {
}
sourceSets {
maybeCreate("androidMain").dependencies { implementation(project.getLibrary("kotlin-stdlib")) }
maybeCreate("androidUnitTest").dependencies { implementation(project.getLibrary("kotlin-test-junit")) }
maybeCreate("androidUnitTest").dependencies { implementation(project.getLibrary("kotlin-test")) }
}
}
}
Expand All @@ -179,7 +185,7 @@ class MppConfigurationPlugin : Plugin<Project> {
}
sourceSets {
maybeCreate("jvmMain").dependencies { implementation(project.getLibrary("kotlin-stdlib")) }
maybeCreate("jvmTest").dependencies { implementation(project.getLibrary("kotlin-test-junit")) }
maybeCreate("jvmTest").dependencies { implementation(project.getLibrary("kotlin-test")) }
}
}
}
Expand All @@ -188,6 +194,10 @@ class MppConfigurationPlugin : Plugin<Project> {
project.apply<JsPlugin>()
}

private fun setupWasmJsTarget(project: Project) {
project.apply<WasmJsPlugin>()
}

private fun setupLinuxX64Target(project: Project) {
project.kotlin {
linuxX64 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum class Target(
ALL_LINUX_HOSTED(linuxHosted = true, macOsHosted = false),
JVM(linuxHosted = true, macOsHosted = false),
JS(linuxHosted = true, macOsHosted = false),
WASM_JS(linuxHosted = true, macOsHosted = false),
LINUX(linuxHosted = true, macOsHosted = false),
ALL_MACOS_HOSTED(linuxHosted = false, macOsHosted = true),
IOS(linuxHosted = false, macOsHosted = true),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.badoo.reaktive.configuration

import com.badoo.reaktive.getLibrary
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl

@OptIn(ExperimentalWasmDsl::class)
class WasmJsPlugin : Plugin<Project> {

override fun apply(target: Project) {
configureWasmJsCompilation(target)
}

private fun configureWasmJsCompilation(target: Project) {
target.extensions.configure(KotlinMultiplatformExtension::class.java) {
wasmJs {
browser()
disableIfUndefined(Target.WASM_JS)
}
sourceSets.getByName("wasmJsMain") {
dependencies {
implementation(project.getLibrary("kotlin-stdlib"))
}
}
sourceSets.getByName("wasmJsTest") {
dependencies {
implementation(project.getLibrary("kotlin-test"))
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class PublishConfigurationPlugin : Plugin<Project> {
KotlinMultiplatformPlugin.METADATA_TARGET_NAME to Target.shouldPublishTarget(project, Target.META),
"jvm" to Target.shouldPublishTarget(project, Target.JVM),
"js" to Target.shouldPublishTarget(project, Target.JS),
"wasmJs" to Target.shouldPublishTarget(project, Target.WASM_JS),
"androidDebug" to Target.shouldPublishTarget(project, Target.JVM),
"androidRelease" to Target.shouldPublishTarget(project, Target.JVM),
"linuxX64" to Target.shouldPublishTarget(project, Target.LINUX),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.badoo.reaktive.test.single

expect class AsyncTestResult
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ import com.badoo.reaktive.single.Single
* @param assertSuccess when provided, it will be called in case of [Single] success.
* This gives an opportunity to assert the result.
*/
expect fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)? = null, assertSuccess: (T) -> Unit)
expect fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)? = null, assertSuccess: (T) -> Unit): AsyncTestResult
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class TestAwaitTest {
.testAwait(assertSuccess = { assertEquals(1, it) })

@Test
fun succeeds_WHEN_upstream_failed_and_assertError_did_not_throw() {
fun succeeds_WHEN_upstream_failed_and_assertError_did_not_throw(): AsyncTestResult {
val error = Exception()

return singleOfError<Nothing>(error)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.badoo.reaktive.test.single

@Suppress("UnusedPrivateMember")
@JsName("Promise")
actual external class AsyncTestResult(
executor: (resolve: (Unit) -> Unit, reject: (Throwable) -> Unit) -> Unit,
)
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package com.badoo.reaktive.test.single

import com.badoo.reaktive.single.Single
import com.badoo.reaktive.single.asPromise
import com.badoo.reaktive.single.doOnBeforeSuccess
import com.badoo.reaktive.single.map
import com.badoo.reaktive.single.onErrorReturn
import com.badoo.reaktive.single.subscribe

actual fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)?, assertSuccess: (T) -> Unit): dynamic =
actual fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)?, assertSuccess: (T) -> Unit): AsyncTestResult =
if (assertError == null) {
doOnBeforeSuccess(assertSuccess)
.asPromise()
.asTestResult()
} else {
map { TestAwaitResult.Success(it) }
.onErrorReturn { TestAwaitResult.Error(it) }
Expand All @@ -19,7 +19,15 @@ actual fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)?, assertSu
is TestAwaitResult.Error -> assertError(result.error)
}
}
.asPromise()
.asTestResult()
}

private fun <T> Single<T>.asTestResult(): AsyncTestResult =
AsyncTestResult { resolve, reject ->
subscribe(
onSuccess = { resolve(Unit) },
onError = reject,
)
}

private sealed class TestAwaitResult<out T> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.badoo.reaktive.test.single

@Suppress("ACTUAL_WITHOUT_EXPECT") // We never instantiate TestResult, see https://youtrack.jetbrains.com/issue/KT-64199
actual typealias AsyncTestResult = Unit
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ actual fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)?, assertSu

assertSuccess(result)
}

return
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.badoo.reaktive.test.single

@Suppress("UnusedPrivateMember")
@JsName("Promise")
actual external class AsyncTestResult(
executor: (resolve: (JsAny) -> Unit, reject: (JsAny) -> Unit) -> Unit,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.badoo.reaktive.test.single

import com.badoo.reaktive.single.Single
import com.badoo.reaktive.single.doOnBeforeSuccess
import com.badoo.reaktive.single.map
import com.badoo.reaktive.single.onErrorReturn
import com.badoo.reaktive.single.subscribe

actual fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)?, assertSuccess: (T) -> Unit): AsyncTestResult =
if (assertError == null) {
doOnBeforeSuccess(assertSuccess)
.asTestResult()
} else {
map { TestAwaitResult.Success(it) }
.onErrorReturn { TestAwaitResult.Error(it) }
.doOnBeforeSuccess { result ->
when (result) {
is TestAwaitResult.Success -> assertSuccess(result.value)
is TestAwaitResult.Error -> assertError(result.error)
}
}
.asTestResult()
}

private fun <T> Single<T>.asTestResult(): AsyncTestResult =
AsyncTestResult { resolve, reject ->
subscribe(
onSuccess = { resolve(Unit.toJsReference()) },
onError = { reject(it.toJsReference()) },
)
}

private sealed class TestAwaitResult<out T> {
class Success<out T>(val value: T) : TestAwaitResult<T>()
class Error(val error: Throwable) : TestAwaitResult<Nothing>()
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ class RepeatWhenTest : ObservableToObservableTests by ObservableToObservableTest
.test()

upstream.onComplete()
assertSame(timeRef, 1)
assertEquals(timeRef, 1)
upstream.onComplete()
assertSame(timeRef, 2)
assertEquals(timeRef, 2)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ class RepeatWhenTest : SingleToObservableTests by SingleToObservableTestsImpl({
.test()

upstream.onComplete()
assertSame(attemptVar, 1)
assertEquals(attemptVar, 1)
upstream.onComplete()
assertSame(attemptVar, 2)
assertEquals(attemptVar, 2)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private class SubjectGenericTestsImpl(
subject.onNext(0)
subject.onComplete()

observers.forEach(TestObservableObserver<*>::assertComplete)
observers.forEach { it.assertComplete() }
}

override fun delivers_error_to_all_observers_WHEN_error_produced() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.badoo.reaktive.disposable

import kotlin.js.JsName

@JsName("disposableWithCallback")
@Suppress("FunctionName")
actual inline fun Disposable(crossinline onDispose: () -> Unit): Disposable =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.badoo.reaktive.scheduler

internal expect fun jsSetTimeout(task: () -> Unit, delayMillis: Int): TimeoutId

internal expect fun jsSetInterval(task: () -> Unit, delayMillis: Int): TimeoutId

internal expect fun jsClearTimeout(id: TimeoutId)

internal expect fun jsClearInterval(id: TimeoutId)

0 comments on commit 61cc293

Please sign in to comment.