[K/JS] Move ES modules logic to a new transformer with IC
This commit is contained in:
@@ -49,7 +49,7 @@ public class AntTaskJsTest extends AbstractAntTaskTest {
|
||||
|
||||
List<String> filePaths = CollectionsKt.map(fileNames, s -> getOutputFileByName(s).getAbsolutePath());
|
||||
|
||||
(useNashorn ? NashornJsTestChecker.INSTANCE : V8JsTestChecker.INSTANCE).check(filePaths, "out", "foo", "box", "OK", withModuleSystem);
|
||||
(useNashorn ? NashornJsTestChecker.INSTANCE : V8JsTestChecker.INSTANCE).check(filePaths, "out", "foo", "box", "OK", withModuleSystem, null);
|
||||
}
|
||||
|
||||
private void doJsAntTestForPostfixPrefix(@Nullable String prefix, @Nullable String postfix) throws Exception {
|
||||
|
||||
@@ -51,9 +51,7 @@ class ClassicJsBackendFacade(
|
||||
"$KOTLIN_TEST_INTERNAL.setModuleId(\"$escapedModuleId\"); }\n" +
|
||||
"$content\n"
|
||||
|
||||
ModuleKind.PLAIN -> content
|
||||
|
||||
ModuleKind.ES -> error("Module emulation markers are not supported for ES modules")
|
||||
ModuleKind.PLAIN, ModuleKind.ES -> content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,36 +12,29 @@ import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDe
|
||||
import org.jetbrains.kotlin.cli.common.isWindows
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.codegen.CompilerOutputSink
|
||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationOptions
|
||||
import org.jetbrains.kotlin.ir.backend.js.codegen.generateEsModules
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformerTmp
|
||||
import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.irMessageLogger
|
||||
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.test.handlers.JsBoxRunner.Companion.TEST_FUNCTION
|
||||
import org.jetbrains.kotlin.js.test.utils.esModulesSubDir
|
||||
import org.jetbrains.kotlin.js.test.utils.extractTestPackage
|
||||
import org.jetbrains.kotlin.js.test.utils.jsIrIncrementalDataProvider
|
||||
import org.jetbrains.kotlin.library.uniqueName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.test.DebugMode
|
||||
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
|
||||
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
|
||||
import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
|
||||
import org.jetbrains.kotlin.test.model.*
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
@@ -49,6 +42,9 @@ import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurato
|
||||
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
|
||||
import java.io.File
|
||||
|
||||
const val REGULAR_EXTENSION = ".js"
|
||||
const val ESM_EXTENSION = ".mjs"
|
||||
|
||||
class JsIrBackendFacade(
|
||||
val testServices: TestServices,
|
||||
private val firstTimeCompilation: Boolean
|
||||
@@ -91,16 +87,16 @@ class JsIrBackendFacade(
|
||||
else -> JsGenerationGranularity.WHOLE_PROGRAM
|
||||
}
|
||||
|
||||
val testPackage = extractTestPackage(testServices)
|
||||
val testPackage = extractTestPackage(testServices, ignoreEsModules = false)
|
||||
val skipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE in module.directives
|
||||
|
||||
if (skipRegularMode) return null
|
||||
|
||||
if (JsEnvironmentConfigurator.incrementalEnabled(testServices)) {
|
||||
val outputFile = if (firstTimeCompilation) {
|
||||
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js")
|
||||
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + module.kind.extension)
|
||||
} else {
|
||||
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name) + ".js")
|
||||
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name) + module.kind.extension)
|
||||
}
|
||||
|
||||
val compiledModule = CompilerResult(
|
||||
@@ -136,11 +132,12 @@ class JsIrBackendFacade(
|
||||
PhaseConfig(jsPhases)
|
||||
}
|
||||
|
||||
|
||||
val loweredIr = compileIr(
|
||||
irModuleFragment,
|
||||
irModuleFragment.apply { resolveTestPathes() },
|
||||
MainModule.Klib(inputArtifact.outputFile.absolutePath),
|
||||
configuration,
|
||||
dependencyModules,
|
||||
dependencyModules.apply { forEach { it.resolveTestPathes() } },
|
||||
emptyMap(),
|
||||
irModuleFragment.irBuiltins,
|
||||
symbolTable,
|
||||
@@ -164,22 +161,27 @@ class JsIrBackendFacade(
|
||||
module: TestModule,
|
||||
loweredIr: LoweredIr,
|
||||
granularity: JsGenerationGranularity,
|
||||
): BinaryArtifacts.Js? {
|
||||
val generateDts = JsEnvironmentConfigurationDirectives.GENERATE_DTS in module.directives
|
||||
): BinaryArtifacts.Js {
|
||||
val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module)
|
||||
.run { if (shouldBeGenerated()) arguments() else null }
|
||||
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives
|
||||
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in module.directives
|
||||
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in module.directives
|
||||
val runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
||||
val perModuleOnly = JsEnvironmentConfigurationDirectives.SPLIT_PER_MODULE in module.directives
|
||||
val isEsModules = JsEnvironmentConfigurationDirectives.ES_MODULES in module.directives ||
|
||||
module.directives[JsEnvironmentConfigurationDirectives.MODULE_KIND].contains(ModuleKind.ES)
|
||||
|
||||
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, TranslationMode.FULL) + ".js")
|
||||
val dceOutputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, TranslationMode.FULL_DCE_MINIMIZED_NAMES) + ".js")
|
||||
if (!esModules) {
|
||||
if (runNewIr2Js) {
|
||||
val transformer = IrModuleToJsTransformerTmp(loweredIr.context, mainArguments)
|
||||
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, TranslationMode.FULL) + module.kind.extension)
|
||||
|
||||
if (runNewIr2Js) {
|
||||
val transformer = IrModuleToJsTransformerTmp(
|
||||
loweredIr.context,
|
||||
mainArguments,
|
||||
moduleToName = JsIrModuleToPath(
|
||||
testServices,
|
||||
isEsModules && granularity != JsGenerationGranularity.WHOLE_PROGRAM
|
||||
)
|
||||
)
|
||||
// If runIrDce then include DCE results
|
||||
// If perModuleOnly then skip whole program
|
||||
// (it.dce => runIrDce) && (perModuleOnly => it.perModule)
|
||||
@@ -199,19 +201,14 @@ class JsIrBackendFacade(
|
||||
relativeRequirePath = false
|
||||
)
|
||||
|
||||
return BinaryArtifacts.Js.JsIrArtifact(outputFile, transformer.generateModule(loweredIr.allModules)).dump(module)
|
||||
}
|
||||
return BinaryArtifacts.Js.JsIrArtifact(outputFile, transformer.generateModule(loweredIr.allModules)).dump(module)
|
||||
}
|
||||
}
|
||||
|
||||
val options = JsGenerationOptions(generatePackageJson = true, generateTypeScriptDefinitions = generateDts)
|
||||
generateEsModules(loweredIr, jsOutputSink(outputFile.parentFile.esModulesSubDir), mainArguments, granularity, options)
|
||||
|
||||
if (runIrDce) {
|
||||
eliminateDeadDeclarations(loweredIr.allModules, loweredIr.context)
|
||||
generateEsModules(loweredIr, jsOutputSink(dceOutputFile.parentFile.esModulesSubDir), mainArguments, granularity, options)
|
||||
return BinaryArtifacts.Js.JsEsArtifact(outputFile, dceOutputFile).dump(module)
|
||||
private fun IrModuleFragment.resolveTestPathes() {
|
||||
JsIrPathReplacer(testServices).let {
|
||||
files.forEach(it::lower)
|
||||
}
|
||||
return BinaryArtifacts.Js.JsEsArtifact(outputFile, null).dump(module)
|
||||
}
|
||||
|
||||
private fun loadIrFromKlib(module: TestModule, configuration: CompilerConfiguration): IrModuleInfo {
|
||||
@@ -238,55 +235,10 @@ class JsIrBackendFacade(
|
||||
) { if (it == mainModuleLib) moduleDescriptor else testServices.jsLibraryProvider.getDescriptorByCompiledLibrary(it) }
|
||||
}
|
||||
|
||||
private fun loadIrFromSources(
|
||||
private fun BinaryArtifacts.Js.JsIrArtifact.dump(
|
||||
module: TestModule,
|
||||
configuration: CompilerConfiguration,
|
||||
inputArtifact: ClassicFrontendOutputArtifact
|
||||
): IrModuleInfo {
|
||||
val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT
|
||||
val messageLogger = configuration.irMessageLogger
|
||||
val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImplForJsIC(WholeWorldStageController()),)
|
||||
val verifySignatures = JsEnvironmentConfigurationDirectives.SKIP_MANGLE_VERIFICATION !in module.directives
|
||||
|
||||
val psi2Ir = Psi2IrTranslator(
|
||||
configuration.languageVersionSettings,
|
||||
Psi2IrConfiguration(errorPolicy.allowErrors),
|
||||
messageLogger::checkNoUnboundSymbols
|
||||
)
|
||||
val psi2IrContext = psi2Ir.createGeneratorContext(
|
||||
inputArtifact.analysisResult.moduleDescriptor,
|
||||
inputArtifact.analysisResult.bindingContext,
|
||||
symbolTable
|
||||
)
|
||||
|
||||
return getIrModuleInfoForSourceFiles(
|
||||
psi2IrContext,
|
||||
inputArtifact.project,
|
||||
configuration,
|
||||
inputArtifact.allKtFiles.values.toList(),
|
||||
sortDependencies(JsEnvironmentConfigurator.getAllRecursiveLibrariesFor(module, testServices)),
|
||||
emptyMap(),
|
||||
symbolTable,
|
||||
messageLogger,
|
||||
loadFunctionInterfacesIntoStdlib = true,
|
||||
verifySignatures,
|
||||
) { testServices.jsLibraryProvider.getDescriptorByCompiledLibrary(it) }
|
||||
}
|
||||
|
||||
private fun jsOutputSink(perFileOutputDir: File): CompilerOutputSink {
|
||||
perFileOutputDir.deleteRecursively()
|
||||
perFileOutputDir.mkdirs()
|
||||
|
||||
return object : CompilerOutputSink {
|
||||
override fun write(module: String, path: String, content: String) {
|
||||
val file = File(File(perFileOutputDir, module), path)
|
||||
file.parentFile.mkdirs()
|
||||
file.writeText(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun BinaryArtifacts.Js.JsIrArtifact.dump(module: TestModule, firstTimeCompilation: Boolean = true): BinaryArtifacts.Js.JsIrArtifact {
|
||||
firstTimeCompilation: Boolean = true
|
||||
): BinaryArtifacts.Js.JsIrArtifact {
|
||||
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||
val moduleId = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
||||
val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
@@ -297,9 +249,15 @@ class JsIrBackendFacade(
|
||||
if (dontSkipRegularMode) {
|
||||
for ((mode, output) in compilerResult.outputs.entries) {
|
||||
val outputFile = if (firstTimeCompilation) {
|
||||
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, mode) + ".js")
|
||||
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, mode) + moduleKind.extension)
|
||||
} else {
|
||||
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name, mode) + ".js")
|
||||
File(
|
||||
JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(
|
||||
testServices,
|
||||
module.name,
|
||||
mode
|
||||
) + moduleKind.extension
|
||||
)
|
||||
}
|
||||
output.writeTo(outputFile, moduleId, moduleKind)
|
||||
}
|
||||
@@ -307,24 +265,13 @@ class JsIrBackendFacade(
|
||||
|
||||
if (generateDts) {
|
||||
outputFile
|
||||
.withReplacedExtensionOrNull("_v5.js", ".d.ts")!!
|
||||
.withReplacedExtensionOrNull("_v5${moduleKind.extension}", ".d.ts")!!
|
||||
.write(compilerResult.tsDefinitions ?: error("No ts definitions"))
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
private fun BinaryArtifacts.Js.JsEsArtifact.dump(module: TestModule): BinaryArtifacts.Js.JsEsArtifact {
|
||||
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||
val moduleName = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
||||
val esmTestFile = outputFile.parentFile.esModulesSubDir.resolve("test.mjs")
|
||||
createEsTestFile(esmTestFile, moduleName)
|
||||
|
||||
val dceEsmTestFile = outputDceFile?.parentFile?.esModulesSubDir?.resolve("test.mjs") ?: return this
|
||||
createEsTestFile(dceEsmTestFile, moduleName)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun CompilationOutputs.writeTo(outputFile: File, moduleId: String, moduleKind: ModuleKind) {
|
||||
val wrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, moduleId = moduleId, moduleKind = moduleKind)
|
||||
outputFile.write(wrappedCode)
|
||||
@@ -344,32 +291,37 @@ class JsIrBackendFacade(
|
||||
writeText(text)
|
||||
}
|
||||
|
||||
private fun createEsTestFile(file: File, moduleName: String) {
|
||||
val customTestModule = testServices.moduleStructure.modules
|
||||
.flatMap { it.files }
|
||||
.singleOrNull { JsEnvironmentConfigurationDirectives.ENTRY_ES_MODULE in it.directives }
|
||||
val customTestModuleText = customTestModule?.let { testServices.sourceFileProvider.getContentOfSourceFile(it) }
|
||||
|
||||
val defaultTestModule =
|
||||
"""
|
||||
import { box } from './${moduleName}/index.js';
|
||||
let res = box();
|
||||
if (res !== "OK") {
|
||||
throw "Wrong result: " + String(res);
|
||||
}
|
||||
""".trimIndent()
|
||||
file.writeText(customTestModuleText ?: defaultTestModule)
|
||||
}
|
||||
|
||||
override fun shouldRunAnalysis(module: TestModule): Boolean {
|
||||
return JsEnvironmentConfigurator.isMainModule(module, testServices)
|
||||
}
|
||||
}
|
||||
|
||||
val ModuleKind.extension: String
|
||||
get() = when (this) {
|
||||
ModuleKind.ES -> ESM_EXTENSION
|
||||
else -> REGULAR_EXTENSION
|
||||
}
|
||||
|
||||
val RegisteredDirectives.moduleKind: ModuleKind
|
||||
get() = get(JsEnvironmentConfigurationDirectives.MODULE_KIND).singleOrNull()
|
||||
?: if (contains(JsEnvironmentConfigurationDirectives.ES_MODULES)) ModuleKind.ES else ModuleKind.PLAIN
|
||||
|
||||
val TestModule.kind: ModuleKind
|
||||
get() = directives.moduleKind
|
||||
|
||||
fun String.augmentWithModuleName(moduleName: String): String {
|
||||
check(endsWith("_v5.js"))
|
||||
val normalizedName = moduleName.run { if (isWindows) minify() else this }
|
||||
return removeSuffix("_v5.js") + "-${normalizedName}_v5.js"
|
||||
return if (moduleName.isPath()) {
|
||||
replaceAfterLast(File.separator, moduleName.replace("./", ""))
|
||||
} else {
|
||||
val suffix = when {
|
||||
endsWith(ESM_EXTENSION) -> ESM_EXTENSION
|
||||
endsWith(REGULAR_EXTENSION) -> REGULAR_EXTENSION
|
||||
else -> error("Unexpected file '$this' extension")
|
||||
}
|
||||
val normalizedName = moduleName.run { if (isWindows) minify() else this }
|
||||
|
||||
return removeSuffix("_v5$suffix") + "-${normalizedName}_v5$suffix"
|
||||
}
|
||||
}
|
||||
|
||||
// D8 ignores Windows settings related to extending of maximum path symbols count
|
||||
@@ -380,4 +332,6 @@ fun String.minify(): String {
|
||||
.replace("_minimal_for_test", "_min")
|
||||
}
|
||||
|
||||
private fun String.isPath(): Boolean = contains("/")
|
||||
|
||||
fun File.augmentWithModuleName(moduleName: String): File = File(absolutePath.augmentWithModuleName(moduleName))
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.js.test.converters
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator.Companion.getJsArtifactSimpleName
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
private typealias K = IrModuleFragment
|
||||
private typealias V = String
|
||||
|
||||
class JsIrModuleToPath(val testServices: TestServices, shouldProvidePaths: Boolean) : Map<K, V> {
|
||||
override val size = if (!shouldProvidePaths) 0 else 1
|
||||
override val entries = emptySet<Map.Entry<K, V>>()
|
||||
override val keys = emptySet<K>()
|
||||
override val values = emptyList<V>()
|
||||
|
||||
override fun isEmpty() = size == 0
|
||||
override fun containsKey(key: K): Boolean = !isEmpty()
|
||||
override fun containsValue(value: V): Boolean = !isEmpty()
|
||||
|
||||
override operator fun get(key: K): V? {
|
||||
return runIf(!isEmpty()) {
|
||||
"./${getJsArtifactSimpleName(testServices, key.safeName)}_v5.mjs"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.js.test.converters
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.util.getAnnotation
|
||||
import org.jetbrains.kotlin.js.test.utils.*
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.isJsFile
|
||||
import org.jetbrains.kotlin.test.services.isMjsFile
|
||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||
|
||||
class JsIrPathReplacer(testServices: TestServices) : DeclarationTransformer {
|
||||
private val replacements = testServices.collectReplacementsMap()
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
super.lower(irFile)
|
||||
irFile.replaceJsModulePath()
|
||||
}
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
return null.also {
|
||||
declaration.replaceJsModulePath()
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrAnnotationContainer.replaceJsModulePath() {
|
||||
val jsModuleAnnotation = getAnnotation(JsAnnotations.jsModuleFqn) ?: return
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val stringLiteral = jsModuleAnnotation.getValueArgument(0) as IrConst<String>
|
||||
val pathReplacement = stringLiteral.getReplacement() ?: return
|
||||
|
||||
jsModuleAnnotation.putValueArgument(0, pathReplacement)
|
||||
}
|
||||
|
||||
private fun IrConst<String>.getReplacement(): IrConst<String>? {
|
||||
val replacement = replacements[value] ?: replacements[value.replace("./", "")] ?: return null
|
||||
return IrConstImpl.string(startOffset, endOffset, type, "./" + replacement.replace("./", ""))
|
||||
}
|
||||
|
||||
private fun TestServices.collectReplacementsMap(): Map<String, String> {
|
||||
return moduleStructure.modules.asSequence()
|
||||
.map { module -> module to module.files.filter { it.isJsFile || it.isMjsFile } }
|
||||
.filter { (_, files) -> files.isNotEmpty() }
|
||||
.flatMap { (module, files) -> files.map { it.relativePath to module.getNameFor(it, this) } }
|
||||
.plus(getAdditionalFiles(this).map { it.name to it.name })
|
||||
.plus(getAdditionalMainFiles(this).map { it.name to it.name })
|
||||
.toMap()
|
||||
}
|
||||
}
|
||||
@@ -5,25 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.test.handlers
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
||||
import org.jetbrains.kotlin.js.testOld.engines.ExternalTool
|
||||
import org.jetbrains.kotlin.js.test.utils.*
|
||||
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.test.services.defaultsProvider
|
||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||
import java.io.File
|
||||
|
||||
private val v8tool by lazy { ExternalTool(System.getProperty("javascript.engine.path.V8")) }
|
||||
|
||||
class JsBoxRunner(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
|
||||
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||
if (someAssertionWasFailed) return
|
||||
|
||||
if (JsEnvironmentConfigurationDirectives.ES_MODULES in testServices.moduleStructure.allDirectives) {
|
||||
runEsCode()
|
||||
} else {
|
||||
if (!someAssertionWasFailed) {
|
||||
runJsCode()
|
||||
}
|
||||
}
|
||||
@@ -43,37 +33,30 @@ class JsBoxRunner(testServices: TestServices) : AbstractJsArtifactsCollector(tes
|
||||
|
||||
val dontSkipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE !in globalDirectives
|
||||
if (dontSkipRegularMode) {
|
||||
for (jsFiles in allJsFiles.values) {
|
||||
runGeneratedCode(jsFiles, testModuleName, testPackage, withModuleSystem)
|
||||
for ((mode, jsFiles) in allJsFiles) {
|
||||
val entryModulePath = extractEntryModulePath(mode, testServices)
|
||||
runGeneratedCode(entryModulePath, jsFiles, testModuleName, testPackage, withModuleSystem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun runEsCode() {
|
||||
val globalDirectives = testServices.moduleStructure.allDirectives
|
||||
|
||||
val esmOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).esModulesSubDir
|
||||
val esmDceOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, TranslationMode.FULL_DCE_MINIMIZED_NAMES).esModulesSubDir
|
||||
|
||||
val dontSkipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE !in globalDirectives
|
||||
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in globalDirectives
|
||||
if (dontSkipRegularMode) {
|
||||
singleRunEsCode(esmOutputDir)
|
||||
if (runIrDce) {
|
||||
singleRunEsCode(esmDceOutputDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun singleRunEsCode(esmOutputDir: File) {
|
||||
val perFileEsModuleFile = "$esmOutputDir/test.mjs"
|
||||
val (allNonEsModuleFiles, inputJsFilesAfter) = extractAllFilesForEsRunner(testServices, esmOutputDir)
|
||||
v8tool.run(*allNonEsModuleFiles.toTypedArray(), perFileEsModuleFile, *inputJsFilesAfter.toTypedArray())
|
||||
}
|
||||
|
||||
private fun runGeneratedCode(jsFiles: List<String>, testModuleName: String?, testPackage: String?, withModuleSystem: Boolean) {
|
||||
private fun runGeneratedCode(
|
||||
entryModulePath: String?,
|
||||
jsFiles: List<String>,
|
||||
testModuleName: String?,
|
||||
testPackage: String?,
|
||||
withModuleSystem: Boolean
|
||||
) {
|
||||
getTestChecker(testServices)
|
||||
.check(jsFiles, testModuleName, testPackage, TEST_FUNCTION, DEFAULT_EXPECTED_RESULT, withModuleSystem)
|
||||
.check(
|
||||
jsFiles,
|
||||
testModuleName,
|
||||
testPackage,
|
||||
TEST_FUNCTION,
|
||||
DEFAULT_EXPECTED_RESULT,
|
||||
withModuleSystem,
|
||||
entryModulePath,
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -24,6 +24,7 @@ class JsDtsHandler(testServices: TestServices) : JsBinaryArtifactHandler(testSer
|
||||
val referenceDtsFile = module.files.first().originalFile.withReplacedExtensionOrNull(".kt", ".d.ts")
|
||||
?: error("Can't find reference .d.ts file")
|
||||
val generatedDtsFile = info.outputFile.withReplacedExtensionOrNull("_v5.js", ".d.ts")
|
||||
?: info.outputFile.withReplacedExtensionOrNull("_v5.mjs", ".d.ts")
|
||||
?: error("Can't find generated .d.ts file")
|
||||
|
||||
val generatedDts = generatedDtsFile.readText()
|
||||
|
||||
@@ -10,9 +10,10 @@ import org.jetbrains.kotlin.js.JavaScript
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.test.JsAdditionalSourceProvider
|
||||
import org.jetbrains.kotlin.js.test.converters.augmentWithModuleName
|
||||
import org.jetbrains.kotlin.js.test.converters.extension
|
||||
import org.jetbrains.kotlin.js.test.converters.kind
|
||||
import org.jetbrains.kotlin.js.test.handlers.JsBoxRunner.Companion.TEST_FUNCTION
|
||||
import org.jetbrains.kotlin.js.testOld.*
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
@@ -30,14 +31,23 @@ import java.io.File
|
||||
|
||||
private const val MODULE_EMULATION_FILE = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/moduleEmulation.js"
|
||||
|
||||
val File.esModulesSubDir: File
|
||||
get() = File(absolutePath + "_esm")
|
||||
fun TestModule.getNameFor(filePath: String, testServices: TestServices): String {
|
||||
return JsEnvironmentConfigurator.getJsArtifactSimpleName(testServices, name) + "-js-" + filePath
|
||||
}
|
||||
|
||||
private fun extractJsFiles(testServices: TestServices, modules: List<TestModule>): Pair<List<String>, List<String>> {
|
||||
val outputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices)
|
||||
fun TestModule.getNameFor(file: TestFile, testServices: TestServices): String {
|
||||
return getNameFor(file.name, testServices)
|
||||
}
|
||||
|
||||
private fun extractJsFiles(
|
||||
testServices: TestServices,
|
||||
modules: List<TestModule>,
|
||||
mode: TranslationMode = TranslationMode.FULL,
|
||||
): Pair<List<String>, List<String>> {
|
||||
val outputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, mode)
|
||||
|
||||
fun copyInputJsFile(module: TestModule, inputJsFile: TestFile): String {
|
||||
val newName = JsEnvironmentConfigurator.getJsArtifactSimpleName(testServices, module.name) + "-js-" + inputJsFile.name
|
||||
val newName = module.getNameFor(inputJsFile, testServices)
|
||||
val targetFile = File(outputDir, newName)
|
||||
targetFile.writeText(inputJsFile.originalContent)
|
||||
return targetFile.absolutePath
|
||||
@@ -45,49 +55,74 @@ private fun extractJsFiles(testServices: TestServices, modules: List<TestModule>
|
||||
|
||||
val inputJsFiles = modules
|
||||
.flatMap { module -> module.files.map { module to it } }
|
||||
.filter { it.second.isJsFile }
|
||||
|
||||
.filter { it.second.isJsFile || it.second.isMjsFile }
|
||||
|
||||
val after = inputJsFiles
|
||||
.filter { (_, inputJsFile) -> inputJsFile.name.endsWith("__after.js") }
|
||||
.filter { (module, inputJsFile) -> inputJsFile.name.endsWith("__after${module.kind.extension}") }
|
||||
.map { (module, inputJsFile) -> copyInputJsFile(module, inputJsFile) }
|
||||
val before = inputJsFiles
|
||||
.filterNot { (_, inputJsFile) -> inputJsFile.name.endsWith("__after.js") }
|
||||
.filterNot { (module, inputJsFile) -> inputJsFile.name.endsWith("__after${module.kind.extension}") }
|
||||
.map { (module, inputJsFile) -> copyInputJsFile(module, inputJsFile) }
|
||||
|
||||
return before to after
|
||||
}
|
||||
|
||||
private fun getAdditionalFiles(testServices: TestServices): List<String> {
|
||||
fun getAdditionalFilePathes(testServices: TestServices, mode: TranslationMode = TranslationMode.FULL): List<String> {
|
||||
return getAdditionalFiles(testServices, mode, true).map { it.absolutePath }
|
||||
}
|
||||
|
||||
fun getAdditionalFiles(
|
||||
testServices: TestServices,
|
||||
mode: TranslationMode = TranslationMode.FULL,
|
||||
shouldCopyFiles: Boolean = false
|
||||
): List<File> {
|
||||
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||
|
||||
val withModuleSystem = testWithModuleSystem(testServices)
|
||||
|
||||
val additionalFiles = mutableListOf<String>()
|
||||
if (withModuleSystem) additionalFiles += File(MODULE_EMULATION_FILE).absolutePath
|
||||
val additionalFiles = mutableListOf<File>()
|
||||
if (withModuleSystem) additionalFiles += File(MODULE_EMULATION_FILE)
|
||||
|
||||
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + JavaScript.DOT_EXTENSION)
|
||||
.takeIf { it.exists() }
|
||||
?.let { additionalFiles += it.absolutePath }
|
||||
?.let { additionalFiles += it }
|
||||
|
||||
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + JavaScript.DOT_MODULE_EXTENSION)
|
||||
.takeIf { it.exists() }
|
||||
?.let {
|
||||
File(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, mode), it.name).apply {
|
||||
if (shouldCopyFiles) it.copyTo(this, true)
|
||||
}
|
||||
}
|
||||
?.let { additionalFiles += it }
|
||||
|
||||
return additionalFiles
|
||||
}
|
||||
|
||||
private fun getAdditionalMjsFiles(testServices: TestServices): List<String> {
|
||||
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||
|
||||
return originalFile.parentFile.resolve(originalFile.nameWithoutExtension + ".mjs")
|
||||
.takeIf { it.exists() }
|
||||
?.let { listOf(it.absolutePath) } ?: emptyList()
|
||||
fun getAdditionalMainFilePathes(testServices: TestServices, mode: TranslationMode = TranslationMode.FULL): List<String> {
|
||||
return getAdditionalMainFiles(testServices, mode, shouldCopyFiles = true).map { it.absolutePath }
|
||||
}
|
||||
|
||||
private fun getAdditionalMainFiles(testServices: TestServices): List<String> {
|
||||
fun getAdditionalMainFiles(
|
||||
testServices: TestServices,
|
||||
mode: TranslationMode = TranslationMode.FULL,
|
||||
shouldCopyFiles: Boolean = false
|
||||
): List<File> {
|
||||
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||
val additionalFiles = mutableListOf<String>()
|
||||
val additionalFiles = mutableListOf<File>()
|
||||
|
||||
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + "__main.js")
|
||||
.takeIf { it.exists() }
|
||||
?.let { additionalFiles += it.absolutePath }
|
||||
?.let { additionalFiles += it }
|
||||
|
||||
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + "__main.mjs")
|
||||
.takeIf { it.exists() }
|
||||
?.let {
|
||||
File(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, mode), it.name).apply {
|
||||
if (shouldCopyFiles) it.copyTo(this, true)
|
||||
}
|
||||
}
|
||||
?.let { additionalFiles += it }
|
||||
|
||||
return additionalFiles
|
||||
}
|
||||
@@ -99,26 +134,31 @@ fun testWithModuleSystem(testServices: TestServices): Boolean {
|
||||
return mainModuleKind != ModuleKind.PLAIN && NO_JS_MODULE_SYSTEM !in globalDirectives
|
||||
}
|
||||
|
||||
fun getModeOutputFilePath(testServices: TestServices, module: TestModule, mode: TranslationMode): String {
|
||||
return JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, mode) + module.kind.extension
|
||||
}
|
||||
|
||||
fun getAllFilesForRunner(
|
||||
testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>
|
||||
): Map<TranslationMode, List<String>> {
|
||||
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||
|
||||
val commonFiles = JsAdditionalSourceProvider.getAdditionalJsFiles(originalFile.parent).map { it.absolutePath }
|
||||
val (inputJsFilesBefore, inputJsFilesAfter) = extractJsFiles(testServices, testServices.moduleStructure.modules)
|
||||
val additionalFiles = getAdditionalFiles(testServices)
|
||||
val additionalMainFiles = getAdditionalMainFiles(testServices)
|
||||
|
||||
if (modulesToArtifact.values.any { it is BinaryArtifacts.Js.JsIrArtifact }) {
|
||||
// JS IR
|
||||
val (module, compilerResult) = modulesToArtifact.entries.mapNotNull { (m, c) -> (c as? BinaryArtifacts.Js.JsIrArtifact)?.let { m to c.compilerResult } }.single()
|
||||
|
||||
val (module, compilerResult) = modulesToArtifact.entries.mapNotNull { (m, c) -> (c as? BinaryArtifacts.Js.JsIrArtifact)?.let { m to c.compilerResult } }
|
||||
.single()
|
||||
val result = mutableMapOf<TranslationMode, List<String>>()
|
||||
|
||||
compilerResult.outputs.entries.forEach { (mode, outputs) ->
|
||||
val paths = mutableListOf<String>()
|
||||
|
||||
val outputFile = JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, mode) + ".js"
|
||||
val outputFile = getModeOutputFilePath(testServices, module, mode)
|
||||
val (inputJsFilesBefore, inputJsFilesAfter) = extractJsFiles(testServices, testServices.moduleStructure.modules, mode)
|
||||
val additionalFiles = getAdditionalFilePathes(testServices, mode)
|
||||
val additionalMainFiles = getAdditionalMainFilePathes(testServices, mode)
|
||||
|
||||
outputs.dependencies.forEach { (moduleId, _) ->
|
||||
paths += outputFile.augmentWithModuleName(moduleId)
|
||||
}
|
||||
@@ -129,12 +169,15 @@ fun getAllFilesForRunner(
|
||||
|
||||
return result
|
||||
} else {
|
||||
// Old BE and ES modules
|
||||
val (inputJsFilesBefore, inputJsFilesAfter) = extractJsFiles(testServices, testServices.moduleStructure.modules)
|
||||
val additionalFiles = getAdditionalFilePathes(testServices)
|
||||
val additionalMainFiles = getAdditionalMainFilePathes(testServices)
|
||||
// Old BE
|
||||
val outputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices)
|
||||
val dceOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, TranslationMode.FULL_DCE_MINIMIZED_NAMES)
|
||||
|
||||
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }.filter { !File(it).isDirectory }
|
||||
val allJsFiles = additionalFiles + inputJsFilesBefore +artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
|
||||
val allJsFiles = additionalFiles + inputJsFilesBefore + artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
|
||||
|
||||
val result = mutableMapOf<TranslationMode, List<String>>()
|
||||
|
||||
@@ -154,38 +197,6 @@ fun getAllFilesForRunner(
|
||||
}
|
||||
}
|
||||
|
||||
fun extractAllFilesForEsRunner(testServices: TestServices, esmOutputDir: File): Pair<List<String>, List<String>> {
|
||||
val modules = testServices.moduleStructure.modules
|
||||
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||
|
||||
val commonFiles = JsAdditionalSourceProvider.getAdditionalJsFiles(originalFile.parent).map { it.absolutePath }
|
||||
val (inputJsFilesBefore, inputJsFilesAfter) = extractJsFiles(testServices, modules)
|
||||
val additionalFiles = getAdditionalFiles(testServices)
|
||||
val additionalMjsFiles = getAdditionalMjsFiles(testServices)
|
||||
val additionalMainFiles = getAdditionalMainFiles(testServices)
|
||||
|
||||
val allNonEsModuleFiles = additionalFiles + inputJsFilesBefore + commonFiles
|
||||
|
||||
// Copy __main file if present
|
||||
if (additionalMainFiles.isNotEmpty()) {
|
||||
val newFileName = File(esmOutputDir, "test.mjs")
|
||||
newFileName.delete()
|
||||
File(additionalMainFiles.first()).copyTo(newFileName)
|
||||
}
|
||||
|
||||
// Copy all .mjs files into generated directory
|
||||
modules.flatMap { it.files }
|
||||
.filter { it.isMjsFile }
|
||||
.map { File(esmOutputDir, it.name).writeText(it.originalContent) }
|
||||
|
||||
additionalMjsFiles.forEach { mjsFile ->
|
||||
val outFile = File(esmOutputDir, File(mjsFile).name)
|
||||
File(mjsFile).copyTo(outFile, overwrite = true)
|
||||
}
|
||||
|
||||
return Pair(allNonEsModuleFiles, inputJsFilesAfter)
|
||||
}
|
||||
|
||||
fun getOnlyJsFilesForRunner(testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>): List<String> {
|
||||
return getAllFilesForRunner(testServices, modulesToArtifact).let {
|
||||
it[TranslationMode.FULL] ?: it[TranslationMode.PER_MODULE]!!
|
||||
@@ -215,8 +226,49 @@ fun getBoxFunction(testServices: TestServices): KtNamedFunction? {
|
||||
}.singleOrNull()
|
||||
}
|
||||
|
||||
fun extractTestPackage(testServices: TestServices): String? =
|
||||
getBoxFunction(testServices)?.containingKtFile?.packageFqName?.asString()?.takeIf { it.isNotEmpty() }
|
||||
fun extractTestPackage(testServices: TestServices, ignoreEsModules: Boolean = true): String? {
|
||||
val runPlainBoxFunction = RUN_PLAIN_BOX_FUNCTION in testServices.moduleStructure.allDirectives
|
||||
if (runPlainBoxFunction) return null
|
||||
|
||||
val ktFiles = testServices.moduleStructure.modules.flatMap { module ->
|
||||
module.files
|
||||
.filter { it.isKtFile }
|
||||
.map {
|
||||
val project = testServices.compilerConfigurationProvider.getProject(module)
|
||||
module to testServices.sourceFileProvider.getKtFileForSourceFile(it, project)
|
||||
}
|
||||
}
|
||||
|
||||
val fileWithBoxFunction = ktFiles.find { (module, ktFile) ->
|
||||
(!ignoreEsModules || module.kind != ModuleKind.ES) &&
|
||||
ktFile.declarations.find { it is KtNamedFunction && it.name == TEST_FUNCTION } != null
|
||||
} ?: return null
|
||||
|
||||
return fileWithBoxFunction.second.packageFqName.asString().takeIf { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun extractEntryModulePath(
|
||||
mode: TranslationMode,
|
||||
testServices: TestServices,
|
||||
): String? =
|
||||
if (getBoxFunction(testServices) == null) {
|
||||
testServices.moduleStructure.modules
|
||||
.find { JsEnvironmentConfigurator.isMainModule(it, testServices) }
|
||||
?.run {
|
||||
files
|
||||
.find { it.isMjsFile && JsEnvironmentConfigurationDirectives.ENTRY_ES_MODULE in it.directives }
|
||||
?.let {
|
||||
JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, mode).absolutePath +
|
||||
File.separator + getNameFor(it, testServices)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
testServices.moduleStructure.modules
|
||||
.find { JsEnvironmentConfigurator.isMainModule(it, testServices) }
|
||||
?.let { getModeOutputFilePath(testServices, it, mode) }
|
||||
}
|
||||
|
||||
|
||||
fun getTestChecker(testServices: TestServices): AbstractJsTestChecker {
|
||||
val runTestInNashorn = java.lang.Boolean.getBoolean("kotlin.js.useNashorn")
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.js.engine.loadFiles
|
||||
import org.junit.Assert
|
||||
|
||||
private const val DIST_DIR_JS_PATH = "dist/js/"
|
||||
private const val ESM_EXTENSION = ".mjs"
|
||||
|
||||
fun createScriptEngine(): ScriptEngine {
|
||||
return if (java.lang.Boolean.getBoolean("kotlin.js.useNashorn")) ScriptEngineNashorn() else ScriptEngineV8()
|
||||
@@ -22,14 +23,26 @@ fun ScriptEngine.overrideAsserter() {
|
||||
eval("this['kotlin-test'].kotlin.test.overrideAsserter_wbnzx$(this['kotlin-test'].kotlin.test.DefaultAsserter);")
|
||||
}
|
||||
|
||||
private fun String.escapePath(): String {
|
||||
return replace("\\", "/")
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun ScriptEngine.runTestFunction(
|
||||
testModuleName: String?,
|
||||
testPackageName: String?,
|
||||
testFunctionName: String,
|
||||
withModuleSystem: Boolean,
|
||||
testFunctionArgs: String = "",
|
||||
entryModulePath: String? = null,
|
||||
): String {
|
||||
if (withModuleSystem && testModuleName == null && entryModulePath == null) {
|
||||
error("Entry point was not found. Please specify ENTRY_ES_MODULE directive near js file, if this is ES Modules test.")
|
||||
}
|
||||
var script = when {
|
||||
entryModulePath != null && entryModulePath.endsWith(ESM_EXTENSION) -> "globalThis".also {
|
||||
eval("import('${entryModulePath.escapePath()}').then(module => Object.assign(globalThis, module)).catch(console.error)")
|
||||
}
|
||||
withModuleSystem -> "\$kotlin_test_internal\$.require('" + testModuleName!! + "')"
|
||||
testModuleName === null -> "this"
|
||||
else -> testModuleName
|
||||
@@ -51,9 +64,10 @@ abstract class AbstractJsTestChecker {
|
||||
testPackageName: String?,
|
||||
testFunctionName: String,
|
||||
expectedResult: String,
|
||||
withModuleSystem: Boolean
|
||||
withModuleSystem: Boolean,
|
||||
entryModulePath: String? = null,
|
||||
) {
|
||||
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, "", withModuleSystem)
|
||||
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, "", withModuleSystem, entryModulePath)
|
||||
Assert.assertEquals(expectedResult, actualResult.normalize())
|
||||
}
|
||||
|
||||
@@ -76,9 +90,10 @@ abstract class AbstractJsTestChecker {
|
||||
testPackageName: String?,
|
||||
testFunctionName: String,
|
||||
testFunctionArgs: String,
|
||||
withModuleSystem: Boolean
|
||||
withModuleSystem: Boolean,
|
||||
entryModulePath: String? = null,
|
||||
) = run(files) {
|
||||
runTestFunction(testModuleName, testPackageName, testFunctionName, withModuleSystem, testFunctionArgs)
|
||||
runTestFunction(testModuleName, testPackageName, testFunctionName, withModuleSystem, testFunctionArgs, entryModulePath)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user