[K/JS] Move ES modules logic to a new transformer with IC

This commit is contained in:
Artem Kobzar
2022-10-13 07:32:44 +00:00
committed by Space Team
parent 54deba63a1
commit de880ce9aa
88 changed files with 2476 additions and 1134 deletions
@@ -1329,31 +1329,47 @@ public class JsToStringGenerationVisitor extends JsVisitor {
@Override
public void visitImport(@NotNull JsImport jsImport) {
p.print("import {");
boolean isMultiline = jsImport.getElements().size() > 1;
p.indentIn();
if (isMultiline)
newlineOpt();
else
space();
JsImport.Target target = jsImport.getTarget();
for (JsImport.Element element : jsImport.getElements()) {
nameDef(element.getName());
JsName alias = element.getAlias();
if (alias != null) {
p.print(" as ");
nameDef(alias);
}
p.print("import ");
if (isMultiline) {
p.print(',');
if (target instanceof JsImport.Target.Default) {
nameDef(((JsImport.Target.Default) target).getName());
} else if (target instanceof JsImport.Target.All) {
p.print("* as ");
nameDef(((JsImport.Target.All) target).getAlias());
} else if (target instanceof JsImport.Target.Elements) {
List<JsImport.Element> elements = ((JsImport.Target.Elements) target).getElements();
p.print("{");
boolean isMultiline = elements.size() > 1;
p.indentIn();
if (isMultiline)
newlineOpt();
} else {
else
space();
for (JsImport.Element element : elements) {
nameDef(element.getName());
JsName alias = element.getAlias();
if (alias != null) {
p.print(" as ");
nameDef(alias);
}
if (isMultiline) {
p.print(',');
newlineOpt();
}
else {
space();
}
}
p.indentOut();
p.print("}");
}
p.indentOut();
p.print("} from ");
p.print(" from ");
p.print(javaScriptString(jsImport.getModule()));
}
@@ -7,8 +7,23 @@ package org.jetbrains.kotlin.js.backend.ast
class JsImport(
val module: String,
val elements: MutableList<Element> = mutableListOf(),
val target: Target,
) : SourceInfoAwareJsNode(), JsStatement {
constructor(module: String, elements: MutableList<Element> = mutableListOf()) : this(module, Target.Elements(elements))
val elements: MutableList<Element>
get() = (target as Target.Elements).elements
sealed class Target {
class Elements(val elements: MutableList<Element>) : Target()
class Default(val name: JsName) : Target() {
constructor(name: String) : this(JsName(name, false))
}
class All(val alias: JsName) : Target() {
constructor(alias: String) : this(JsName(alias, false))
}
}
class Element(
val name: JsName,
@@ -25,7 +40,7 @@ class JsImport(
}
override fun deepCopy(): JsStatement =
JsImport(module, elements.map { it }.toMutableList())
JsImport(module, target)
override fun traverse(v: JsVisitorWithContext, ctx: JsContext<*>) {
v.visit(this, ctx)
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.text.StringUtil
private val LINE_SEPARATOR = System.getProperty("line.separator")!!
private val END_MARKER = "<END>$LINE_SEPARATOR"
private val ESM_EXTENSION = ".mjs"
abstract class ProcessBasedScriptEngine(
private val executablePath: String
@@ -58,6 +59,7 @@ abstract class ProcessBasedScriptEngine(
}
override fun loadFile(path: String) {
if (path.endsWith(ESM_EXTENSION)) return
eval("load('${path.replace('\\', '/')}');")
}
@@ -75,27 +75,31 @@ function restoreGlobalState() {
resetRealm();
// noinspection InfiniteLoopJS
while (true) {
let code = readline().replace(/\\n/g, '\n');
async function loop() {
while (true) {
let code = readline().replace(/\\n/g, '\n');
try {
switch (code) {
case "!reset":
resetRealm()
break;
case "!saveGlobalState":
saveGlobalState();
break;
case "!restoreGlobalState":
restoreGlobalState();
break;
default:
print(Realm.eval(currentRealmIndex, code));
try {
switch (code) {
case "!reset":
resetRealm()
break;
case "!saveGlobalState":
saveGlobalState();
break;
case "!restoreGlobalState":
restoreGlobalState();
break;
default:
print(await Realm.eval(currentRealmIndex, code));
}
} catch(e) {
printErr(e.stack != null ? e.stack : e.toString());
printErr('\nCODE:\n' + code);
}
} catch(e) {
printErr(e.stack != null ? e.stack : e.toString());
printErr('\nCODE:\n' + code);
}
print('<END>');
print('<END>');
}
}
loop()
@@ -23,4 +23,7 @@ object JavaScript {
const val EXTENSION = "js"
const val DOT_EXTENSION = "." + EXTENSION
const val MODULE_EXTENSION = "mjs"
const val DOT_MODULE_EXTENSION = "." + MODULE_EXTENSION
}
@@ -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)
}
@@ -1906,18 +1906,6 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
public void testAllFilesPresentInExport() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/export"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("overriddenExternalMethodWithSameStableNameMethod.kt")
public void testOverriddenExternalMethodWithSameStableNameMethod() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameStableNameMethod.kt");
}
@Test
@TestMetadata("reservedModuleName.kt")
public void testReservedModuleName() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/reservedModuleName.kt");
}
}
@Nested
@@ -2217,35 +2217,173 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/export"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("bridgeSavingAfterExport.kt")
public void testBridgeSavingAfterExport() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/bridgeSavingAfterExport.kt");
}
@Test
@TestMetadata("bridgeSavingAfterExportInExportedFile.kt")
public void testBridgeSavingAfterExportInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/bridgeSavingAfterExportInExportedFile.kt");
}
@Test
@TestMetadata("defaultInlineClassConstructorParam.kt")
public void testDefaultInlineClassConstructorParam() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/defaultInlineClassConstructorParam.kt");
}
@Test
@TestMetadata("defaultInlineClassConstructorParamInExportedFile.kt")
public void testDefaultInlineClassConstructorParamInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/defaultInlineClassConstructorParamInExportedFile.kt");
}
@Test
@TestMetadata("exportAllFile.kt")
public void testExportAllFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportAllFile.kt");
}
@Test
@TestMetadata("exportEnumClass.kt")
public void testExportEnumClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportEnumClass.kt");
}
@Test
@TestMetadata("exportFileWithEnumClass.kt")
public void testExportFileWithEnumClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithEnumClass.kt");
}
@Test
@TestMetadata("exportFileWithInterface.kt")
public void testExportFileWithInterface() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithInterface.kt");
}
@Test
@TestMetadata("exportFileWithNestedClass.kt")
public void testExportFileWithNestedClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithNestedClass.kt");
}
@Test
@TestMetadata("exportFileWithNestedObject.kt")
public void testExportFileWithNestedObject() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithNestedObject.kt");
}
@Test
@TestMetadata("exportFileWithProtectedMembers.kt")
public void testExportFileWithProtectedMembers() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithProtectedMembers.kt");
}
@Test
@TestMetadata("exportFileWithTopLevelProperty.kt")
public void testExportFileWithTopLevelProperty() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithTopLevelProperty.kt");
}
@Test
@TestMetadata("exportInnerClass.kt")
public void testExportInnerClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportInnerClass.kt");
}
@Test
@TestMetadata("exportInterface.kt")
public void testExportInterface() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportInterface.kt");
}
@Test
@TestMetadata("exportNestedClass.kt")
public void testExportNestedClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportNestedClass.kt");
}
@Test
@TestMetadata("exportNestedObject.kt")
public void testExportNestedObject() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportNestedObject.kt");
}
@Test
@TestMetadata("exportProtectedMembers.kt")
public void testExportProtectedMembers() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportProtectedMembers.kt");
}
@Test
@TestMetadata("exportTopLevelProperty.kt")
public void testExportTopLevelProperty() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
}
@Test
@TestMetadata("nonIndetifierModuleName.kt")
public void testNonIndetifierModuleName() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/nonIndetifierModuleName.kt");
}
@Test
@TestMetadata("nonIndetifierModuleNameInExportedFile.kt")
public void testNonIndetifierModuleNameInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/nonIndetifierModuleNameInExportedFile.kt");
}
@Test
@TestMetadata("overriddenChainNonExportIntermediate.kt")
public void testOverriddenChainNonExportIntermediate() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenChainNonExportIntermediate.kt");
}
@Test
@TestMetadata("overriddenChainNonExportIntermediateInExportedFile.kt")
public void testOverriddenChainNonExportIntermediateInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenChainNonExportIntermediateInExportedFile.kt");
}
@Test
@TestMetadata("overriddenExternalMethodWithSameNameMethod.kt")
public void testOverriddenExternalMethodWithSameNameMethod() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameNameMethod.kt");
}
@Test
@TestMetadata("overriddenExternalMethodWithSameStableNameMethod.kt")
public void testOverriddenExternalMethodWithSameStableNameMethod() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameStableNameMethod.kt");
}
@Test
@TestMetadata("overriddenExternalMethodWithSameStableNameMethodInExportedFile.kt")
public void testOverriddenExternalMethodWithSameStableNameMethodInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameStableNameMethodInExportedFile.kt");
}
@Test
@TestMetadata("reservedModuleName.kt")
public void testReservedModuleName() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/reservedModuleName.kt");
}
@Test
@TestMetadata("reservedModuleNameInExportedFile.kt")
public void testReservedModuleNameInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/reservedModuleNameInExportedFile.kt");
}
@Test
@TestMetadata("vararg.kt")
public void testVararg() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/vararg.kt");
}
}
@Nested
@@ -2217,35 +2217,173 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/esModules/export"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("bridgeSavingAfterExport.kt")
public void testBridgeSavingAfterExport() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/bridgeSavingAfterExport.kt");
}
@Test
@TestMetadata("bridgeSavingAfterExportInExportedFile.kt")
public void testBridgeSavingAfterExportInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/bridgeSavingAfterExportInExportedFile.kt");
}
@Test
@TestMetadata("defaultInlineClassConstructorParam.kt")
public void testDefaultInlineClassConstructorParam() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/defaultInlineClassConstructorParam.kt");
}
@Test
@TestMetadata("defaultInlineClassConstructorParamInExportedFile.kt")
public void testDefaultInlineClassConstructorParamInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/defaultInlineClassConstructorParamInExportedFile.kt");
}
@Test
@TestMetadata("exportAllFile.kt")
public void testExportAllFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportAllFile.kt");
}
@Test
@TestMetadata("exportEnumClass.kt")
public void testExportEnumClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportEnumClass.kt");
}
@Test
@TestMetadata("exportFileWithEnumClass.kt")
public void testExportFileWithEnumClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithEnumClass.kt");
}
@Test
@TestMetadata("exportFileWithInterface.kt")
public void testExportFileWithInterface() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithInterface.kt");
}
@Test
@TestMetadata("exportFileWithNestedClass.kt")
public void testExportFileWithNestedClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithNestedClass.kt");
}
@Test
@TestMetadata("exportFileWithNestedObject.kt")
public void testExportFileWithNestedObject() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithNestedObject.kt");
}
@Test
@TestMetadata("exportFileWithProtectedMembers.kt")
public void testExportFileWithProtectedMembers() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithProtectedMembers.kt");
}
@Test
@TestMetadata("exportFileWithTopLevelProperty.kt")
public void testExportFileWithTopLevelProperty() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportFileWithTopLevelProperty.kt");
}
@Test
@TestMetadata("exportInnerClass.kt")
public void testExportInnerClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportInnerClass.kt");
}
@Test
@TestMetadata("exportInterface.kt")
public void testExportInterface() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportInterface.kt");
}
@Test
@TestMetadata("exportNestedClass.kt")
public void testExportNestedClass() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportNestedClass.kt");
}
@Test
@TestMetadata("exportNestedObject.kt")
public void testExportNestedObject() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportNestedObject.kt");
}
@Test
@TestMetadata("exportProtectedMembers.kt")
public void testExportProtectedMembers() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportProtectedMembers.kt");
}
@Test
@TestMetadata("exportTopLevelProperty.kt")
public void testExportTopLevelProperty() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/exportTopLevelProperty.kt");
}
@Test
@TestMetadata("nonIndetifierModuleName.kt")
public void testNonIndetifierModuleName() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/nonIndetifierModuleName.kt");
}
@Test
@TestMetadata("nonIndetifierModuleNameInExportedFile.kt")
public void testNonIndetifierModuleNameInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/nonIndetifierModuleNameInExportedFile.kt");
}
@Test
@TestMetadata("overriddenChainNonExportIntermediate.kt")
public void testOverriddenChainNonExportIntermediate() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenChainNonExportIntermediate.kt");
}
@Test
@TestMetadata("overriddenChainNonExportIntermediateInExportedFile.kt")
public void testOverriddenChainNonExportIntermediateInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenChainNonExportIntermediateInExportedFile.kt");
}
@Test
@TestMetadata("overriddenExternalMethodWithSameNameMethod.kt")
public void testOverriddenExternalMethodWithSameNameMethod() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameNameMethod.kt");
}
@Test
@TestMetadata("overriddenExternalMethodWithSameStableNameMethod.kt")
public void testOverriddenExternalMethodWithSameStableNameMethod() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameStableNameMethod.kt");
}
@Test
@TestMetadata("overriddenExternalMethodWithSameStableNameMethodInExportedFile.kt")
public void testOverriddenExternalMethodWithSameStableNameMethodInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameStableNameMethodInExportedFile.kt");
}
@Test
@TestMetadata("reservedModuleName.kt")
public void testReservedModuleName() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/reservedModuleName.kt");
}
@Test
@TestMetadata("reservedModuleNameInExportedFile.kt")
public void testReservedModuleNameInExportedFile() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/reservedModuleNameInExportedFile.kt");
}
@Test
@TestMetadata("vararg.kt")
public void testVararg() throws Exception {
runTest("js/js.translator/testData/box/esModules/export/vararg.kt");
}
}
@Nested
@@ -456,6 +456,12 @@ public class IrJsTypeScriptExportTestGenerated extends AbstractIrJsTypeScriptExp
runTest("js/js.translator/testData/typescript-export/module-systems/commonjs.kt");
}
@Test
@TestMetadata("esm.kt")
public void testEsm() throws Exception {
runTest("js/js.translator/testData/typescript-export/module-systems/esm.kt");
}
@Test
@TestMetadata("plain.kt")
public void testPlain() throws Exception {
@@ -484,6 +490,12 @@ public class IrJsTypeScriptExportTestGenerated extends AbstractIrJsTypeScriptExp
runTest("js/js.translator/testData/typescript-export/module-systems-in-exported-file/commonjs.kt");
}
@Test
@TestMetadata("esm.kt")
public void testEsm() throws Exception {
runTest("js/js.translator/testData/typescript-export/module-systems-in-exported-file/esm.kt");
}
@Test
@TestMetadata("plain.kt")
public void testPlain() throws Exception {
@@ -0,0 +1,31 @@
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: bridge_saving_after_export
// FILE: lib.kt
@JsExport
open class A<T> {
open fun foo(value: T): T = value
}
@JsExport
class B: A<String>() {
override fun foo(value: String): String = value
}
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { A, B } from "./bridgeSavingAfterExport-bridge_saving_after_export_v5.mjs";
export function box() {
var a = new A()
var aFoo = a.foo("ok")
if (aFoo != "ok") return "fail 1"
var b = new B()
var bFoo = b.foo("ok")
if (bFoo != "ok") return "fail 2"
return "OK"
}
@@ -0,0 +1,30 @@
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: bridge_saving_after_export
// FILE: lib.kt
@file:JsExport
open class A<T> {
open fun foo(value: T): T = value
}
class B: A<String>() {
override fun foo(value: String): String = value
}
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { A, B } from "./bridgeSavingAfterExportInExportedFile-bridge_saving_after_export_v5.mjs";
export function box() {
var a = new A()
var aFoo = a.foo("ok")
if (aFoo != "ok") return "fail 1"
var b = new B()
var bFoo = b.foo("ok")
if (bFoo != "ok") return "fail 2"
return "OK"
}
@@ -0,0 +1,22 @@
// IGNORE_FIR
// KT-49225
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// SPLIT_PER_MODULE
// MODULE: lib
// FILE: lib.kt
value class Koo(val koo: String = "OK")
@JsExport
class Bar(val koo: Koo = Koo())
// MODULE: main(lib)
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { Bar } from "./defaultInlineClassConstructorParam-kotlin_lib_v5.mjs";
export function box() {
return new Bar().koo;
}
@@ -0,0 +1,24 @@
// IGNORE_FIR
// KT-49225
// ES_MODULES
// DONT_TARGET_EXACT_BACKEND: JS
// SPLIT_PER_MODULE
// MODULE: lib
// FILE: koo.kt
value class Koo(val koo: String = "OK")
// FILE: bar.kt
@file:JsExport
class Bar(val koo: Koo = Koo())
// MODULE: main(lib)
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { Bar } from "./defaultInlineClassConstructorParamInExportedFile-kotlin_lib_v5.mjs";
export function box() {
return new Bar().koo;
}
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1252
// INFER_MAIN_MODULE
// ES_MODULES
// MODULE: export_all_file
@@ -19,5 +18,9 @@ class B : A() {
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { B } from "./export_all_file/index.js";
console.assert(new B().foo("K") == "OK");
import { B } from "./exportAllFile-export_all_file_v5.mjs";
export function box() {
return new B().foo("K")
}
@@ -0,0 +1,103 @@
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: export_enum_class
// FILE: lib.kt
@JsExport
enum class Foo(val constructorParameter: String) {
A("aConstructorParameter"),
B("bConstructorParameter");
val foo = ordinal
fun bar(value: String) = value
fun bay() = name
companion object {
val baz = "baz"
}
}
@JsExport
enum class Bar {
A,
B {
var d = "d"
init {
d = "d2"
}
fun huh() = "huh"
};
val foo = ordinal
fun bar(value: String) = value
fun bay() = name
}
@JsExport
class OuterClass {
enum class NestedEnum {
A,
B;
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { Foo, Bar, OuterClass } from "./exportEnumClass-export_enum_class_v5.mjs"
export function box() {
if (Foo.A !== Foo.A) return "fail1"
if (Foo.B !== Foo.B) return "fail2"
if (Foo.Companion.baz !== "baz") return "fail3"
if (Foo.A.foo !== 0) return "fail4"
if (Foo.B.foo !== 1) return "fail5"
if (Foo.A.bar("A") !== "A") return "fail6"
if (Foo.B.bar("B") !== "B") return "fail7"
if (Foo.A.bay() !== "A") return "fail8"
if (Foo.B.bay() !== "B") return "fail9"
if (Foo.A.constructorParameter !== "aConstructorParameter") return "fail10"
if (Foo.B.constructorParameter !== "bConstructorParameter") return "fail11"
if (Bar.A.foo !== 0) return "fail12"
if (Bar.B.foo !== 1) return "fail13"
if (Bar.A.bar("A") !== "A") return "fail14"
if (Bar.B.bar("B") !== "B") return "fail15"
if (Bar.A.bay() !== "A") return "fail15"
if (Bar.B.bay() !== "B") return "fail16"
if (Bar.B.constructor.prototype.hasOwnProperty('d')) return "fail17"
if (Bar.B.constructor.prototype.hasOwnProperty('huh')) return "fail18"
if (Foo.valueOf("A") !== Foo.A) return "fail19"
if (Foo.valueOf("B") !== Foo.B) return "fail20"
if (Foo.values().indexOf(Foo.A) === -1) return "fail21"
if (Foo.values().indexOf(Foo.B) === -1) return "fail22"
if (Foo.A.name !== "A") return "fail23"
if (Foo.B.name !== "B") return "fail24"
if (Foo.A.ordinal !== 0) return "fail25"
if (Foo.B.ordinal !== 1) return "fail26"
if (OuterClass.NestedEnum.A.name !== "A") return "fail27"
if (OuterClass.NestedEnum.B.name !== "B") return "fail28"
if (OuterClass.NestedEnum.A.ordinal !== 0) return "fail29"
if (OuterClass.NestedEnum.B.ordinal !== 1) return "fail30"
return "OK"
}
@@ -0,0 +1,100 @@
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: export_enum_class
// FILE: lib.kt
@file:JsExport
enum class Foo(val constructorParameter: String) {
A("aConstructorParameter"),
B("bConstructorParameter");
val foo = ordinal
fun bar(value: String) = value
fun bay() = name
companion object {
val baz = "baz"
}
}
enum class Bar {
A,
B {
var d = "d"
init {
d = "d2"
}
fun huh() = "huh"
};
val foo = ordinal
fun bar(value: String) = value
fun bay() = name
}
class OuterClass {
enum class NestedEnum {
A,
B;
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { Foo, Bar, OuterClass } from "./exportFileWithEnumClass-export_enum_class_v5.mjs"
export function box() {
if (Foo.A !== Foo.A) return "fail1"
if (Foo.B !== Foo.B) return "fail2"
if (Foo.Companion.baz !== "baz") return "fail3"
if (Foo.A.foo !== 0) return "fail4"
if (Foo.B.foo !== 1) return "fail5"
if (Foo.A.bar("A") !== "A") return "fail6"
if (Foo.B.bar("B") !== "B") return "fail7"
if (Foo.A.bay() !== "A") return "fail8"
if (Foo.B.bay() !== "B") return "fail9"
if (Foo.A.constructorParameter !== "aConstructorParameter") return "fail10"
if (Foo.B.constructorParameter !== "bConstructorParameter") return "fail11"
if (Bar.A.foo !== 0) return "fail12"
if (Bar.B.foo !== 1) return "fail13"
if (Bar.A.bar("A") !== "A") return "fail14"
if (Bar.B.bar("B") !== "B") return "fail15"
if (Bar.A.bay() !== "A") return "fail15"
if (Bar.B.bay() !== "B") return "fail16"
if (Bar.B.constructor.prototype.hasOwnProperty('d')) return "fail17"
if (Bar.B.constructor.prototype.hasOwnProperty('huh')) return "fail18"
if (Foo.valueOf("A") !== Foo.A) return "fail19"
if (Foo.valueOf("B") !== Foo.B) return "fail20"
if (Foo.values().indexOf(Foo.A) === -1) return "fail21"
if (Foo.values().indexOf(Foo.B) === -1) return "fail22"
if (Foo.A.name !== "A") return "fail23"
if (Foo.B.name !== "B") return "fail24"
if (Foo.A.ordinal !== 0) return "fail25"
if (Foo.B.ordinal !== 1) return "fail26"
if (OuterClass.NestedEnum.A.name !== "A") return "fail27"
if (OuterClass.NestedEnum.B.name !== "B") return "fail28"
if (OuterClass.NestedEnum.A.ordinal !== 0) return "fail29"
if (OuterClass.NestedEnum.B.ordinal !== 1) return "fail30"
return "OK"
}
@@ -0,0 +1,99 @@
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: export_interface
// FILE: not_exported.kt
interface ParentI {
val str: String
}
interface ExtendedI: I {
fun bar(): Int
}
open class NotExportedClass(override var value: Int) : ExtendedI {
override var variable: Int = value
override open fun foo(): String = "Not Exported"
override val str: String = "test 1"
override open fun bar(): Int = 42
}
// FILE: exportes.kt
@file:JsExport
interface I : ParentI {
val value: Int
var variable: Int
fun foo(): String
}
class ExportedClass(override val value: Int) : ExtendedI {
override var variable: Int = value
override fun foo(): String = "Exported"
override val str: String = "test 2"
override open fun bar(): Int = 43
}
class AnotherOne : NotExportedClass(42) {
override fun foo(): String = "Another One Exported"
}
fun generateNotExported(value: Int): NotExportedClass {
return NotExportedClass(value)
}
fun consume(i: I): String {
return "Value is ${i.value}, variable is ${i.variable} and result is '${i.foo()}'"
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import * as pkg from "./exportFileWithInterface-export_interface_v5.mjs"
export function box() {
const { I, ExportedClass, AnotherOne, generateNotExported, consume } = pkg
if (I !== undefined) return "Fail: module should not export interface in runtime"
const exported = new ExportedClass(1)
const another = new AnotherOne()
const notExported = generateNotExported (3)
if (exported.foo() !== "Exported") return "Fail: foo function was not generated for ExportedClass"
if (another.foo() !== "Another One Exported") return "Fail: foo function was not generated for AnotherOne"
if (notExported.foo() !== "Not Exported") return "Fail: foo function was not generated for NotExportedClass"
if (exported.value !== 1) return "Fail: value getter was not generated for ExportedClass"
if (another.value !== 42) return "Fail: value getter was not generated for AnotherOne"
if (notExported.value !== 3) return "Fail: value getter was not generated for NotExportedClass"
if (exported.variable !== 1) return "Fail: variable getter was not generated for ExportedClass"
if (another.variable !== 42) return "Fail: variable getter was not generated for AnotherOne"
if (notExported.variable !== 3) return "Fail: variable getter was not generated for NotExportedClass"
exported.variable = 101
another.variable = 102
notExported.variable = 103
if (exported.variable !== 101) return "Fail: variable setter was not generated for ExportedClass"
if (another.variable !== 102) return "Fail: variable setter was not generated for AnotherOne"
if (notExported.variable !== 103) return "Fail: variable setter was not generated for NotExportedClass"
try {
notExported.value = 42
} catch(e) {}
if (notExported.value !== 3) return "Fail: value setter was generated for NotExportedClass, but it shouldn't"
if (consume(exported) !== "Value is 1, variable is 101 and result is 'Exported'") return "Fail: methods or fields of ExportedClass was mangled"
if (consume(another) !== "Value is 42, variable is 102 and result is 'Another One Exported'") return "Fail: methods or fields of AnotherOne was mangled"
if (consume(notExported) !== "Value is 3, variable is 103 and result is 'Not Exported'") return "Fail: methods or fields of NotExported was mangled"
if (notExported.str !== undefined) return "Fail: str should not exist inside NotExportedClass"
if (exported.str !== undefined) return "Fail: str should not exist inside ExportedClass"
if (notExported.bar !== undefined) return "Fail: bar should not exist inside NotExportedClass"
if (exported.bar !== undefined) return "Fail: bar should not exist inside ExportedClass"
return "OK"
}
@@ -0,0 +1,51 @@
// EXPECTED_REACHABLE_NODES: 1252
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// SKIP_DCE_DRIVEN
// MODULE: export_nested_class
// FILE: lib.kt
@file:JsExport
abstract class A {
abstract fun foo(k: String): String
}
class B {
class Foo : A() {
override fun foo(k: String): String {
return "O" + k
}
fun bar(k: String): String {
return foo(k)
}
}
}
object MyObject {
class A {
fun valueA() = "OK"
}
class B {
fun valueB() = "OK"
}
class C {
fun valueC() = "OK"
}
}
// FILE: test.mjs
// ENTRY_ES_MODULE
import { B, MyObject } from "./exportFileWithNestedClass-export_nested_class_v5.mjs"
export function box() {
if (new B.Foo().bar("K") != "OK") return "fail 1";
const myObject = MyObject.getInstance()
if (new myObject.A().valueA() != "OK") return "fail 2";
if (new myObject.B().valueB() != "OK") return "fail 3";
if (new myObject.C().valueC() != "OK") return "fail 4";
return "OK"
}
@@ -0,0 +1,70 @@
// EXPECTED_REACHABLE_NODES: 1265
// ES_MODULES
// DONT_TARGET_EXACT_BACKEND: JS
// SKIP_MINIFICATION
// SKIP_DCE_DRIVEN
// SKIP_NODE_JS
// See KT-43783
// MODULE: nestedObjectExport
// FILE: lib.kt
@file:JsExport
class Abc {
companion object AbcCompanion {
fun xyz(): String = "Companion object method OK"
val prop: String
get() = "Companion object property OK"
}
}
class Foo {
companion object {
fun xyz(): String = "Companion object method OK"
val prop: String
get() = "Companion object property OK"
}
}
sealed class MyEnum(val name: String) {
object A: MyEnum("A")
object B: MyEnum("B")
object C: MyEnum("C")
}
object MyObject {
object A {
fun valueA() = "OK"
}
object B {
fun valueB() = "OK"
}
object C {
fun valueC() = "OK"
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { Foo, Abc, MyEnum, MyObject } from "./exportFileWithNestedObject-nestedObjectExport_v5.mjs"
export function box() {
if (Abc.AbcCompanion.xyz() != 'Companion object method OK') return 'companion object function failure';
if (Abc.AbcCompanion.prop != 'Companion object property OK') return 'companion object property failure';
if (Foo.Companion.xyz() != 'Companion object method OK') return 'companion object function failure';
if (Foo.Companion.prop != 'Companion object property OK') return 'companion object property failure';
if (MyEnum.A.name != 'A') return 'MyEnum.A failure';
if (MyEnum.B.name != 'B') return 'MyEnum.B failure';
if (MyEnum.C.name != 'C') return 'MyEnum.C failure';
if (MyObject.getInstance().A.valueA() != "OK") return 'MyObject.A failure';
if (MyObject.getInstance().B.valueB() != "OK") return 'MyObject.B failure';
if (MyObject.getInstance().C.valueC() != "OK") return 'MyObject.C failure';
return 'OK';
}
@@ -0,0 +1,69 @@
// EXPECTED_REACHABLE_NODES: 1265
// ES_MODULES
// DONT_TARGET_EXACT_BACKEND: JS
// SKIP_MINIFICATION
// SKIP_NODE_JS
// SKIP_DCE_DRIVEN
// MODULE: exportProtectedMembers
// FILE: lib.kt
@file:JsExport
open class Foo protected constructor() {
protected fun bar(): String = "protected method"
private var _baz: String = "baz"
protected var baz: String
get() = _baz
set(value) {
_baz = value
}
protected val bazReadOnly: String
get() = _baz
protected val quux: String = "quux"
protected var quuz: String = "quuz"
protected class NestedClass {
val prop: String = "nested class property"
}
protected object NestedObject {
val prop: String = "nested object property"
}
protected companion object {
val prop: String = "companion object property"
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { Foo } from "./exportFileWithProtectedMembers-exportProtectedMembers_v5.mjs"
export function box() {
var foo = new Foo();
if (foo.bar() != 'protected method') return 'failed to call protected method';
if (foo.baz != 'baz') return 'failed to read `baz`';
if (foo.bazReadOnly != 'baz') return 'failed to read `bazReadOnly`';
foo.baz = 'beer';
if (foo.baz != 'beer') return 'failed to write protected var';
if (foo.bazReadOnly != 'beer') return 'unexpected value of `bazReadOnly` after modifying `baz`';
if (foo.quux != 'quux') return 'failed to read `quux`';
if (foo.quuz != 'quuz') return 'failed to read `quuz`';
foo.quuz = 'ale';
if (foo.quuz != 'ale') return 'failed to write `quuz`';
var nestedClass = new Foo.NestedClass()
if (nestedClass.prop != 'nested class property')
return 'failed to read protected class property'
if (Foo.NestedObject.prop != 'nested object property')
return 'failed to read protected nested object property'
if (Foo.Companion.prop != 'companion object property')
return 'failed to read protected companion object property'
return 'OK';
}
@@ -0,0 +1,58 @@
// DONT_TARGET_EXACT_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1252
// INFER_MAIN_MODULE
// ES_MODULES
// MODULE: exported_properites
// FILE: lib.kt
@file:JsExport
val regularValueProperty: String = "regularValueProperty"
val regularPropertyGetter: String
get() = "regularPropertyGetter"
var regularVariableProperty: String = "regularVariableProperty"
var regularVariableGetterWithSetter: String = "regularVariableGetterWithSetter"
get() = "$field by custom getter"
set(value) { field = "$value set by custom setter" }
// FILE: entry.mjs
// ENTRY_ES_MODULE
import {
regularValueProperty,
regularPropertyGetter,
regularVariableProperty,
regularVariableGetterWithSetter
} from "./exportFileWithTopLevelProperty-exported_properites_v5.mjs";
export function box() {
if (typeof regularValueProperty.get !== "function" || regularValueProperty.get() !== "regularValueProperty") {
return "Fail: wrongly exported getter for regular `val` property"
}
if (typeof regularValueProperty.set !== "undefined") {
return "Fail: wrongly exported setter for regular `val` property"
}
if (typeof regularPropertyGetter.get !== "function" || regularPropertyGetter.get() !== "regularPropertyGetter") {
return "Fail: wrongly exported getter for a `val` property with custom getter"
}
if (typeof regularPropertyGetter.set !== "undefined") {
return "Fail: wrongly exported setter for a `val` property with custom getter"
}
if (typeof regularVariableProperty.get !== "function" || regularVariableProperty.get() !== "regularVariableProperty") {
return "Fail: wrongly exported getter for regular `var` property"
}
if (typeof regularVariableProperty.set !== "function" || (regularVariableProperty.set("test1"), regularVariableProperty.get()) !== "test1") {
return "Fail: wrongly exported setter for regular `var` property"
}
if (typeof regularVariableGetterWithSetter.get !== "function" || regularVariableGetterWithSetter.get() !== "regularVariableGetterWithSetter by custom getter") {
return "Fail: wrongly exported getter for a `var` property with custom getter and setter"
}
if (typeof regularVariableGetterWithSetter.set !== "function" || (regularVariableGetterWithSetter.set("test1"), regularVariableGetterWithSetter.get()) !== "test1 set by custom setter by custom getter") {
return "Fail: wrongly exported setter for a `var` property with custom getter and setter"
}
return "OK"
}
@@ -0,0 +1,66 @@
// EXPECTED_REACHABLE_NODES: 1252
// IGNORE_BACKEND: JS
// ES_MODULES
// DONT_TARGET_EXACT_BACKEND: JS
// MODULE: export_inner_class
// FILE: lib.kt
@JsExport
class RegularParent(val value: String) {
inner class RegularInner(val message: String, val anotherValue: Int) {
fun getResult() = value + message
}
}
@JsExport
class ParentForSecondary {
inner class InnerWithSecondaryConstructor(val value: String) {
@JsName("innerSuccess")
constructor(): this("OK")
}
}
@JsExport
class ParentWithSecondary(val value: String) {
@JsName("createO")
constructor(): this("O")
inner class InnerWithSecondaryConstructor(val anotherValue: String) {
@JsName("createK")
constructor(): this("K")
fun getResult() = value + anotherValue
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { RegularParent, ParentForSecondary, ParentWithSecondary } from "./exportInnerClass-export_inner_class_v5.mjs"
export function box() {
var regularParent = new RegularParent("O")
var regularInner = new regularParent.RegularInner("K", 42)
if (regularInner.anotherValue !== 42) return "Fail: second parameter of the RegularInner primary constructor was ignored"
if (regularInner.getResult() !== "OK") return "Fail: something is going wrong with the outer this capturing logic"
var parentForSecondary = new ParentForSecondary()
var innerWithSecondary = new parentForSecondary.InnerWithSecondaryConstructor("OK")
if (innerWithSecondary.value !== "OK") return "Fail: something is going wrong with primary constructor when a secondary one exists"
var fromSecondary = parentForSecondary.InnerWithSecondaryConstructor.innerSuccess()
if (fromSecondary.value !== "OK") return "Fail: something is going wrong with secondary constructor inside the inner class"
var parentFromSecondary = ParentWithSecondary.createO()
var innerFromSecondary = parentFromSecondary.InnerWithSecondaryConstructor.createK()
if (innerFromSecondary.getResult() !== "OK") return "Fail: there is a problem when both parent and inner class have secondary constructors"
return "OK"
}
@@ -0,0 +1,105 @@
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: export_interface
// FILE: lib.kt
interface ParentI {
val str: String
}
@JsExport
interface I : ParentI {
val value: Int
var variable: Int
fun foo(): String
}
interface ExtendedI: I {
fun bar(): Int
}
open class NotExportedClass(override var value: Int) : ExtendedI {
override var variable: Int = value
override open fun foo(): String = "Not Exported"
override val str: String = "test 1"
override open fun bar(): Int = 42
}
@JsExport
class ExportedClass(override val value: Int) : ExtendedI {
override var variable: Int = value
override fun foo(): String = "Exported"
override val str: String = "test 2"
override open fun bar(): Int = 43
}
@JsExport
class AnotherOne : NotExportedClass(42) {
override fun foo(): String = "Another One Exported"
}
@JsExport
fun generateNotExported(value: Int): NotExportedClass {
return NotExportedClass(value)
}
@JsExport
fun consume(i: I): String {
return "Value is ${i.value}, variable is ${i.variable} and result is '${i.foo()}'"
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import * as pkg from "./exportInterface-export_interface_v5.mjs"
export function box() {
const { I, ExportedClass, AnotherOne, generateNotExported, consume } = pkg
if (I !== undefined) return "Fail: module should not export interface in runtime"
const exported = new ExportedClass(1)
const another = new AnotherOne()
const notExported = generateNotExported (3)
if (exported.foo() !== "Exported") return "Fail: foo function was not generated for ExportedClass"
if (another.foo() !== "Another One Exported") return "Fail: foo function was not generated for AnotherOne"
if (notExported.foo() !== "Not Exported") return "Fail: foo function was not generated for NotExportedClass"
if (exported.value !== 1) return "Fail: value getter was not generated for ExportedClass"
if (another.value !== 42) return "Fail: value getter was not generated for AnotherOne"
if (notExported.value !== 3) return "Fail: value getter was not generated for NotExportedClass"
if (exported.variable !== 1) return "Fail: variable getter was not generated for ExportedClass"
if (another.variable !== 42) return "Fail: variable getter was not generated for AnotherOne"
if (notExported.variable !== 3) return "Fail: variable getter was not generated for NotExportedClass"
exported.variable = 101
another.variable = 102
notExported.variable = 103
if (exported.variable !== 101) return "Fail: variable setter was not generated for ExportedClass"
if (another.variable !== 102) return "Fail: variable setter was not generated for AnotherOne"
if (notExported.variable !== 103) return "Fail: variable setter was not generated for NotExportedClass"
try {
notExported.value = 42
} catch(e) {}
if (notExported.value !== 3) return "Fail: value setter was generated for NotExportedClass, but it shouldn't"
if (consume(exported) !== "Value is 1, variable is 101 and result is 'Exported'") return "Fail: methods or fields of ExportedClass was mangled"
if (consume(another) !== "Value is 42, variable is 102 and result is 'Another One Exported'") return "Fail: methods or fields of AnotherOne was mangled"
if (consume(notExported) !== "Value is 3, variable is 103 and result is 'Not Exported'") return "Fail: methods or fields of NotExported was mangled"
if (notExported.str !== undefined) return "Fail: str should not exist inside NotExportedClass"
if (exported.str !== undefined) return "Fail: str should not exist inside ExportedClass"
if (notExported.bar !== undefined) return "Fail: bar should not exist inside NotExportedClass"
if (exported.bar !== undefined) return "Fail: bar should not exist inside ExportedClass"
return "OK"
}
@@ -0,0 +1,52 @@
// EXPECTED_REACHABLE_NODES: 1252
// IGNORE_BACKEND: JS
// ES_MODULES
// DONT_TARGET_EXACT_BACKEND: JS
// SKIP_DCE_DRIVEN
// MODULE: export_nested_class
// FILE: lib.kt
abstract class A {
abstract fun foo(k: String): String
}
@JsExport
class B {
class Foo : A() {
override fun foo(k: String): String {
return "O" + k
}
fun bar(k: String): String {
return foo(k)
}
}
}
@JsExport
object MyObject {
class A {
fun valueA() = "OK"
}
class B {
fun valueB() = "OK"
}
class C {
fun valueC() = "OK"
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { B, MyObject } from "./exportNestedClass-export_nested_class_v5.mjs"
export function box() {
if (new B.Foo().bar("K") != "OK") return "fail 1";
const myObject = MyObject.getInstance()
if (new myObject.A().valueA() != "OK") return "fail 2";
if (new myObject.B().valueB() != "OK") return "fail 3";
if (new myObject.C().valueC() != "OK") return "fail 4";
return "OK"
}
@@ -0,0 +1,73 @@
// EXPECTED_REACHABLE_NODES: 1265
// ES_MODULES
// DONT_TARGET_EXACT_BACKEND: JS
// SKIP_MINIFICATION
// SKIP_DCE_DRIVEN
// SKIP_NODE_JS
// See KT-43783
// MODULE: nestedObjectExport
// FILE: lib.kt
@JsExport
class Abc {
companion object AbcCompanion {
fun xyz(): String = "Companion object method OK"
val prop: String
get() = "Companion object property OK"
}
}
@JsExport
class Foo {
companion object {
fun xyz(): String = "Companion object method OK"
val prop: String
get() = "Companion object property OK"
}
}
@JsExport
sealed class MyEnum(val name: String) {
object A: MyEnum("A")
object B: MyEnum("B")
object C: MyEnum("C")
}
@JsExport
object MyObject {
object A {
fun valueA() = "OK"
}
object B {
fun valueB() = "OK"
}
object C {
fun valueC() = "OK"
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { Abc, Foo, MyEnum, MyObject } from "./exportNestedObject-nestedObjectExport_v5.mjs"
export function box() {
if (Abc.AbcCompanion.xyz() != 'Companion object method OK') return 'companion object function failure';
if (Abc.AbcCompanion.prop != 'Companion object property OK') return 'companion object property failure';
if (Foo.Companion.xyz() != 'Companion object method OK') return 'companion object function failure';
if (Foo.Companion.prop != 'Companion object property OK') return 'companion object property failure';
if (MyEnum.A.name != 'A') return 'MyEnum.A failure';
if (MyEnum.B.name != 'B') return 'MyEnum.B failure';
if (MyEnum.C.name != 'C') return 'MyEnum.C failure';
if (MyObject.getInstance().A.valueA() != "OK") return 'MyObject.A failure';
if (MyObject.getInstance().B.valueB() != "OK") return 'MyObject.B failure';
if (MyObject.getInstance().C.valueC() != "OK") return 'MyObject.C failure';
return 'OK';
}
@@ -0,0 +1,69 @@
// EXPECTED_REACHABLE_NODES: 1265
// ES_MODULES
// DONT_TARGET_EXACT_BACKEND: JS
// SKIP_MINIFICATION
// SKIP_NODE_JS
// SKIP_DCE_DRIVEN
// MODULE: exportProtectedMembers
// FILE: lib.kt
@JsExport
open class Foo protected constructor() {
protected fun bar(): String = "protected method"
private var _baz: String = "baz"
protected var baz: String
get() = _baz
set(value) {
_baz = value
}
protected val bazReadOnly: String
get() = _baz
protected val quux: String = "quux"
protected var quuz: String = "quuz"
protected class NestedClass {
val prop: String = "nested class property"
}
protected object NestedObject {
val prop: String = "nested object property"
}
protected companion object {
val prop: String = "companion object property"
}
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { Foo } from "./exportProtectedMembers-exportProtectedMembers_v5.mjs"
export function box() {
var foo = new Foo();
if (foo.bar() != 'protected method') return 'failed to call protected method';
if (foo.baz != 'baz') return 'failed to read `baz`';
if (foo.bazReadOnly != 'baz') return 'failed to read `bazReadOnly`';
foo.baz = 'beer';
if (foo.baz != 'beer') return 'failed to write protected var';
if (foo.bazReadOnly != 'beer') return 'unexpected value of `bazReadOnly` after modifying `baz`';
if (foo.quux != 'quux') return 'failed to read `quux`';
if (foo.quuz != 'quuz') return 'failed to read `quuz`';
foo.quuz = 'ale';
if (foo.quuz != 'ale') return 'failed to write `quuz`';
var nestedClass = new Foo.NestedClass()
if (nestedClass.prop != 'nested class property')
return 'failed to read protected class property'
if (Foo.NestedObject.prop != 'nested object property')
return 'failed to read protected nested object property'
if (Foo.Companion.prop != 'companion object property')
return 'failed to read protected companion object property'
return 'OK';
}
@@ -0,0 +1,60 @@
// DONT_TARGET_EXACT_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1252
// ES_MODULES
// MODULE: exported_properites
// FILE: lib.kt
@JsExport
val regularValueProperty: String = "regularValueProperty"
@JsExport
val regularPropertyGetter: String
get() = "regularPropertyGetter"
@JsExport
var regularVariableProperty: String = "regularVariableProperty"
@JsExport
var regularVariableGetterWithSetter: String = "regularVariableGetterWithSetter"
get() = "$field by custom getter"
set(value) { field = "$value set by custom setter" }
// FILE: entry.mjs
// ENTRY_ES_MODULE
import {
regularValueProperty,
regularPropertyGetter,
regularVariableProperty,
regularVariableGetterWithSetter
} from "./exportTopLevelProperty-exported_properites_v5.mjs";
export function box() {
if (typeof regularValueProperty.get !== "function" || regularValueProperty.get() !== "regularValueProperty") {
return "Fail: wrongly exported getter for regular `val` property"
}
if (typeof regularValueProperty.set !== "undefined") {
return "Fail: wrongly exported setter for regular `val` property"
}
if (typeof regularPropertyGetter.get !== "function" || regularPropertyGetter.get() !== "regularPropertyGetter") {
return "Fail: wrongly exported getter for a `val` property with custom getter"
}
if (typeof regularPropertyGetter.set !== "undefined") {
return "Fail: wrongly exported setter for a `val` property with custom getter"
}
if (typeof regularVariableProperty.get !== "function" || regularVariableProperty.get() !== "regularVariableProperty") {
return "Fail: wrongly exported getter for regular `var` property"
}
if (typeof regularVariableProperty.set !== "function" || (regularVariableProperty.set("test1"), regularVariableProperty.get()) !== "test1") {
return "Fail: wrongly exported setter for regular `var` property"
}
if (typeof regularVariableGetterWithSetter.get !== "function" || regularVariableGetterWithSetter.get() !== "regularVariableGetterWithSetter by custom getter") {
return "Fail: wrongly exported getter for a `var` property with custom getter and setter"
}
if (typeof regularVariableGetterWithSetter.set !== "function" || (regularVariableGetterWithSetter.set("test1"), regularVariableGetterWithSetter.get()) !== "test1 set by custom setter by custom getter") {
return "Fail: wrongly exported setter for a `var` property with custom getter and setter"
}
return "OK"
}
@@ -1,10 +1,9 @@
// DONT_TARGET_EXACT_BACKEND: JS
// SKIP_MINIFICATION
// INFER_MAIN_MODULE
// SKIP_NODE_JS
// ES_MODULES
// MODULE: non_identifier_module_name
// MODULE: lib
// FILE: lib.kt
@JsName("foo")
@JsExport
@@ -12,5 +11,8 @@ public fun foo(k: String): String = "O$k"
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { foo } from "./non_identifier_module_name/index.js";
console.assert(foo("K") == "OK");
import { foo } from "./nonIndetifierModuleName-lib_v5.mjs";
export function box() {
return foo("K")
}
@@ -0,0 +1,21 @@
// EXPECTED_REACHABLE_NODES: 1270
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// SKIP_MINIFICATION
// SKIP_NODE_JS
// MODULE: lib
// FILE: lib.kt
@file:JsExport
@JsName("foo")
public fun foo(k: String): String = "O$k"
// FILE: enty.mjs
// ENTRY_ES_MODULE
import { foo } from "./nonIndetifierModuleNameInExportedFile-lib_v5.mjs";
export function box() {
return foo("K")
}
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1252
// INFER_MAIN_MODULE
// ES_MODULES
// MODULE: overriden_chain_non_export_intermediate
@@ -28,12 +27,19 @@ class C : B() {
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { C } from "./overriden_chain_non_export_intermediate/index.js";
import { C } from "./overriddenChainNonExportIntermediate-overriden_chain_non_export_intermediate_v5.mjs";
function test(c) {
if (c.foo() === "foo" && c.bar() === "bar" && c.bay() == "bay") return "OK"
export function box() {
const c = new C()
return "fail"
}
const foo = c.foo()
if (foo !== "foo") return `Fail: expect c.foo() to return 'foo' but it returns ${foo}`
console.assert(test(new C()) == "OK");
const bar = c.bar()
if (bar !== "bar") return `Fail: expect c.bar() to return 'bar' but it returns ${bar}`
const bay = c.bay()
if (bay !== "bay") return `Fail: expect c.bay() to return 'bay' but it returns ${bay}`
return "OK"
}
@@ -0,0 +1,39 @@
// EXPECTED_REACHABLE_NODES: 1252
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: overriden_chain_non_export_intermediate
// FILE: not_exported.kt
abstract class B : A() {
abstract fun baz(): String
override fun foo(): String = "foo"
}
// FILE: exported.kt
@file:JsExport
abstract class A {
abstract fun foo(): String
abstract fun bar(): String
}
class C : B() {
override fun bar(): String = "bar"
override fun baz(): String = "baz"
fun bay(): String = "bay"
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { C } from "./overriddenChainNonExportIntermediateInExportedFile-overriden_chain_non_export_intermediate_v5.mjs"
export function box() {
var c = new C();
if (c.foo() === "foo" && c.bar() === "bar" && c.bay() == "bay") return "OK"
return "fail"
}
@@ -1,9 +1,8 @@
// EXPECTED_REACHABLE_NODES: 1252
// INFER_MAIN_MODULE
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: overriden_external_method_with_same_name_method
// MODULE: lib
// FILE: lib.kt
external abstract class Foo {
abstract fun o(): String
@@ -32,10 +31,9 @@ Foo.prototype.k = function() {
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { Baz } from "./overriden_external_method_with_same_name_method/index.js";
import { Baz } from "./overriddenExternalMethodWithSameNameMethod-lib_v5.mjs";
function test(foo) {
export function box() {
const foo = new Baz()
return foo.o() + foo.k()
}
console.assert(test(new Baz()) == "OK");
}
@@ -1,12 +1,8 @@
// EXPECTED_REACHABLE_NODES: 1252
// IGNORE_BACKEND: JS
// INFER_MAIN_MODULE
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// TODO: Fix tests on Windows
// DONT_TARGET_EXACT_BACKEND: JS_IR
// MODULE: overriden_external_method_with_same_stable_name_method
// MODULE: lib
// FILE: lib.kt
external abstract class Foo {
abstract fun o(): String
@@ -36,12 +32,11 @@ Foo.prototype.k = function() {
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { Baz } from "./overriden-external-method-with-same-stable-name-method/index.js";
import { Baz } from "./overriddenExternalMethodWithSameStableNameMethod-lib_v5.mjs";
function test(foo) {
export function box() {
const foo = new Baz()
const oStable = foo.oStable("OK")
if (oStable !== "OK") return "false: " + oStable
return foo.o() + foo.k()
}
console.assert(test(new Baz()) == "OK");
}
@@ -0,0 +1,49 @@
// EXPECTED_REACHABLE_NODES: 1252
// DONT_TARGET_EXACT_BACKEND: JS
// ES_MODULES
// MODULE: lib
// FILE: not_exported.kt
external abstract class Foo {
abstract fun o(): String
}
abstract class Bar : Foo() {
@JsName("oStable")
abstract fun String.o(): String
override fun o(): String {
return "O".o()
}
}
// FILE: exported.kt
@file:JsExport
class Baz : Bar() {
override fun String.o(): String {
return this
}
}
// FILE: foo.js
function Foo() {}
Foo.prototype.k = function() {
return "K"
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { Baz } from "./overriddenExternalMethodWithSameStableNameMethodInExportedFile-lib_v5.mjs"
export function box() {
return test(new Baz());
}
function test(foo) {
const oStable = foo.oStable("OK")
if (oStable !== "OK") return "false: " + oStable
return foo.o() + foo.k()
}
@@ -1,7 +1,6 @@
// IGNORE_BACKEND: JS
// DONT_TARGET_EXACT_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1270
// SKIP_MINIFICATION
// INFER_MAIN_MODULE
// ES_MODULES
// MODULE: if
@@ -12,6 +11,8 @@ public fun foo(k: String): String = "O$k"
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { foo } from "./if/index.js";
import { foo } from "./reservedModuleName-if_v5.mjs";
console.assert(foo("K") == "OK");
export function box() {
return foo("K")
}
@@ -0,0 +1,19 @@
// DONT_TARGET_EXACT_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1270
// SKIP_MINIFICATION
// ES_MODULES
// MODULE: if
// FILE: lib.kt
@file:JsExport
@JsName("foo")
public fun foo(k: String): String = "O$k"
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { foo } from "./reservedModuleNameInExportedFile-if_v5.mjs";
export function box() {
return foo("K")
}
@@ -0,0 +1,28 @@
// DONT_TARGET_EXACT_BACKEND: JS
// EXPECTED_REACHABLE_NODES: 1270
// SKIP_MINIFICATION
// ES_MODULES
// MODULE: vararg
// FILE: lib.kt
@JsExport
fun uintVararg(vararg uints: UInt): String {
for (u in uints) {
if (u == 0u) return "Failed"
}
return "OK"
}
@JsExport
fun uint(a: Int): UInt {
return a.toUInt()
}
// FILE: main.mjs
// ENTRY_ES_MODULE
import { uint, uintVararg } from "./vararg-vararg_v5.mjs"
export function box() {
return uintVararg([uint(1), uint(2), uint(3)])
}
@@ -30,6 +30,8 @@ fun testOk(ok: Any): String {
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { convolutedOk, testOk } from "./main/index.js";
import { convolutedOk, testOk } from "./inlinedObjectLiteralIsCheck_v5.mjs";
console.assert(testOk(convolutedOk()) == "OK");
export function box() {
return testOk(convolutedOk())
}
@@ -48,8 +48,5 @@ fun box(): String {
return "Fail6: ${res.component2}"
}
return "OK"
}
@@ -1,4 +1,4 @@
import { Point } from "./main/index.js";
import { Point } from "./dataClass_v5.mjs";
export default function() {
var p = new Point(3, 7);
@@ -1,4 +1,4 @@
import * as api from "./main/index.js";
import * as api from "./exportedDefaultStub_v5.mjs";
export default function() {
var ping = api.ping;
@@ -1,4 +1,4 @@
import { A, B } from "./main/index.js";
import { A, B } from "./jsExportInClass_v5.mjs";
export default function() {
return {
@@ -1,4 +1,4 @@
import { ping, Something } from "./main/index.js"
import { ping, Something } from "./recursiveExport_v5.mjs"
export default function() {
return {
@@ -24,7 +24,7 @@ open class B {
// FILE: entry.mjs
// ENTRY_ES_MODULE
import { A, B } from "./main/index.js";
import { A, B } from "./inheritanceInNativeClass_v5.mjs";
function createA() {
function ADerived() {
@@ -46,7 +46,7 @@ function createB() {
return new BDerived();
}
function box() {
export function box() {
let a = createA();
if (a.bar(0) != 124) return "fail1";
@@ -54,6 +54,4 @@ function box() {
if (b.bar(0) != 42) return "fail2";
return "OK";
}
console.assert(box() == "OK");
}
@@ -1,5 +1,5 @@
type Nullable<T> = T | null | undefined
export namespace foo {
export declare namespace foo {
const prop: number;
class C {
constructor(x: number);
@@ -0,0 +1,33 @@
type Nullable<T> = T | null | undefined
export declare const value: { get(): number; };
export declare const variable: { get(): number; set(value: number): void; };
export declare class C {
constructor(x: number);
get x(): number;
doubleX(): number;
}
export declare const O: {
getInstance(): {
get value(): number;
};
};
export declare const Parent: {
getInstance(): typeof __NonExistentParent;
};
declare abstract class __NonExistentParent extends _objects_.foo$Parent {
private constructor();
}
declare namespace __NonExistentParent {
class Nested {
constructor();
get value(): number;
}
}
export declare function box(): string;
declare namespace _objects_ {
const foo$Parent: {
get value(): number;
} & {
new(): any;
};
}
@@ -0,0 +1,40 @@
/** This file is generated by {@link :js:js.test:generateJsExportOnFileTestFilesForTS} task. DO NOT MODIFY MANUALLY */
// CHECK_TYPESCRIPT_DECLARATIONS
// SKIP_MINIFICATION
// SKIP_NODE_JS
// INFER_MAIN_MODULE
// MODULE: JS_TESTS
// MODULE_KIND: ES
// FILE: esm.kt
@file:JsExport
package foo
val value = 10
var variable = 10
class C(val x: Int) {
fun doubleX() = x * 2
}
object O {
val value = 10
}
object Parent {
val value = 10
class Nested {
val value = 10
}
}
fun box(): String = "OK"
@@ -1,5 +1,5 @@
type Nullable<T> = T | null | undefined
export namespace foo {
export declare namespace foo {
const prop: number;
class C {
constructor(x: number);
@@ -1,5 +1,5 @@
type Nullable<T> = T | null | undefined
export namespace foo {
export declare namespace foo {
const prop: number;
class C {
constructor(x: number);
@@ -0,0 +1,33 @@
type Nullable<T> = T | null | undefined
export declare const value: { get(): number; };
export declare const variable: { get(): number; set(value: number): void; };
export declare class C {
constructor(x: number);
get x(): number;
doubleX(): number;
}
export declare const O: {
getInstance(): {
get value(): number;
};
};
export declare const Parent: {
getInstance(): typeof __NonExistentParent;
};
declare abstract class __NonExistentParent extends _objects_.foo$Parent {
private constructor();
}
declare namespace __NonExistentParent {
class Nested {
constructor();
get value(): number;
}
}
export declare function box(): string;
declare namespace _objects_ {
const foo$Parent: {
get value(): number;
} & {
new(): any;
};
}
@@ -0,0 +1,36 @@
// CHECK_TYPESCRIPT_DECLARATIONS
// SKIP_MINIFICATION
// SKIP_NODE_JS
// INFER_MAIN_MODULE
// MODULE: JS_TESTS
// MODULE_KIND: ES
// FILE: esm.kt
package foo
@JsExport
val value = 10
@JsExport
var variable = 10
@JsExport
class C(val x: Int) {
fun doubleX() = x * 2
}
@JsExport
object O {
val value = 10
}
@JsExport
object Parent {
val value = 10
class Nested {
val value = 10
}
}
@JsExport
fun box(): String = "OK"
@@ -1,5 +1,5 @@
type Nullable<T> = T | null | undefined
export namespace foo {
export declare namespace foo {
const prop: number;
class C {
constructor(x: number);
@@ -8,6 +8,12 @@ declare namespace JS_TESTS {
foo(): number;
};
function takesO(o: typeof foo.O): number;
const WithSimpleObjectInside: {
get value(): string;
get SimpleObject(): {
get value(): string;
};
};
abstract class Parent {
private constructor();
}
@@ -26,6 +26,14 @@ fun takesO(o: O): Int =
O.x + O.foo()
object WithSimpleObjectInside {
val value: String = "WithSimpleObjectInside"
object SimpleObject {
val value: String = "SimpleObject"
}
}
object Parent {
object Nested1 {
val value: String = "Nested1"
@@ -7,6 +7,7 @@ var getParent = JS_TESTS.foo.getParent;
var createNested1 = JS_TESTS.foo.createNested1;
var createNested2 = JS_TESTS.foo.createNested2;
var createNested3 = JS_TESTS.foo.createNested3;
var WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
function assert(condition) {
if (!condition) {
throw "Assertion failed";
@@ -27,5 +28,7 @@ function box() {
assert(createNested1() === nested1);
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2);
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3);
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
return "OK";
}
@@ -6,6 +6,7 @@ import getParent = JS_TESTS.foo.getParent;
import createNested1 = JS_TESTS.foo.createNested1;
import createNested2 = JS_TESTS.foo.createNested2;
import createNested3 = JS_TESTS.foo.createNested3;
import WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
function assert(condition: boolean) {
if (!condition) {
@@ -30,5 +31,8 @@ function box(): string {
assert(createNested1() === nested1)
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2)
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3)
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
return "OK";
}
@@ -8,6 +8,12 @@ declare namespace JS_TESTS {
foo(): number;
};
function takesO(o: typeof foo.O): number;
const WithSimpleObjectInside: {
get value(): string;
get SimpleObject(): {
get value(): string;
};
};
abstract class Parent {
private constructor();
}
@@ -21,6 +21,14 @@ object O {
fun takesO(o: O): Int =
O.x + O.foo()
@JsExport
object WithSimpleObjectInside {
val value: String = "WithSimpleObjectInside"
object SimpleObject {
val value: String = "SimpleObject"
}
}
@JsExport
object Parent {
object Nested1 {
@@ -7,6 +7,7 @@ var getParent = JS_TESTS.foo.getParent;
var createNested1 = JS_TESTS.foo.createNested1;
var createNested2 = JS_TESTS.foo.createNested2;
var createNested3 = JS_TESTS.foo.createNested3;
var WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
function assert(condition) {
if (!condition) {
throw "Assertion failed";
@@ -27,5 +28,7 @@ function box() {
assert(createNested1() === nested1);
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2);
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3);
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
return "OK";
}
@@ -6,6 +6,7 @@ import getParent = JS_TESTS.foo.getParent;
import createNested1 = JS_TESTS.foo.createNested1;
import createNested2 = JS_TESTS.foo.createNested2;
import createNested3 = JS_TESTS.foo.createNested3;
import WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
function assert(condition: boolean) {
if (!condition) {
@@ -30,5 +31,8 @@ function box(): string {
assert(createNested1() === nested1)
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2)
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3)
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
return "OK";
}