[K/JS] Introduce the ability to consume platform-specific cli arguments inside the main function ^KT-16981 Fixed

This commit is contained in:
Artem Kobzar
2023-11-18 11:01:34 +00:00
committed by Space Team
parent ceded87a3a
commit 1832f5a3f7
15 changed files with 93 additions and 3 deletions
@@ -57,6 +57,7 @@ fun copyK2JSCompilerArguments(from: K2JSCompilerArguments, to: K2JSCompilerArgum
to.outputPrefix = from.outputPrefix
to.partialLinkageLogLevel = from.partialLinkageLogLevel
to.partialLinkageMode = from.partialLinkageMode
to.platformArgumentsProviderJsExpression = from.platformArgumentsProviderJsExpression
to.sourceMap = from.sourceMap
to.sourceMapBaseDirs = from.sourceMapBaseDirs
to.sourceMapEmbedSources = from.sourceMapEmbedSources
@@ -494,6 +494,16 @@ In combination with '-meta-info', this generates both IR and pre-IR versions of
field = value
}
@Argument(
value = "-Xplatform-arguments-in-main-function",
description = "JS expression that will be executed in runtime and be put as an Array<String> parameter of the main function"
)
var platformArgumentsProviderJsExpression: String? = null
set(value) {
checkFrozen()
field = value
}
@GradleOption(
value = DefaultValue.BOOLEAN_TRUE_DEFAULT,
gradleInputType = GradleInputTypes.INPUT,
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants
import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.RUNTIME_DIAGNOSTIC_EXCEPTION
import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.RUNTIME_DIAGNOSTIC_LOG
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.fir.reportToMessageCollector
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
@@ -211,6 +210,10 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
configurationJs.put(JSConfigurationKeys.GENERATE_DTS, arguments.generateDts)
configurationJs.put(JSConfigurationKeys.GENERATE_INLINE_ANONYMOUS_FUNCTIONS, arguments.irGenerateInlineAnonymousFunctions)
arguments.platformArgumentsProviderJsExpression?.let {
configurationJs.put(JSConfigurationKeys.DEFINE_PLATFORM_MAIN_FUNCTION_ARGUMENTS, it)
}
val zipAccessor = DisposableZipFileSystemAccessor(64)
Disposer.register(rootDisposable, zipAccessor)
configurationJs.put(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR, zipAccessor)
@@ -105,6 +105,7 @@ class JsIrBackendContext(
val devMode = configuration[JSConfigurationKeys.DEVELOPER_MODE] ?: false
val errorPolicy = configuration[JSConfigurationKeys.ERROR_TOLERANCE_POLICY] ?: ErrorTolerancePolicy.DEFAULT
override val es6mode = configuration[JSConfigurationKeys.USE_ES6_CLASSES] ?: false
val platformArgumentsProviderJsExpression = configuration[JSConfigurationKeys.DEFINE_PLATFORM_MAIN_FUNCTION_ARGUMENTS]
val externalPackageFragment = mutableMapOf<IrFileSymbol, IrFile>()
@@ -179,7 +179,13 @@ internal class ICHasher {
hashCalculator.update(value.ordinal)
}
hashCalculator.updateConfigKeys(config, listOf(JSConfigurationKeys.SOURCE_MAP_PREFIX)) { value: String ->
hashCalculator.updateConfigKeys(
config,
listOf(
JSConfigurationKeys.SOURCE_MAP_PREFIX,
JSConfigurationKeys.DEFINE_PLATFORM_MAIN_FUNCTION_ARGUMENTS
)
) { value: String ->
hashCalculator.update(value)
}
@@ -72,7 +72,11 @@ class MainFunctionCallWrapperLowering(private val context: JsIrBackendContext) :
return listOfNotNull(
runIf(generateArgv) {
JsIrBuilder.buildArray(
context.platformArgumentsProviderJsExpression?.let {
JsIrBuilder.buildCall(context.intrinsics.jsCode).apply {
putValueArgument(0, it.toIrConst(context.irBuiltIns.stringType))
}
} ?: JsIrBuilder.buildArray(
mainFunctionArgs.map { it.toIrConst(context.irBuiltIns.stringType) },
valueParameters.first().type,
context.irBuiltIns.stringType
+2
View File
@@ -49,6 +49,8 @@ where advanced options include:
Define the compile-time log level for partial linkage.
-Xpartial-linkage={enable|disable}
Use partial linkage mode.
-Xplatform-arguments-in-main-function
JS expression that will be executed in runtime and be put as an Array<String> parameter of the main function
-Xstrict-implicit-export-types Generate strict types for implicitly exported entities inside d.ts files. This is available in the IR backend only.
-Xtyped-arrays Translate primitive arrays into JS typed arrays.
-Xes-classes Let generated JavaScript code use ES2015 classes.
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider;
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer;
import org.jetbrains.kotlin.serialization.js.ModuleKind;
import javax.annotation.Nullable;
import java.io.File;
import java.util.List;
import java.util.Map;
@@ -80,6 +81,9 @@ public class JSConfigurationKeys {
public static final CompilerConfigurationKey<Boolean> GENERATE_POLYFILLS =
CompilerConfigurationKey.create("generate polyfills for newest properties, methods and classes from ES6+");
public static final CompilerConfigurationKey<String> DEFINE_PLATFORM_MAIN_FUNCTION_ARGUMENTS =
CompilerConfigurationKey.create("provide platform specific args as a parameter of the main function");
public static final CompilerConfigurationKey<Boolean> GENERATE_DTS =
CompilerConfigurationKey.create("generate TypeScript definition file");
@@ -47,6 +47,24 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
}
@DisplayName("nodejs main function arguments")
@GradleTest
fun testNodeJsMainArguments(gradleVersion: GradleVersion) {
project("kotlin-js-nodejs-project", gradleVersion) {
buildGradle.appendText(
"""
|
|tasks.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExec).configureEach {
| args += ["test", "'Hello, World'"]
|}
""".trimMargin()
)
build("nodeRun") {
assertOutputContains("ACCEPTED: test;'Hello, World'")
}
}
}
@DisplayName("stale output is cleaned")
@GradleTest
fun testCleanOutputWithEmptySources(gradleVersion: GradleVersion) {
@@ -17,6 +17,7 @@ kotlin {
useCommonJs()
binaries.executable()
nodejs {
passProcessArgvToMainFunction()
}
}
}
@@ -11,4 +11,8 @@ fun best(): Int {
fun simpleBest(): Int {
return 73
}
fun main(args: Array<String>) {
println("ACCEPTED: ${args.drop(2).joinToString(";")}")
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.targets.js.dsl
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION)
annotation class ExperimentalMainFunctionArgumentsDsl
@@ -47,6 +47,12 @@ interface KotlinJsTargetDsl : KotlinTarget, KotlinTargetWithNodeJsDsl {
fun useCommonJs()
fun useEsModules()
/**
* The function accepts [jsExpression] and puts this expression as the "args: Array<String>" argument in place of main-function call
*/
@ExperimentalMainFunctionArgumentsDsl
fun passAsArgumentToMainFunction(jsExpression: String)
fun generateTypeScriptDefinitions()
val binaries: KotlinJsBinaryContainer
@@ -98,4 +104,7 @@ interface KotlinJsBrowserDsl : KotlinJsSubTargetDsl {
interface KotlinJsNodeDsl : KotlinJsSubTargetDsl {
fun runTask(body: Action<NodeJsExec>)
@ExperimentalMainFunctionArgumentsDsl
fun passProcessArgvToMainFunction()
}
@@ -433,6 +433,19 @@ constructor(
}
override fun passAsArgumentToMainFunction(jsExpression: String) {
compilations
.all {
it.binaries
.withType(JsIrBinary::class.java)
.all {
it.linkTask.configure { linkTask ->
linkTask.compilerOptions.freeCompilerArgs.add("-Xplatform-arguments-in-main-function=$jsExpression")
}
}
}
}
private fun KotlinJsOptions.configureCommonJsOptions() {
moduleKind = "commonjs"
sourceMap = true
@@ -32,6 +32,10 @@ abstract class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) :
project.tasks.withType<NodeJsExec>().named(runTaskName).configure(body)
}
override fun passProcessArgvToMainFunction() {
target.passAsArgumentToMainFunction("process.argv")
}
override fun locateOrRegisterRunTask(binary: JsIrBinary, name: String) {
if (project.locateTask<NodeJsExec>(name) != null) return