[WASM] Support for mjs universal launcher

This commit is contained in:
Igor Yakovlev
2022-06-03 18:45:40 +02:00
committed by teamcity
parent c8806763fa
commit f996278171
20 changed files with 103 additions and 171 deletions
+1 -1
View File
@@ -503,10 +503,10 @@ tasks {
":kotlin-test:kotlin-test-js-ir:kotlin-test-js-ir-it".takeIf { !kotlinBuildProperties.isInJpsBuildIdeaSync },
":kotlinx-metadata-jvm",
":tools:binary-compatibility-validator",
//":kotlin-stdlib-wasm",
)).forEach {
dependsOn("$it:check")
}
dependsOn(":kotlin-stdlib-wasm:runWasmStdLibTestsWithD8") //Instead of :kotlin-stdlib-wasm:check
}
register("gradlePluginTest") {
@@ -249,13 +249,6 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xwasm-debug-info", description = "Add debug info to WebAssembly compiled module")
var wasmDebug: Boolean by FreezableVar(true)
@Argument(
value = "-Xwasm-launcher",
valueDescription = "esm|nodejs|d8",
description = "Picks flavor for the wasm launcher. Default is ESM."
)
var wasmLauncher: String? by NullableStringFreezableVar("esm")
@Argument(value = "-Xwasm-kclass-fqn", description = "Enable support for FQ names in KClass")
var wasmKClassFqn: Boolean by FreezableVar(false)
@@ -11,7 +11,6 @@ import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.backend.common.CompilationException
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.backend.wasm.WasmLoaderKind
import org.jetbrains.kotlin.backend.wasm.compileWasm
import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr
import org.jetbrains.kotlin.backend.wasm.wasmPhases
@@ -362,18 +361,9 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
generateWat = true,
)
val launcherKind = when (arguments.wasmLauncher) {
"esm" -> WasmLoaderKind.BROWSER
"nodejs" -> WasmLoaderKind.NODE
"d8" -> WasmLoaderKind.D8
"d8NodeCompatible" -> WasmLoaderKind.D8NodeCompatible
else -> throw IllegalArgumentException("Unrecognized flavor for the wasm launcher")
}
writeCompilationResult(
result = res,
dir = outputFile.parentFile,
loaderKind = launcherKind,
fileNameBase = outputFile.nameWithoutExtension
)
@@ -120,66 +120,49 @@ fun WasmCompiledModuleFragment.generateJs(): String {
return runtime + jsCode
}
enum class WasmLoaderKind {
D8,
D8NodeCompatible,
NODE,
BROWSER,
}
fun generateJsWasmLoader(kind: WasmLoaderKind, wasmFilePath: String, externalJs: String): String {
val nodeExitOnD8 =
if (kind == WasmLoaderKind.D8NodeCompatible) "if ((typeof process !== 'undefined') && (typeof process.versions.node !== 'undefined')) process.exit(0)\n"
else ""
val instantiation = when (kind) {
WasmLoaderKind.D8, WasmLoaderKind.D8NodeCompatible ->
"""
const wasmModule = new WebAssembly.Module(read('$wasmFilePath', 'binary'));
const wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
""".trimIndent()
WasmLoaderKind.NODE ->
"""
const fs = require('fs');
var path = require('path');
const wasmBuffer = fs.readFileSync(path.resolve(__dirname, './$wasmFilePath'));
const wasmModule = new WebAssembly.Module(wasmBuffer);
const wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
""".trimIndent()
WasmLoaderKind.BROWSER ->
"""
const { instance: wasmInstance } = await WebAssembly.instantiateStreaming(fetch("$wasmFilePath"), { js_code });
""".trimIndent()
fun generateJsWasmLoader(wasmFilePath: String, externalJs: String): String =
externalJs + """
const isNodeJs = (typeof process !== 'undefined') && (process.release.name === 'node');
const isD8 = !isNodeJs && (typeof d8 !== 'undefined');
const isBrowser = !isNodeJs && !isD8 && (typeof window !== 'undefined');
if (!isNodeJs && !isD8 && !isBrowser) {
throw "Supported JS engine not detected";
}
val init =
"""
const wasmExports = wasmInstance.exports;
wasmExports.__init();
wasmExports.startUnitTests?.();
""".trimIndent()
val export = when (kind) {
WasmLoaderKind.D8, WasmLoaderKind.BROWSER ->
"export default wasmExports;\n"
WasmLoaderKind.NODE ->
"module.exports = wasmExports;\n"
WasmLoaderKind.D8NodeCompatible -> ""
let wasmInstance;
let require; // Placed here to give access to it from externals (js_code)
if (isNodeJs) {
const module = await import('node:module');
require = module.createRequire(import.meta.url);
const fs = require('fs');
const path = require('path');
const url = require('url');
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const wasmBuffer = fs.readFileSync(path.resolve(__dirname, './$wasmFilePath'));
const wasmModule = new WebAssembly.Module(wasmBuffer);
wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
}
return nodeExitOnD8 + externalJs + instantiation + init + export
}
if (isD8) {
const wasmBuffer = read('$wasmFilePath', 'binary');
const wasmModule = new WebAssembly.Module(wasmBuffer);
wasmInstance = new WebAssembly.Instance(wasmModule, { js_code });
}
if (isBrowser) {
wasmInstance = (await WebAssembly.instantiateStreaming(fetch('$wasmFilePath'), { js_code })).instance;
}
const wasmExports = wasmInstance.exports;
wasmExports.__init();
export default wasmExports;
""".trimIndent()
fun writeCompilationResult(
result: WasmCompilerResult,
dir: File,
loaderKind: WasmLoaderKind,
fileNameBase: String = "index",
) {
dir.mkdirs()
@@ -187,6 +170,7 @@ fun writeCompilationResult(
File(dir, "$fileNameBase.wat").writeText(result.wat)
}
File(dir, "$fileNameBase.wasm").writeBytes(result.wasm)
val jsWithLoader = generateJsWasmLoader(loaderKind, "./$fileNameBase.wasm", result.js)
File(dir, "$fileNameBase.js").writeText(jsWithLoader)
val jsWithLoader = generateJsWasmLoader("./$fileNameBase.wasm", result.js)
File(dir, "$fileNameBase.mjs").writeText(jsWithLoader)
}
-1
View File
@@ -45,7 +45,6 @@ where advanced options include:
Turn on range checks for the array access functions
-Xwasm-enable-asserts Turn on asserts
-Xwasm-kclass-fqn Enable support for FQ names in KClass
-Xwasm-launcher=esm|nodejs|d8 Picks flavor for the wasm launcher. Default is ESM.
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
-Xallow-result-return-type Allow compiling code when `kotlin.Result` is used as a return type
-Xbuiltins-from-sources Compile builtIns from sources
@@ -148,7 +148,7 @@ abstract class BasicWasmBoxTest(
)
val testJsQuiet = """
import exports from './index.js';
import exports from './index.mjs';
let actualResult
try {
@@ -176,19 +176,19 @@ abstract class BasicWasmBoxTest(
val path = dir.absolutePath
println(" ------ $name WAT file://$path/index.wat")
println(" ------ $name WASM file://$path/index.wasm")
println(" ------ $name JS file://$path/index.js")
println(" ------ $name Test file://$path/test.js")
println(" ------ $name JS file://$path/index.mjs")
println(" ------ $name Test file://$path/test.mjs")
}
writeCompilationResult(res, dir, WasmLoaderKind.D8)
File(dir, "test.js").writeText(testJs)
writeCompilationResult(res, dir)
File(dir, "test.mjs").writeText(testJs)
ExternalTool(System.getProperty("javascript.engine.path.V8"))
.run(
"--experimental-wasm-gc",
"--experimental-wasm-eh",
*jsFilesBefore.map { File(it).absolutePath }.toTypedArray(),
"--module",
"./test.js",
"./test.mjs",
*jsFilesAfter.map { File(it).absolutePath }.toTypedArray(),
workingDirectory = dir
)
@@ -200,14 +200,14 @@ abstract class BasicWasmBoxTest(
if (debugMode >= DebugMode.SUPER_DEBUG) {
fun writeBrowserTest(name: String, res: WasmCompilerResult) {
val dir = File(outputDirBase, name)
writeCompilationResult(res, dir, WasmLoaderKind.BROWSER)
File(dir, "test.js").writeText(testJsVerbose)
writeCompilationResult(res, dir)
File(dir, "test.mjs").writeText(testJsVerbose)
File(dir, "index.html").writeText(
"""
<!DOCTYPE html>
<html lang="en">
<body>
<script src="test.js" type="module"></script>
<script src="test.mjs" type="module"></script>
</body>
</html>
""".trimIndent()
@@ -215,8 +215,8 @@ abstract class BasicWasmBoxTest(
val path = dir.absolutePath
println(" ------ $name WAT file://$path/index.wat")
println(" ------ $name WASM file://$path/index.wasm")
println(" ------ $name JS file://$path/index.js")
println(" ------ $name TEST file://$path/test.js")
println(" ------ $name JS file://$path/index.mjs")
println(" ------ $name TEST file://$path/test.mjs")
println(" ------ $name HTML file://$path/index.html")
}
+2 -35
View File
@@ -1,6 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink
import java.io.OutputStream
plugins {
`maven-publish`
@@ -77,13 +76,7 @@ val commonTestSources by task<Sync> {
kotlin {
wasm {
nodejs {
testTask {
useMocha {
timeout = "10s"
}
}
}
nodejs()
}
sourceSets {
@@ -144,33 +137,7 @@ val compileTestKotlinWasm by tasks.existing(KotlinCompile::class) {
}
val compileTestDevelopmentExecutableKotlinWasm = tasks.named<KotlinJsIrLink>("compileTestDevelopmentExecutableKotlinWasm") {
(this as KotlinCompile<*>).kotlinOptions.freeCompilerArgs += listOf("-Xwasm-enable-array-range-checks", "-Xwasm-launcher=d8")
}
val runWasmStdLibTestsWithD8 by tasks.registering(Exec::class) {
dependsOn(":js:js.tests:unzipV8")
dependsOn(compileTestDevelopmentExecutableKotlinWasm)
val unzipV8Task = tasks.getByPath(":js:js.tests:unzipV8")
val d8Path = File(unzipV8Task.outputs.files.single(), "d8")
executable = d8Path.toString()
val compiledFile = compileTestDevelopmentExecutableKotlinWasm
.get()
.kotlinOptions
.outputFile
?.let { File(it) }
check(compiledFile != null)
if (System.getenv("TEAMCITY_VERSION") == null) {
standardOutput = object : OutputStream() {
override fun write(b: Int) = Unit
}
errorOutput = standardOutput
}
workingDir = compiledFile.parentFile
args = listOf("--experimental-wasm-gc", "--experimental-wasm-eh", "--module", compiledFile.name)
(this as KotlinCompile<*>).kotlinOptions.freeCompilerArgs += listOf("-Xwasm-enable-array-range-checks")
}
val runtimeElements by configurations.creating {}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinTargetTestRun
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetContainerDsl
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmSubTargetContainerDsl
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.testing.KotlinReportAggregatingTestRun
import org.jetbrains.kotlin.gradle.testing.KotlinTaskTestRun
@@ -82,6 +83,7 @@ open class KotlinJsReportAggregatingTestRun(
target.whenBrowserConfigured { doConfigureInChildren(this) }
target.whenNodejsConfigured { doConfigureInChildren(this) }
(target as? KotlinWasmSubTargetContainerDsl)?.whenD8Configured { doConfigureInChildren(this) }
}
override fun filter(configureFilter: Closure<*>) = filter { target.project.configure(this, configureFilter) }
@@ -63,9 +63,6 @@ open class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
}
}
override val additionalCompilerOption: String?
get() = "-Xwasm-launcher=esm".takeIf { target.platformType == KotlinPlatformType.wasm }
override fun commonWebpackConfig(body: KotlinWebpackConfig.() -> Unit) {
webpackTaskConfigurations.add {
webpackConfigApplier(body)
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.gradle.targets.js.ir
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.targets.js.d8.D8Exec
import org.jetbrains.kotlin.gradle.targets.js.d8.D8RootPlugin
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmD8Dsl
@@ -34,7 +33,4 @@ open class KotlinD8Ir @Inject constructor(target: KotlinJsIrTarget) :
override fun configureTestDependencies(test: KotlinJsTest) {
test.dependsOn(d8.setupTaskProvider)
}
override val additionalCompilerOption: String?
get() = "-Xwasm-launcher=d8".takeIf { target.platformType == KotlinPlatformType.wasm }
}
@@ -52,6 +52,10 @@ constructor(
(this as KotlinJsIrSubTarget).produceExecutable()
}
target.whenD8Configured {
(this as KotlinJsIrSubTarget).produceExecutable()
}
return compilation.binaries.executableIrInternal(compilation)
}
@@ -106,6 +110,10 @@ constructor(
(this as KotlinJsIrSubTarget).produceLibrary()
}
target.whenD8Configured {
(this as KotlinJsIrSubTarget).produceLibrary()
}
return createBinaries(
compilation = compilation,
jsBinaryType = KotlinJsBinaryType.LIBRARY,
@@ -102,17 +102,6 @@ abstract class KotlinJsIrSubTarget(
}
}
private fun addLinkOptions(compilation: KotlinJsIrCompilation) {
val additionalCompilerOption = additionalCompilerOption ?: return
compilation.binaries
.withType(JsIrBinary::class.java)
.all {
it.linkTask.configure { linkTask ->
linkTask.kotlinOptions.freeCompilerArgs += additionalCompilerOption
}
}
}
private fun configureTestsRun(testRun: KotlinJsPlatformTestRun, compilation: KotlinJsIrCompilation) {
fun KotlinJsPlatformTestRun.subtargetTestTaskName(): String = disambiguateCamelCased(
lowerCamelCaseName(
@@ -121,8 +110,6 @@ abstract class KotlinJsIrSubTarget(
)
)
addLinkOptions(compilation)
val testJs = project.registerTask<KotlinJsTest>(
testRun.subtargetTestTaskName(),
listOf(compilation)
@@ -177,7 +164,6 @@ abstract class KotlinJsIrSubTarget(
protected abstract fun configureDefaultTestFramework(test: KotlinJsTest)
protected abstract fun configureTestDependencies(test: KotlinJsTest)
protected abstract val additionalCompilerOption: String?
private fun configureMain() {
target.compilations.all { compilation ->
@@ -43,7 +43,4 @@ open class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) :
test.testFramework = KotlinWasmNode(test)
}
}
override val additionalCompilerOption: String?
get() = "-Xwasm-launcher=nodejs".takeIf { target.platformType == KotlinPlatformType.wasm }
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
import org.gradle.api.Project
import org.gradle.process.ExecSpec
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
@@ -28,6 +29,8 @@ val KotlinJsCompilation.npmProject: NpmProject
open class NpmProject(@Transient val compilation: KotlinJsCompilation) : Serializable {
val compilationName = compilation.disambiguatedName
private val extension = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js"
val name: String by lazy {
buildNpmProjectName()
}
@@ -65,7 +68,7 @@ open class NpmProject(@Transient val compilation: KotlinJsCompilation) : Seriali
get() = dir.resolve(DIST_FOLDER)
val main: String
get() = "$DIST_FOLDER/$name.js"
get() = "$DIST_FOLDER/$name$extension"
val externalsDirRoot by lazy {
project.buildDir.resolve("externals").resolve(name)
@@ -14,14 +14,19 @@ import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
import org.jetbrains.kotlin.gradle.targets.js.d8.D8RootPlugin
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
import org.jetbrains.kotlin.gradle.targets.js.isTeamCity
import org.jetbrains.kotlin.gradle.targets.js.writeWasmUnitTestRunner
import org.jetbrains.kotlin.gradle.utils.getValue
internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTestFramework {
override val settingsState: String = "KotlinWasmD8"
@Transient
override val compilation: KotlinJsCompilation = kotlinJsTest.compilation
@Transient
private val project: Project = compilation.target.project
private val d8 = D8RootPlugin.apply(project.rootProject)
private val d8Executable by project.provider { d8.requireConfigured().executablePath }
private val isTeamCity by lazy { project.isTeamCity }
init {
kotlinJsTest.outputs.upToDateWhen { false }
@@ -33,10 +38,10 @@ internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTe
nodeJsArgs: MutableList<String>,
debug: Boolean
): TCServiceMessagesTestExecutionSpec {
val compiledFile = task.inputFileProperty.get().asFile
val testRunnerFile = writeWasmUnitTestRunner(task.inputFileProperty.get().asFile)
forkOptions.executable = d8Executable.absolutePath
forkOptions.workingDir = compiledFile.parentFile
forkOptions.workingDir = testRunnerFile.parentFile
val clientSettings = TCServiceMessagesClientSettings(
task.name,
@@ -44,7 +49,7 @@ internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTe
prependSuiteName = true,
stackTraceParser = ::parseNodeJsStackTraceAsJvm,
ignoreOutOfRootNodes = true,
escapeTCMessagesInLog = project.isTeamCity
escapeTCMessagesInLog = isTeamCity
)
val cliArgs = KotlinTestRunnerCliArgs(
@@ -53,26 +58,20 @@ internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTe
)
val args = mutableListOf(
"--module",
compiledFile.absolutePath,
"--experimental-wasm-typed-funcref",
"--experimental-wasm-gc",
"--experimental-wasm-eh",
testRunnerFile.absolutePath,
)
args.add("--")
args.addAll(cliArgs.toList())
val dryRunArgs = mutableListOf<String>()
dryRunArgs.addAll(args)
dryRunArgs.add("--dryRun")
return TCServiceMessagesTestExecutionSpec(
forkOptions = forkOptions,
args = args,
checkExitCode = false,
clientSettings = clientSettings,
dryRunArgs = dryRunArgs
dryRunArgs = args + "--dryRun"
)
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.gradle.targets.js.testing
import org.gradle.api.Project
import org.gradle.process.ProcessForkOptions
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
@@ -13,11 +12,13 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
import org.jetbrains.kotlin.gradle.targets.js.isTeamCity
import org.jetbrains.kotlin.gradle.targets.js.writeWasmUnitTestRunner
internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJsTestFramework {
override val settingsState: String = "KotlinWasmNode"
@Transient
override val compilation: KotlinJsCompilation = kotlinJsTest.compilation
private val project: Project = compilation.target.project
private val isTeamCity by lazy { compilation.target.project.isTeamCity }
init {
kotlinJsTest.outputs.upToDateWhen { false }
@@ -29,7 +30,7 @@ internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJs
nodeJsArgs: MutableList<String>,
debug: Boolean
): TCServiceMessagesTestExecutionSpec {
val compiledFile = task.inputFileProperty.get().asFile
val testRunnerFile = writeWasmUnitTestRunner(task.inputFileProperty.get().asFile)
val clientSettings = TCServiceMessagesClientSettings(
task.name,
@@ -37,7 +38,7 @@ internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJs
prependSuiteName = true,
stackTraceParser = ::parseNodeJsStackTraceAsJvm,
ignoreOutOfRootNodes = true,
escapeTCMessagesInLog = project.isTeamCity
escapeTCMessagesInLog = isTeamCity
)
val cliArgs = KotlinTestRunnerCliArgs(
@@ -47,22 +48,17 @@ internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJs
val args = mutableListOf<String>()
with(args) {
add("--experimental-wasm-typed-funcref")
add("--experimental-wasm-gc")
add("--experimental-wasm-eh")
add(compiledFile.absolutePath)
add(testRunnerFile.absolutePath)
addAll(cliArgs.toList())
}
val dryRunArgs = mutableListOf<String>()
dryRunArgs.addAll(args)
dryRunArgs.add("--dryRun")
return TCServiceMessagesTestExecutionSpec(
forkOptions = forkOptions,
args = args,
checkExitCode = false,
clientSettings = clientSettings,
dryRunArgs = dryRunArgs
dryRunArgs = args + "--dryRun"
)
}
@@ -61,6 +61,7 @@ class KotlinKarma(
private var configDirectory: File by property {
defaultConfigDirectory
}
private val isTeamCity by lazy { project.isTeamCity }
override val requiredNpmDependencies: Set<RequiredKotlinJsDependency>
get() = requiredDependencies + webpackConfig.getRequiredDependencies(versions)
@@ -380,7 +381,7 @@ class KotlinKarma(
prependSuiteName = true,
stackTraceParser = ::parseNodeJsStackTraceAsJvm,
ignoreOutOfRootNodes = true,
escapeTCMessagesInLog = project.isTeamCity
escapeTCMessagesInLog = isTeamCity
)
config.basePath = npmProject.nodeModulesDir.absolutePath
@@ -28,6 +28,7 @@ class KotlinMocha(@Transient override val compilation: KotlinJsCompilation, priv
private val project: Project = compilation.target.project
private val npmProject = compilation.npmProject
private val versions = NodeJsRootPlugin.apply(project.rootProject).versions
private val isTeamCity by lazy { project.isTeamCity }
override val settingsState: String
get() = "mocha"
@@ -59,7 +60,7 @@ class KotlinMocha(@Transient override val compilation: KotlinJsCompilation, priv
prependSuiteName = true,
stackTraceParser = ::parseNodeJsStackTraceAsJvm,
ignoreOutOfRootNodes = true,
escapeTCMessagesInLog = project.isTeamCity
escapeTCMessagesInLog = isTeamCity
)
val cliArgs = KotlinTestRunnerCliArgs(
@@ -68,3 +68,14 @@ val Project.isTeamCity: Boolean
} else {
project.hasProperty(TCServiceMessagesTestExecutor.TC_PROJECT_PROPERTY)
}
internal fun writeWasmUnitTestRunner(compiledFile: File): File {
val testRunnerFile = compiledFile.parentFile.resolve("runUnitTests.mjs")
testRunnerFile.writeText(
"""
import exports from '${compiledFile.absolutePath}';
exports.startUnitTests?.();
""".trimIndent()
)
return testRunnerFile
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
@@ -27,8 +28,9 @@ internal open class BaseKotlin2JsCompileConfig<TASK : Kotlin2JsCompile>(
task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true
task.outputFileProperty.value(task.project.provider {
val extensionName = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js"
task.kotlinOptions.outputFile?.let(::File)
?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}.js")
?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}$extensionName")
}).disallowChanges()
task.optionalOutputFile.fileProvider(task.outputFileProperty.flatMap { outputFile ->