[K/JS, K/Wasm] Generate star imports for external objects with the @JsModule annotation for ES modules

This commit is contained in:
Artem Kobzar
2023-07-18 15:36:19 +00:00
committed by Space Team
parent e61a11f0a3
commit 41f27d19b5
5 changed files with 58 additions and 42 deletions
@@ -11,10 +11,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.isSimpleProperty
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -85,11 +82,16 @@ class JsNameLinkingNamer(
parent.child(getJsNameOrKotlinName()).asString() parent.child(getJsNameOrKotlinName()).asString()
} }
val name = JsName(sanitizeName(nameString), true) val name = JsName(sanitizeName(nameString), true)
val nameRef = name.makeRef()
if (isEsModules) { if (isEsModules) {
imports[this] = JsImport(jsModule, JsImport.Target.Default(name.makeRef())) val importSubject = when {
this is IrClass && isObject -> JsImport.Target.All(nameRef)
else -> JsImport.Target.Default(nameRef)
}
imports[this] = JsImport(jsModule, importSubject)
} else { } else {
importedModules += JsImportedModule(jsModule, name, name.makeRef()) importedModules += JsImportedModule(jsModule, name, nameRef)
} }
return name return name
} }
@@ -366,22 +366,21 @@ class ComplexExternalDeclarationsToTopLevelFunctionsLowering(val context: WasmBa
} }
private fun referenceTopLevelExternalDeclaration(declaration: IrDeclarationWithName): String { private fun referenceTopLevelExternalDeclaration(declaration: IrDeclarationWithName): String {
var name = declaration.getJsNameOrKotlinName().identifier var name: String? = declaration.getJsNameOrKotlinName().identifier
val qualifier = currentFile.getJsQualifier() val qualifier = currentFile.getJsQualifier()
val module = currentFile.getJsModule() val module = currentFile.getJsModule()
?: declaration.getJsModule()?.also { ?: declaration.getJsModule()?.also {
// JsModule on top level declarations imports "default" name = if (declaration is IrClass && declaration.isObject) null else "default"
name = "default"
} }
if (qualifier == null && module == null) if (qualifier == null && module == null)
return name return name!!
val qualifieReference = JsModuleAndQualifierReference(module, qualifier) val qualifieReference = JsModuleAndQualifierReference(module, qualifier)
context.jsModuleAndQualifierReferences += qualifieReference context.jsModuleAndQualifierReferences += qualifieReference
return qualifieReference.jsVariableName + "." + name return qualifieReference.jsVariableName + name?.let { ".$it" }.orEmpty()
} }
} }
+21 -7
View File
@@ -28,13 +28,23 @@ package default
@JsModule("./jsModule.mjs") @JsModule("./jsModule.mjs")
external object jsModule { external object jsModule {
val defaultX: Int val x: Int
fun defaultF(): Int fun f(): Int
class defaultC { class C {
constructor(x: String) constructor(x: String)
val x: String val x: String
} }
@JsName("default")
object Default {
val defaultX: Int
fun defaultF(): Int
class defaultC {
constructor(x: String)
val x: String
}
}
} }
@@ -44,9 +54,13 @@ fun box(): String {
if (named.f() != 10) return "Fail2" if (named.f() != 10) return "Fail2"
if (named.C("10").x != "10") return "Fail3" if (named.C("10").x != "10") return "Fail3"
if (default.jsModule.defaultX != 10) return "Fail4" if (default.jsModule.Default.defaultX != 10) return "Fail4"
if (default.jsModule.defaultF() != 10) return "Fail5" if (default.jsModule.Default.defaultF() != 10) return "Fail5"
if (default.jsModule.defaultC("10").x != "10") return "Fail6" if (default.jsModule.Default.defaultC("10").x != "10") return "Fail6"
if (default.jsModule.x != 10) return "Fail7"
if (default.jsModule.f() != 10) return "Fail8"
if (default.jsModule.C("10").x != "10") return "Fail9"
return "OK" return "OK"
} }
@@ -4,13 +4,16 @@ package foo
@JsModule("./externalObject.mjs") @JsModule("./externalObject.mjs")
external object A { external object A {
val x: Int = definedExternally @JsName("default")
object Default {
val x: Int = definedExternally
fun foo(y: Int): Int = definedExternally fun foo(y: Int): Int = definedExternally
}
} }
fun box(): String { fun box(): String {
assertEquals(23, A.x) assertEquals(23, A.Default.x)
assertEquals(65, A.foo(42)) assertEquals(65, A.Default.foo(42))
return "OK" return "OK"
} }
@@ -1,21 +1,19 @@
export default { export function createX () {
createX: function () { return {x: "X1"};
return {x: "X1"}; }
}, export function createXY () {
createXY: function () { return {x: "X2", y: "Y2"};
return {x: "X2", y: "Y2"}; }
}, export function createXYZ() {
createXYZ: function () { return {x: "X3", y: "Y3", z: "Z3"};
return {x: "X3", y: "Y3", z: "Z3"}; }
}, export function createClassXYZ() {
createClassXYZ: function () { return {x: "X4", y: "Y4", z: "Z4"};
return {x: "X4", y: "Y4", z: "Z4"}; }
}, export function createNestedInterfaceXYZ() {
createNestedInterfaceXYZ: function () { return {x: "X5", y: "Y5", z: "Z5"};
return {x: "X5", y: "Y5", z: "Z5"}; }
},
x: "X6", export const x = "X6"
y: "Y6", export const y = "Y6"
z: "Z6" export const z = "Z6"
};