From 8d995f3c8c82b30e8d573ecf2b038358c207be96 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Wed, 6 Apr 2022 20:01:06 +0200 Subject: [PATCH] Release 1.1.0 (#4) * (build-logic, core logging):Add Context function - Publish generated files - Restructure file generation logic * core: Fix indent of contract call * all: Unify test platform APIs * Add serialization module Co-Authored-By: Michael Rittmeister * Add EmptyJsonObject.kt * Final preparations for 1.1.0 * Install Proper Java version in CI * Fix kbson test dependency * Fix gradle buildscript * Export json dependency as api * Fix ios api Co-authored-by: NyCode --- .github/workflows/ci.yml | 16 +++ build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 3 +- .../main/kotlin/AbstractGenerateFilesTask.kt | 44 +++++++ .../kotlin/GenerateContextFunctionsTask.kt | 99 ++++++++++++++++ .../kotlin/GenerateLoggerFunctionsTask.kt | 78 ++++--------- buildSrc/src/main/kotlin/GradleExtensions.kt | 3 + buildSrc/src/main/kotlin/Targets.kt | 17 +-- .../src/main/kotlin/all-platforms.gradle.kts | 9 ++ .../kotlin/apple-mobile-platforms.gradle.kts | 7 ++ .../src/main/kotlin/desktop-X86.gradle.kts | 10 ++ .../src/main/kotlin/desktop-all.gradle.kts | 7 ++ buildSrc/src/main/kotlin/full-js.gradle.kts | 7 ++ buildSrc/src/main/kotlin/nodejs.gradle.kts | 7 ++ .../kotlin/stdx-generated-elements.gradle.kts | 22 ++++ .../src/main/kotlin/stdx-module.gradle.kts | 11 +- core/build.gradle.kts | 15 ++- .../dev/schlaubi/stdx/core/StringUtil.kt | 2 + coroutines/build.gradle.kts | 2 +- coroutines/src/commonTest/kotlin/Platform.kt | 1 - .../src/commonTest/kotlin/SuspendLazyTest.kt | 4 +- coroutines/src/jsTest/kotlin/Platform.kt | 1 - coroutines/src/jvmTest/kotlin/Platform.kt | 1 - coroutines/src/nativeTest/kotlin/Platform.kt | 1 - envconf/build.gradle.kts | 7 +- full/build.gradle.kts | 10 +- gradle.properties | 3 +- logging/build.gradle.kts | 25 +--- .../schlaubi/stdx/logging/InlinedLogger.kt | 56 +++++++++ .../schlaubi/stdx/logging/InlinedLogger.kt | 108 ++++++++++++++++++ .../schlaubi/stdx/logging/InlinedLogger.kt | 106 +++++++++++++++++ .../schlaubi/stdx/logging/InlinedLogger.kt | 108 ++++++++++++++++++ serialization/api/stdx-serialization.api | 58 ++++++++++ serialization/build.gradle.kts | 30 +++++ .../stdx/serialization/EmptyJsonObject.kt | 10 ++ serialization/src/commonTest/kotlin/Utils.kt | 45 ++++++++ .../stdx/serialization/InstantSerializer.kt | 22 ++++ .../stdx/serialization/LocalDateSerializer.kt | 20 ++++ .../serialization/LocalDateTimeSerializer.kt | 20 ++++ .../stdx/serialization/LocalTimeSerializer.kt | 20 ++++ .../serialization/UUIDBinarySerializer.kt | 43 +++++++ .../serialization/UUIDStringSerializer.kt | 22 ++++ .../kotlin/BinarySerializationTests.kt | 36 ++++++ .../kotlin/LocalDateSerializationTests.kt | 35 ++++++ .../kotlin/LocalDateTimeSerializationTests.kt | 35 ++++++ .../kotlin/LocalTimeSerializationTests.kt | 35 ++++++ .../kotlin/StringSerializationTests.kt | 39 +++++++ serialization/src/jvmTest/kotlin/Utils.kt | 11 ++ settings.gradle.kts | 2 +- test-tools/README.md | 3 + test-tools/api/stdx-test-tools.api | 9 ++ test-tools/build.gradle.kts | 5 + test-tools/src/commonMain/kotlin/Platform.kt | 28 +++++ test-tools/src/jsMain/kotlin/Platform.kt | 11 ++ test-tools/src/jvmMain/kotlin/Platform.kt | 7 ++ test-tools/src/nativeMain/kotlin/Platform.kt | 7 ++ 56 files changed, 1228 insertions(+), 117 deletions(-) create mode 100644 buildSrc/src/main/kotlin/AbstractGenerateFilesTask.kt create mode 100644 buildSrc/src/main/kotlin/GenerateContextFunctionsTask.kt create mode 100644 buildSrc/src/main/kotlin/all-platforms.gradle.kts create mode 100644 buildSrc/src/main/kotlin/apple-mobile-platforms.gradle.kts create mode 100644 buildSrc/src/main/kotlin/desktop-X86.gradle.kts create mode 100644 buildSrc/src/main/kotlin/desktop-all.gradle.kts create mode 100644 buildSrc/src/main/kotlin/full-js.gradle.kts create mode 100644 buildSrc/src/main/kotlin/nodejs.gradle.kts create mode 100644 buildSrc/src/main/kotlin/stdx-generated-elements.gradle.kts delete mode 100644 coroutines/src/commonTest/kotlin/Platform.kt delete mode 100644 coroutines/src/jsTest/kotlin/Platform.kt delete mode 100644 coroutines/src/jvmTest/kotlin/Platform.kt delete mode 100644 coroutines/src/nativeTest/kotlin/Platform.kt create mode 100644 logging/src/commonGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt create mode 100644 logging/src/jsGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt create mode 100644 logging/src/jvmGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt create mode 100644 logging/src/nativeGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt create mode 100644 serialization/api/stdx-serialization.api create mode 100644 serialization/build.gradle.kts create mode 100644 serialization/src/commonMain/kotlin/dev/schlaubi/stdx/serialization/EmptyJsonObject.kt create mode 100644 serialization/src/commonTest/kotlin/Utils.kt create mode 100644 serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/InstantSerializer.kt create mode 100644 serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateSerializer.kt create mode 100644 serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateTimeSerializer.kt create mode 100644 serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalTimeSerializer.kt create mode 100644 serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDBinarySerializer.kt create mode 100644 serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDStringSerializer.kt create mode 100644 serialization/src/jvmTest/kotlin/BinarySerializationTests.kt create mode 100644 serialization/src/jvmTest/kotlin/LocalDateSerializationTests.kt create mode 100644 serialization/src/jvmTest/kotlin/LocalDateTimeSerializationTests.kt create mode 100644 serialization/src/jvmTest/kotlin/LocalTimeSerializationTests.kt create mode 100644 serialization/src/jvmTest/kotlin/StringSerializationTests.kt create mode 100644 serialization/src/jvmTest/kotlin/Utils.kt create mode 100644 test-tools/README.md create mode 100644 test-tools/api/stdx-test-tools.api create mode 100644 test-tools/build.gradle.kts create mode 100644 test-tools/src/commonMain/kotlin/Platform.kt create mode 100644 test-tools/src/jsMain/kotlin/Platform.kt create mode 100644 test-tools/src/jvmMain/kotlin/Platform.kt create mode 100644 test-tools/src/nativeMain/kotlin/Platform.kt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37bfb04..ed95e78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,10 @@ jobs: name: Run tests and linter steps: - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: 'temurin' # See 'Supported distributions' for available options + java-version: '17' - uses: gradle/gradle-build-action@v2 name: Validate Code with: @@ -30,6 +34,10 @@ jobs: name: Run binary compatibility validator steps: - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: 'temurin' # See 'Supported distributions' for available options + java-version: '17' - uses: gradle/gradle-build-action@v2 name: Validate Binary Compatibility with: @@ -50,6 +58,10 @@ jobs: ACTIONS_ALLOW_UNSECURE_COMMANDS: true steps: - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: 'temurin' # See 'Supported distributions' for available options + java-version: '17' - uses: gradle/gradle-build-action@v2 name: Publish Code with: @@ -61,6 +73,10 @@ jobs: if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: 'temurin' # See 'Supported distributions' for available options + java-version: '17' - uses: gradle/gradle-build-action@v2 name: Generate Docs with: diff --git a/build.gradle.kts b/build.gradle.kts index d6372b8..06567e1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { allprojects { - version = "1.0.1" + version = "1.1.0" group = "dev.schlaubi" repositories { mavenCentral() diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 5e36258..edb0b28 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -9,7 +9,8 @@ repositories { } dependencies { - implementation(kotlin("gradle-plugin", version = "1.6.10")) + implementation(kotlin("gradle-plugin", version = "1.6.20")) + implementation(kotlin("serialization", version = "1.6.20")) implementation("org.jetbrains.dokka", "dokka-gradle-plugin", "1.6.10") implementation("org.jlleitschuh.gradle", "ktlint-gradle", "10.2.1") implementation("com.squareup", "kotlinpoet", "1.11.0") diff --git a/buildSrc/src/main/kotlin/AbstractGenerateFilesTask.kt b/buildSrc/src/main/kotlin/AbstractGenerateFilesTask.kt new file mode 100644 index 0000000..8073b14 --- /dev/null +++ b/buildSrc/src/main/kotlin/AbstractGenerateFilesTask.kt @@ -0,0 +1,44 @@ +import com.squareup.kotlinpoet.FileSpec +import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory +import java.nio.file.Files +import java.nio.file.Path + +abstract class AbstractGenerateFilesTask : DefaultTask() { + + @get:Input + abstract val `package`: Property + + @get:OutputDirectory + protected val outputDir = project.projectDir + .toPath() + .resolvePaths("src") + + protected fun generateFile( + sourceSet: String, + fileName: String, + filter: (CharSequence) -> CharSequence = { it }, + block: FileSpec.Builder.() -> Unit + ) { + val file = FileSpec.builder(`package`.get(), fileName) + .apply(block) + .addFileComment("This file is generated by Gradle task $name please do not edit it manually") + .build() + + val builder = StringBuilder() + file.writeTo(builder) + val newOutput = filter(builder) + + val out = outputDir + .resolve("${sourceSet}Generated") + .resolvePaths(*file.packageName.split('.').toTypedArray()) + .resolve("$fileName.kt") + Files.createDirectories(out.parent) + Files.writeString(out, newOutput) + } + + protected fun Path.resolvePaths(vararg relative: String) = + relative.toList().fold(this) { parent, currentRelative -> parent.resolve(currentRelative) } +} diff --git a/buildSrc/src/main/kotlin/GenerateContextFunctionsTask.kt b/buildSrc/src/main/kotlin/GenerateContextFunctionsTask.kt new file mode 100644 index 0000000..52e2852 --- /dev/null +++ b/buildSrc/src/main/kotlin/GenerateContextFunctionsTask.kt @@ -0,0 +1,99 @@ +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.LambdaTypeName +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.TypeAliasSpec +import com.squareup.kotlinpoet.TypeVariableName +import org.gradle.api.tasks.TaskAction + +const val returnTypeParameter = "ReturnType" + +abstract class GenerateContextFunctionsTask : AbstractGenerateFilesTask() { + @TaskAction + fun generate() { + generateFile("common", "ContextFunctions", { + it.replace("import `?lambda_A(, [A-Z])*`?\n".toRegex(), "") + .replaceFirst("lambda_A", "A.() -> ReturnType") + .replace("`lambda_A(?:, ((?:(?:, )?[A-Z])*)`)?".toRegex(), "context($1) A.() -> ReturnType") + }) { + addImport("kotlin.contracts", "InvocationKind", "contract") + + val alphabet = ('A'..'Z').toList() + + val functions = ArrayList(alphabet.size) + + repeat(alphabet.size) { + val count = it + 1 + val current = alphabet.take(count) + val typeVariables = (current.map(Char::toString) + returnTypeParameter).map { name -> + TypeVariableName(name) + } + + val lambdaRaw = LambdaTypeName.get( + typeVariables.first(), + returnType = typeVariables.last() + ).toString() + + val lambda = "lambda_${typeVariables.dropLast(1).joinToString(", ") { variable -> variable.name }}" + + val typeAlias = ClassName(packageName, "ContextReceiver$count") + + addTypeAlias( + TypeAliasSpec.builder(typeAlias.simpleName, ClassName("", lambda)) + .addModifiers(KModifier.PUBLIC) + .addTypeVariables(typeVariables) + .addKdoc( + """ + Lambda with $count context receivers. + + @see context""".trimIndent() + ) + .build() + ) + + val argumentList = if (count > 1) { + (typeVariables.subList(1, typeVariables.size - 1) + .map { variable -> variable.name.toLowerCase() } + 'a').joinToString( + ", " + ) + } else { + 'a' + } + + val function = FunSpec.builder("context") + .addModifiers(KModifier.PUBLIC, KModifier.INLINE) + .addTypeVariables(typeVariables) + .apply { + typeVariables.dropLast(1).forEach { type -> + addParameter(type.name.toLowerCase(), type) + } + } + .addParameter("block", typeAlias.parameterizedBy(typeVariables)) + .returns(typeVariables.last()) + .addKdoc( + """ + Adds ${ + typeVariables.dropLast(1) + .joinToString("], [", "[", "]") { it.name.toLowerCase() } + } to the context of [block] and returns its return value. + """.trimIndent() + ) + .addCode( + """ + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + + return block.invoke($argumentList) + """.trimIndent() + ) + .build() + + functions += function + } + + functions.forEach { addFunction(it) } + } + } +} diff --git a/buildSrc/src/main/kotlin/GenerateLoggerFunctionsTask.kt b/buildSrc/src/main/kotlin/GenerateLoggerFunctionsTask.kt index 41f1899..40ed663 100644 --- a/buildSrc/src/main/kotlin/GenerateLoggerFunctionsTask.kt +++ b/buildSrc/src/main/kotlin/GenerateLoggerFunctionsTask.kt @@ -3,36 +3,22 @@ import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.ParameterSpec -import org.gradle.api.DefaultTask import org.gradle.api.provider.ListProperty -import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import org.intellij.lang.annotations.Language -import java.nio.file.Path -abstract class GenerateLoggerFunctionsTask : DefaultTask() { - - @get:Input - abstract val `package`: Property +abstract class GenerateLoggerFunctionsTask : AbstractGenerateFilesTask() { @get:Input abstract val logLevels: ListProperty - private val outputDir = project.buildDir - .toPath() - .resolvePaths("generated", "src") - @Suppress("PrivatePropertyName") private val KLogger = ClassName("mu", "KLogger") - init { - outputs.dir(outputDir) - } - @TaskAction fun generate() { - generateFile("commonMain") { + generateFile("common", "InlinedLogger") { logLevels.get().forEach { level -> val functionName = "${level}Inlined" @@ -41,49 +27,48 @@ abstract class GenerateLoggerFunctionsTask : DefaultTask() { } } - generateFile("jvmMain") { + generateFile("jvm", "InlinedLogger") { generateLoggerFunctions { level, functionName -> // e.g debug -> isDebugEnabled val enabledPropertyName = "is${level[0].toUpperCase()}${level.drop(1)}Enabled" debugLevelInlined(functionName, level, KModifier.ACTUAL) { val code = """ - if ($enabledPropertyName) { - $level(message()) - } - """.trimIndent() + if ($enabledPropertyName) { + $level(message()) + } + """.trimIndent() addCode(code) } debugLevelInlinedWithThrowable(functionName, level, KModifier.ACTUAL) { val code = """ - if ($enabledPropertyName) { - val computedMessage = message() - - $level(throwable) { computedMessage } - } - """.trimIndent() + if ($enabledPropertyName) { + val computedMessage = message() + + $level(throwable) { computedMessage } + } + """.trimIndent() addCode(code) } } } - generateNonSLF4JFile("jsMain") - generateNonSLF4JFile("nativeMain") + generateNonSLF4JFile("js") + generateNonSLF4JFile("native") } private fun generateNonSLF4JFile(name: String) { - generateFile(name) { - addImport("mu", "KotlinLoggingLevel") - addImport("mu", "isLoggingEnabled") + generateFile(name, "InlinedLogger") { + addImport("mu", "KotlinLoggingLevel", "isLoggingEnabled") generateLoggerFunctions { level, functionName -> @Language("kotlin") fun code(call: String) = """ - if (KotlinLoggingLevel.${level.toUpperCase()}.isLoggingEnabled()) { - val computedLogMessage = message() - $call - } - """.trimIndent() + if (KotlinLoggingLevel.${level.toUpperCase()}.isLoggingEnabled()) { + val computedLogMessage = message() + $call + } + """.trimIndent() debugLevelInlined(functionName, level, KModifier.ACTUAL) { addCode(code("$level { computedLogMessage }")) @@ -103,17 +88,6 @@ abstract class GenerateLoggerFunctionsTask : DefaultTask() { } } - private fun generateFile(sourceSet: String, block: FileSpec.Builder.() -> Unit) { - val file = FileSpec.builder(`package`.get(), "InlinedLogger") - .apply { - commonImports() - } - .apply(block) - .build() - - file.writeTo(outputDir.resolve(sourceSet)) - } - private fun FileSpec.Builder.debugLevelInlined( functionName: String, level: String?, @@ -156,12 +130,4 @@ abstract class GenerateLoggerFunctionsTask : DefaultTask() { code() } } - - - private fun FileSpec.Builder.commonImports() { - addImport(KLogger.packageName, KLogger.simpleName) - } } - -private fun Path.resolvePaths(vararg relative: String) = - relative.toList().fold(this) { parent, currentRelative -> parent.resolve(currentRelative) } diff --git a/buildSrc/src/main/kotlin/GradleExtensions.kt b/buildSrc/src/main/kotlin/GradleExtensions.kt index d06a5a1..1440351 100644 --- a/buildSrc/src/main/kotlin/GradleExtensions.kt +++ b/buildSrc/src/main/kotlin/GradleExtensions.kt @@ -6,6 +6,9 @@ private fun notation(group: String, name: String, version: String? = null) = fun KotlinDependencyHandler.api(group: String, name: String, version: String? = null) = api(notation(group, name, version)) +fun KotlinDependencyHandler.compileOnly(group: String, name: String, version: String? = null) = + compileOnly(notation(group, name, version)) + fun KotlinDependencyHandler.implementation(group: String, name: String, version: String? = null) = implementation(notation(group, name, version)) diff --git a/buildSrc/src/main/kotlin/Targets.kt b/buildSrc/src/main/kotlin/Targets.kt index 4eefe88..03c2164 100644 --- a/buildSrc/src/main/kotlin/Targets.kt +++ b/buildSrc/src/main/kotlin/Targets.kt @@ -35,18 +35,19 @@ inline fun KotlinMultiplatformExtension.native(block: KotlinMultiplatformExtensi native(block()) fun KotlinMultiplatformExtension.native(target: KotlinNativeTarget) { + val nativeMain = sourceSets.maybeCreate("nativeMain").apply { + dependsOn(sourceSets.getByName("commonMain")) + } + val nativeTest = sourceSets.maybeCreate("nativeTest").apply { + dependsOn(sourceSets.getByName("commonTest")) + } + sourceSets.apply { getByName(target.name + "Main") { - dependsOn(getByName("nativeMain")) + dependsOn(nativeMain) } getByName(target.name + "Test") { - dependsOn(getByName("nativeTest")) + dependsOn(nativeTest) } } } - -fun KotlinMultiplatformExtension.all() { - fullJs() - desktopAll() - appleMobilePlatforms() -} diff --git a/buildSrc/src/main/kotlin/all-platforms.gradle.kts b/buildSrc/src/main/kotlin/all-platforms.gradle.kts new file mode 100644 index 0000000..c921428 --- /dev/null +++ b/buildSrc/src/main/kotlin/all-platforms.gradle.kts @@ -0,0 +1,9 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + fullJs() + desktopAll() + appleMobilePlatforms() +} diff --git a/buildSrc/src/main/kotlin/apple-mobile-platforms.gradle.kts b/buildSrc/src/main/kotlin/apple-mobile-platforms.gradle.kts new file mode 100644 index 0000000..d1b9f97 --- /dev/null +++ b/buildSrc/src/main/kotlin/apple-mobile-platforms.gradle.kts @@ -0,0 +1,7 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + appleMobilePlatforms() +} diff --git a/buildSrc/src/main/kotlin/desktop-X86.gradle.kts b/buildSrc/src/main/kotlin/desktop-X86.gradle.kts new file mode 100644 index 0000000..76e2425 --- /dev/null +++ b/buildSrc/src/main/kotlin/desktop-X86.gradle.kts @@ -0,0 +1,10 @@ +import gradle.kotlin.dsl.accessors._ab93fe423733af93ad8bc6bc1a01bf3e.kotlin +import org.gradle.kotlin.dsl.kotlin + +plugins { + kotlin("multiplatform") +} + +kotlin { + desktopOSX86() +} diff --git a/buildSrc/src/main/kotlin/desktop-all.gradle.kts b/buildSrc/src/main/kotlin/desktop-all.gradle.kts new file mode 100644 index 0000000..c2e94e8 --- /dev/null +++ b/buildSrc/src/main/kotlin/desktop-all.gradle.kts @@ -0,0 +1,7 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + desktopAll() +} diff --git a/buildSrc/src/main/kotlin/full-js.gradle.kts b/buildSrc/src/main/kotlin/full-js.gradle.kts new file mode 100644 index 0000000..cc5f25d --- /dev/null +++ b/buildSrc/src/main/kotlin/full-js.gradle.kts @@ -0,0 +1,7 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + fullJs() +} diff --git a/buildSrc/src/main/kotlin/nodejs.gradle.kts b/buildSrc/src/main/kotlin/nodejs.gradle.kts new file mode 100644 index 0000000..fab2892 --- /dev/null +++ b/buildSrc/src/main/kotlin/nodejs.gradle.kts @@ -0,0 +1,7 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + nodeJs() +} diff --git a/buildSrc/src/main/kotlin/stdx-generated-elements.gradle.kts b/buildSrc/src/main/kotlin/stdx-generated-elements.gradle.kts new file mode 100644 index 0000000..8c713d8 --- /dev/null +++ b/buildSrc/src/main/kotlin/stdx-generated-elements.gradle.kts @@ -0,0 +1,22 @@ +plugins { + kotlin("multiplatform") +} + + +afterEvaluate { + kotlin { + sourceSets { + listOf("common", "jvm", "js", "native").forEach { platform -> + val path = "${platform}Main" + val dir = projectDir.resolve("src").resolve("${platform}Generated") + kotlin.sourceSets.findByName(path)?.apply { + kotlin.srcDir(dir) + } + } + } + } +} + +tasks { + task("generateElements") +} diff --git a/buildSrc/src/main/kotlin/stdx-module.gradle.kts b/buildSrc/src/main/kotlin/stdx-module.gradle.kts index 706a57b..c80061b 100644 --- a/buildSrc/src/main/kotlin/stdx-module.gradle.kts +++ b/buildSrc/src/main/kotlin/stdx-module.gradle.kts @@ -21,6 +21,10 @@ kotlin { commonTest { dependencies { implementation(kotlin("test")) + + if (project.name != "stdx-test-tools") { + implementation(project(":stdx-test-tools")) + } } } @@ -106,11 +110,4 @@ fun KotlinMultiplatformExtension.configureTargets() { } } } - - sourceSets.create("nativeMain") { - dependsOn(sourceSets.commonMain.get()) - } - sourceSets.create("nativeTest") { - dependsOn(sourceSets.commonTest.get()) - } } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index bb54479..17d5e0c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -2,8 +2,21 @@ plugins { `stdx-module` `stdx-ktlint` `stdx-publishing` + `stdx-generated-elements` } kotlin { - all() + fullJs() +} + +tasks { + val generateContextFunctions = task("generateContextFunctions") { + `package`.set("dev.schlaubi.stdx.core") + // wait for Kotlin 1.7.0 or stabilization of the feature + enabled = false + } + + generateElements { + dependsOn(generateContextFunctions) + } } diff --git a/core/src/commonMain/kotlin/dev/schlaubi/stdx/core/StringUtil.kt b/core/src/commonMain/kotlin/dev/schlaubi/stdx/core/StringUtil.kt index 1318f1f..9b1fe28 100644 --- a/core/src/commonMain/kotlin/dev/schlaubi/stdx/core/StringUtil.kt +++ b/core/src/commonMain/kotlin/dev/schlaubi/stdx/core/StringUtil.kt @@ -1,3 +1,5 @@ +@file:Suppress("NOTHING_TO_INLINE") + package dev.schlaubi.stdx.core import kotlin.contracts.contract diff --git a/coroutines/build.gradle.kts b/coroutines/build.gradle.kts index f6f9fa8..91da794 100644 --- a/coroutines/build.gradle.kts +++ b/coroutines/build.gradle.kts @@ -2,10 +2,10 @@ plugins { `stdx-module` `stdx-ktlint` `stdx-publishing` + `all-platforms` } kotlin { - all() sourceSets { all { diff --git a/coroutines/src/commonTest/kotlin/Platform.kt b/coroutines/src/commonTest/kotlin/Platform.kt deleted file mode 100644 index 5bdee83..0000000 --- a/coroutines/src/commonTest/kotlin/Platform.kt +++ /dev/null @@ -1 +0,0 @@ -internal expect val isJS: Boolean diff --git a/coroutines/src/commonTest/kotlin/SuspendLazyTest.kt b/coroutines/src/commonTest/kotlin/SuspendLazyTest.kt index 3a9944c..c31f678 100644 --- a/coroutines/src/commonTest/kotlin/SuspendLazyTest.kt +++ b/coroutines/src/commonTest/kotlin/SuspendLazyTest.kt @@ -18,14 +18,14 @@ class SuspendLazyTest { @Test fun testPublicationSuspendLazy() = runTest { - if (!isJS) { + if (!Platform.isJs) { testSafeMode(LazyThreadSafetyMode.PUBLICATION) } } @Test fun testSynchronizedSuspendLazy() = runTest { - if (!isJS) { + if (!Platform.isJs) { testSafeMode(LazyThreadSafetyMode.SYNCHRONIZED) } } diff --git a/coroutines/src/jsTest/kotlin/Platform.kt b/coroutines/src/jsTest/kotlin/Platform.kt deleted file mode 100644 index 215371f..0000000 --- a/coroutines/src/jsTest/kotlin/Platform.kt +++ /dev/null @@ -1 +0,0 @@ -internal actual val isJS = true diff --git a/coroutines/src/jvmTest/kotlin/Platform.kt b/coroutines/src/jvmTest/kotlin/Platform.kt deleted file mode 100644 index ead9564..0000000 --- a/coroutines/src/jvmTest/kotlin/Platform.kt +++ /dev/null @@ -1 +0,0 @@ -internal actual val isJS = false diff --git a/coroutines/src/nativeTest/kotlin/Platform.kt b/coroutines/src/nativeTest/kotlin/Platform.kt deleted file mode 100644 index ead9564..0000000 --- a/coroutines/src/nativeTest/kotlin/Platform.kt +++ /dev/null @@ -1 +0,0 @@ -internal actual val isJS = false diff --git a/envconf/build.gradle.kts b/envconf/build.gradle.kts index c495c8d..c98e06b 100644 --- a/envconf/build.gradle.kts +++ b/envconf/build.gradle.kts @@ -6,6 +6,8 @@ import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTes import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest plugins { + nodejs + `desktop-all` `stdx-module` `stdx-ktlint` `stdx-publishing` @@ -13,11 +15,6 @@ plugins { val testEnv = mapOf("HELLO" to "HELLO", "PREFIX_HELLO" to "HELLO") -kotlin { - nodeJs() - desktopAll() -} - tasks { withType { environment(testEnv) diff --git a/full/build.gradle.kts b/full/build.gradle.kts index 8d095ae..7167216 100644 --- a/full/build.gradle.kts +++ b/full/build.gradle.kts @@ -13,18 +13,12 @@ rootProject.subprojects { dependencies { rootProject.subprojects.forEach { subproject -> if (subproject.plugins.hasPlugin("maven-publish") && subproject.name !in groupProjects) { - subproject.publishing.publications.withType { - if (!artifactId.endsWith("-metadata") && - !artifactId.endsWith("-kotlinMultiplatform") - ) { - api(groupId, artifactId, version) - } - } + api("dev.schlaubi", subproject.name, subproject.version.toString()) } } } -if(runMainCI) { +if (runMainCI) { publishing { publications.create("maven") { from(components["java"]) diff --git a/gradle.properties b/gradle.properties index cb6a070..fd696ee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,6 @@ kotlin.code.style=official -kotlin.mpp.enableGranularSourceSetsMetadata=true -kotlin.native.enableDependencyPropagation=false kotlin.js.generate.executable.default=false +kotlin.mpp.stability.nowarn=true #dokka will run out of memory with the default meta space org.gradle.jvmargs=-XX:MaxMetaspaceSize=1024m kotlin.native.binary.memoryModel=experimental diff --git a/logging/build.gradle.kts b/logging/build.gradle.kts index 0b21098..680b85d 100644 --- a/logging/build.gradle.kts +++ b/logging/build.gradle.kts @@ -1,24 +1,14 @@ plugins { + `full-js` + `desktop-X86` `stdx-module` `stdx-ktlint` `stdx-publishing` -} - -afterEvaluate { - listOf("common", "jvm", "js", "native").forEach { platform -> - val path = "${platform}Main" - val dir = buildDir.resolve("generated").resolve("src").resolve(path) - kotlin.sourceSets.findByName(path)?.apply { - kotlin.srcDir(dir) - } - } + `stdx-generated-elements` } kotlin { - fullJs() - desktopOSX86() - sourceSets { commonMain { dependencies { @@ -34,12 +24,7 @@ tasks { logLevels.set(listOf("debug", "trace", "error", "info", "warn")) } - afterEvaluate { - "metadataCommonMainClasses"{ - dependsOn(generateLoggerFunctions) - } - findByName("compileKotlinJvm")?.apply { - dependsOn(generateLoggerFunctions) - } + generateElements { + dependsOn(generateLoggerFunctions) } } diff --git a/logging/src/commonGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt b/logging/src/commonGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt new file mode 100644 index 0000000..8eaed34 --- /dev/null +++ b/logging/src/commonGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt @@ -0,0 +1,56 @@ +// This file is generated by Gradle task generateLoggerFunctions please do not edit it manually +package dev.schlaubi.stdx.logging + +import kotlin.Throwable +import kotlin.Unit +import mu.KLogger + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public expect inline fun KLogger.debugInlined(message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public expect inline fun KLogger.debugInlined(throwable: Throwable, message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public expect inline fun KLogger.traceInlined(message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public expect inline fun KLogger.traceInlined(throwable: Throwable, message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public expect inline fun KLogger.errorInlined(message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public expect inline fun KLogger.errorInlined(throwable: Throwable, message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public expect inline fun KLogger.infoInlined(message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public expect inline fun KLogger.infoInlined(throwable: Throwable, message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public expect inline fun KLogger.warnInlined(message: LazyLogMessage): Unit + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public expect inline fun KLogger.warnInlined(throwable: Throwable, message: LazyLogMessage): Unit diff --git a/logging/src/jsGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt b/logging/src/jsGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt new file mode 100644 index 0000000..4ff4f6c --- /dev/null +++ b/logging/src/jsGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt @@ -0,0 +1,108 @@ +// This file is generated by Gradle task generateLoggerFunctions please do not edit it manually +package dev.schlaubi.stdx.logging + +import kotlin.Throwable +import kotlin.Unit +import mu.KLogger +import mu.KotlinLoggingLevel +import mu.isLoggingEnabled + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public actual inline fun KLogger.debugInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.DEBUG.isLoggingEnabled()) { + val computedLogMessage = message() + debug { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public actual inline fun KLogger.debugInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.DEBUG.isLoggingEnabled()) { + val computedLogMessage = message() + debug(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public actual inline fun KLogger.traceInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.TRACE.isLoggingEnabled()) { + val computedLogMessage = message() + trace { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public actual inline fun KLogger.traceInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.TRACE.isLoggingEnabled()) { + val computedLogMessage = message() + trace(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public actual inline fun KLogger.errorInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.ERROR.isLoggingEnabled()) { + val computedLogMessage = message() + error { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public actual inline fun KLogger.errorInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.ERROR.isLoggingEnabled()) { + val computedLogMessage = message() + error(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public actual inline fun KLogger.infoInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.INFO.isLoggingEnabled()) { + val computedLogMessage = message() + info { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public actual inline fun KLogger.infoInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.INFO.isLoggingEnabled()) { + val computedLogMessage = message() + info(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public actual inline fun KLogger.warnInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.WARN.isLoggingEnabled()) { + val computedLogMessage = message() + warn { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public actual inline fun KLogger.warnInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.WARN.isLoggingEnabled()) { + val computedLogMessage = message() + warn(throwable) { computedLogMessage } + } +} diff --git a/logging/src/jvmGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt b/logging/src/jvmGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt new file mode 100644 index 0000000..1468e85 --- /dev/null +++ b/logging/src/jvmGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt @@ -0,0 +1,106 @@ +// This file is generated by Gradle task generateLoggerFunctions please do not edit it manually +package dev.schlaubi.stdx.logging + +import kotlin.Throwable +import kotlin.Unit +import mu.KLogger + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public actual inline fun KLogger.debugInlined(message: LazyLogMessage): Unit { + if (isDebugEnabled) { + debug(message()) + } +} + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public actual inline fun KLogger.debugInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (isDebugEnabled) { + val computedMessage = message() + + debug(throwable) { computedMessage } + } +} + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public actual inline fun KLogger.traceInlined(message: LazyLogMessage): Unit { + if (isTraceEnabled) { + trace(message()) + } +} + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public actual inline fun KLogger.traceInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (isTraceEnabled) { + val computedMessage = message() + + trace(throwable) { computedMessage } + } +} + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public actual inline fun KLogger.errorInlined(message: LazyLogMessage): Unit { + if (isErrorEnabled) { + error(message()) + } +} + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public actual inline fun KLogger.errorInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (isErrorEnabled) { + val computedMessage = message() + + error(throwable) { computedMessage } + } +} + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public actual inline fun KLogger.infoInlined(message: LazyLogMessage): Unit { + if (isInfoEnabled) { + info(message()) + } +} + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public actual inline fun KLogger.infoInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (isInfoEnabled) { + val computedMessage = message() + + info(throwable) { computedMessage } + } +} + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public actual inline fun KLogger.warnInlined(message: LazyLogMessage): Unit { + if (isWarnEnabled) { + warn(message()) + } +} + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public actual inline fun KLogger.warnInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (isWarnEnabled) { + val computedMessage = message() + + warn(throwable) { computedMessage } + } +} diff --git a/logging/src/nativeGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt b/logging/src/nativeGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt new file mode 100644 index 0000000..4ff4f6c --- /dev/null +++ b/logging/src/nativeGenerated/dev/schlaubi/stdx/logging/InlinedLogger.kt @@ -0,0 +1,108 @@ +// This file is generated by Gradle task generateLoggerFunctions please do not edit it manually +package dev.schlaubi.stdx.logging + +import kotlin.Throwable +import kotlin.Unit +import mu.KLogger +import mu.KotlinLoggingLevel +import mu.isLoggingEnabled + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public actual inline fun KLogger.debugInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.DEBUG.isLoggingEnabled()) { + val computedLogMessage = message() + debug { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.debug] so it can call suspend functions + */ +public actual inline fun KLogger.debugInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.DEBUG.isLoggingEnabled()) { + val computedLogMessage = message() + debug(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public actual inline fun KLogger.traceInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.TRACE.isLoggingEnabled()) { + val computedLogMessage = message() + trace { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.trace] so it can call suspend functions + */ +public actual inline fun KLogger.traceInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.TRACE.isLoggingEnabled()) { + val computedLogMessage = message() + trace(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public actual inline fun KLogger.errorInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.ERROR.isLoggingEnabled()) { + val computedLogMessage = message() + error { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.error] so it can call suspend functions + */ +public actual inline fun KLogger.errorInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.ERROR.isLoggingEnabled()) { + val computedLogMessage = message() + error(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public actual inline fun KLogger.infoInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.INFO.isLoggingEnabled()) { + val computedLogMessage = message() + info { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.info] so it can call suspend functions + */ +public actual inline fun KLogger.infoInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.INFO.isLoggingEnabled()) { + val computedLogMessage = message() + info(throwable) { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public actual inline fun KLogger.warnInlined(message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.WARN.isLoggingEnabled()) { + val computedLogMessage = message() + warn { computedLogMessage } + } +} + +/** + * Inline version of [KLogger.warn] so it can call suspend functions + */ +public actual inline fun KLogger.warnInlined(throwable: Throwable, message: LazyLogMessage): Unit { + if (KotlinLoggingLevel.WARN.isLoggingEnabled()) { + val computedLogMessage = message() + warn(throwable) { computedLogMessage } + } +} diff --git a/serialization/api/stdx-serialization.api b/serialization/api/stdx-serialization.api new file mode 100644 index 0000000..d64e2dc --- /dev/null +++ b/serialization/api/stdx-serialization.api @@ -0,0 +1,58 @@ +public final class dev/schlaubi/stdx/serialization/EmptyJsonObjectKt { + public static final fun emptyJsonObject ()Lkotlinx/serialization/json/JsonObject; +} + +public final class dev/schlaubi/stdx/serialization/InstantSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Ldev/schlaubi/stdx/serialization/InstantSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/time/Instant; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/time/Instant;)V +} + +public final class dev/schlaubi/stdx/serialization/LocalDateSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Ldev/schlaubi/stdx/serialization/LocalDateSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/time/LocalDate; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/time/LocalDate;)V +} + +public final class dev/schlaubi/stdx/serialization/LocalDateTimeSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Ldev/schlaubi/stdx/serialization/LocalDateTimeSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/time/LocalDateTime; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/time/LocalDateTime;)V +} + +public final class dev/schlaubi/stdx/serialization/LocalTimeSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Ldev/schlaubi/stdx/serialization/LocalTimeSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/time/LocalTime; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/time/LocalTime;)V +} + +public final class dev/schlaubi/stdx/serialization/UUIDBinarySerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Ldev/schlaubi/stdx/serialization/UUIDBinarySerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/util/UUID; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/util/UUID;)V +} + +public final class dev/schlaubi/stdx/serialization/UUIDStringSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Ldev/schlaubi/stdx/serialization/UUIDStringSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/util/UUID; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/util/UUID;)V +} + diff --git a/serialization/build.gradle.kts b/serialization/build.gradle.kts new file mode 100644 index 0000000..7713acd --- /dev/null +++ b/serialization/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + `stdx-module` + `stdx-ktlint` + `stdx-publishing` + `all-platforms` + kotlin("plugin.serialization") +} + +kotlin { + sourceSets { + commonMain { + dependencies { + api("org.jetbrains.kotlinx", "kotlinx-serialization-core", "1.3.2") + api("org.jetbrains.kotlinx", "kotlinx-serialization-json", "1.3.2") + } + } + commonTest { + dependencies { + implementation("org.jetbrains.kotlinx", "kotlinx-serialization-json", "1.3.2") + implementation("org.jetbrains.kotlinx", "kotlinx-serialization-protobuf", "1.3.2") + } + } + + findByName("jvmTest")?.apply { + dependencies { + implementation("com.github.jershell", "kbson", "0.4.4") + } + } + } +} diff --git a/serialization/src/commonMain/kotlin/dev/schlaubi/stdx/serialization/EmptyJsonObject.kt b/serialization/src/commonMain/kotlin/dev/schlaubi/stdx/serialization/EmptyJsonObject.kt new file mode 100644 index 0000000..3fcc878 --- /dev/null +++ b/serialization/src/commonMain/kotlin/dev/schlaubi/stdx/serialization/EmptyJsonObject.kt @@ -0,0 +1,10 @@ +package dev.schlaubi.stdx.serialization + +import kotlinx.serialization.json.JsonObject + +private val emptyJsonObject = JsonObject(emptyMap()) + +/** + * Returns an empty [JsonObject]. + */ +public fun emptyJsonObject(): JsonObject = emptyJsonObject diff --git a/serialization/src/commonTest/kotlin/Utils.kt b/serialization/src/commonTest/kotlin/Utils.kt new file mode 100644 index 0000000..fd54f90 --- /dev/null +++ b/serialization/src/commonTest/kotlin/Utils.kt @@ -0,0 +1,45 @@ +import kotlinx.serialization.BinaryFormat +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialFormat +import kotlinx.serialization.StringFormat +import kotlin.test.assertEquals + +/** + * Signature of a function of [SerialFormat] which encodes [T] to [Serialized]. + * + * @param Serialized the type of the formats serialized value. + */ +typealias Encoder = Format.(serializer: KSerializer, obj: T) -> Serialized + +/** + * Signature of a function of [SerialFormat] which decodes [Serialized] to [T]. + * + * @param Serialized the type of the formats serialized value. + */ +typealias Decoder = Format.(serializer: KSerializer, serialized: Serialized) -> T + +fun Format.testSerializer( + obj: T, + serializer: KSerializer, + encoder: Encoder, + decoder: Decoder +) { + val serialized = encoder(serializer, obj) + val deserialized = decoder(serializer, serialized) + + assertEquals(obj, deserialized, "Deserialized value must be equal to original value") +} + +fun BinaryFormat.testSerializer(obj: T, serializer: KSerializer) = testSerializer( + obj, + serializer, + BinaryFormat::encodeToByteArray, + BinaryFormat::decodeFromByteArray +) + +fun StringFormat.testSerializer(obj: T, serializer: KSerializer) = testSerializer( + obj, + serializer, + StringFormat::encodeToString, + StringFormat::decodeFromString +) diff --git a/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/InstantSerializer.kt b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/InstantSerializer.kt new file mode 100644 index 0000000..5fcdec1 --- /dev/null +++ b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/InstantSerializer.kt @@ -0,0 +1,22 @@ +package dev.schlaubi.stdx.serialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.Instant + +public object InstantSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("Instant", PrimitiveKind.LONG) + + override fun deserialize(decoder: Decoder): Instant { + return Instant.ofEpochMilli(decoder.decodeLong()) + } + + override fun serialize(encoder: Encoder, value: Instant) { + encoder.encodeLong(value.toEpochMilli()) + } +} diff --git a/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateSerializer.kt b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateSerializer.kt new file mode 100644 index 0000000..deb6573 --- /dev/null +++ b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateSerializer.kt @@ -0,0 +1,20 @@ +package dev.schlaubi.stdx.serialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalDate + +public object LocalDateSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): LocalDate = + LocalDate.parse(decoder.decodeString()) + + override fun serialize(encoder: Encoder, value: LocalDate): Unit = + encoder.encodeString(value.toString()) +} diff --git a/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateTimeSerializer.kt b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateTimeSerializer.kt new file mode 100644 index 0000000..3f826dc --- /dev/null +++ b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalDateTimeSerializer.kt @@ -0,0 +1,20 @@ +package dev.schlaubi.stdx.serialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalDateTime + +public object LocalDateTimeSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): LocalDateTime = + LocalDateTime.parse(decoder.decodeString()) + + override fun serialize(encoder: Encoder, value: LocalDateTime): Unit = + encoder.encodeString(value.toString()) +} diff --git a/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalTimeSerializer.kt b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalTimeSerializer.kt new file mode 100644 index 0000000..f4b9755 --- /dev/null +++ b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/LocalTimeSerializer.kt @@ -0,0 +1,20 @@ +package dev.schlaubi.stdx.serialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalTime + +public object LocalTimeSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("LocalTime", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): LocalTime = + LocalTime.parse(decoder.decodeString()) + + override fun serialize(encoder: Encoder, value: LocalTime): Unit = + encoder.encodeString(value.toString()) +} diff --git a/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDBinarySerializer.kt b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDBinarySerializer.kt new file mode 100644 index 0000000..41f311b --- /dev/null +++ b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDBinarySerializer.kt @@ -0,0 +1,43 @@ +package dev.schlaubi.stdx.serialization + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.descriptors.element +import kotlinx.serialization.encoding.* +import java.util.* + +public object UUIDBinarySerializer : KSerializer { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("UUID") { + element("mostSignificantBits") + element("leastSignificantBits") + } + + @OptIn(ExperimentalSerializationApi::class) + override fun deserialize(decoder: Decoder): UUID = decoder.decodeStructure(descriptor) { + var mostSignificantBits: Long? = null + var leastSignificantBits: Long? = null + if (decodeSequentially()) { + mostSignificantBits = decodeLongElement(descriptor, 0) + leastSignificantBits = decodeLongElement(descriptor, 1) + } else while (true) { + when (val index = decodeElementIndex(descriptor)) { + 0 -> mostSignificantBits = decodeLongElement(descriptor, 0) + 1 -> leastSignificantBits = decodeLongElement(descriptor, 1) + CompositeDecoder.DECODE_DONE -> break + else -> error("Unexpected index: $index") + } + } + requireNotNull(mostSignificantBits) + requireNotNull(leastSignificantBits) + UUID(mostSignificantBits, leastSignificantBits) + } + + override fun serialize(encoder: Encoder, value: UUID) { + encoder.encodeStructure(descriptor) { + encodeLongElement(descriptor, 0, value.mostSignificantBits) + encodeLongElement(descriptor, 1, value.leastSignificantBits) + } + } +} diff --git a/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDStringSerializer.kt b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDStringSerializer.kt new file mode 100644 index 0000000..14686e4 --- /dev/null +++ b/serialization/src/jvmMain/kotlin/dev/schlaubi/stdx/serialization/UUIDStringSerializer.kt @@ -0,0 +1,22 @@ +package dev.schlaubi.stdx.serialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.util.* + +public object UUIDStringSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): UUID { + return UUID.fromString(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: UUID) { + encoder.encodeString(value.toString()) + } +} diff --git a/serialization/src/jvmTest/kotlin/BinarySerializationTests.kt b/serialization/src/jvmTest/kotlin/BinarySerializationTests.kt new file mode 100644 index 0000000..b92bbfc --- /dev/null +++ b/serialization/src/jvmTest/kotlin/BinarySerializationTests.kt @@ -0,0 +1,36 @@ +import com.github.jershell.kbson.KBson +import dev.schlaubi.stdx.serialization.UUIDBinarySerializer +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.protobuf.ProtoBuf +import org.intellij.lang.annotations.Language +import java.util.* +import kotlin.test.Test +import kotlin.test.assertEquals + +@OptIn(ExperimentalSerializationApi::class) +internal class BinarySerializationTests { + + @Test + fun `Serialize uuid to and from json`() { + Json.testSerializer(UUID.randomUUID(), UUIDBinarySerializer) + } + + @Test + fun `Deserialize uuid from json`() { + val uuid = UUID.randomUUID() + @Language("JSON") + val jsonText = + """{"mostSignificantBits":${uuid.mostSignificantBits},"leastSignificantBits":"${uuid.leastSignificantBits}"}""" + val decodedUuid = Json.decodeFromString(UUIDBinarySerializer, jsonText) + assertEquals(uuid, decodedUuid) + } + + @Test + fun `Serialize and Deserialize uuid to and from protobuf`() = + ProtoBuf.testSerializer(UUID.randomUUID(), UUIDBinarySerializer) + + @Test + fun `Serialize and Deserialize uuid to and from bson`() = + KBson.default.testSerializer(UUID.randomUUID(), UUIDBinarySerializer) +} diff --git a/serialization/src/jvmTest/kotlin/LocalDateSerializationTests.kt b/serialization/src/jvmTest/kotlin/LocalDateSerializationTests.kt new file mode 100644 index 0000000..24f5361 --- /dev/null +++ b/serialization/src/jvmTest/kotlin/LocalDateSerializationTests.kt @@ -0,0 +1,35 @@ +import com.github.jershell.kbson.KBson +import dev.schlaubi.stdx.serialization.LocalDateSerializer +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.protobuf.ProtoBuf +import java.time.LocalDate +import kotlin.test.Test + +/** + * Wrapper class used for testing [LocalDate] serialization in bson. + */ +@Serializable +data class LocalDateWrapper(@Serializable(with = LocalDateSerializer::class) val value: LocalDate) + +@OptIn(ExperimentalSerializationApi::class) +internal class LocalDateSerializationTests { + + @Test + fun `Serialize LocalDate to and from json`() { + Json.testSerializer(LocalDate.now(), LocalDateSerializer) + } + + @Test + fun `Serialize LocalDate to and from protobuf`() { + ProtoBuf.testSerializer(LocalDate.now(), LocalDateSerializer) + } + + @Test + fun `Serialize LocalDate to and from bson`() { + KBson.default.testSerializer( + LocalDateWrapper(LocalDate.now()), LocalDateWrapper.serializer() + ) + } +} diff --git a/serialization/src/jvmTest/kotlin/LocalDateTimeSerializationTests.kt b/serialization/src/jvmTest/kotlin/LocalDateTimeSerializationTests.kt new file mode 100644 index 0000000..3b73f55 --- /dev/null +++ b/serialization/src/jvmTest/kotlin/LocalDateTimeSerializationTests.kt @@ -0,0 +1,35 @@ +import com.github.jershell.kbson.KBson +import dev.schlaubi.stdx.serialization.LocalDateTimeSerializer +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.protobuf.ProtoBuf +import java.time.LocalDateTime +import kotlin.test.Test + +/** + * Wrapper class used for testing [LocalDateTime] serialization in bson. + */ +@Serializable +data class LocalDateTimeWrapper(@Serializable(with = LocalDateTimeSerializer::class) val value: LocalDateTime) + +@OptIn(ExperimentalSerializationApi::class) +internal class LocalDateTimeSerializationTests { + + @Test + fun `Serialize LocalDateTime to and from json`() { + Json.testSerializer(LocalDateTime.now(), LocalDateTimeSerializer) + } + + @Test + fun `Serialize LocalDateTime to and from protobuf`() { + ProtoBuf.testSerializer(LocalDateTime.now(), LocalDateTimeSerializer) + } + + @Test + fun `Serialize LocalDateTime to and from bson`() { + KBson.default.testSerializer( + LocalDateTimeWrapper(LocalDateTime.now()), LocalDateTimeWrapper.serializer() + ) + } +} diff --git a/serialization/src/jvmTest/kotlin/LocalTimeSerializationTests.kt b/serialization/src/jvmTest/kotlin/LocalTimeSerializationTests.kt new file mode 100644 index 0000000..4d71027 --- /dev/null +++ b/serialization/src/jvmTest/kotlin/LocalTimeSerializationTests.kt @@ -0,0 +1,35 @@ +import com.github.jershell.kbson.KBson +import dev.schlaubi.stdx.serialization.LocalTimeSerializer +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.protobuf.ProtoBuf +import java.time.LocalTime +import kotlin.test.Test + +/** + * Wrapper class used for testing [LocalTime] serialization in bson. + */ +@Serializable +data class LocalTimeWrapper(@Serializable(with = LocalTimeSerializer::class) val value: LocalTime) + +@OptIn(ExperimentalSerializationApi::class) +internal class LocalTimeSerializationTests { + + @Test + fun `Serialize LocalTime to and from json`() { + Json.testSerializer(LocalTime.now(), LocalTimeSerializer) + } + + @Test + fun `Serialize LocalTime to and from protobuf`() { + ProtoBuf.testSerializer(LocalTime.now(), LocalTimeSerializer) + } + + @Test + fun `Serialize LocalTime to and from bson`() { + KBson.default.testSerializer( + LocalTimeWrapper(LocalTime.now()), LocalTimeWrapper.serializer() + ) + } +} diff --git a/serialization/src/jvmTest/kotlin/StringSerializationTests.kt b/serialization/src/jvmTest/kotlin/StringSerializationTests.kt new file mode 100644 index 0000000..011a458 --- /dev/null +++ b/serialization/src/jvmTest/kotlin/StringSerializationTests.kt @@ -0,0 +1,39 @@ +import com.github.jershell.kbson.KBson +import dev.schlaubi.stdx.serialization.UUIDStringSerializer +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.protobuf.ProtoBuf +import org.junit.jupiter.api.Test +import java.util.* +import kotlin.test.assertEquals + +/** + * Wrapper class used for testing [UUID] serialization in bson. + */ +@Serializable +data class UUIDWrapper(@Serializable(with = UUIDStringSerializer::class) val uuid: UUID) + +@OptIn(ExperimentalSerializationApi::class) +internal class StringSerializationTests { + @Test + fun `Serialize uuid to and from json`() { + Json.testSerializer(UUID.randomUUID(), UUIDStringSerializer) + } + + @Test + fun `Deserialize uuid from json`() { + val uuid = UUID.randomUUID() + val jsonText = """"$uuid"""" + val decodedUuid = Json.decodeFromString(UUIDStringSerializer, jsonText) + assertEquals(uuid, decodedUuid) + } + + @Test + fun `Serialize and Deserialize uuid to and from protobuf`() = + ProtoBuf.testSerializer(UUID.randomUUID(), UUIDStringSerializer) + + @Test + fun `Serialize and Deserialize uuid to and from bson`() = + KBson.default.testSerializer(UUIDWrapper(UUID.randomUUID()), UUIDWrapper.serializer()) +} diff --git a/serialization/src/jvmTest/kotlin/Utils.kt b/serialization/src/jvmTest/kotlin/Utils.kt new file mode 100644 index 0000000..6281b46 --- /dev/null +++ b/serialization/src/jvmTest/kotlin/Utils.kt @@ -0,0 +1,11 @@ +@file:JvmName("UtilsJvmKt") + +import com.github.jershell.kbson.KBson +import kotlinx.serialization.KSerializer + +fun KBson.testSerializer(obj: T, serializer: KSerializer) = testSerializer( + obj, + serializer, + KBson::dump, + KBson::load +) diff --git a/settings.gradle.kts b/settings.gradle.kts index d2a8c7e..f3ba5c9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "stdx-kt" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -include("core", "coroutines", "logging", "envconf", "bom", "full") +include("core", "coroutines", "logging", "envconf", "serialization", "test-tools", "bom", "full") rootProject.children.forEach { it.name = "stdx-${it.name}" diff --git a/test-tools/README.md b/test-tools/README.md new file mode 100644 index 0000000..4c8c11a --- /dev/null +++ b/test-tools/README.md @@ -0,0 +1,3 @@ +# test-tools + +Platform specific APIs used in tests diff --git a/test-tools/api/stdx-test-tools.api b/test-tools/api/stdx-test-tools.api new file mode 100644 index 0000000..d857db1 --- /dev/null +++ b/test-tools/api/stdx-test-tools.api @@ -0,0 +1,9 @@ +public final class Platform { + public static final field INSTANCE LPlatform; + public final fun isBrowser ()Z + public final fun isJs ()Z + public final fun isJvm ()Z + public final fun isNative ()Z + public final fun isNode ()Z +} + diff --git a/test-tools/build.gradle.kts b/test-tools/build.gradle.kts new file mode 100644 index 0000000..7779a98 --- /dev/null +++ b/test-tools/build.gradle.kts @@ -0,0 +1,5 @@ +plugins { + `stdx-module` + `stdx-ktlint` + `all-platforms` +} diff --git a/test-tools/src/commonMain/kotlin/Platform.kt b/test-tools/src/commonMain/kotlin/Platform.kt new file mode 100644 index 0000000..ca11ead --- /dev/null +++ b/test-tools/src/commonMain/kotlin/Platform.kt @@ -0,0 +1,28 @@ +/** + * Allows retrieving Platform specific information. + */ +public expect object Platform { + /** + * Whether this test runs in the browser. + */ + public val isBrowser: Boolean + /** + * Whether this test runs in NodeJS. + */ + public val isNode: Boolean + + /** + * Whether this test runs in JS. + */ + public val isJs: Boolean + + /** + * Whether this test runs in a native target. + */ + public val isNative: Boolean + + /** + * Whether this test runs on the JVM. + */ + public val isJvm: Boolean +} diff --git a/test-tools/src/jsMain/kotlin/Platform.kt b/test-tools/src/jsMain/kotlin/Platform.kt new file mode 100644 index 0000000..e5d1ef9 --- /dev/null +++ b/test-tools/src/jsMain/kotlin/Platform.kt @@ -0,0 +1,11 @@ +public actual object Platform { + public actual val isBrowser: Boolean = js( + "typeof window !== 'undefined' && typeof window.document !== 'undefined' || typeof self !== 'undefined' && typeof self.location !== 'undefined'" // ktlint-disable max-line-length + ) as Boolean + public actual val isNode: Boolean = js( + "typeof process !== 'undefined' && process.versions != null && process.versions.node != null" + ) as Boolean + public actual val isJs: Boolean = true + public actual val isNative: Boolean = false + public actual val isJvm: Boolean = false +} diff --git a/test-tools/src/jvmMain/kotlin/Platform.kt b/test-tools/src/jvmMain/kotlin/Platform.kt new file mode 100644 index 0000000..5ddf3db --- /dev/null +++ b/test-tools/src/jvmMain/kotlin/Platform.kt @@ -0,0 +1,7 @@ +public actual object Platform { + public actual val isBrowser: Boolean = false + public actual val isNode: Boolean = false + public actual val isJs: Boolean = false + public actual val isNative: Boolean = false + public actual val isJvm: Boolean = true +} diff --git a/test-tools/src/nativeMain/kotlin/Platform.kt b/test-tools/src/nativeMain/kotlin/Platform.kt new file mode 100644 index 0000000..47e59c7 --- /dev/null +++ b/test-tools/src/nativeMain/kotlin/Platform.kt @@ -0,0 +1,7 @@ +public actual object Platform { + public actual val isBrowser: Boolean = false + public actual val isNode: Boolean = false + public actual val isJs: Boolean = false + public actual val isNative: Boolean = true + public actual val isJvm: Boolean = false +}