[K/JS] Move ES modules logic to a new transformer with IC
This commit is contained in:
+1
-1
@@ -123,7 +123,7 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
@Argument(
|
@Argument(
|
||||||
value = "-module-kind",
|
value = "-module-kind",
|
||||||
valueDescription = "{plain|amd|commonjs|umd}",
|
valueDescription = "{plain|amd|commonjs|umd|es}",
|
||||||
description = "Kind of the JS module generated by the compiler"
|
description = "Kind of the JS module generated by the compiler"
|
||||||
)
|
)
|
||||||
var moduleKind: String? by NullableStringFreezableVar(K2JsArgumentConstants.MODULE_PLAIN)
|
var moduleKind: String? by NullableStringFreezableVar(K2JsArgumentConstants.MODULE_PLAIN)
|
||||||
|
|||||||
@@ -551,7 +551,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
var moduleKind: ModuleKind? = if (moduleKindName != null) moduleKindMap[moduleKindName] else ModuleKind.PLAIN
|
var moduleKind: ModuleKind? = if (moduleKindName != null) moduleKindMap[moduleKindName] else ModuleKind.PLAIN
|
||||||
if (moduleKind == null) {
|
if (moduleKind == null) {
|
||||||
messageCollector.report(
|
messageCollector.report(
|
||||||
ERROR, "Unknown module kind: $moduleKindName. Valid values are: plain, amd, commonjs, umd", null
|
ERROR, "Unknown module kind: $moduleKindName. Valid values are: plain, amd, commonjs, umd, es", null
|
||||||
)
|
)
|
||||||
moduleKind = ModuleKind.PLAIN
|
moduleKind = ModuleKind.PLAIN
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,459 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 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.ir.backend.js.codegen
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.LoweredIr
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity.*
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.*
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.JsCodeOutliningLowering
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrFileToJsTransformer
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.processClassModels
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
|
||||||
import org.jetbrains.kotlin.ir.util.file
|
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
|
||||||
import org.jetbrains.kotlin.ir.util.hasInterfaceParent
|
|
||||||
import org.jetbrains.kotlin.ir.util.isInterface
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
interface CompilerOutputSink {
|
|
||||||
fun write(module: String, path: String, content: String)
|
|
||||||
}
|
|
||||||
|
|
||||||
class JsGenerationOptions(
|
|
||||||
val jsExtension: String = "js",
|
|
||||||
val generatePackageJson: Boolean = false,
|
|
||||||
val generateTypeScriptDefinitions: Boolean = false,
|
|
||||||
)
|
|
||||||
|
|
||||||
class IrToJs(
|
|
||||||
private val backendContext: JsIrBackendContext,
|
|
||||||
private val guid: (IrDeclaration) -> String,
|
|
||||||
private val outputSink: CompilerOutputSink,
|
|
||||||
private val mainArguments: List<String>?,
|
|
||||||
private val granularity: JsGenerationGranularity,
|
|
||||||
private val mainModuleName: String,
|
|
||||||
private val options: JsGenerationOptions,
|
|
||||||
) {
|
|
||||||
val indexFileName = "index.${options.jsExtension}"
|
|
||||||
|
|
||||||
val FileUnit.initFunctionName
|
|
||||||
get() = "KotlinInit$" + sanitizeName(pathToJsModule(file))
|
|
||||||
|
|
||||||
sealed class CodegenUnitReference
|
|
||||||
object ThisUnitReference : CodegenUnitReference()
|
|
||||||
inner class OtherUnitReference(
|
|
||||||
module: IrModuleFragment,
|
|
||||||
) : CodegenUnitReference() {
|
|
||||||
// Path to entry point of other module from "top-level", e.g. directory which contains all other modules
|
|
||||||
val importPath = "./" + module.jsModuleName + "/" + indexFileName
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class CodegenUnit {
|
|
||||||
abstract val packageFragments: Iterable<IrPackageFragment>
|
|
||||||
abstract val externalPackageFragments: Iterable<IrPackageFragment>
|
|
||||||
abstract fun referenceCodegenUnitOfDeclaration(declaration: IrDeclaration): CodegenUnitReference
|
|
||||||
abstract val pathToKotlinModulesRoot: String
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class FileUnit(val file: IrFile, val externalFile: IrFile?) : CodegenUnit() {
|
|
||||||
override val packageFragments =
|
|
||||||
listOf(file)
|
|
||||||
|
|
||||||
override val externalPackageFragments =
|
|
||||||
listOfNotNull(externalFile)
|
|
||||||
|
|
||||||
override fun referenceCodegenUnitOfDeclaration(declaration: IrDeclaration): CodegenUnitReference =
|
|
||||||
when (val declarationFile = declaration.file) {
|
|
||||||
file -> ThisUnitReference
|
|
||||||
else -> OtherUnitReference(declarationFile.module)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val pathToKotlinModulesRoot: String by lazy {
|
|
||||||
"../".repeat(file.fqName.pathSegments().size + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class ModuleUnit(val module: IrModuleFragment) : CodegenUnit() {
|
|
||||||
override val packageFragments: Iterable<IrPackageFragment> =
|
|
||||||
module.files
|
|
||||||
|
|
||||||
override val externalPackageFragments: Iterable<IrPackageFragment> =
|
|
||||||
packageFragments.mapNotNull { backendContext.externalPackageFragment[it.symbol] }
|
|
||||||
|
|
||||||
override fun referenceCodegenUnitOfDeclaration(declaration: IrDeclaration): CodegenUnitReference =
|
|
||||||
when (val declarationModule = declaration.file.module) {
|
|
||||||
module -> ThisUnitReference
|
|
||||||
else -> OtherUnitReference(declarationModule)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val pathToKotlinModulesRoot: String = "../"
|
|
||||||
}
|
|
||||||
|
|
||||||
class WholeProgramUnit(
|
|
||||||
val modules: Iterable<IrModuleFragment>,
|
|
||||||
val externalModules: Iterable<IrPackageFragment>
|
|
||||||
) : CodegenUnit() {
|
|
||||||
override val packageFragments: Iterable<IrPackageFragment> =
|
|
||||||
modules.flatMap { it.files }
|
|
||||||
|
|
||||||
override val externalPackageFragments: Iterable<IrPackageFragment>
|
|
||||||
get() = externalModules
|
|
||||||
|
|
||||||
override fun referenceCodegenUnitOfDeclaration(declaration: IrDeclaration): CodegenUnitReference =
|
|
||||||
ThisUnitReference
|
|
||||||
|
|
||||||
override val pathToKotlinModulesRoot: String
|
|
||||||
get() = "../"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pathToJsModule(file: IrFile): String =
|
|
||||||
"${fileJsRootModuleName(file)}/${fileJsSubModulePath(file)}"
|
|
||||||
|
|
||||||
private fun fileJsRootModuleName(file: IrFile): String =
|
|
||||||
when (granularity) {
|
|
||||||
WHOLE_PROGRAM -> mainModuleName
|
|
||||||
PER_MODULE, PER_FILE -> file.module.jsModuleName
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fileJsSubModulePath(file: IrFile): String =
|
|
||||||
when (granularity) {
|
|
||||||
WHOLE_PROGRAM, PER_MODULE -> indexFileName
|
|
||||||
|
|
||||||
PER_FILE -> {
|
|
||||||
val maybeSingleOpenClass = (file.declarations.singleOrNull() as? IrClass)?.takeIf {
|
|
||||||
it.modality == Modality.ABSTRACT || it.modality == Modality.OPEN
|
|
||||||
}
|
|
||||||
|
|
||||||
val hash = abs((maybeSingleOpenClass?.let { guid(it) } ?: file.path).hashCode())
|
|
||||||
val filePrefix = maybeSingleOpenClass?.name?.asString()?.let { sanitizeName(it) + ".class" } ?: file.name
|
|
||||||
val fileName = "${filePrefix}_$hash.${options.jsExtension}"
|
|
||||||
val packagePath = file.fqName.pathSegments().joinToString("") { it.identifier + "/" }
|
|
||||||
"$packagePath$fileName"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GeneratedUnit(
|
|
||||||
val jsStatements: List<JsStatement>,
|
|
||||||
val exportedDeclarations: List<ExportedDeclaration>,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun generateUnit(unit: CodegenUnit): GeneratedUnit {
|
|
||||||
val exportedDeclarations: List<ExportedDeclaration> =
|
|
||||||
with(ExportModelGenerator(backendContext, generateNamespacesForPackages = false)) {
|
|
||||||
(unit.externalPackageFragments + unit.packageFragments).flatMap { packageFragment ->
|
|
||||||
generateExport(packageFragment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val stableNames: Set<String> = collectStableNames(unit)
|
|
||||||
val nameGenerator = NewNamerImpl(backendContext, unit, guid, stableNames)
|
|
||||||
|
|
||||||
val staticContext = JsStaticContext(
|
|
||||||
backendContext = backendContext,
|
|
||||||
irNamer = nameGenerator,
|
|
||||||
globalNameScope = nameGenerator.staticNames
|
|
||||||
)
|
|
||||||
|
|
||||||
val declarationStatements: List<JsStatement> = unit.packageFragments.flatMap {
|
|
||||||
StaticMembersLowering(backendContext).lower(it as IrFile)
|
|
||||||
it.accept(IrFileToJsTransformer(), staticContext).statements
|
|
||||||
}
|
|
||||||
|
|
||||||
val preDeclarationBlock = JsCompositeBlock()
|
|
||||||
val postDeclarationBlock = JsCompositeBlock()
|
|
||||||
processClassModels(staticContext.classModels, preDeclarationBlock, postDeclarationBlock)
|
|
||||||
|
|
||||||
val statements = mutableListOf<JsStatement>()
|
|
||||||
statements += nameGenerator.internalImports.values
|
|
||||||
statements += preDeclarationBlock
|
|
||||||
statements += declarationStatements
|
|
||||||
statements += postDeclarationBlock
|
|
||||||
|
|
||||||
// Generate module initialization
|
|
||||||
|
|
||||||
val initializerBlock = staticContext.initializerBlock
|
|
||||||
when (unit) {
|
|
||||||
is WholeProgramUnit, is ModuleUnit -> {
|
|
||||||
// Run initialization during ES module initialization
|
|
||||||
statements += initializerBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
is FileUnit -> {
|
|
||||||
// Postpone initialization by putting it into a separate function
|
|
||||||
// Will be called later in proper order after class model is initialized
|
|
||||||
val initFunction = JsFunction(emptyScope, JsBlock(initializerBlock.statements), "init fun")
|
|
||||||
initFunction.name = JsName(unit.initFunctionName, false)
|
|
||||||
statements += initFunction.makeStmt()
|
|
||||||
statements += JsExport(initFunction.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate internal export
|
|
||||||
|
|
||||||
val internalExports = mutableListOf<JsExport.Element>()
|
|
||||||
fun export(declaration: IrDeclarationWithName) {
|
|
||||||
internalExports += JsExport.Element(nameGenerator.getNameForStaticDeclaration(declaration), JsName(guid(declaration), false))
|
|
||||||
}
|
|
||||||
|
|
||||||
for (fragment in unit.packageFragments) {
|
|
||||||
for (declaration in fragment.declarations) {
|
|
||||||
if (declaration is IrDeclarationWithName) {
|
|
||||||
if (declaration.origin == JsCodeOutliningLowering.OUTLINED_JS_CODE_ORIGIN) continue
|
|
||||||
export(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default implementations of interface methods are nested under interface declarations in IR at this point,
|
|
||||||
// but they are effectively used as a static declaration and can be directly referenced by other codegen unit,
|
|
||||||
// thus requiring internal export
|
|
||||||
declaration.acceptChildrenVoid(object : IrElementVisitorVoid {
|
|
||||||
override fun visitElement(element: IrElement) {
|
|
||||||
element.acceptChildrenVoid(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
|
||||||
if (declaration.hasInterfaceParent() && declaration.body != null) {
|
|
||||||
export(declaration)
|
|
||||||
}
|
|
||||||
super.visitSimpleFunction(declaration)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statements += JsExport(JsExport.Subject.Elements(internalExports), null)
|
|
||||||
|
|
||||||
// Generate external export
|
|
||||||
|
|
||||||
val globalNames = NameTable<String>(nameGenerator.staticNames)
|
|
||||||
val exporter = ExportModelToJsStatements(
|
|
||||||
staticContext,
|
|
||||||
declareNewNamespace = { globalNames.declareFreshName(it, it) }
|
|
||||||
)
|
|
||||||
exportedDeclarations.forEach {
|
|
||||||
statements += exporter.generateDeclarationExport(
|
|
||||||
it,
|
|
||||||
null,
|
|
||||||
esModules = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return GeneratedUnit(statements, exportedDeclarations)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectStableNames(unit: CodegenUnit): Set<String> {
|
|
||||||
val newStableStaticNamesCollectorVisitor =
|
|
||||||
NewStableStaticNamesCollectorVisitor(needToCollectReferences = granularity != WHOLE_PROGRAM)
|
|
||||||
unit.packageFragments.forEach { it.acceptVoid(newStableStaticNamesCollectorVisitor) }
|
|
||||||
unit.externalPackageFragments.forEach { it.acceptVoid(newStableStaticNamesCollectorVisitor) }
|
|
||||||
|
|
||||||
return newStableStaticNamesCollectorVisitor.collectedStableNames
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns import statement and call expression
|
|
||||||
private fun invokeFunctionFromEntryJsFile(
|
|
||||||
function: IrFunction,
|
|
||||||
args: List<JsExpression> = emptyList()
|
|
||||||
): Pair<JsStatement, JsExpression> {
|
|
||||||
val name = guid(function)
|
|
||||||
val importPath = if (granularity == WHOLE_PROGRAM) "./$indexFileName" else "../" + pathToJsModule(function.file)
|
|
||||||
return Pair(
|
|
||||||
JsImport(importPath, mutableListOf(JsImport.Element(name, null))),
|
|
||||||
JsInvocation(JsNameRef(name), args)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun invokeFunctionFromEntryJsFileAsStatements(
|
|
||||||
function: IrFunction,
|
|
||||||
args: List<JsExpression> = emptyList()
|
|
||||||
): List<JsStatement> =
|
|
||||||
invokeFunctionFromEntryJsFile(function, args)
|
|
||||||
.let { listOf(it.first, it.second.makeStmt()) }
|
|
||||||
|
|
||||||
fun generateModules(
|
|
||||||
mainModule: IrModuleFragment,
|
|
||||||
allModules: List<IrModuleFragment>
|
|
||||||
) {
|
|
||||||
when (granularity) {
|
|
||||||
WHOLE_PROGRAM ->
|
|
||||||
generateModule(mainModule, allModules)
|
|
||||||
|
|
||||||
PER_MODULE,
|
|
||||||
PER_FILE ->
|
|
||||||
allModules.forEach { module ->
|
|
||||||
generateModule(mainModule = module, allModules = emptyList())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateModuleLevelCode(module: IrModuleFragment, statements: MutableList<JsStatement>) {
|
|
||||||
if (mainArguments != null) {
|
|
||||||
val mainFunction = JsMainFunctionDetector(backendContext).getMainFunctionOrNull(module)
|
|
||||||
if (mainFunction != null) {
|
|
||||||
val generateArgv = mainFunction.valueParameters.firstOrNull()?.isStringArrayParameter() ?: false
|
|
||||||
val generateContinuation = mainFunction.isLoweredSuspendFunction(backendContext)
|
|
||||||
|
|
||||||
val mainArgumentsArray =
|
|
||||||
if (generateArgv)
|
|
||||||
JsArrayLiteral(mainArguments.map { JsStringLiteral(it) })
|
|
||||||
else
|
|
||||||
null
|
|
||||||
|
|
||||||
val continuation =
|
|
||||||
if (generateContinuation) {
|
|
||||||
val (import, invoke) = invokeFunctionFromEntryJsFile(backendContext.coroutineEmptyContinuation.owner.getter!!)
|
|
||||||
statements += import
|
|
||||||
invoke
|
|
||||||
} else
|
|
||||||
null
|
|
||||||
|
|
||||||
statements += invokeFunctionFromEntryJsFileAsStatements(
|
|
||||||
mainFunction, listOfNotNull(mainArgumentsArray, continuation)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: tests
|
|
||||||
// backendContext.testRoots[module]?.let { testContainer ->
|
|
||||||
// statements += invokeFunctionFromEntryJsFileAsStatements(testContainer)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateModule(
|
|
||||||
mainModule: IrModuleFragment,
|
|
||||||
allModules: List<IrModuleFragment>,
|
|
||||||
) {
|
|
||||||
val moduleName = mainModule.jsModuleName
|
|
||||||
val indexJsStatements = mutableListOf<JsStatement>()
|
|
||||||
val exportedDeclarations = mutableListOf<ExportedDeclaration>()
|
|
||||||
|
|
||||||
when (granularity) {
|
|
||||||
PER_FILE -> {
|
|
||||||
for (file in mainModule.files.sortedBy(::fileInitOrder)) {
|
|
||||||
if (file.declarations.isEmpty()) continue
|
|
||||||
|
|
||||||
val pathToSubModule = fileJsSubModulePath(file)
|
|
||||||
indexJsStatements += JsExport(JsExport.Subject.All, fromModule = "./$pathToSubModule")
|
|
||||||
|
|
||||||
val unit = FileUnit(file, backendContext.externalPackageFragment[file.symbol])
|
|
||||||
val generatedUnit = generateUnit(unit)
|
|
||||||
|
|
||||||
val importElements = JsImport.Element(unit.initFunctionName, null)
|
|
||||||
indexJsStatements += JsImport("./$pathToSubModule", mutableListOf(importElements))
|
|
||||||
indexJsStatements += JsInvocation(JsNameRef(JsName(unit.initFunctionName, false))).makeStmt()
|
|
||||||
|
|
||||||
exportedDeclarations += generatedUnit.exportedDeclarations
|
|
||||||
|
|
||||||
outputSink.write(
|
|
||||||
file.module.jsModuleName,
|
|
||||||
pathToSubModule,
|
|
||||||
"// Kotlin file: ${file.path}\n" + generatedUnit.jsStatements.toJsCodeString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
generateModuleLevelCode(mainModule, indexJsStatements)
|
|
||||||
}
|
|
||||||
|
|
||||||
PER_MODULE -> {
|
|
||||||
val generatedUnit = generateUnit(ModuleUnit(mainModule))
|
|
||||||
indexJsStatements += generatedUnit.jsStatements
|
|
||||||
generateModuleLevelCode(mainModule, indexJsStatements)
|
|
||||||
exportedDeclarations += generatedUnit.exportedDeclarations
|
|
||||||
}
|
|
||||||
|
|
||||||
WHOLE_PROGRAM -> {
|
|
||||||
val generatedUnit = generateUnit(WholeProgramUnit(allModules, backendContext.externalPackageFragment.values))
|
|
||||||
indexJsStatements += generatedUnit.jsStatements
|
|
||||||
allModules.forEach {
|
|
||||||
generateModuleLevelCode(it, indexJsStatements)
|
|
||||||
}
|
|
||||||
exportedDeclarations += generatedUnit.exportedDeclarations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outputSink.write(moduleName, indexFileName, indexJsStatements.toJsCodeString())
|
|
||||||
|
|
||||||
if (options.generatePackageJson) {
|
|
||||||
outputSink.write(moduleName, "package.json", """{ "main": "$indexFileName", "type": "module" }""")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.generateTypeScriptDefinitions && exportedDeclarations.isNotEmpty()) {
|
|
||||||
val dts = ExportedModule(moduleName, moduleKind = ModuleKind.ES, exportedDeclarations).toTypeScript()
|
|
||||||
outputSink.write(moduleName, "index.d.ts", dts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fileInitOrder(file: IrFile): Int =
|
|
||||||
when (val singleDeclaration = file.declarations.singleOrNull()) {
|
|
||||||
// Initialize parent classes before child classes
|
|
||||||
// TODO: Comment about open classes in separate files
|
|
||||||
is IrClass -> singleDeclaration.getInheritanceChainLength()
|
|
||||||
// Initialize regular files after all open classes
|
|
||||||
else -> Int.MAX_VALUE
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrClass.getInheritanceChainLength(): Int {
|
|
||||||
if (symbol == backendContext.irBuiltIns.anyClass)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
// FIXME: Filter out interfaces
|
|
||||||
superTypes.forEach { superType ->
|
|
||||||
val superClass: IrClass? = superType.classOrNull?.owner
|
|
||||||
if (superClass != null && /* !!! */ !superClass.isInterface)
|
|
||||||
return superClass.getInheritanceChainLength() + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val IrModuleFragment.jsModuleName: String
|
|
||||||
get() = name.asString()
|
|
||||||
.replace("[.:@]".toRegex(), "_")
|
|
||||||
.dropWhile { it == '<' }
|
|
||||||
.dropLastWhile { it == '>' }
|
|
||||||
|
|
||||||
private fun List<JsStatement>.toJsCodeString(): String =
|
|
||||||
JsCompositeBlock(this).toString()
|
|
||||||
|
|
||||||
enum class JsGenerationGranularity {
|
|
||||||
WHOLE_PROGRAM,
|
|
||||||
PER_MODULE,
|
|
||||||
PER_FILE
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateEsModules(
|
|
||||||
ir: LoweredIr,
|
|
||||||
outputSink: CompilerOutputSink,
|
|
||||||
mainArguments: List<String>?,
|
|
||||||
granularity: JsGenerationGranularity,
|
|
||||||
options: JsGenerationOptions,
|
|
||||||
) {
|
|
||||||
// Declaration numeration to create temporary GUID
|
|
||||||
// TODO: Replace with an actual GUID
|
|
||||||
val numerator = StaticDeclarationNumerator()
|
|
||||||
ir.allModules.forEach { numerator.add(it) }
|
|
||||||
|
|
||||||
fun guid(declaration: IrDeclaration): String {
|
|
||||||
val name = sanitizeName((declaration as IrDeclarationWithName).name.toString())
|
|
||||||
val number = numerator.numeration[declaration]
|
|
||||||
?: error("Can't find number for declaration ${declaration.fqNameWhenAvailable}")
|
|
||||||
// TODO: Use shorter names in release mode
|
|
||||||
return "${name}_GUID_${number}"
|
|
||||||
}
|
|
||||||
|
|
||||||
val ir2js = IrToJs(ir.context, ::guid, outputSink, mainArguments, granularity, ir.mainModule.jsModuleName, options)
|
|
||||||
ir2js.generateModules(ir.mainModule, ir.allModules)
|
|
||||||
}
|
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.ir.backend.js.codegen
|
||||||
|
|
||||||
|
enum class JsGenerationGranularity {
|
||||||
|
WHOLE_PROGRAM,
|
||||||
|
PER_MODULE,
|
||||||
|
PER_FILE
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ data class ExportedConstructSignature(
|
|||||||
val returnType: ExportedType,
|
val returnType: ExportedType,
|
||||||
) : ExportedDeclaration()
|
) : ExportedDeclaration()
|
||||||
|
|
||||||
class ExportedProperty(
|
data class ExportedProperty(
|
||||||
val name: String,
|
val name: String,
|
||||||
val type: ExportedType,
|
val type: ExportedType,
|
||||||
val mutable: Boolean = true,
|
val mutable: Boolean = true,
|
||||||
@@ -94,7 +94,7 @@ data class ExportedObject(
|
|||||||
override val members: List<ExportedDeclaration>,
|
override val members: List<ExportedDeclaration>,
|
||||||
override val nestedClasses: List<ExportedClass>,
|
override val nestedClasses: List<ExportedClass>,
|
||||||
override val ir: IrClass,
|
override val ir: IrClass,
|
||||||
val irGetter: IrFunction
|
val irGetter: IrSimpleFunction
|
||||||
) : ExportedClass()
|
) : ExportedClass()
|
||||||
|
|
||||||
class ExportedParameter(
|
class ExportedParameter(
|
||||||
|
|||||||
+82
-36
@@ -5,8 +5,16 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.export
|
package org.jetbrains.kotlin.ir.backend.js.export
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsAstUtils
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.defineProperty
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsAssignment
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.prototypeOf
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsElementAccess
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||||
import org.jetbrains.kotlin.ir.util.companionObject
|
import org.jetbrains.kotlin.ir.util.companionObject
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||||
@@ -17,8 +25,14 @@ class ExportModelToJsStatements(
|
|||||||
) {
|
) {
|
||||||
private val namespaceToRefMap = mutableMapOf<String, JsNameRef>()
|
private val namespaceToRefMap = mutableMapOf<String, JsNameRef>()
|
||||||
|
|
||||||
fun generateModuleExport(module: ExportedModule, internalModuleName: JsName): List<JsStatement> {
|
fun generateModuleExport(
|
||||||
return module.declarations.flatMap { generateDeclarationExport(it, JsNameRef(internalModuleName), esModules = false) }
|
module: ExportedModule,
|
||||||
|
internalModuleName: JsName?,
|
||||||
|
esModules: Boolean
|
||||||
|
): List<JsStatement> {
|
||||||
|
return module.declarations.flatMap {
|
||||||
|
generateDeclarationExport(it, internalModuleName?.makeRef(), esModules)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateDeclarationExport(
|
fun generateDeclarationExport(
|
||||||
@@ -60,17 +74,12 @@ class ExportModelToJsStatements(
|
|||||||
|
|
||||||
is ExportedFunction -> {
|
is ExportedFunction -> {
|
||||||
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
||||||
if (esModules) {
|
when {
|
||||||
listOf(JsExport(name, alias = JsName(declaration.name, false)))
|
namespace != null ->
|
||||||
} else {
|
listOf(jsAssignment(jsElementAccess(declaration.name, namespace), JsNameRef(name)).makeStmt())
|
||||||
if (namespace != null) {
|
|
||||||
listOf(
|
esModules -> listOf(JsExport(name, alias = JsName(declaration.name, false)))
|
||||||
jsAssignment(
|
else -> emptyList()
|
||||||
jsElementAccess(declaration.name, namespace),
|
|
||||||
JsNameRef(name)
|
|
||||||
).makeStmt()
|
|
||||||
)
|
|
||||||
} else emptyList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,39 +87,76 @@ class ExportModelToJsStatements(
|
|||||||
is ExportedConstructSignature -> emptyList()
|
is ExportedConstructSignature -> emptyList()
|
||||||
|
|
||||||
is ExportedProperty -> {
|
is ExportedProperty -> {
|
||||||
require(namespace != null) { "Only namespaced properties are allowed" }
|
require(namespace != null || esModules) { "Only namespaced properties are allowed" }
|
||||||
val getter = declaration.irGetter?.let { JsNameRef(namer.getNameForStaticDeclaration(it)) }
|
val getter = declaration.irGetter?.let { namer.getNameForStaticDeclaration(it) }
|
||||||
val setter = declaration.irSetter?.let { JsNameRef(namer.getNameForStaticDeclaration(it)) }
|
val setter = declaration.irSetter?.let { namer.getNameForStaticDeclaration(it) }
|
||||||
listOf(defineProperty(namespace, declaration.name, getter, setter, namer).makeStmt())
|
if (namespace == null) {
|
||||||
|
val property = JsVars.JsVar(
|
||||||
|
JsName(declaration.name, false),
|
||||||
|
JsObjectLiteral(false).apply {
|
||||||
|
getter?.let {
|
||||||
|
val fieldName = when (declaration.irGetter.origin) {
|
||||||
|
JsLoweredDeclarationOrigin.OBJECT_GET_INSTANCE_FUNCTION -> "getInstance"
|
||||||
|
else -> "get"
|
||||||
|
}
|
||||||
|
propertyInitializers += JsPropertyInitializer(JsStringLiteral(fieldName), it.makeRef())
|
||||||
|
}
|
||||||
|
setter?.let { propertyInitializers += JsPropertyInitializer(JsStringLiteral("set"), it.makeRef()) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
listOf(
|
||||||
|
JsVars(property),
|
||||||
|
JsExport(property.name, JsName(declaration.name, false))
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
listOf(defineProperty(namespace, declaration.name, getter?.makeRef(), setter?.makeRef(), namer).makeStmt())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is ErrorDeclaration -> emptyList()
|
is ErrorDeclaration -> emptyList()
|
||||||
|
|
||||||
is ExportedObject -> {
|
is ExportedObject -> {
|
||||||
require(namespace != null) { "Only namespaced properties are allowed" }
|
require(namespace != null || esModules) { "Only namespaced properties are allowed" }
|
||||||
val newNameSpace = jsElementAccess(declaration.name, namespace)
|
val newNameSpace = when {
|
||||||
val getter = JsNameRef(namer.getNameForStaticDeclaration(declaration.irGetter))
|
namespace != null -> jsElementAccess(declaration.name, namespace)
|
||||||
|
else ->
|
||||||
|
jsElementAccess(Namer.PROTOTYPE_NAME, namer.getNameForClass(declaration.ir).makeRef())
|
||||||
|
}
|
||||||
val staticsExport = declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules) }
|
val staticsExport = declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules) }
|
||||||
listOf(defineProperty(namespace, declaration.name, getter, null, namer).makeStmt()) + staticsExport
|
|
||||||
|
val objectExport = when (namespace) {
|
||||||
|
null -> generateDeclarationExport(
|
||||||
|
ExportedProperty(declaration.name, ExportedType.Primitive.Any, irGetter = declaration.irGetter),
|
||||||
|
namespace,
|
||||||
|
esModules
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> listOf(
|
||||||
|
defineProperty(
|
||||||
|
namespace,
|
||||||
|
declaration.name,
|
||||||
|
namer.getNameForStaticDeclaration(declaration.irGetter).makeRef(),
|
||||||
|
null,
|
||||||
|
namer
|
||||||
|
).makeStmt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
objectExport + staticsExport
|
||||||
}
|
}
|
||||||
|
|
||||||
is ExportedRegularClass -> {
|
is ExportedRegularClass -> {
|
||||||
if (declaration.isInterface) return emptyList()
|
if (declaration.isInterface) return emptyList()
|
||||||
val newNameSpace = if (namespace != null)
|
|
||||||
jsElementAccess(declaration.name, namespace)
|
|
||||||
else
|
|
||||||
prototypeOf(namer.getNameForClass(declaration.ir).makeRef(), namer)
|
|
||||||
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
||||||
val klassExport =
|
val newNameSpace = when {
|
||||||
if (esModules) {
|
namespace != null -> jsElementAccess(declaration.name, namespace)
|
||||||
JsExport(name, alias = JsName(declaration.name, false))
|
esModules -> name.makeRef()
|
||||||
} else {
|
else -> prototypeOf(namer.getNameForClass(declaration.ir).makeRef(), namer)
|
||||||
if (namespace != null) {
|
}
|
||||||
jsAssignment(
|
val klassExport = when {
|
||||||
newNameSpace,
|
namespace != null -> jsAssignment(newNameSpace, JsNameRef(name)).makeStmt()
|
||||||
JsNameRef(name)
|
esModules -> JsExport(name, alias = JsName(declaration.name, false))
|
||||||
).makeStmt()
|
else -> null
|
||||||
} else null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are only used when exporting secondary constructors annotated with @JsName
|
// These are only used when exporting secondary constructors annotated with @JsName
|
||||||
|
|||||||
+77
-49
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.export
|
package org.jetbrains.kotlin.ir.backend.js.export
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getFqNameWithJsNameWhenAvailable
|
import org.jetbrains.kotlin.ir.backend.js.utils.getFqNameWithJsNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
||||||
@@ -15,11 +16,14 @@ import org.jetbrains.kotlin.ir.util.parentAsClass
|
|||||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
import javax.lang.model.type.IntersectionType
|
|
||||||
|
|
||||||
private const val Nullable = "Nullable"
|
private const val Nullable = "Nullable"
|
||||||
private const val objects = "_objects_"
|
private const val objects = "_objects_"
|
||||||
|
private const val declare = "declare "
|
||||||
|
private const val declareExorted = "export $declare"
|
||||||
|
|
||||||
|
private const val NonExistent = "__NonExistent"
|
||||||
private const val syntheticObjectNameSeparator = '$'
|
private const val syntheticObjectNameSeparator = '$'
|
||||||
|
|
||||||
fun ExportedModule.toTypeScript(): String {
|
fun ExportedModule.toTypeScript(): String {
|
||||||
@@ -61,32 +65,36 @@ class ExportModelToTsDeclarations {
|
|||||||
return joinToString("\n") {
|
return joinToString("\n") {
|
||||||
it.toTypeScript(
|
it.toTypeScript(
|
||||||
indent = moduleKind.indent,
|
indent = moduleKind.indent,
|
||||||
prefix = if (moduleKind == ModuleKind.PLAIN) "" else "export "
|
prefix = if (moduleKind == ModuleKind.PLAIN) "" else declareExorted,
|
||||||
|
esModules = moduleKind == ModuleKind.ES
|
||||||
|
)
|
||||||
|
} + generateObjectsNamespaceIfNeeded(
|
||||||
|
indent = moduleKind.indent,
|
||||||
|
prefix = if (moduleKind == ModuleKind.PLAIN) "" else declare,
|
||||||
)
|
)
|
||||||
} + generateObjectsNamespaceIfNeeded(moduleKind.indent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateObjectsNamespaceIfNeeded(indent: String): String {
|
private fun generateObjectsNamespaceIfNeeded(indent: String, prefix: String): String {
|
||||||
return if (objectsSyntheticProperties.isEmpty()) {
|
return if (objectsSyntheticProperties.isEmpty()) {
|
||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
"\n" + ExportedNamespace(objects, objectsSyntheticProperties).toTypeScript(indent, "")
|
"\n" + ExportedNamespace(objects, objectsSyntheticProperties).toTypeScript(indent, prefix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<ExportedDeclaration>.toTypeScript(indent: String): String =
|
private fun List<ExportedDeclaration>.toTypeScript(indent: String): String =
|
||||||
joinToString("") { it.toTypeScript(indent) + "\n" }
|
joinToString("") { it.toTypeScript(indent) + "\n" }
|
||||||
|
|
||||||
private fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): String =
|
private fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = "", esModules: Boolean = false): String =
|
||||||
indent + when (this) {
|
indent + when (this) {
|
||||||
is ErrorDeclaration -> generateTypeScriptString()
|
is ErrorDeclaration -> generateTypeScriptString()
|
||||||
is ExportedNamespace -> generateTypeScriptString(indent, prefix)
|
|
||||||
is ExportedFunction -> generateTypeScriptString(indent, prefix)
|
|
||||||
is ExportedConstructor -> generateTypeScriptString(indent)
|
is ExportedConstructor -> generateTypeScriptString(indent)
|
||||||
is ExportedConstructSignature -> generateTypeScriptString(indent)
|
is ExportedConstructSignature -> generateTypeScriptString(indent)
|
||||||
is ExportedProperty -> generateTypeScriptString(indent, prefix)
|
is ExportedNamespace -> generateTypeScriptString(indent, prefix)
|
||||||
is ExportedObject -> generateTypeScriptString(indent, prefix)
|
is ExportedFunction -> generateTypeScriptString(indent, prefix)
|
||||||
is ExportedRegularClass -> generateTypeScriptString(indent, prefix)
|
is ExportedRegularClass -> generateTypeScriptString(indent, prefix)
|
||||||
|
is ExportedProperty -> generateTypeScriptString(indent, prefix, esModules)
|
||||||
|
is ExportedObject -> generateTypeScriptString(indent, prefix, esModules)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ErrorDeclaration.generateTypeScriptString(): String {
|
private fun ErrorDeclaration.generateTypeScriptString(): String {
|
||||||
@@ -107,34 +115,45 @@ class ExportModelToTsDeclarations {
|
|||||||
return "new($renderedParameters): ${returnType.toTypeScript(indent)};"
|
return "new($renderedParameters): ${returnType.toTypeScript(indent)};"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExportedProperty.generateTypeScriptString(indent: String, prefix: String): String {
|
private fun ExportedProperty.generateTypeScriptString(indent: String, prefix: String, esModules: Boolean = false): String {
|
||||||
val visibility = if (isProtected) "protected " else ""
|
val extraIndent = "$indent "
|
||||||
val keyword = when {
|
|
||||||
isMember -> (if (isAbstract) "abstract " else "")
|
|
||||||
else -> if (mutable) "let " else "const "
|
|
||||||
}
|
|
||||||
val possibleStatic = if (isMember && isStatic) "static " else ""
|
|
||||||
val containsUnresolvedChar = !name.isValidES5Identifier()
|
|
||||||
val memberName = when {
|
|
||||||
isMember && containsUnresolvedChar -> "\"$name\""
|
|
||||||
else -> name
|
|
||||||
}
|
|
||||||
val typeToTypeScript = type.toTypeScript(indent)
|
|
||||||
|
|
||||||
return if (isMember && !isField) {
|
|
||||||
val getter = "$prefix$visibility$possibleStatic${keyword}get $memberName(): $typeToTypeScript;"
|
|
||||||
if (!mutable) {
|
|
||||||
getter
|
|
||||||
} else {
|
|
||||||
getter + "\n" + "$indent$prefix$visibility$possibleStatic${keyword}set $memberName(value: $typeToTypeScript);"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isMember && containsUnresolvedChar) {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
val readonly = if (isMember && !mutable) "readonly " else ""
|
|
||||||
val optional = if (isOptional) "?" else ""
|
val optional = if (isOptional) "?" else ""
|
||||||
"$prefix$visibility$possibleStatic$keyword$readonly$memberName$optional: $typeToTypeScript;"
|
val containsUnresolvedChar = !name.isValidES5Identifier()
|
||||||
|
val memberName = if (containsUnresolvedChar) "\"$name\"" else name
|
||||||
|
val isObjectGetter = irGetter?.origin == JsLoweredDeclarationOrigin.OBJECT_GET_INSTANCE_FUNCTION
|
||||||
|
|
||||||
|
val typeToTypeScript = type.toTypeScript(if (!isMember && esModules && isObjectGetter) extraIndent else indent)
|
||||||
|
|
||||||
|
return if (isMember) {
|
||||||
|
val static = if (isStatic) "static " else ""
|
||||||
|
val abstract = if (isAbstract) "abstract " else ""
|
||||||
|
val visibility = if (isProtected) "protected " else ""
|
||||||
|
|
||||||
|
if (isField) {
|
||||||
|
val readonly = if (!mutable) "readonly " else ""
|
||||||
|
"$prefix$visibility$static$abstract$readonly$memberName$optional: $typeToTypeScript;"
|
||||||
|
} else {
|
||||||
|
val getter = "$prefix$visibility$static${abstract}get $memberName(): $typeToTypeScript;"
|
||||||
|
val setter = runIf(mutable) { "\n$indent$prefix$visibility$static${abstract}set $memberName(value: $typeToTypeScript);" }
|
||||||
|
getter + setter.orEmpty()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when {
|
||||||
|
containsUnresolvedChar -> ""
|
||||||
|
esModules -> {
|
||||||
|
if (isObjectGetter) {
|
||||||
|
"${prefix}const $name: {\n${extraIndent}getInstance(): $typeToTypeScript;\n};"
|
||||||
|
} else {
|
||||||
|
val getter = "get(): $typeToTypeScript;"
|
||||||
|
val setter = runIf(mutable) { " set(value: $typeToTypeScript): void;" }
|
||||||
|
"${prefix}const $name: { $getter${setter.orEmpty()} };"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val keyword = if (mutable) "let " else "const "
|
||||||
|
"$prefix$keyword$memberName$optional: $typeToTypeScript;"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,14 +190,19 @@ class ExportModelToTsDeclarations {
|
|||||||
return if (!isMember && containsUnresolvedChar) {
|
return if (!isMember && containsUnresolvedChar) {
|
||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
"${prefix}$visibility$keyword$escapedName$renderedTypeParameters($renderedParameters): $renderedReturnType;"
|
"$prefix$visibility$keyword$escapedName$renderedTypeParameters($renderedParameters): $renderedReturnType;"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExportedObject.generateTypeScriptString(indent: String, prefix: String): String {
|
private fun ExportedObject.generateTypeScriptString(indent: String, prefix: String, esModules: Boolean = false): String {
|
||||||
val shouldRenderSeparatedAbstractClass = !couldBeProperty()
|
val shouldRenderSeparatedAbstractClass = !couldBeProperty()
|
||||||
|
|
||||||
var t: ExportedType = ExportedType.InlineInterfaceType(members)
|
val extraMembers = nestedClasses
|
||||||
|
.takeIf { !shouldRenderSeparatedAbstractClass }
|
||||||
|
?.map { it as ExportedObject }
|
||||||
|
.orEmpty()
|
||||||
|
|
||||||
|
var t: ExportedType = ExportedType.InlineInterfaceType(members + extraMembers)
|
||||||
|
|
||||||
for (superInterface in superClasses + superInterfaces) {
|
for (superInterface in superClasses + superInterfaces) {
|
||||||
t = ExportedType.IntersectionType(t, superInterface)
|
t = ExportedType.IntersectionType(t, superInterface)
|
||||||
@@ -208,13 +232,14 @@ class ExportModelToTsDeclarations {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return if (!shouldRenderSeparatedAbstractClass) {
|
return if (!shouldRenderSeparatedAbstractClass) {
|
||||||
property.generateTypeScriptString(indent, prefix)
|
property.generateTypeScriptString(indent, prefix, esModules)
|
||||||
} else {
|
} else {
|
||||||
|
val className = NonExistent.takeIf { esModules }.orEmpty() + name
|
||||||
val propertyRef = "$objects.$propertyName"
|
val propertyRef = "$objects.$propertyName"
|
||||||
val shouldCreateExtraProperty = members.isNotEmpty() || superInterfaces.isNotEmpty() || superClasses.isNotEmpty()
|
val shouldCreateExtraProperty = members.isNotEmpty() || superInterfaces.isNotEmpty() || superClasses.isNotEmpty()
|
||||||
val newSuperClass = ExportedType.ClassType(propertyRef, emptyList(), ir).takeIf { shouldCreateExtraProperty }
|
val newSuperClass = ExportedType.ClassType(propertyRef, emptyList(), ir).takeIf { shouldCreateExtraProperty }
|
||||||
ExportedRegularClass(
|
val classForRender = ExportedRegularClass(
|
||||||
name = name,
|
name = className,
|
||||||
isInterface = false,
|
isInterface = false,
|
||||||
isAbstract = true,
|
isAbstract = true,
|
||||||
superClasses = listOfNotNull(newSuperClass),
|
superClasses = listOfNotNull(newSuperClass),
|
||||||
@@ -224,8 +249,14 @@ class ExportModelToTsDeclarations {
|
|||||||
nestedClasses = nestedClasses,
|
nestedClasses = nestedClasses,
|
||||||
ir = ir
|
ir = ir
|
||||||
)
|
)
|
||||||
.generateTypeScriptString(indent, prefix)
|
|
||||||
.also { if (shouldCreateExtraProperty) objectsSyntheticProperties.add(property) }
|
.also { if (shouldCreateExtraProperty) objectsSyntheticProperties.add(property) }
|
||||||
|
|
||||||
|
if (esModules && !property.isMember) {
|
||||||
|
property.copy(type = ExportedType.TypeOf(className), name = name)
|
||||||
|
.generateTypeScriptString(indent, prefix, esModules) + "\n${classForRender.generateTypeScriptString(indent, declare)}"
|
||||||
|
} else {
|
||||||
|
classForRender.generateTypeScriptString(indent, prefix)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,10 +303,7 @@ class ExportModelToTsDeclarations {
|
|||||||
val klassExport =
|
val klassExport =
|
||||||
"$prefix$modifiers$keyword $name$renderedTypeParameters$superClassClause$superInterfacesClause {\n$bodyString}"
|
"$prefix$modifiers$keyword $name$renderedTypeParameters$superClassClause$superInterfacesClause {\n$bodyString}"
|
||||||
val staticsExport =
|
val staticsExport =
|
||||||
if (nestedClasses.isNotEmpty()) "\n" + ExportedNamespace(name, nestedClasses).toTypeScript(
|
if (nestedClasses.isNotEmpty()) "\n" + ExportedNamespace(name, nestedClasses).toTypeScript(indent, prefix) else ""
|
||||||
indent,
|
|
||||||
prefix
|
|
||||||
) else ""
|
|
||||||
|
|
||||||
return if (name.isValidES5Identifier()) klassExport + staticsExport else ""
|
return if (name.isValidES5Identifier()) klassExport + staticsExport else ""
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ class JsExecutableProducer(
|
|||||||
val jsMultiModuleCache = JsMultiModuleCache(caches)
|
val jsMultiModuleCache = JsMultiModuleCache(caches)
|
||||||
val cachedProgram = jsMultiModuleCache.loadProgramHeadersFromCache()
|
val cachedProgram = jsMultiModuleCache.loadProgramHeadersFromCache()
|
||||||
|
|
||||||
val resolver = CrossModuleDependenciesResolver(cachedProgram.map { it.jsIrHeader })
|
val resolver = CrossModuleDependenciesResolver(moduleKind, cachedProgram.map { it.jsIrHeader })
|
||||||
val crossModuleReferences = resolver.resolveCrossModuleDependencies(relativeRequirePath)
|
val crossModuleReferences = resolver.resolveCrossModuleDependencies(relativeRequirePath)
|
||||||
|
|
||||||
jsMultiModuleCache.loadRequiredJsIrModules(crossModuleReferences)
|
jsMultiModuleCache.loadRequiredJsIrModules(crossModuleReferences)
|
||||||
|
|||||||
+1
-1
@@ -159,7 +159,7 @@ class IrModuleToJsTransformer(
|
|||||||
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
||||||
val globalNames = NameTable<String>(namer.globalNames)
|
val globalNames = NameTable<String>(namer.globalNames)
|
||||||
val exportStatements = ExportModelToJsStatements(staticContext) { globalNames.declareFreshName(it, it) }
|
val exportStatements = ExportModelToJsStatements(staticContext) { globalNames.declareFreshName(it, it) }
|
||||||
.generateModuleExport(exportedModule, internalModuleName)
|
.generateModuleExport(exportedModule, internalModuleName, false)
|
||||||
|
|
||||||
val (crossModuleImports, importedKotlinModules) = generateCrossModuleImports(nameGenerator, modules, dependencies, { JsName(sanitizeName(it), false) })
|
val (crossModuleImports, importedKotlinModules) = generateCrossModuleImports(nameGenerator, modules, dependencies, { JsName(sanitizeName(it), false) })
|
||||||
val crossModuleExports = generateCrossModuleExports(modules, refInfo, internalModuleName)
|
val crossModuleExports = generateCrossModuleExports(modules, refInfo, internalModuleName)
|
||||||
|
|||||||
+7
-5
@@ -94,6 +94,7 @@ class IrModuleToJsTransformerTmp(
|
|||||||
|
|
||||||
private val mainModuleName = backendContext.configuration[CommonConfigurationKeys.MODULE_NAME]!!
|
private val mainModuleName = backendContext.configuration[CommonConfigurationKeys.MODULE_NAME]!!
|
||||||
private val moduleKind = backendContext.configuration[JSConfigurationKeys.MODULE_KIND]!!
|
private val moduleKind = backendContext.configuration[JSConfigurationKeys.MODULE_KIND]!!
|
||||||
|
private val isEsModules = moduleKind == ModuleKind.ES
|
||||||
private val sourceMapInfo = SourceMapsInfo.from(backendContext.configuration)
|
private val sourceMapInfo = SourceMapsInfo.from(backendContext.configuration)
|
||||||
|
|
||||||
private class IrAndExportedDeclarations(val fragment: IrModuleFragment, val files: List<Pair<IrFile, List<ExportedDeclaration>>>)
|
private class IrAndExportedDeclarations(val fragment: IrModuleFragment, val files: List<Pair<IrFile, List<ExportedDeclaration>>>)
|
||||||
@@ -103,7 +104,7 @@ class IrModuleToJsTransformerTmp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun associateIrAndExport(modules: Iterable<IrModuleFragment>): List<IrAndExportedDeclarations> {
|
private fun associateIrAndExport(modules: Iterable<IrModuleFragment>): List<IrAndExportedDeclarations> {
|
||||||
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = true)
|
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = !isEsModules)
|
||||||
|
|
||||||
return modules.map { module ->
|
return modules.map { module ->
|
||||||
val files = module.files.map { file ->
|
val files = module.files.map { file ->
|
||||||
@@ -166,7 +167,7 @@ class IrModuleToJsTransformerTmp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun generateBinaryAst(files: Collection<IrFile>, allModules: Collection<IrModuleFragment>): List<JsIrFragmentAndBinaryAst> {
|
fun generateBinaryAst(files: Collection<IrFile>, allModules: Collection<IrModuleFragment>): List<JsIrFragmentAndBinaryAst> {
|
||||||
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = true)
|
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = !isEsModules)
|
||||||
|
|
||||||
val exportData = files.map { it to exportModelGenerator.generateExportWithExternals(it) }
|
val exportData = files.map { it to exportModelGenerator.generateExportWithExternals(it) }
|
||||||
|
|
||||||
@@ -235,12 +236,13 @@ class IrModuleToJsTransformerTmp(
|
|||||||
polyfills.statements += backendContext.polyfills.getAllPolyfillsFor(file)
|
polyfills.statements += backendContext.polyfills.getAllPolyfillsFor(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
val internalModuleName = ReservedJsNames.makeInternalModuleName().takeIf { !isEsModules }
|
||||||
val globalNames = NameTable<String>(globalNameScope)
|
val globalNames = NameTable<String>(globalNameScope)
|
||||||
val exportStatements =
|
val exportStatements =
|
||||||
ExportModelToJsStatements(staticContext, { globalNames.declareFreshName(it, it) }).generateModuleExport(
|
ExportModelToJsStatements(staticContext, { globalNames.declareFreshName(it, it) }).generateModuleExport(
|
||||||
ExportedModule(mainModuleName, moduleKind, exports),
|
ExportedModule(mainModuleName, moduleKind, exports),
|
||||||
internalModuleName,
|
internalModuleName,
|
||||||
|
isEsModules
|
||||||
)
|
)
|
||||||
|
|
||||||
result.exports.statements += exportStatements
|
result.exports.statements += exportStatements
|
||||||
@@ -379,7 +381,7 @@ private fun generateWrappedModuleBody(
|
|||||||
// mutable container allows explicitly remove elements from itself,
|
// mutable container allows explicitly remove elements from itself,
|
||||||
// so we are able to help GC to free heavy JsIrModule objects
|
// so we are able to help GC to free heavy JsIrModule objects
|
||||||
// TODO: It makes sense to invent something better, because this logic can be easily broken
|
// TODO: It makes sense to invent something better, because this logic can be easily broken
|
||||||
val moduleToRef = program.asCrossModuleDependencies(relativeRequirePath).toMutableList()
|
val moduleToRef = program.asCrossModuleDependencies(moduleKind, relativeRequirePath).toMutableList()
|
||||||
val mainModule = moduleToRef.removeLast().let { (main, mainRef) ->
|
val mainModule = moduleToRef.removeLast().let { (main, mainRef) ->
|
||||||
generateSingleWrappedModuleBody(
|
generateSingleWrappedModuleBody(
|
||||||
mainModuleName,
|
mainModuleName,
|
||||||
@@ -433,7 +435,7 @@ fun generateSingleWrappedModuleBody(
|
|||||||
sourceMapsInfo: SourceMapsInfo?,
|
sourceMapsInfo: SourceMapsInfo?,
|
||||||
generateScriptModule: Boolean,
|
generateScriptModule: Boolean,
|
||||||
generateCallToMain: Boolean,
|
generateCallToMain: Boolean,
|
||||||
crossModuleReferences: CrossModuleReferences = CrossModuleReferences.Empty,
|
crossModuleReferences: CrossModuleReferences = CrossModuleReferences.Empty(moduleKind),
|
||||||
outJsProgram: Boolean = true
|
outJsProgram: Boolean = true
|
||||||
): CompilationOutputs {
|
): CompilationOutputs {
|
||||||
val program = Merger(
|
val program = Merger(
|
||||||
|
|||||||
+32
-8
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.utils.toJsIdentifier
|
import org.jetbrains.kotlin.ir.backend.js.utils.toJsIdentifier
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
|
|
||||||
class JsIrProgramFragment(val packageFqn: String) {
|
class JsIrProgramFragment(val packageFqn: String) {
|
||||||
val nameBindings = mutableMapOf<String, JsName>()
|
val nameBindings = mutableMapOf<String, JsName>()
|
||||||
@@ -57,8 +58,8 @@ class JsIrModuleHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class JsIrProgram(private var modules: List<JsIrModule>) {
|
class JsIrProgram(private var modules: List<JsIrModule>) {
|
||||||
fun asCrossModuleDependencies(relativeRequirePath: Boolean): List<Pair<JsIrModule, CrossModuleReferences>> {
|
fun asCrossModuleDependencies(moduleKind: ModuleKind, relativeRequirePath: Boolean): List<Pair<JsIrModule, CrossModuleReferences>> {
|
||||||
val resolver = CrossModuleDependenciesResolver(modules.map { it.makeModuleHeader() })
|
val resolver = CrossModuleDependenciesResolver(moduleKind, modules.map { it.makeModuleHeader() })
|
||||||
modules = emptyList()
|
modules = emptyList()
|
||||||
val crossModuleReferences = resolver.resolveCrossModuleDependencies(relativeRequirePath)
|
val crossModuleReferences = resolver.resolveCrossModuleDependencies(relativeRequirePath)
|
||||||
return crossModuleReferences.entries.map {
|
return crossModuleReferences.entries.map {
|
||||||
@@ -75,9 +76,12 @@ class JsIrProgram(private var modules: List<JsIrModule>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CrossModuleDependenciesResolver(private val headers: List<JsIrModuleHeader>) {
|
class CrossModuleDependenciesResolver(
|
||||||
|
private val moduleKind: ModuleKind,
|
||||||
|
private val headers: List<JsIrModuleHeader>
|
||||||
|
) {
|
||||||
fun resolveCrossModuleDependencies(relativeRequirePath: Boolean): Map<JsIrModuleHeader, CrossModuleReferences> {
|
fun resolveCrossModuleDependencies(relativeRequirePath: Boolean): Map<JsIrModuleHeader, CrossModuleReferences> {
|
||||||
val headerToBuilder = headers.associateWith { JsIrModuleCrossModuleReferecenceBuilder(it, relativeRequirePath) }
|
val headerToBuilder = headers.associateWith { JsIrModuleCrossModuleReferecenceBuilder(moduleKind, it, relativeRequirePath) }
|
||||||
val definitionModule = mutableMapOf<String, JsIrModuleCrossModuleReferecenceBuilder>()
|
val definitionModule = mutableMapOf<String, JsIrModuleCrossModuleReferecenceBuilder>()
|
||||||
|
|
||||||
val mainModuleHeader = headers.last()
|
val mainModuleHeader = headers.last()
|
||||||
@@ -110,7 +114,11 @@ private fun String.prettyTag() = takeWhile { c -> c != '|' }
|
|||||||
|
|
||||||
private class CrossModuleRef(val module: JsIrModuleCrossModuleReferecenceBuilder, val tag: String)
|
private class CrossModuleRef(val module: JsIrModuleCrossModuleReferecenceBuilder, val tag: String)
|
||||||
|
|
||||||
private class JsIrModuleCrossModuleReferecenceBuilder(val header: JsIrModuleHeader, val relativeRequirePath: Boolean) {
|
private class JsIrModuleCrossModuleReferecenceBuilder(
|
||||||
|
val moduleKind: ModuleKind,
|
||||||
|
val header: JsIrModuleHeader,
|
||||||
|
val relativeRequirePath: Boolean
|
||||||
|
) {
|
||||||
val imports = mutableListOf<CrossModuleRef>()
|
val imports = mutableListOf<CrossModuleRef>()
|
||||||
val exports = mutableSetOf<String>()
|
val exports = mutableSetOf<String>()
|
||||||
var transitiveJsExportFrom = emptyList<JsIrModuleHeader>()
|
var transitiveJsExportFrom = emptyList<JsIrModuleHeader>()
|
||||||
@@ -155,7 +163,13 @@ private class JsIrModuleCrossModuleReferecenceBuilder(val header: JsIrModuleHead
|
|||||||
val transitiveExport = transitiveJsExportFrom.mapNotNull {
|
val transitiveExport = transitiveJsExportFrom.mapNotNull {
|
||||||
if (it.hasJsExports) import(it) else null
|
if (it.hasJsExports) import(it) else null
|
||||||
}
|
}
|
||||||
return CrossModuleReferences(importedModules.values.toList(), transitiveExport, exportNames, resultImports)
|
return CrossModuleReferences(
|
||||||
|
moduleKind,
|
||||||
|
importedModules.values.toList(),
|
||||||
|
transitiveExport,
|
||||||
|
exportNames,
|
||||||
|
resultImports
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun relativeRequirePath(moduleHeader: JsIrModuleHeader): String? {
|
private fun relativeRequirePath(moduleHeader: JsIrModuleHeader): String? {
|
||||||
@@ -177,6 +191,7 @@ private class JsIrModuleCrossModuleReferecenceBuilder(val header: JsIrModuleHead
|
|||||||
class CrossModuleImport(val exportedAs: String, val moduleExporter: JsName)
|
class CrossModuleImport(val exportedAs: String, val moduleExporter: JsName)
|
||||||
|
|
||||||
class CrossModuleReferences(
|
class CrossModuleReferences(
|
||||||
|
val moduleKind: ModuleKind,
|
||||||
val importedModules: List<JsImportedModule>, // additional Kotlin imported modules
|
val importedModules: List<JsImportedModule>, // additional Kotlin imported modules
|
||||||
val transitiveJsExportFrom: List<JsName>, // the list of modules which provide their js exports for transitive export
|
val transitiveJsExportFrom: List<JsName>, // the list of modules which provide their js exports for transitive export
|
||||||
val exports: Map<String, String>, // tag -> index
|
val exports: Map<String, String>, // tag -> index
|
||||||
@@ -190,12 +205,21 @@ class CrossModuleReferences(
|
|||||||
val tagToName = module.fragments.flatMap { it.nameBindings.entries }.associate { it.key to it.value }
|
val tagToName = module.fragments.flatMap { it.nameBindings.entries }.associate { it.key to it.value }
|
||||||
jsImports = imports.entries.associate {
|
jsImports = imports.entries.associate {
|
||||||
val importedAs = tagToName[it.key] ?: error("Internal error: cannot find imported name for symbol ${it.key.prettyTag()}")
|
val importedAs = tagToName[it.key] ?: error("Internal error: cannot find imported name for symbol ${it.key.prettyTag()}")
|
||||||
val exportRef = JsNameRef(it.value.exportedAs, ReservedJsNames.makeCrossModuleNameRef(it.value.moduleExporter))
|
val exportRef = JsNameRef(
|
||||||
|
it.value.exportedAs,
|
||||||
|
it.value.moduleExporter.let {
|
||||||
|
if (moduleKind == ModuleKind.ES) {
|
||||||
|
it.makeRef()
|
||||||
|
} else {
|
||||||
|
ReservedJsNames.makeCrossModuleNameRef(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
it.key to JsVars.JsVar(importedAs, exportRef)
|
it.key to JsVars.JsVar(importedAs, exportRef)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val Empty = CrossModuleReferences(listOf(), emptyList(), emptyMap(), emptyMap())
|
fun Empty(moduleKind: ModuleKind) = CrossModuleReferences(moduleKind, listOf(), emptyList(), emptyMap(), emptyMap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-4
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
|||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.partitionIsInstance
|
||||||
|
|
||||||
class Merger(
|
class Merger(
|
||||||
private val moduleName: String,
|
private val moduleName: String,
|
||||||
@@ -20,6 +21,7 @@ class Merger(
|
|||||||
private val generateCallToMain: Boolean,
|
private val generateCallToMain: Boolean,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val isEsModules = moduleKind == ModuleKind.ES
|
||||||
private val importStatements = mutableMapOf<String, JsStatement>()
|
private val importStatements = mutableMapOf<String, JsStatement>()
|
||||||
private val importedModulesMap = mutableMapOf<JsImportedModuleKey, JsImportedModule>()
|
private val importedModulesMap = mutableMapOf<JsImportedModuleKey, JsImportedModule>()
|
||||||
|
|
||||||
@@ -65,6 +67,14 @@ class Merger(
|
|||||||
if (crossModuleReferences.exports.isNotEmpty()) {
|
if (crossModuleReferences.exports.isNotEmpty()) {
|
||||||
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
||||||
|
|
||||||
|
if (isEsModules) {
|
||||||
|
val exportedElements = crossModuleReferences.exports.entries.map { (tag, hash) ->
|
||||||
|
val internalName = nameMap[tag] ?: error("Missing name for declaration '$tag'")
|
||||||
|
JsExport.Element(internalName, JsName(hash, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalExports += JsExport(JsExport.Subject.Elements(exportedElements))
|
||||||
|
} else {
|
||||||
val createExportBlock = jsAssignment(
|
val createExportBlock = jsAssignment(
|
||||||
ReservedJsNames.makeCrossModuleNameRef(internalModuleName),
|
ReservedJsNames.makeCrossModuleNameRef(internalModuleName),
|
||||||
JsAstUtils.or(ReservedJsNames.makeCrossModuleNameRef(internalModuleName), JsObjectLiteral())
|
JsAstUtils.or(ReservedJsNames.makeCrossModuleNameRef(internalModuleName), JsObjectLiteral())
|
||||||
@@ -78,6 +88,7 @@ class Merger(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun JsIrProgramFragment.buildRenames(nameMap: MutableMap<String, JsName>): Map<JsName, JsName> {
|
private fun JsIrProgramFragment.buildRenames(nameMap: MutableMap<String, JsName>): Map<JsName, JsName> {
|
||||||
val result = mutableMapOf<JsName, JsName>()
|
val result = mutableMapOf<JsName, JsName>()
|
||||||
@@ -125,6 +136,21 @@ class Merger(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun declareAndCallJsExporter(): List<JsStatement> {
|
private fun declareAndCallJsExporter(): List<JsStatement> {
|
||||||
|
if (isEsModules) {
|
||||||
|
val allExportRelatedStatements = fragments.flatMap { it.exports.statements }
|
||||||
|
val (allExportStatements, restStatements) = allExportRelatedStatements.partitionIsInstance<JsStatement, JsExport>()
|
||||||
|
val (currentModuleExportStatements, restExportStatements) = allExportStatements.partition { it.fromModule == null }
|
||||||
|
val exportedElements = currentModuleExportStatements.takeIf { it.isNotEmpty() }
|
||||||
|
?.asSequence()
|
||||||
|
?.flatMap { (it.subject as JsExport.Subject.Elements).elements }
|
||||||
|
?.distinctBy { (it.alias ?: it.name).ident }
|
||||||
|
?.map { if (it.name.ident == it.alias?.ident) JsExport.Element(it.name, null) else it }
|
||||||
|
?.toList()
|
||||||
|
|
||||||
|
val oneLargeExportStatement = exportedElements?.let { JsExport(JsExport.Subject.Elements(it)) }
|
||||||
|
|
||||||
|
return restStatements + listOfNotNull(oneLargeExportStatement) + restExportStatements
|
||||||
|
} else {
|
||||||
val exportBody = JsBlock(fragments.flatMap { it.exports.statements })
|
val exportBody = JsBlock(fragments.flatMap { it.exports.statements })
|
||||||
if (exportBody.isEmpty) {
|
if (exportBody.isEmpty) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
@@ -145,6 +171,7 @@ class Merger(
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun transitiveJsExport(): List<JsStatement> {
|
private fun transitiveJsExport(): List<JsStatement> {
|
||||||
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
||||||
@@ -214,9 +241,6 @@ class Merger(
|
|||||||
|
|
||||||
if (generateScriptModule) {
|
if (generateScriptModule) {
|
||||||
with(program.globalBlock) {
|
with(program.globalBlock) {
|
||||||
if (!generateScriptModule) {
|
|
||||||
statements += JsStringLiteral("use strict").makeStmt()
|
|
||||||
}
|
|
||||||
statements.addWithComment("block: polyfills", polyfillDeclarationBlock.statements)
|
statements.addWithComment("block: polyfills", polyfillDeclarationBlock.statements)
|
||||||
statements.addWithComment("block: imports", importStatements)
|
statements.addWithComment("block: imports", importStatements)
|
||||||
statements += moduleBody
|
statements += moduleBody
|
||||||
@@ -228,7 +252,7 @@ class Merger(
|
|||||||
parameters += JsParameter(internalModuleName)
|
parameters += JsParameter(internalModuleName)
|
||||||
parameters += (importedJsModules).map { JsParameter(it.internalName) }
|
parameters += (importedJsModules).map { JsParameter(it.internalName) }
|
||||||
with(body) {
|
with(body) {
|
||||||
if (!generateScriptModule) {
|
if (!isEsModules) {
|
||||||
statements += JsStringLiteral("use strict").makeStmt()
|
statements += JsStringLiteral("use strict").makeStmt()
|
||||||
}
|
}
|
||||||
statements.addWithComment("block: imports", importStatements)
|
statements.addWithComment("block: imports", importStatements)
|
||||||
|
|||||||
+17
-2
@@ -17,7 +17,7 @@ object ModuleWrapperTranslation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun wrap(
|
fun wrap(
|
||||||
moduleId: String, function: JsExpression, importedModules: List<JsImportedModule>,
|
moduleId: String, function: JsFunction, importedModules: List<JsImportedModule>,
|
||||||
program: JsProgram, kind: ModuleKind
|
program: JsProgram, kind: ModuleKind
|
||||||
): List<JsStatement> {
|
): List<JsStatement> {
|
||||||
return when (kind) {
|
return when (kind) {
|
||||||
@@ -25,7 +25,7 @@ object ModuleWrapperTranslation {
|
|||||||
ModuleKind.COMMON_JS -> wrapCommonJs(function, importedModules, program)
|
ModuleKind.COMMON_JS -> wrapCommonJs(function, importedModules, program)
|
||||||
ModuleKind.UMD -> wrapUmd(moduleId, function, importedModules, program)
|
ModuleKind.UMD -> wrapUmd(moduleId, function, importedModules, program)
|
||||||
ModuleKind.PLAIN -> wrapPlain(moduleId, function, importedModules, program)
|
ModuleKind.PLAIN -> wrapPlain(moduleId, function, importedModules, program)
|
||||||
ModuleKind.ES -> error("ES modules are not supported in legacy wrapper")
|
ModuleKind.ES -> wrapEsModule(function, importedModules)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +100,21 @@ object ModuleWrapperTranslation {
|
|||||||
return listOf(invocation.makeStmt())
|
return listOf(invocation.makeStmt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun wrapEsModule(function: JsFunction, importedModules: List<JsImportedModule>): List<JsStatement> {
|
||||||
|
val importStatements = importedModules.zip(function.parameters.drop(1)).map {
|
||||||
|
JsImport(
|
||||||
|
it.first.externalName,
|
||||||
|
if (it.first.plainReference == null) {
|
||||||
|
JsImport.Target.All(alias = it.second.name)
|
||||||
|
} else {
|
||||||
|
JsImport.Target.Default(name = it.second.name)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return importStatements + function.body.statements.dropLast(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun wrapPlain(
|
private fun wrapPlain(
|
||||||
moduleId: String, function: JsExpression,
|
moduleId: String, function: JsExpression,
|
||||||
importedModules: List<JsImportedModule>, program: JsProgram
|
importedModules: List<JsImportedModule>, program: JsProgram
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 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.ir.backend.js.utils
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.codegen.IrToJs
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrDeclarationReference
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsImport
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
|
||||||
|
|
||||||
class StaticDeclarationNumerator {
|
|
||||||
var currentNumber = 0
|
|
||||||
val numeration = mutableMapOf<IrDeclaration, Int>()
|
|
||||||
|
|
||||||
fun add(moduleFragment: IrModuleFragment) {
|
|
||||||
moduleFragment.files.forEach { add(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(declaration: IrDeclaration) {
|
|
||||||
// TODO: We should not visit declarations multiple times.
|
|
||||||
// Investigate enum tests in dce-driven mode.
|
|
||||||
if (declaration !in numeration) {
|
|
||||||
numeration[declaration] = currentNumber
|
|
||||||
currentNumber++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun add(packageFragment: IrPackageFragment) {
|
|
||||||
packageFragment.acceptChildrenVoid(object : IrElementVisitorVoid {
|
|
||||||
override fun visitElement(element: IrElement) {
|
|
||||||
element.acceptChildrenVoid(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase) {
|
|
||||||
if (declaration !is IrVariable) {
|
|
||||||
add(declaration)
|
|
||||||
}
|
|
||||||
super.visitDeclaration(declaration)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NewStableStaticNamesCollectorVisitor(val needToCollectReferences: Boolean) : IrElementVisitorVoid {
|
|
||||||
val collectedStableNames = mutableSetOf<String>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
collectedStableNames.addAll(RESERVED_IDENTIFIERS)
|
|
||||||
collectedStableNames.add(Namer.IMPLICIT_RECEIVER_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrDeclaration.collectStableName() {
|
|
||||||
collectedStableNames += stableNameForExternalDeclaration(this) ?: return
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
|
||||||
element.acceptChildrenVoid(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase) {
|
|
||||||
super.visitDeclaration(declaration)
|
|
||||||
declaration.collectStableName()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDeclarationReference(expression: IrDeclarationReference) {
|
|
||||||
super.visitDeclarationReference(expression)
|
|
||||||
if (needToCollectReferences) {
|
|
||||||
val declaration = expression.symbol.owner as? IrDeclaration
|
|
||||||
declaration?.collectStableName()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NewNamerImpl(
|
|
||||||
val context: JsIrBackendContext,
|
|
||||||
val unit: IrToJs.CodegenUnit,
|
|
||||||
val exportId: (IrDeclarationWithName) -> String,
|
|
||||||
stableNames: Set<String>,
|
|
||||||
) : IrNamerBase() {
|
|
||||||
val staticNames = NameTable<IrDeclaration>(
|
|
||||||
reserved = stableNames.toMutableSet()
|
|
||||||
)
|
|
||||||
val internalImports = mutableMapOf<String, JsImport>()
|
|
||||||
|
|
||||||
override fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
|
||||||
require(function.dispatchReceiverParameter != null)
|
|
||||||
val name = jsFunctionSignature(function, context)
|
|
||||||
return name.toJsName()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameForMemberField(field: IrField): JsName {
|
|
||||||
val fieldName = sanitizeName(
|
|
||||||
try {
|
|
||||||
exportId(field)
|
|
||||||
} catch (e: IllegalStateException) {
|
|
||||||
// TODO: Fix DCE with inline classes and remove this hack
|
|
||||||
field.name.asString() + "_LIKELY_ELIMINATED_BY_DCE"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// TODO: Webpack not minimize member names, it is long name, which is not minimized, so it affects final JS bundle size
|
|
||||||
// Use shorter names
|
|
||||||
return JsName("f_$fieldName", false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameForStaticDeclaration(declaration: IrDeclarationWithName): JsName {
|
|
||||||
staticNames.names[declaration]?.let { return JsName(it, false) }
|
|
||||||
|
|
||||||
fun registerImport(moduleId: String, importedName: String) {
|
|
||||||
val fullModuleId = if (moduleId.startsWith(".")) {
|
|
||||||
unit.pathToKotlinModulesRoot + moduleId
|
|
||||||
} else {
|
|
||||||
// TODO: Do we cover this path in tests?
|
|
||||||
moduleId
|
|
||||||
}
|
|
||||||
|
|
||||||
val import = internalImports.getOrPut(fullModuleId) {
|
|
||||||
JsImport(fullModuleId)
|
|
||||||
}
|
|
||||||
import.elements += JsImport.Element(importedName, staticNames.names[declaration]!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (declaration.isEffectivelyExternal()) {
|
|
||||||
val jsModule: String? = declaration.getJsModule()
|
|
||||||
val maybeParentFile: IrFile? = declaration.parent as? IrFile
|
|
||||||
val fileJsModule: String? = maybeParentFile?.getJsModule()
|
|
||||||
val jsQualifier: String? = maybeParentFile?.getJsQualifier()
|
|
||||||
|
|
||||||
when {
|
|
||||||
jsModule != null -> {
|
|
||||||
// TODO: Support jsQualifier
|
|
||||||
staticNames.declareFreshName(declaration, declaration.name.asString())
|
|
||||||
registerImport(jsModule, "default")
|
|
||||||
}
|
|
||||||
|
|
||||||
fileJsModule != null -> {
|
|
||||||
// TODO: Support jsQualifier
|
|
||||||
staticNames.declareFreshName(declaration, declaration.name.asString())
|
|
||||||
registerImport(fileJsModule, declaration.getJsNameOrKotlinName().identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
var name = declaration.getJsNameOrKotlinName().identifier
|
|
||||||
if (jsQualifier != null)
|
|
||||||
name = "$jsQualifier.$name"
|
|
||||||
|
|
||||||
staticNames.declareStableName(declaration, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else { // Non-external declaration
|
|
||||||
val name = declaration.nameIfPropertyAccessor() ?: declaration.name.asString()
|
|
||||||
staticNames.declareFreshName(declaration, name)
|
|
||||||
val unitReference = unit.referenceCodegenUnitOfDeclaration(declaration)
|
|
||||||
if (unitReference is IrToJs.OtherUnitReference) {
|
|
||||||
registerImport(unitReference.importPath, exportId(declaration))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return JsName(staticNames.names[declaration]!!, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Cache?
|
|
||||||
private fun stableNameForExternalDeclaration(declaration: IrDeclaration): String? {
|
|
||||||
if (declaration !is IrDeclarationWithName ||
|
|
||||||
!declaration.hasStaticDispatch() ||
|
|
||||||
!declaration.isEffectivelyExternal() ||
|
|
||||||
declaration.isPropertyAccessor ||
|
|
||||||
declaration.isPropertyField
|
|
||||||
) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (declaration is IrConstructor) {
|
|
||||||
return stableNameForExternalDeclaration(declaration.parentAsClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
val importedFromModuleOnly =
|
|
||||||
declaration.getJsModule() != null && !declaration.isJsNonModule()
|
|
||||||
|
|
||||||
val jsName = declaration.getJsName()
|
|
||||||
|
|
||||||
val jsQualifier = declaration.fileOrNull?.getJsQualifier()
|
|
||||||
|
|
||||||
return when {
|
|
||||||
importedFromModuleOnly ->
|
|
||||||
null
|
|
||||||
|
|
||||||
jsQualifier != null ->
|
|
||||||
jsQualifier.split('1')[0]
|
|
||||||
|
|
||||||
jsName != null ->
|
|
||||||
jsName
|
|
||||||
|
|
||||||
else ->
|
|
||||||
declaration.name.identifier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ where possible options include:
|
|||||||
-libraries <path> Paths to Kotlin libraries with .meta.js and .kjsm files, separated by system path separator
|
-libraries <path> Paths to Kotlin libraries with .meta.js and .kjsm files, separated by system path separator
|
||||||
-main {call|noCall} Define whether the `main` function should be called upon execution
|
-main {call|noCall} Define whether the `main` function should be called upon execution
|
||||||
-meta-info Generate .meta.js and .kjsm files with metadata. Use to create a library
|
-meta-info Generate .meta.js and .kjsm files with metadata. Use to create a library
|
||||||
-module-kind {plain|amd|commonjs|umd}
|
-module-kind {plain|amd|commonjs|umd|es}
|
||||||
Kind of the JS module generated by the compiler
|
Kind of the JS module generated by the compiler
|
||||||
-no-stdlib Don't automatically include the default Kotlin/JS stdlib into compilation dependencies
|
-no-stdlib Don't automatically include the default Kotlin/JS stdlib into compilation dependencies
|
||||||
-output <filepath> Destination *.js file for the compilation result
|
-output <filepath> Destination *.js file for the compilation result
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ object BinaryArtifacts {
|
|||||||
|
|
||||||
class JsIrArtifact(override val outputFile: File, val compilerResult: CompilerResult, val icCache: Map<String, ByteArray>? = null) : Js()
|
class JsIrArtifact(override val outputFile: File, val compilerResult: CompilerResult, val icCache: Map<String, ByteArray>? = null) : Js()
|
||||||
|
|
||||||
class JsEsArtifact(override val outputFile: File, val outputDceFile: File?) : Js()
|
|
||||||
|
|
||||||
data class IncrementalJsArtifact(val originalArtifact: Js, val recompiledArtifact: Js) : Js() {
|
data class IncrementalJsArtifact(val originalArtifact: Js, val recompiledArtifact: Js) : Js() {
|
||||||
override val outputFile: File
|
override val outputFile: File
|
||||||
get() = unwrap().outputFile
|
get() = unwrap().outputFile
|
||||||
|
|||||||
@@ -1329,15 +1329,27 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitImport(@NotNull JsImport jsImport) {
|
public void visitImport(@NotNull JsImport jsImport) {
|
||||||
p.print("import {");
|
JsImport.Target target = jsImport.getTarget();
|
||||||
boolean isMultiline = jsImport.getElements().size() > 1;
|
|
||||||
|
p.print("import ");
|
||||||
|
|
||||||
|
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();
|
p.indentIn();
|
||||||
if (isMultiline)
|
if (isMultiline)
|
||||||
newlineOpt();
|
newlineOpt();
|
||||||
else
|
else
|
||||||
space();
|
space();
|
||||||
|
|
||||||
for (JsImport.Element element : jsImport.getElements()) {
|
for (JsImport.Element element : elements) {
|
||||||
nameDef(element.getName());
|
nameDef(element.getName());
|
||||||
JsName alias = element.getAlias();
|
JsName alias = element.getAlias();
|
||||||
if (alias != null) {
|
if (alias != null) {
|
||||||
@@ -1348,12 +1360,16 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
if (isMultiline) {
|
if (isMultiline) {
|
||||||
p.print(',');
|
p.print(',');
|
||||||
newlineOpt();
|
newlineOpt();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
space();
|
space();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.indentOut();
|
p.indentOut();
|
||||||
p.print("} from ");
|
p.print("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print(" from ");
|
||||||
p.print(javaScriptString(jsImport.getModule()));
|
p.print(javaScriptString(jsImport.getModule()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,23 @@ package org.jetbrains.kotlin.js.backend.ast
|
|||||||
|
|
||||||
class JsImport(
|
class JsImport(
|
||||||
val module: String,
|
val module: String,
|
||||||
val elements: MutableList<Element> = mutableListOf(),
|
val target: Target,
|
||||||
) : SourceInfoAwareJsNode(), JsStatement {
|
) : 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(
|
class Element(
|
||||||
val name: JsName,
|
val name: JsName,
|
||||||
@@ -25,7 +40,7 @@ class JsImport(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun deepCopy(): JsStatement =
|
override fun deepCopy(): JsStatement =
|
||||||
JsImport(module, elements.map { it }.toMutableList())
|
JsImport(module, target)
|
||||||
|
|
||||||
override fun traverse(v: JsVisitorWithContext, ctx: JsContext<*>) {
|
override fun traverse(v: JsVisitorWithContext, ctx: JsContext<*>) {
|
||||||
v.visit(this, ctx)
|
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 LINE_SEPARATOR = System.getProperty("line.separator")!!
|
||||||
private val END_MARKER = "<END>$LINE_SEPARATOR"
|
private val END_MARKER = "<END>$LINE_SEPARATOR"
|
||||||
|
private val ESM_EXTENSION = ".mjs"
|
||||||
|
|
||||||
abstract class ProcessBasedScriptEngine(
|
abstract class ProcessBasedScriptEngine(
|
||||||
private val executablePath: String
|
private val executablePath: String
|
||||||
@@ -58,6 +59,7 @@ abstract class ProcessBasedScriptEngine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun loadFile(path: String) {
|
override fun loadFile(path: String) {
|
||||||
|
if (path.endsWith(ESM_EXTENSION)) return
|
||||||
eval("load('${path.replace('\\', '/')}');")
|
eval("load('${path.replace('\\', '/')}');")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ function restoreGlobalState() {
|
|||||||
resetRealm();
|
resetRealm();
|
||||||
|
|
||||||
// noinspection InfiniteLoopJS
|
// noinspection InfiniteLoopJS
|
||||||
while (true) {
|
async function loop() {
|
||||||
|
while (true) {
|
||||||
let code = readline().replace(/\\n/g, '\n');
|
let code = readline().replace(/\\n/g, '\n');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -90,7 +91,7 @@ while (true) {
|
|||||||
restoreGlobalState();
|
restoreGlobalState();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print(Realm.eval(currentRealmIndex, code));
|
print(await Realm.eval(currentRealmIndex, code));
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
printErr(e.stack != null ? e.stack : e.toString());
|
printErr(e.stack != null ? e.stack : e.toString());
|
||||||
@@ -98,4 +99,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
print('<END>');
|
print('<END>');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loop()
|
||||||
@@ -23,4 +23,7 @@ object JavaScript {
|
|||||||
|
|
||||||
const val EXTENSION = "js"
|
const val EXTENSION = "js"
|
||||||
const val DOT_EXTENSION = "." + EXTENSION
|
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());
|
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 {
|
private void doJsAntTestForPostfixPrefix(@Nullable String prefix, @Nullable String postfix) throws Exception {
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ class ClassicJsBackendFacade(
|
|||||||
"$KOTLIN_TEST_INTERNAL.setModuleId(\"$escapedModuleId\"); }\n" +
|
"$KOTLIN_TEST_INTERNAL.setModuleId(\"$escapedModuleId\"); }\n" +
|
||||||
"$content\n"
|
"$content\n"
|
||||||
|
|
||||||
ModuleKind.PLAIN -> content
|
ModuleKind.PLAIN, ModuleKind.ES -> content
|
||||||
|
|
||||||
ModuleKind.ES -> error("Module emulation markers are not supported for ES modules")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,36 +12,29 @@ import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDe
|
|||||||
import org.jetbrains.kotlin.cli.common.isWindows
|
import org.jetbrains.kotlin.cli.common.isWindows
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
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.*
|
||||||
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.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.ic.JsExecutableProducer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
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.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformerTmp
|
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.SourceMapsInfo
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
|
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.declarations.impl.IrFactoryImplForJsIC
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
import org.jetbrains.kotlin.ir.util.irMessageLogger
|
import org.jetbrains.kotlin.ir.util.irMessageLogger
|
||||||
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
import org.jetbrains.kotlin.js.test.handlers.JsBoxRunner.Companion.TEST_FUNCTION
|
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.extractTestPackage
|
||||||
import org.jetbrains.kotlin.js.test.utils.jsIrIncrementalDataProvider
|
import org.jetbrains.kotlin.js.test.utils.jsIrIncrementalDataProvider
|
||||||
import org.jetbrains.kotlin.library.uniqueName
|
import org.jetbrains.kotlin.library.uniqueName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
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.serialization.js.ModuleKind
|
||||||
import org.jetbrains.kotlin.test.DebugMode
|
import org.jetbrains.kotlin.test.DebugMode
|
||||||
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
|
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.frontend.classic.moduleDescriptorProvider
|
||||||
import org.jetbrains.kotlin.test.model.*
|
import org.jetbrains.kotlin.test.model.*
|
||||||
import org.jetbrains.kotlin.test.services.*
|
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 org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
const val REGULAR_EXTENSION = ".js"
|
||||||
|
const val ESM_EXTENSION = ".mjs"
|
||||||
|
|
||||||
class JsIrBackendFacade(
|
class JsIrBackendFacade(
|
||||||
val testServices: TestServices,
|
val testServices: TestServices,
|
||||||
private val firstTimeCompilation: Boolean
|
private val firstTimeCompilation: Boolean
|
||||||
@@ -91,16 +87,16 @@ class JsIrBackendFacade(
|
|||||||
else -> JsGenerationGranularity.WHOLE_PROGRAM
|
else -> JsGenerationGranularity.WHOLE_PROGRAM
|
||||||
}
|
}
|
||||||
|
|
||||||
val testPackage = extractTestPackage(testServices)
|
val testPackage = extractTestPackage(testServices, ignoreEsModules = false)
|
||||||
val skipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE in module.directives
|
val skipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE in module.directives
|
||||||
|
|
||||||
if (skipRegularMode) return null
|
if (skipRegularMode) return null
|
||||||
|
|
||||||
if (JsEnvironmentConfigurator.incrementalEnabled(testServices)) {
|
if (JsEnvironmentConfigurator.incrementalEnabled(testServices)) {
|
||||||
val outputFile = if (firstTimeCompilation) {
|
val outputFile = if (firstTimeCompilation) {
|
||||||
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js")
|
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + module.kind.extension)
|
||||||
} else {
|
} else {
|
||||||
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name) + ".js")
|
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name) + module.kind.extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
val compiledModule = CompilerResult(
|
val compiledModule = CompilerResult(
|
||||||
@@ -136,11 +132,12 @@ class JsIrBackendFacade(
|
|||||||
PhaseConfig(jsPhases)
|
PhaseConfig(jsPhases)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val loweredIr = compileIr(
|
val loweredIr = compileIr(
|
||||||
irModuleFragment,
|
irModuleFragment.apply { resolveTestPathes() },
|
||||||
MainModule.Klib(inputArtifact.outputFile.absolutePath),
|
MainModule.Klib(inputArtifact.outputFile.absolutePath),
|
||||||
configuration,
|
configuration,
|
||||||
dependencyModules,
|
dependencyModules.apply { forEach { it.resolveTestPathes() } },
|
||||||
emptyMap(),
|
emptyMap(),
|
||||||
irModuleFragment.irBuiltins,
|
irModuleFragment.irBuiltins,
|
||||||
symbolTable,
|
symbolTable,
|
||||||
@@ -164,22 +161,27 @@ class JsIrBackendFacade(
|
|||||||
module: TestModule,
|
module: TestModule,
|
||||||
loweredIr: LoweredIr,
|
loweredIr: LoweredIr,
|
||||||
granularity: JsGenerationGranularity,
|
granularity: JsGenerationGranularity,
|
||||||
): BinaryArtifacts.Js? {
|
): BinaryArtifacts.Js {
|
||||||
val generateDts = JsEnvironmentConfigurationDirectives.GENERATE_DTS in module.directives
|
|
||||||
val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module)
|
val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module)
|
||||||
.run { if (shouldBeGenerated()) arguments() else null }
|
.run { if (shouldBeGenerated()) arguments() else null }
|
||||||
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives
|
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives
|
||||||
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_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 runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
||||||
val perModuleOnly = JsEnvironmentConfigurationDirectives.SPLIT_PER_MODULE 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) + module.kind.extension)
|
||||||
|
|
||||||
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) {
|
if (runNewIr2Js) {
|
||||||
val transformer = IrModuleToJsTransformerTmp(loweredIr.context, mainArguments)
|
val transformer = IrModuleToJsTransformerTmp(
|
||||||
|
loweredIr.context,
|
||||||
|
mainArguments,
|
||||||
|
moduleToName = JsIrModuleToPath(
|
||||||
|
testServices,
|
||||||
|
isEsModules && granularity != JsGenerationGranularity.WHOLE_PROGRAM
|
||||||
|
)
|
||||||
|
)
|
||||||
// If runIrDce then include DCE results
|
// If runIrDce then include DCE results
|
||||||
// If perModuleOnly then skip whole program
|
// If perModuleOnly then skip whole program
|
||||||
// (it.dce => runIrDce) && (perModuleOnly => it.perModule)
|
// (it.dce => runIrDce) && (perModuleOnly => it.perModule)
|
||||||
@@ -203,15 +205,10 @@ class JsIrBackendFacade(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val options = JsGenerationOptions(generatePackageJson = true, generateTypeScriptDefinitions = generateDts)
|
private fun IrModuleFragment.resolveTestPathes() {
|
||||||
generateEsModules(loweredIr, jsOutputSink(outputFile.parentFile.esModulesSubDir), mainArguments, granularity, options)
|
JsIrPathReplacer(testServices).let {
|
||||||
|
files.forEach(it::lower)
|
||||||
if (runIrDce) {
|
|
||||||
eliminateDeadDeclarations(loweredIr.allModules, loweredIr.context)
|
|
||||||
generateEsModules(loweredIr, jsOutputSink(dceOutputFile.parentFile.esModulesSubDir), mainArguments, granularity, options)
|
|
||||||
return BinaryArtifacts.Js.JsEsArtifact(outputFile, dceOutputFile).dump(module)
|
|
||||||
}
|
}
|
||||||
return BinaryArtifacts.Js.JsEsArtifact(outputFile, null).dump(module)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadIrFromKlib(module: TestModule, configuration: CompilerConfiguration): IrModuleInfo {
|
private fun loadIrFromKlib(module: TestModule, configuration: CompilerConfiguration): IrModuleInfo {
|
||||||
@@ -238,55 +235,10 @@ class JsIrBackendFacade(
|
|||||||
) { if (it == mainModuleLib) moduleDescriptor else testServices.jsLibraryProvider.getDescriptorByCompiledLibrary(it) }
|
) { if (it == mainModuleLib) moduleDescriptor else testServices.jsLibraryProvider.getDescriptorByCompiledLibrary(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadIrFromSources(
|
private fun BinaryArtifacts.Js.JsIrArtifact.dump(
|
||||||
module: TestModule,
|
module: TestModule,
|
||||||
configuration: CompilerConfiguration,
|
firstTimeCompilation: Boolean = true
|
||||||
inputArtifact: ClassicFrontendOutputArtifact
|
): BinaryArtifacts.Js.JsIrArtifact {
|
||||||
): 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 {
|
|
||||||
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
|
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
|
||||||
val moduleId = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
val moduleId = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
||||||
val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||||
@@ -297,9 +249,15 @@ class JsIrBackendFacade(
|
|||||||
if (dontSkipRegularMode) {
|
if (dontSkipRegularMode) {
|
||||||
for ((mode, output) in compilerResult.outputs.entries) {
|
for ((mode, output) in compilerResult.outputs.entries) {
|
||||||
val outputFile = if (firstTimeCompilation) {
|
val outputFile = if (firstTimeCompilation) {
|
||||||
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, mode) + ".js")
|
File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name, mode) + moduleKind.extension)
|
||||||
} else {
|
} else {
|
||||||
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name, mode) + ".js")
|
File(
|
||||||
|
JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(
|
||||||
|
testServices,
|
||||||
|
module.name,
|
||||||
|
mode
|
||||||
|
) + moduleKind.extension
|
||||||
|
)
|
||||||
}
|
}
|
||||||
output.writeTo(outputFile, moduleId, moduleKind)
|
output.writeTo(outputFile, moduleId, moduleKind)
|
||||||
}
|
}
|
||||||
@@ -307,24 +265,13 @@ class JsIrBackendFacade(
|
|||||||
|
|
||||||
if (generateDts) {
|
if (generateDts) {
|
||||||
outputFile
|
outputFile
|
||||||
.withReplacedExtensionOrNull("_v5.js", ".d.ts")!!
|
.withReplacedExtensionOrNull("_v5${moduleKind.extension}", ".d.ts")!!
|
||||||
.write(compilerResult.tsDefinitions ?: error("No ts definitions"))
|
.write(compilerResult.tsDefinitions ?: error("No ts definitions"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return this
|
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) {
|
private fun CompilationOutputs.writeTo(outputFile: File, moduleId: String, moduleKind: ModuleKind) {
|
||||||
val wrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, moduleId = moduleId, moduleKind = moduleKind)
|
val wrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, moduleId = moduleId, moduleKind = moduleKind)
|
||||||
outputFile.write(wrappedCode)
|
outputFile.write(wrappedCode)
|
||||||
@@ -344,32 +291,37 @@ class JsIrBackendFacade(
|
|||||||
writeText(text)
|
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 {
|
override fun shouldRunAnalysis(module: TestModule): Boolean {
|
||||||
return JsEnvironmentConfigurator.isMainModule(module, testServices)
|
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 {
|
fun String.augmentWithModuleName(moduleName: String): String {
|
||||||
check(endsWith("_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 }
|
val normalizedName = moduleName.run { if (isWindows) minify() else this }
|
||||||
return removeSuffix("_v5.js") + "-${normalizedName}_v5.js"
|
|
||||||
|
return removeSuffix("_v5$suffix") + "-${normalizedName}_v5$suffix"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// D8 ignores Windows settings related to extending of maximum path symbols count
|
// 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")
|
.replace("_minimal_for_test", "_min")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.isPath(): Boolean = contains("/")
|
||||||
|
|
||||||
fun File.augmentWithModuleName(moduleName: String): File = File(absolutePath.augmentWithModuleName(moduleName))
|
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
|
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.js.test.utils.*
|
||||||
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
|
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
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.defaultsProvider
|
||||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
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) {
|
class JsBoxRunner(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
|
||||||
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||||
if (someAssertionWasFailed) return
|
if (!someAssertionWasFailed) {
|
||||||
|
|
||||||
if (JsEnvironmentConfigurationDirectives.ES_MODULES in testServices.moduleStructure.allDirectives) {
|
|
||||||
runEsCode()
|
|
||||||
} else {
|
|
||||||
runJsCode()
|
runJsCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,37 +33,30 @@ class JsBoxRunner(testServices: TestServices) : AbstractJsArtifactsCollector(tes
|
|||||||
|
|
||||||
val dontSkipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE !in globalDirectives
|
val dontSkipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE !in globalDirectives
|
||||||
if (dontSkipRegularMode) {
|
if (dontSkipRegularMode) {
|
||||||
for (jsFiles in allJsFiles.values) {
|
for ((mode, jsFiles) in allJsFiles) {
|
||||||
runGeneratedCode(jsFiles, testModuleName, testPackage, withModuleSystem)
|
val entryModulePath = extractEntryModulePath(mode, testServices)
|
||||||
|
runGeneratedCode(entryModulePath, jsFiles, testModuleName, testPackage, withModuleSystem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runEsCode() {
|
private fun runGeneratedCode(
|
||||||
val globalDirectives = testServices.moduleStructure.allDirectives
|
entryModulePath: String?,
|
||||||
|
jsFiles: List<String>,
|
||||||
val esmOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).esModulesSubDir
|
testModuleName: String?,
|
||||||
val esmDceOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, TranslationMode.FULL_DCE_MINIMIZED_NAMES).esModulesSubDir
|
testPackage: String?,
|
||||||
|
withModuleSystem: Boolean
|
||||||
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) {
|
|
||||||
getTestChecker(testServices)
|
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 {
|
companion object {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class JsDtsHandler(testServices: TestServices) : JsBinaryArtifactHandler(testSer
|
|||||||
val referenceDtsFile = module.files.first().originalFile.withReplacedExtensionOrNull(".kt", ".d.ts")
|
val referenceDtsFile = module.files.first().originalFile.withReplacedExtensionOrNull(".kt", ".d.ts")
|
||||||
?: error("Can't find reference .d.ts file")
|
?: error("Can't find reference .d.ts file")
|
||||||
val generatedDtsFile = info.outputFile.withReplacedExtensionOrNull("_v5.js", ".d.ts")
|
val generatedDtsFile = info.outputFile.withReplacedExtensionOrNull("_v5.js", ".d.ts")
|
||||||
|
?: info.outputFile.withReplacedExtensionOrNull("_v5.mjs", ".d.ts")
|
||||||
?: error("Can't find generated .d.ts file")
|
?: error("Can't find generated .d.ts file")
|
||||||
|
|
||||||
val generatedDts = generatedDtsFile.readText()
|
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.config.JSConfigurationKeys
|
||||||
import org.jetbrains.kotlin.js.test.JsAdditionalSourceProvider
|
import org.jetbrains.kotlin.js.test.JsAdditionalSourceProvider
|
||||||
import org.jetbrains.kotlin.js.test.converters.augmentWithModuleName
|
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.test.handlers.JsBoxRunner.Companion.TEST_FUNCTION
|
||||||
import org.jetbrains.kotlin.js.testOld.*
|
import org.jetbrains.kotlin.js.testOld.*
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
import org.jetbrains.kotlin.test.TargetBackend
|
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"
|
private const val MODULE_EMULATION_FILE = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/moduleEmulation.js"
|
||||||
|
|
||||||
val File.esModulesSubDir: File
|
fun TestModule.getNameFor(filePath: String, testServices: TestServices): String {
|
||||||
get() = File(absolutePath + "_esm")
|
return JsEnvironmentConfigurator.getJsArtifactSimpleName(testServices, name) + "-js-" + filePath
|
||||||
|
}
|
||||||
|
|
||||||
private fun extractJsFiles(testServices: TestServices, modules: List<TestModule>): Pair<List<String>, List<String>> {
|
fun TestModule.getNameFor(file: TestFile, testServices: TestServices): String {
|
||||||
val outputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices)
|
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 {
|
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)
|
val targetFile = File(outputDir, newName)
|
||||||
targetFile.writeText(inputJsFile.originalContent)
|
targetFile.writeText(inputJsFile.originalContent)
|
||||||
return targetFile.absolutePath
|
return targetFile.absolutePath
|
||||||
@@ -45,49 +55,74 @@ private fun extractJsFiles(testServices: TestServices, modules: List<TestModule>
|
|||||||
|
|
||||||
val inputJsFiles = modules
|
val inputJsFiles = modules
|
||||||
.flatMap { module -> module.files.map { module to it } }
|
.flatMap { module -> module.files.map { module to it } }
|
||||||
.filter { it.second.isJsFile }
|
.filter { it.second.isJsFile || it.second.isMjsFile }
|
||||||
|
|
||||||
|
|
||||||
val after = inputJsFiles
|
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) }
|
.map { (module, inputJsFile) -> copyInputJsFile(module, inputJsFile) }
|
||||||
val before = inputJsFiles
|
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) }
|
.map { (module, inputJsFile) -> copyInputJsFile(module, inputJsFile) }
|
||||||
|
|
||||||
return before to after
|
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 originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||||
|
|
||||||
val withModuleSystem = testWithModuleSystem(testServices)
|
val withModuleSystem = testWithModuleSystem(testServices)
|
||||||
|
|
||||||
val additionalFiles = mutableListOf<String>()
|
val additionalFiles = mutableListOf<File>()
|
||||||
if (withModuleSystem) additionalFiles += File(MODULE_EMULATION_FILE).absolutePath
|
if (withModuleSystem) additionalFiles += File(MODULE_EMULATION_FILE)
|
||||||
|
|
||||||
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + JavaScript.DOT_EXTENSION)
|
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + JavaScript.DOT_EXTENSION)
|
||||||
.takeIf { it.exists() }
|
.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
|
return additionalFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAdditionalMjsFiles(testServices: TestServices): List<String> {
|
fun getAdditionalMainFilePathes(testServices: TestServices, mode: TranslationMode = TranslationMode.FULL): List<String> {
|
||||||
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
return getAdditionalMainFiles(testServices, mode, shouldCopyFiles = true).map { it.absolutePath }
|
||||||
|
|
||||||
return originalFile.parentFile.resolve(originalFile.nameWithoutExtension + ".mjs")
|
|
||||||
.takeIf { it.exists() }
|
|
||||||
?.let { listOf(it.absolutePath) } ?: emptyList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||||
val additionalFiles = mutableListOf<String>()
|
val additionalFiles = mutableListOf<File>()
|
||||||
|
|
||||||
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + "__main.js")
|
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + "__main.js")
|
||||||
.takeIf { it.exists() }
|
.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
|
return additionalFiles
|
||||||
}
|
}
|
||||||
@@ -99,26 +134,31 @@ fun testWithModuleSystem(testServices: TestServices): Boolean {
|
|||||||
return mainModuleKind != ModuleKind.PLAIN && NO_JS_MODULE_SYSTEM !in globalDirectives
|
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(
|
fun getAllFilesForRunner(
|
||||||
testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>
|
testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>
|
||||||
): Map<TranslationMode, List<String>> {
|
): Map<TranslationMode, List<String>> {
|
||||||
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
|
||||||
|
|
||||||
val commonFiles = JsAdditionalSourceProvider.getAdditionalJsFiles(originalFile.parent).map { it.absolutePath }
|
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 }) {
|
if (modulesToArtifact.values.any { it is BinaryArtifacts.Js.JsIrArtifact }) {
|
||||||
// JS IR
|
// 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>>()
|
val result = mutableMapOf<TranslationMode, List<String>>()
|
||||||
|
|
||||||
compilerResult.outputs.entries.forEach { (mode, outputs) ->
|
compilerResult.outputs.entries.forEach { (mode, outputs) ->
|
||||||
val paths = mutableListOf<String>()
|
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, _) ->
|
outputs.dependencies.forEach { (moduleId, _) ->
|
||||||
paths += outputFile.augmentWithModuleName(moduleId)
|
paths += outputFile.augmentWithModuleName(moduleId)
|
||||||
}
|
}
|
||||||
@@ -129,12 +169,15 @@ fun getAllFilesForRunner(
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
} else {
|
} 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 outputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices)
|
||||||
val dceOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, TranslationMode.FULL_DCE_MINIMIZED_NAMES)
|
val dceOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices, TranslationMode.FULL_DCE_MINIMIZED_NAMES)
|
||||||
|
|
||||||
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }.filter { !File(it).isDirectory }
|
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>>()
|
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> {
|
fun getOnlyJsFilesForRunner(testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>): List<String> {
|
||||||
return getAllFilesForRunner(testServices, modulesToArtifact).let {
|
return getAllFilesForRunner(testServices, modulesToArtifact).let {
|
||||||
it[TranslationMode.FULL] ?: it[TranslationMode.PER_MODULE]!!
|
it[TranslationMode.FULL] ?: it[TranslationMode.PER_MODULE]!!
|
||||||
@@ -215,8 +226,49 @@ fun getBoxFunction(testServices: TestServices): KtNamedFunction? {
|
|||||||
}.singleOrNull()
|
}.singleOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun extractTestPackage(testServices: TestServices): String? =
|
fun extractTestPackage(testServices: TestServices, ignoreEsModules: Boolean = true): String? {
|
||||||
getBoxFunction(testServices)?.containingKtFile?.packageFqName?.asString()?.takeIf { it.isNotEmpty() }
|
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 {
|
fun getTestChecker(testServices: TestServices): AbstractJsTestChecker {
|
||||||
val runTestInNashorn = java.lang.Boolean.getBoolean("kotlin.js.useNashorn")
|
val runTestInNashorn = java.lang.Boolean.getBoolean("kotlin.js.useNashorn")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.js.engine.loadFiles
|
|||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
|
|
||||||
private const val DIST_DIR_JS_PATH = "dist/js/"
|
private const val DIST_DIR_JS_PATH = "dist/js/"
|
||||||
|
private const val ESM_EXTENSION = ".mjs"
|
||||||
|
|
||||||
fun createScriptEngine(): ScriptEngine {
|
fun createScriptEngine(): ScriptEngine {
|
||||||
return if (java.lang.Boolean.getBoolean("kotlin.js.useNashorn")) ScriptEngineNashorn() else ScriptEngineV8()
|
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);")
|
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(
|
fun ScriptEngine.runTestFunction(
|
||||||
testModuleName: String?,
|
testModuleName: String?,
|
||||||
testPackageName: String?,
|
testPackageName: String?,
|
||||||
testFunctionName: String,
|
testFunctionName: String,
|
||||||
withModuleSystem: Boolean,
|
withModuleSystem: Boolean,
|
||||||
testFunctionArgs: String = "",
|
testFunctionArgs: String = "",
|
||||||
|
entryModulePath: String? = null,
|
||||||
): String {
|
): 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 {
|
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!! + "')"
|
withModuleSystem -> "\$kotlin_test_internal\$.require('" + testModuleName!! + "')"
|
||||||
testModuleName === null -> "this"
|
testModuleName === null -> "this"
|
||||||
else -> testModuleName
|
else -> testModuleName
|
||||||
@@ -51,9 +64,10 @@ abstract class AbstractJsTestChecker {
|
|||||||
testPackageName: String?,
|
testPackageName: String?,
|
||||||
testFunctionName: String,
|
testFunctionName: String,
|
||||||
expectedResult: 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())
|
Assert.assertEquals(expectedResult, actualResult.normalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,9 +90,10 @@ abstract class AbstractJsTestChecker {
|
|||||||
testPackageName: String?,
|
testPackageName: String?,
|
||||||
testFunctionName: String,
|
testFunctionName: String,
|
||||||
testFunctionArgs: String,
|
testFunctionArgs: String,
|
||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean,
|
||||||
|
entryModulePath: String? = null,
|
||||||
) = run(files) {
|
) = 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 {
|
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);
|
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
|
@Nested
|
||||||
|
|||||||
+138
@@ -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);
|
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
|
@Test
|
||||||
@TestMetadata("exportAllFile.kt")
|
@TestMetadata("exportAllFile.kt")
|
||||||
public void testExportAllFile() throws Exception {
|
public void testExportAllFile() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/exportAllFile.kt");
|
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
|
@Test
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/nonIndetifierModuleName.kt");
|
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
|
@Test
|
||||||
@TestMetadata("overriddenChainNonExportIntermediate.kt")
|
@TestMetadata("overriddenChainNonExportIntermediate.kt")
|
||||||
public void testOverriddenChainNonExportIntermediate() throws Exception {
|
public void testOverriddenChainNonExportIntermediate() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/overriddenChainNonExportIntermediate.kt");
|
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
|
@Test
|
||||||
@TestMetadata("overriddenExternalMethodWithSameNameMethod.kt")
|
@TestMetadata("overriddenExternalMethodWithSameNameMethod.kt")
|
||||||
public void testOverriddenExternalMethodWithSameNameMethod() throws Exception {
|
public void testOverriddenExternalMethodWithSameNameMethod() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameNameMethod.kt");
|
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
|
@Test
|
||||||
@TestMetadata("reservedModuleName.kt")
|
@TestMetadata("reservedModuleName.kt")
|
||||||
public void testReservedModuleName() throws Exception {
|
public void testReservedModuleName() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/reservedModuleName.kt");
|
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
|
@Nested
|
||||||
|
|||||||
+138
@@ -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);
|
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
|
@Test
|
||||||
@TestMetadata("exportAllFile.kt")
|
@TestMetadata("exportAllFile.kt")
|
||||||
public void testExportAllFile() throws Exception {
|
public void testExportAllFile() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/exportAllFile.kt");
|
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
|
@Test
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/nonIndetifierModuleName.kt");
|
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
|
@Test
|
||||||
@TestMetadata("overriddenChainNonExportIntermediate.kt")
|
@TestMetadata("overriddenChainNonExportIntermediate.kt")
|
||||||
public void testOverriddenChainNonExportIntermediate() throws Exception {
|
public void testOverriddenChainNonExportIntermediate() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/overriddenChainNonExportIntermediate.kt");
|
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
|
@Test
|
||||||
@TestMetadata("overriddenExternalMethodWithSameNameMethod.kt")
|
@TestMetadata("overriddenExternalMethodWithSameNameMethod.kt")
|
||||||
public void testOverriddenExternalMethodWithSameNameMethod() throws Exception {
|
public void testOverriddenExternalMethodWithSameNameMethod() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/overriddenExternalMethodWithSameNameMethod.kt");
|
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
|
@Test
|
||||||
@TestMetadata("reservedModuleName.kt")
|
@TestMetadata("reservedModuleName.kt")
|
||||||
public void testReservedModuleName() throws Exception {
|
public void testReservedModuleName() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/esModules/export/reservedModuleName.kt");
|
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
|
@Nested
|
||||||
|
|||||||
Generated
+12
@@ -456,6 +456,12 @@ public class IrJsTypeScriptExportTestGenerated extends AbstractIrJsTypeScriptExp
|
|||||||
runTest("js/js.translator/testData/typescript-export/module-systems/commonjs.kt");
|
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
|
@Test
|
||||||
@TestMetadata("plain.kt")
|
@TestMetadata("plain.kt")
|
||||||
public void testPlain() throws Exception {
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("plain.kt")
|
@TestMetadata("plain.kt")
|
||||||
public void testPlain() throws Exception {
|
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"
|
||||||
|
}
|
||||||
+30
@@ -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"
|
||||||
|
}
|
||||||
+22
@@ -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;
|
||||||
|
}
|
||||||
Vendored
+24
@@ -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
|
// DONT_TARGET_EXACT_BACKEND: JS
|
||||||
// EXPECTED_REACHABLE_NODES: 1252
|
// EXPECTED_REACHABLE_NODES: 1252
|
||||||
// INFER_MAIN_MODULE
|
|
||||||
// ES_MODULES
|
// ES_MODULES
|
||||||
|
|
||||||
// MODULE: export_all_file
|
// MODULE: export_all_file
|
||||||
@@ -19,5 +18,9 @@ class B : A() {
|
|||||||
|
|
||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// 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';
|
||||||
|
}
|
||||||
+69
@@ -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';
|
||||||
|
}
|
||||||
+58
@@ -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
|
// DONT_TARGET_EXACT_BACKEND: JS
|
||||||
// SKIP_MINIFICATION
|
// SKIP_MINIFICATION
|
||||||
// INFER_MAIN_MODULE
|
|
||||||
// SKIP_NODE_JS
|
// SKIP_NODE_JS
|
||||||
// ES_MODULES
|
// ES_MODULES
|
||||||
|
|
||||||
// MODULE: non_identifier_module_name
|
// MODULE: lib
|
||||||
// FILE: lib.kt
|
// FILE: lib.kt
|
||||||
@JsName("foo")
|
@JsName("foo")
|
||||||
@JsExport
|
@JsExport
|
||||||
@@ -12,5 +11,8 @@ public fun foo(k: String): String = "O$k"
|
|||||||
|
|
||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// ENTRY_ES_MODULE
|
||||||
import { foo } from "./non_identifier_module_name/index.js";
|
import { foo } from "./nonIndetifierModuleName-lib_v5.mjs";
|
||||||
console.assert(foo("K") == "OK");
|
|
||||||
|
export function box() {
|
||||||
|
return foo("K")
|
||||||
|
}
|
||||||
|
|||||||
+21
@@ -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")
|
||||||
|
}
|
||||||
+13
-7
@@ -1,6 +1,5 @@
|
|||||||
// DONT_TARGET_EXACT_BACKEND: JS
|
// DONT_TARGET_EXACT_BACKEND: JS
|
||||||
// EXPECTED_REACHABLE_NODES: 1252
|
// EXPECTED_REACHABLE_NODES: 1252
|
||||||
// INFER_MAIN_MODULE
|
|
||||||
|
|
||||||
// ES_MODULES
|
// ES_MODULES
|
||||||
// MODULE: overriden_chain_non_export_intermediate
|
// MODULE: overriden_chain_non_export_intermediate
|
||||||
@@ -28,12 +27,19 @@ class C : B() {
|
|||||||
|
|
||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// 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) {
|
export function box() {
|
||||||
if (c.foo() === "foo" && c.bar() === "bar" && c.bay() == "bay") return "OK"
|
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}`
|
||||||
|
|
||||||
|
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
console.assert(test(new C()) == "OK");
|
|
||||||
js/js.translator/testData/box/esModules/export/overriddenChainNonExportIntermediateInExportedFile.kt
Vendored
+39
@@ -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"
|
||||||
|
}
|
||||||
Vendored
+4
-6
@@ -1,9 +1,8 @@
|
|||||||
// EXPECTED_REACHABLE_NODES: 1252
|
// EXPECTED_REACHABLE_NODES: 1252
|
||||||
// INFER_MAIN_MODULE
|
|
||||||
// DONT_TARGET_EXACT_BACKEND: JS
|
// DONT_TARGET_EXACT_BACKEND: JS
|
||||||
// ES_MODULES
|
// ES_MODULES
|
||||||
|
|
||||||
// MODULE: overriden_external_method_with_same_name_method
|
// MODULE: lib
|
||||||
// FILE: lib.kt
|
// FILE: lib.kt
|
||||||
external abstract class Foo {
|
external abstract class Foo {
|
||||||
abstract fun o(): String
|
abstract fun o(): String
|
||||||
@@ -32,10 +31,9 @@ Foo.prototype.k = function() {
|
|||||||
|
|
||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// 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()
|
return foo.o() + foo.k()
|
||||||
}
|
}
|
||||||
|
|
||||||
console.assert(test(new Baz()) == "OK");
|
|
||||||
Vendored
+5
-10
@@ -1,12 +1,8 @@
|
|||||||
// EXPECTED_REACHABLE_NODES: 1252
|
// EXPECTED_REACHABLE_NODES: 1252
|
||||||
// IGNORE_BACKEND: JS
|
// DONT_TARGET_EXACT_BACKEND: JS
|
||||||
// INFER_MAIN_MODULE
|
|
||||||
// ES_MODULES
|
// ES_MODULES
|
||||||
|
|
||||||
// TODO: Fix tests on Windows
|
// MODULE: lib
|
||||||
// DONT_TARGET_EXACT_BACKEND: JS_IR
|
|
||||||
|
|
||||||
// MODULE: overriden_external_method_with_same_stable_name_method
|
|
||||||
// FILE: lib.kt
|
// FILE: lib.kt
|
||||||
external abstract class Foo {
|
external abstract class Foo {
|
||||||
abstract fun o(): String
|
abstract fun o(): String
|
||||||
@@ -36,12 +32,11 @@ Foo.prototype.k = function() {
|
|||||||
|
|
||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// 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")
|
const oStable = foo.oStable("OK")
|
||||||
if (oStable !== "OK") return "false: " + oStable
|
if (oStable !== "OK") return "false: " + oStable
|
||||||
return foo.o() + foo.k()
|
return foo.o() + foo.k()
|
||||||
}
|
}
|
||||||
|
|
||||||
console.assert(test(new Baz()) == "OK");
|
|
||||||
+49
@@ -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
|
// EXPECTED_REACHABLE_NODES: 1270
|
||||||
// SKIP_MINIFICATION
|
// SKIP_MINIFICATION
|
||||||
// INFER_MAIN_MODULE
|
|
||||||
// ES_MODULES
|
// ES_MODULES
|
||||||
|
|
||||||
// MODULE: if
|
// MODULE: if
|
||||||
@@ -12,6 +11,8 @@ public fun foo(k: String): String = "O$k"
|
|||||||
|
|
||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// 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")
|
||||||
|
}
|
||||||
+19
@@ -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)])
|
||||||
|
}
|
||||||
+4
-2
@@ -30,6 +30,8 @@ fun testOk(ok: Any): String {
|
|||||||
|
|
||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// 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 "Fail6: ${res.component2}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Point } from "./main/index.js";
|
import { Point } from "./dataClass_v5.mjs";
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
var p = new Point(3, 7);
|
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() {
|
export default function() {
|
||||||
var ping = api.ping;
|
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() {
|
export default function() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ping, Something } from "./main/index.js"
|
import { ping, Something } from "./recursiveExport_v5.mjs"
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ open class B {
|
|||||||
// FILE: entry.mjs
|
// FILE: entry.mjs
|
||||||
// ENTRY_ES_MODULE
|
// ENTRY_ES_MODULE
|
||||||
|
|
||||||
import { A, B } from "./main/index.js";
|
import { A, B } from "./inheritanceInNativeClass_v5.mjs";
|
||||||
|
|
||||||
function createA() {
|
function createA() {
|
||||||
function ADerived() {
|
function ADerived() {
|
||||||
@@ -46,7 +46,7 @@ function createB() {
|
|||||||
return new BDerived();
|
return new BDerived();
|
||||||
}
|
}
|
||||||
|
|
||||||
function box() {
|
export function box() {
|
||||||
let a = createA();
|
let a = createA();
|
||||||
if (a.bar(0) != 124) return "fail1";
|
if (a.bar(0) != 124) return "fail1";
|
||||||
|
|
||||||
@@ -55,5 +55,3 @@ function box() {
|
|||||||
|
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
console.assert(box() == "OK");
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
export namespace foo {
|
export declare namespace foo {
|
||||||
const prop: number;
|
const prop: number;
|
||||||
class C {
|
class C {
|
||||||
constructor(x: number);
|
constructor(x: number);
|
||||||
|
|||||||
+33
@@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
+40
@@ -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
-1
@@ -1,5 +1,5 @@
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
export namespace foo {
|
export declare namespace foo {
|
||||||
const prop: number;
|
const prop: number;
|
||||||
class C {
|
class C {
|
||||||
constructor(x: number);
|
constructor(x: number);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
export namespace foo {
|
export declare namespace foo {
|
||||||
const prop: number;
|
const prop: number;
|
||||||
class C {
|
class C {
|
||||||
constructor(x: number);
|
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
|
type Nullable<T> = T | null | undefined
|
||||||
export namespace foo {
|
export declare namespace foo {
|
||||||
const prop: number;
|
const prop: number;
|
||||||
class C {
|
class C {
|
||||||
constructor(x: number);
|
constructor(x: number);
|
||||||
|
|||||||
+6
@@ -8,6 +8,12 @@ declare namespace JS_TESTS {
|
|||||||
foo(): number;
|
foo(): number;
|
||||||
};
|
};
|
||||||
function takesO(o: typeof foo.O): number;
|
function takesO(o: typeof foo.O): number;
|
||||||
|
const WithSimpleObjectInside: {
|
||||||
|
get value(): string;
|
||||||
|
get SimpleObject(): {
|
||||||
|
get value(): string;
|
||||||
|
};
|
||||||
|
};
|
||||||
abstract class Parent {
|
abstract class Parent {
|
||||||
private constructor();
|
private constructor();
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -26,6 +26,14 @@ fun takesO(o: O): Int =
|
|||||||
O.x + O.foo()
|
O.x + O.foo()
|
||||||
|
|
||||||
|
|
||||||
|
object WithSimpleObjectInside {
|
||||||
|
val value: String = "WithSimpleObjectInside"
|
||||||
|
object SimpleObject {
|
||||||
|
val value: String = "SimpleObject"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
object Parent {
|
object Parent {
|
||||||
object Nested1 {
|
object Nested1 {
|
||||||
val value: String = "Nested1"
|
val value: String = "Nested1"
|
||||||
|
|||||||
+3
@@ -7,6 +7,7 @@ var getParent = JS_TESTS.foo.getParent;
|
|||||||
var createNested1 = JS_TESTS.foo.createNested1;
|
var createNested1 = JS_TESTS.foo.createNested1;
|
||||||
var createNested2 = JS_TESTS.foo.createNested2;
|
var createNested2 = JS_TESTS.foo.createNested2;
|
||||||
var createNested3 = JS_TESTS.foo.createNested3;
|
var createNested3 = JS_TESTS.foo.createNested3;
|
||||||
|
var WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
|
||||||
function assert(condition) {
|
function assert(condition) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw "Assertion failed";
|
throw "Assertion failed";
|
||||||
@@ -27,5 +28,7 @@ function box() {
|
|||||||
assert(createNested1() === nested1);
|
assert(createNested1() === nested1);
|
||||||
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2);
|
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2);
|
||||||
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3);
|
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3);
|
||||||
|
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
|
||||||
|
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -6,6 +6,7 @@ import getParent = JS_TESTS.foo.getParent;
|
|||||||
import createNested1 = JS_TESTS.foo.createNested1;
|
import createNested1 = JS_TESTS.foo.createNested1;
|
||||||
import createNested2 = JS_TESTS.foo.createNested2;
|
import createNested2 = JS_TESTS.foo.createNested2;
|
||||||
import createNested3 = JS_TESTS.foo.createNested3;
|
import createNested3 = JS_TESTS.foo.createNested3;
|
||||||
|
import WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
|
||||||
|
|
||||||
function assert(condition: boolean) {
|
function assert(condition: boolean) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
@@ -30,5 +31,8 @@ function box(): string {
|
|||||||
assert(createNested1() === nested1)
|
assert(createNested1() === nested1)
|
||||||
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2)
|
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2)
|
||||||
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3)
|
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3)
|
||||||
|
|
||||||
|
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
|
||||||
|
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,12 @@ declare namespace JS_TESTS {
|
|||||||
foo(): number;
|
foo(): number;
|
||||||
};
|
};
|
||||||
function takesO(o: typeof foo.O): number;
|
function takesO(o: typeof foo.O): number;
|
||||||
|
const WithSimpleObjectInside: {
|
||||||
|
get value(): string;
|
||||||
|
get SimpleObject(): {
|
||||||
|
get value(): string;
|
||||||
|
};
|
||||||
|
};
|
||||||
abstract class Parent {
|
abstract class Parent {
|
||||||
private constructor();
|
private constructor();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ object O {
|
|||||||
fun takesO(o: O): Int =
|
fun takesO(o: O): Int =
|
||||||
O.x + O.foo()
|
O.x + O.foo()
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
object WithSimpleObjectInside {
|
||||||
|
val value: String = "WithSimpleObjectInside"
|
||||||
|
object SimpleObject {
|
||||||
|
val value: String = "SimpleObject"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
object Parent {
|
object Parent {
|
||||||
object Nested1 {
|
object Nested1 {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ var getParent = JS_TESTS.foo.getParent;
|
|||||||
var createNested1 = JS_TESTS.foo.createNested1;
|
var createNested1 = JS_TESTS.foo.createNested1;
|
||||||
var createNested2 = JS_TESTS.foo.createNested2;
|
var createNested2 = JS_TESTS.foo.createNested2;
|
||||||
var createNested3 = JS_TESTS.foo.createNested3;
|
var createNested3 = JS_TESTS.foo.createNested3;
|
||||||
|
var WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
|
||||||
function assert(condition) {
|
function assert(condition) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw "Assertion failed";
|
throw "Assertion failed";
|
||||||
@@ -27,5 +28,7 @@ function box() {
|
|||||||
assert(createNested1() === nested1);
|
assert(createNested1() === nested1);
|
||||||
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2);
|
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2);
|
||||||
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3);
|
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3);
|
||||||
|
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
|
||||||
|
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import getParent = JS_TESTS.foo.getParent;
|
|||||||
import createNested1 = JS_TESTS.foo.createNested1;
|
import createNested1 = JS_TESTS.foo.createNested1;
|
||||||
import createNested2 = JS_TESTS.foo.createNested2;
|
import createNested2 = JS_TESTS.foo.createNested2;
|
||||||
import createNested3 = JS_TESTS.foo.createNested3;
|
import createNested3 = JS_TESTS.foo.createNested3;
|
||||||
|
import WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside;
|
||||||
|
|
||||||
function assert(condition: boolean) {
|
function assert(condition: boolean) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
@@ -30,5 +31,8 @@ function box(): string {
|
|||||||
assert(createNested1() === nested1)
|
assert(createNested1() === nested1)
|
||||||
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2)
|
assert(createNested2() !== nested2 && createNested2() instanceof Parent.Nested1.Nested2)
|
||||||
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3)
|
assert(createNested3() !== nested3 && createNested3() instanceof Parent.Nested1.Nested2.Companion.Nested3)
|
||||||
|
|
||||||
|
assert(WithSimpleObjectInside.value === "WithSimpleObjectInside");
|
||||||
|
assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject");
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
+4
@@ -183,4 +183,8 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun useEsModules() {
|
||||||
|
error("ES modules are not supported in legacy JS compiler. Please, use IR one instead.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
@@ -53,6 +53,7 @@ interface KotlinJsTargetDsl : KotlinTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun useCommonJs()
|
fun useCommonJs()
|
||||||
|
fun useEsModules()
|
||||||
|
|
||||||
val binaries: KotlinJsBinaryContainer
|
val binaries: KotlinJsBinaryContainer
|
||||||
|
|
||||||
|
|||||||
+21
@@ -358,9 +358,30 @@ constructor(
|
|||||||
legacyTarget?.useCommonJs()
|
legacyTarget?.useCommonJs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun useEsModules() {
|
||||||
|
compilations.all {
|
||||||
|
it.kotlinOptions.configureEsModulesOptions()
|
||||||
|
|
||||||
|
binaries
|
||||||
|
.withType(JsIrBinary::class.java)
|
||||||
|
.all {
|
||||||
|
it.linkTask.configure { linkTask ->
|
||||||
|
linkTask.kotlinOptions.configureEsModulesOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private fun KotlinJsOptions.configureCommonJsOptions() {
|
private fun KotlinJsOptions.configureCommonJsOptions() {
|
||||||
moduleKind = "commonjs"
|
moduleKind = "commonjs"
|
||||||
sourceMap = true
|
sourceMap = true
|
||||||
sourceMapEmbedSources = "never"
|
sourceMapEmbedSources = "never"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KotlinJsOptions.configureEsModulesOptions() {
|
||||||
|
moduleKind = "es"
|
||||||
|
sourceMap = true
|
||||||
|
sourceMapEmbedSources = "never"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user