diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt index e9c2b345dbe..10b324195c3 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt @@ -16,16 +16,14 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_RESULT_TYPE_PARAMETER -import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName -import org.jetbrains.kotlin.ir.backend.js.utils.isExportedInterface -import org.jetbrains.kotlin.ir.backend.js.utils.isJsExport -import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName +import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.keysToMap @@ -34,7 +32,6 @@ class ExportModelGenerator( val context: JsIrBackendContext, val generateNamespacesForPackages: Boolean ) { - fun generateExport(file: IrPackageFragment): List { val namespaceFqName = file.fqName val exports = file.declarations.flatMap { declaration -> listOfNotNull(exportDeclaration(declaration)) } @@ -507,8 +504,8 @@ class ExportModelGenerator( classifier is IrClassSymbol -> { val klass = classifier.owner - val isImplicitlyExported = !klass.isExported(context) - val name = if (generateNamespacesForPackages) klass.fqNameWhenAvailable!!.asString() else klass.name.asString() + val isImplicitlyExported = !klass.isExported(context) && !klass.isExternal + val name = klass.getExportableName() when (klass.kind) { ClassKind.ANNOTATION_CLASS, @@ -534,6 +531,19 @@ class ExportModelGenerator( return exportedType.withNullability(isNullable) } + private fun IrClass.getExportableName(): String { + val qualifier = (parent as? IrFile)?.getJsQualifier() + val supQualifier = (parent as? IrClass)?.getExportableName() + val name = getJsNameOrKotlinName() + + return when { + qualifier != null -> "$qualifier.$name" + isExternal && !isExported(context) -> "${supQualifier?.plus(".") ?: ""}$name" + generateNamespacesForPackages -> fqNameWhenAvailable!!.asString() + else -> name.asString() + } + } + private fun IrDeclarationWithName.getExportedIdentifier(): String = with(getJsNameOrKotlinName()) { if (isSpecial) diff --git a/js/js.translator/testData/typescript-export/implicitExport/declarations.d.ts b/js/js.translator/testData/typescript-export/implicitExport/declarations.d.ts index f27b2a7d3e5..caff6524f12 100644 --- a/js/js.translator/testData/typescript-export/implicitExport/declarations.d.ts +++ b/js/js.translator/testData/typescript-export/implicitExport/declarations.d.ts @@ -37,5 +37,9 @@ declare namespace JS_TESTS { class H /* extends foo.NonExportedGenericType */ { constructor(); } + function foo(a: number): Promise; + function bar(): Error; + const console: Console; + const error: WebAssembly.CompileError; } } diff --git a/js/js.translator/testData/typescript-export/implicitExport/declarations.kt b/js/js.translator/testData/typescript-export/implicitExport/declarations.kt index 233610e6818..64da71aca65 100644 --- a/js/js.translator/testData/typescript-export/implicitExport/declarations.kt +++ b/js/js.translator/testData/typescript-export/implicitExport/declarations.kt @@ -2,12 +2,27 @@ // RUN_PLAIN_BOX_FUNCTION // SKIP_MINIFICATION // SKIP_NODE_JS +// KJS_WITH_FULL_RUNTIME // INFER_MAIN_MODULE // MODULE: JS_TESTS +// FILE: qualified.kt +@file:JsQualifier("WebAssembly") +package qualified + +external interface CompileError + +// FILE: notQualified.kt +package notQualified + +external interface Console + // FILE: declarations.kt package foo +import notQualified.Console +import qualified.CompileError + interface NonExportedInterface interface NonExportedGenericInterface open class NonExportedType(val value: Int) @@ -52,4 +67,22 @@ class F : A(NonExportedType(42)), NonExportedInterface class G : NonExportedGenericInterface @JsExport -class H : NonExportedGenericType(NonExportedType(42)) \ No newline at end of file +class H : NonExportedGenericType(NonExportedType(42)) + +@JsExport +fun foo(a: Int): kotlin.js.Promise { + return kotlin.js.Promise { res, rej -> res(a) } +} + +@JsExport +fun bar(): Throwable { + return Throwable("Test Error") +} + +@JsExport +val console: Console + get() = js("console") + +@JsExport +val error: CompileError + get() = js("{}") \ No newline at end of file