From eb2326eabbad6f54cde03b62e1b4668f3eb20be8 Mon Sep 17 00:00:00 2001 From: Artem Kobzar Date: Mon, 3 Oct 2022 11:07:25 +0000 Subject: [PATCH] [K/JS] Add ability to exclude declarations from export by a new annotation @JsExport.Ignore. --- .../kotlin/codegen/PackageCodegenImpl.java | 28 ++++++-- .../jetbrains/kotlin/diagnostics/Errors.java | 1 - .../rendering/DefaultErrorMessages.java | 1 - .../checkers/OptionalExpectationChecker.kt | 11 +--- .../resolve/checkers/usageCheckerUtils.kt | 8 ++- .../backend/js/export/ExportModelGenerator.kt | 5 +- .../transformers/irToJs/JsClassGenerator.kt | 3 +- .../ir/backend/js/utils/AnnotationUtils.kt | 4 ++ .../jvm/lower/ProcessOptionalAnnotations.kt | 14 +++- .../kotlin/ir/util/AdditionalIrUtils.kt | 9 ++- .../box/multiplatform/optionalExpectation.kt | 6 +- .../optionalExpectationIncorrectUse/common.kt | 1 - .../output.txt | 6 -- .../js/resolve/JsPlatformConfigurator.kt | 3 +- .../js/resolve/diagnostics/ErrorsJs.java | 1 + .../js/translate/utils/AnnotationsUtils.java | 3 + js/js.tests/build.gradle.kts | 1 - .../kotlin/js/test/BoxJsTestGenerated.java | 18 ++++++ .../kotlin/js/test/ir/FirJsTestGenerated.java | 18 ++++++ .../js/test/ir/IrBoxJsTestGenerated.java | 18 ++++++ .../ir/IrJsTypeScriptExportTestGenerated.java | 64 +++++++++++++++++++ .../box/export/excludeMembersFromExport.kt | 52 +++++++++++++++ .../box/export/excludeTopLevelFromExport.kt | 49 ++++++++++++++ ...deTopLevelFromExportWithoutFileJsExport.kt | 55 ++++++++++++++++ .../excluded-exported-declarations.d.ts | 7 ++ .../excluded-exported-declarations.kt | 63 ++++++++++++++++++ .../excluded-exported-declarations__main.js | 33 ++++++++++ .../excluded-exported-declarations__main.ts | 36 +++++++++++ .../tsconfig.json | 4 ++ .../excluded-exported-declarations.d.ts | 7 ++ .../excluded-exported-declarations.kt | 59 +++++++++++++++++ .../excluded-exported-declarations__main.js | 33 ++++++++++ .../excluded-exported-declarations__main.ts | 36 +++++++++++ .../tsconfig.json | 4 ++ .../not-exported-declarations.d.ts | 15 +++++ .../not-exported-declarations.kt | 63 ++++++++++++++++++ .../not-exported-declarations__main.js | 32 ++++++++++ .../not-exported-declarations__main.ts | 35 ++++++++++ .../tsconfig.json | 4 ++ .../not-exported-declarations.d.ts | 15 +++++ .../not-exported-declarations.kt | 59 +++++++++++++++++ .../not-exported-declarations__main.js | 32 ++++++++++ .../not-exported-declarations__main.ts | 35 ++++++++++ .../not-exported-declarations/tsconfig.json | 4 ++ libraries/stdlib/api/js-v1/kotlin.js.kt | 8 +++ libraries/stdlib/api/js/kotlin.js.kt | 8 +++ .../common/src/kotlin/JsAnnotationsH.kt | 16 ++++- libraries/stdlib/js/src/kotlin/annotations.kt | 13 +++- .../stdlib/wasm/src/kotlin/js/annotations.kt | 12 +++- 49 files changed, 970 insertions(+), 42 deletions(-) create mode 100644 js/js.translator/testData/box/export/excludeMembersFromExport.kt create mode 100644 js/js.translator/testData/box/export/excludeTopLevelFromExport.kt create mode 100644 js/js.translator/testData/box/export/excludeTopLevelFromExportWithoutFileJsExport.kt create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.d.ts create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.kt create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.js create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.ts create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/tsconfig.json create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.d.ts create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.kt create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.js create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.ts create mode 100644 js/js.translator/testData/typescript-export/excluded-exported-declarations/tsconfig.json create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.d.ts create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.kt create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.js create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.ts create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/tsconfig.json create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.d.ts create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.kt create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.js create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.ts create mode 100644 js/js.translator/testData/typescript-export/not-exported-declarations/tsconfig.json diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java index e86e37f487c..a887679d58e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java @@ -89,13 +89,8 @@ public class PackageCodegenImpl implements PackageCodegen { for (KtDeclaration declaration : file.getDeclarations()) { if (declaration instanceof KtClassOrObject) { - ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration); if (PsiUtilsKt.hasExpectModifier(declaration)) { - if (descriptor != null && OptionalAnnotationUtil.shouldGenerateExpectClass(descriptor)) { - assert OptionalAnnotationUtil.isOptionalAnnotationClass(descriptor) : - "Expect class should be generated only if it's an optional annotation: " + descriptor; - state.getFactory().getPackagePartRegistry().getOptionalAnnotations().add(descriptor); - } + addDescriptorToOptionalAnnotationsIfNeeded((KtClassOrObject) declaration, state); continue; } @@ -120,6 +115,27 @@ public class PackageCodegenImpl implements PackageCodegen { } } + private static void addDescriptorToOptionalAnnotationsIfNeeded(@NotNull KtClassOrObject declaration, @NotNull GenerationState state) { + ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration); + if (descriptor == null || !OptionalAnnotationUtil.shouldGenerateExpectClass(descriptor)) { + return; + } + + assert OptionalAnnotationUtil.isOptionalAnnotationClass(descriptor) : + "Expect class should be generated only if it's an optional annotation: " + descriptor; + + state.getFactory().getPackagePartRegistry().getOptionalAnnotations().add(descriptor); + + KtClassBody body = declaration.getBody(); + + if (body != null) { + for (KtDeclaration childDeclaration : body.getDeclarations()) { + if (!(childDeclaration instanceof KtClassOrObject)) continue; + addDescriptorToOptionalAnnotationsIfNeeded((KtClassOrObject) childDeclaration, state); + } + } + } + private void generateFile(@NotNull KtFile file) { JvmFileClassInfo fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(file); if (fileClassInfo.getWithJvmMultifileClass()) return; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 81adc89c5a1..b5e975173b6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -789,7 +789,6 @@ public interface Errors { DiagnosticFactory0 ACTUAL_MISSING = DiagnosticFactory0.create(ERROR, ACTUAL_DECLARATION_NAME); DiagnosticFactory0 OPTIONAL_EXPECTATION_NOT_ON_EXPECTED = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 NESTED_OPTIONAL_EXPECTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 7ff56088dfd..b2c5c349ed1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -333,7 +333,6 @@ public class DefaultErrorMessages { MAP.put(ACTUAL_MISSING, "Declaration must be marked with 'actual'"); MAP.put(OPTIONAL_EXPECTATION_NOT_ON_EXPECTED, "'@OptionalExpectation' can only be used on an expected annotation class"); - MAP.put(NESTED_OPTIONAL_EXPECTATION, "'@OptionalExpectation' cannot be used on a nested class"); MAP.put(OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY, "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry"); MAP.put(OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE, "Declaration annotated with '@OptionalExpectation' can only be used in common module sources"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt index df5ad2d85e3..86acb662e9d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt @@ -7,25 +7,16 @@ package org.jetbrains.kotlin.resolve.checkers import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil object OptionalExpectationChecker { fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, trace: BindingTrace) { - val isExpect = descriptor is MemberDescriptor && descriptor.isExpect - if (isExpect) { - if (DescriptorUtils.isAnnotationClass(descriptor) && descriptor.containingDeclaration !is PackageFragmentDescriptor) { - getOptionalExpectationEntry(declaration, trace)?.let { - trace.report(Errors.NESTED_OPTIONAL_EXPECTATION.on(it)) - } - } - } else { + if (descriptor !is MemberDescriptor || !descriptor.isExpect) { getOptionalExpectationEntry(declaration, trace)?.let { trace.report(Errors.OPTIONAL_EXPECTATION_NOT_ON_EXPECTED.on(it)) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/usageCheckerUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/usageCheckerUtils.kt index 5a5fa8c9308..34bc908e7f5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/usageCheckerUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/usageCheckerUtils.kt @@ -12,9 +12,11 @@ internal fun PsiElement.isUsageAsAnnotationOrImport(): Boolean { val parent = parent if (parent is KtUserType) { - return parent.parent is KtTypeReference && - parent.parent.parent is KtConstructorCalleeExpression && - parent.parent.parent.parent is KtAnnotationEntry + return (parent.parent is KtUserType && parent.isUsageAsAnnotationOrImport()) || ( + parent.parent is KtTypeReference && + parent.parent.parent is KtConstructorCalleeExpression && + parent.parent.parent.parent is KtAnnotationEntry + ) } return parent is KtDotQualifiedExpression && parent.parent is KtImportDirective 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 f444d95176d..a45c6d1b5c4 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 @@ -22,8 +22,6 @@ 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.js.config.JSConfigurationKeys -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.runIf @@ -740,6 +738,9 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont if (context.additionalExportedDeclarations.contains(declaration)) return true + if (declaration.isJsExportIgnore()) + return false + if (declaration is IrOverridableDeclaration<*>) { val overriddenNonEmpty = declaration .overriddenSymbols diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index f225dd0810f..1372340633e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -113,7 +113,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null) continue - if (!property.visibility.isPublicAPI || property.isSimpleProperty) + if (!property.visibility.isPublicAPI || property.isSimpleProperty || property.isJsExportIgnore()) continue if ( @@ -223,6 +223,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo } private fun IrSimpleFunction.isDefinedInsideExportedInterface(): Boolean { + if (isJsExportIgnore() || correspondingPropertySymbol?.owner?.isJsExportIgnore() == true) return false return (!isFakeOverride && parentClassOrNull.isExportedInterface(context.staticContext.backendContext)) || overriddenSymbols.any { it.owner.isDefinedInsideExportedInterface() } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt index f0aa7585b7f..a150049656b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt @@ -25,6 +25,7 @@ object JsAnnotations { val jsQualifierFqn = FqName("kotlin.js.JsQualifier") val jsExportFqn = FqName("kotlin.js.JsExport") val jsImplicitExportFqn = FqName("kotlin.js.JsImplicitExport") + val jsExportIgnoreFqn = FqName("kotlin.js.JsExport.Ignore") val jsNativeGetter = FqName("kotlin.js.nativeGetter") val jsNativeSetter = FqName("kotlin.js.nativeSetter") val jsNativeInvoke = FqName("kotlin.js.nativeInvoke") @@ -61,6 +62,9 @@ fun IrAnnotationContainer.isJsExport(): Boolean = fun IrAnnotationContainer.isJsImplicitExport(): Boolean = hasAnnotation(JsAnnotations.jsImplicitExportFqn) +fun IrAnnotationContainer.isJsExportIgnore(): Boolean = + hasAnnotation(JsAnnotations.jsExportIgnoreFqn) + fun IrAnnotationContainer.isJsNativeGetter(): Boolean = hasAnnotation(JsAnnotations.jsNativeGetter) fun IrAnnotationContainer.isJsNativeSetter(): Boolean = hasAnnotation(JsAnnotations.jsNativeSetter) diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ProcessOptionalAnnotations.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ProcessOptionalAnnotations.kt index df80d535fba..10074c7cfbc 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ProcessOptionalAnnotations.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ProcessOptionalAnnotations.kt @@ -23,9 +23,17 @@ class ProcessOptionalAnnotations(private val context: JvmBackendContext) : FileL override fun lower(irFile: IrFile) { for (declaration in irFile.declarations) { if (declaration !is IrClass || !declaration.isOptionalAnnotationClass) continue - // TODO FirMetadataSource.Class - val metadataSource = (declaration.metadata as? DescriptorMetadataSource.Class)?.descriptor ?: continue - context.state.factory.packagePartRegistry.optionalAnnotations += metadataSource + declaration.registerOptionalAnnotations() + } + } + + private fun IrClass.registerOptionalAnnotations() { + // TODO FirMetadataSource.Class + val metadataSource = (metadata as? DescriptorMetadataSource.Class)?.descriptor ?: return + context.state.factory.packagePartRegistry.optionalAnnotations += metadataSource + + declarations.forEach { + if (it is IrClass && it.isOptionalAnnotationClass) it.registerOptionalAnnotations() } } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt index 69edeaf473b..0161a280115 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrClassPublicSymbolImpl import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -89,12 +90,18 @@ val IrClass.packageFqName: FqName? get() = symbol.signature?.packageFqName() ?: parent.getPackageFragment()?.fqName fun IrDeclarationWithName.hasEqualFqName(fqName: FqName): Boolean = - name == fqName.shortName() && when (val parent = parent) { + symbol.hasEqualFqName(fqName) || name == fqName.shortName() && when (val parent = parent) { is IrPackageFragment -> parent.fqName == fqName.parent() is IrDeclarationWithName -> parent.hasEqualFqName(fqName.parent()) else -> false } +fun IrSymbol.hasEqualFqName(fqName: FqName): Boolean { + return this is IrClassPublicSymbolImpl && with(signature as? IdSignature.CommonSignature ?: return false) { + FqName("$packageFqName.$declarationFqName") == fqName + } +} + fun List.hasAnnotation(fqName: FqName): Boolean = any { it.annotationClass.hasEqualFqName(fqName) } diff --git a/compiler/testData/codegen/box/multiplatform/optionalExpectation.kt b/compiler/testData/codegen/box/multiplatform/optionalExpectation.kt index dda4ccaaddd..750502c5fbe 100644 --- a/compiler/testData/codegen/box/multiplatform/optionalExpectation.kt +++ b/compiler/testData/codegen/box/multiplatform/optionalExpectation.kt @@ -13,7 +13,10 @@ package a expect annotation class A(val x: Int) @OptionalExpectation -expect annotation class B(val s: String) +expect annotation class B(val s: String) { + @OptionalExpectation + annotation class C(val a: Boolean) +} // FILE: actual.kt @@ -33,6 +36,7 @@ import a.B @A(42) @B("OK") +@B.C(true) fun box(): String { return "OK" } diff --git a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt index 264c61ce9cb..1f0557b4212 100644 --- a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt +++ b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt @@ -20,7 +20,6 @@ annotation class InOtherAnnotation(val a: A) fun useInOtherAnnotation() {} - expect class C { @OptionalExpectation annotation class Nested diff --git a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt index 7b44c395564..d3f482bea17 100644 --- a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt +++ b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt @@ -16,9 +16,6 @@ annotation class InOtherAnnotation(val a: A) compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry @InOtherAnnotation(A()) ^ -compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:25:5: error: '@OptionalExpectation' cannot be used on a nested class - @OptionalExpectation - ^ -- JVM -- Exit code: COMPILATION_ERROR @@ -41,9 +38,6 @@ annotation class InOtherAnnotation(val a: A) compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry @InOtherAnnotation(A()) ^ -compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:25:5: error: '@OptionalExpectation' cannot be used on a nested class - @OptionalExpectation - ^ compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:1:24: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry fun useInReturnType(): A? = null ^ diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt index e8a473c028e..796ee7860be 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.js.resolve -import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useImpl import org.jetbrains.kotlin.container.useInstance @@ -25,7 +24,7 @@ object JsPlatformConfigurator : PlatformConfiguratorBase( JsRuntimeAnnotationChecker, JsDynamicDeclarationChecker, JsExportAnnotationChecker, - JsExportDeclarationChecker, + JsExportDeclarationChecker ), additionalCallCheckers = listOf( JsModuleCallChecker, diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java index 4c2fa71f124..fec5d77883a 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java @@ -107,6 +107,7 @@ public interface ErrorsJs { DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory0 NESTED_JS_EXPORT = DiagnosticFactory0.create(ERROR); + DiagnosticFactory1 WRONG_EXPORTED_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory2 NON_EXPORTABLE_TYPE = DiagnosticFactory2.create(WARNING, DECLARATION_SIGNATURE_OR_DEFAULT); diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java b/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java index a51374df310..060ce04ed9b 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.js.PredefinedAnnotation; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtAnnotationEntry; @@ -41,6 +42,7 @@ import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.isEf public final class AnnotationsUtils { public static final FqName JS_NAME = new FqName("kotlin.js.JsName"); private static final FqName JS_EXPORT = new FqName("kotlin.js.JsExport"); + private static final FqName JS_EXPORT_IGNORE = new FqName("kotlin.js.JsExport.Ignore"); public static final FqName JS_MODULE_ANNOTATION = new FqName("kotlin.js.JsModule"); private static final FqName JS_NON_MODULE_ANNOTATION = new FqName("kotlin.js.JsNonModule"); public static final FqName JS_QUALIFIER_ANNOTATION = new FqName("kotlin.js.JsQualifier"); @@ -122,6 +124,7 @@ public final class AnnotationsUtils { if (memberDescriptor.getVisibility() != DescriptorVisibilities.PUBLIC) return false; } + if (hasAnnotationOrInsideAnnotatedClass(descriptor, JS_EXPORT_IGNORE)) return false; if (hasAnnotationOrInsideAnnotatedClass(descriptor, JS_EXPORT)) return true; if (CollectionsKt.any(getContainingFileAnnotations(bindingContext, descriptor), annotation -> diff --git a/js/js.tests/build.gradle.kts b/js/js.tests/build.gradle.kts index b849d80741f..09e331497a4 100644 --- a/js/js.tests/build.gradle.kts +++ b/js/js.tests/build.gradle.kts @@ -156,7 +156,6 @@ val unzipJsShell by task { val testDataDir = project(":js:js.translator").projectDir.resolve("testData") val typescriptTestsDir = testDataDir.resolve("typescript-export") - val installTsDependencies = task("installTsDependencies") { workingDir.set(testDataDir) args.set(listOf("install")) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java index b1a611b5d06..817361bbccc 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java @@ -2118,6 +2118,24 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/export/defaultInlineClassConstructorParamInExportedFile.kt"); } + @Test + @TestMetadata("excludeMembersFromExport.kt") + public void testExcludeMembersFromExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeMembersFromExport.kt"); + } + + @Test + @TestMetadata("excludeTopLevelFromExport.kt") + public void testExcludeTopLevelFromExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeTopLevelFromExport.kt"); + } + + @Test + @TestMetadata("excludeTopLevelFromExportWithoutFileJsExport.kt") + public void testExcludeTopLevelFromExportWithoutFileJsExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeTopLevelFromExportWithoutFileJsExport.kt"); + } + @Test @TestMetadata("exportAllFile.kt") public void testExportAllFile() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/FirJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/FirJsTestGenerated.java index c44378b665c..f93ccb92046 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/FirJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/FirJsTestGenerated.java @@ -2590,6 +2590,24 @@ public class FirJsTestGenerated extends AbstractFirJsTest { runTest("js/js.translator/testData/box/export/defaultInlineClassConstructorParamInExportedFile.kt"); } + @Test + @TestMetadata("excludeMembersFromExport.kt") + public void testExcludeMembersFromExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeMembersFromExport.kt"); + } + + @Test + @TestMetadata("excludeTopLevelFromExport.kt") + public void testExcludeTopLevelFromExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeTopLevelFromExport.kt"); + } + + @Test + @TestMetadata("excludeTopLevelFromExportWithoutFileJsExport.kt") + public void testExcludeTopLevelFromExportWithoutFileJsExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeTopLevelFromExportWithoutFileJsExport.kt"); + } + @Test @TestMetadata("exportAllFile.kt") public void testExportAllFile() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index 076bf15c204..7383f4a290e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -2590,6 +2590,24 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/export/defaultInlineClassConstructorParamInExportedFile.kt"); } + @Test + @TestMetadata("excludeMembersFromExport.kt") + public void testExcludeMembersFromExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeMembersFromExport.kt"); + } + + @Test + @TestMetadata("excludeTopLevelFromExport.kt") + public void testExcludeTopLevelFromExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeTopLevelFromExport.kt"); + } + + @Test + @TestMetadata("excludeTopLevelFromExportWithoutFileJsExport.kt") + public void testExcludeTopLevelFromExportWithoutFileJsExport() throws Exception { + runTest("js/js.translator/testData/box/export/excludeTopLevelFromExportWithoutFileJsExport.kt"); + } + @Test @TestMetadata("exportAllFile.kt") public void testExportAllFile() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsTypeScriptExportTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsTypeScriptExportTestGenerated.java index e1fa45a6b5c..a2465bd44eb 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsTypeScriptExportTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsTypeScriptExportTestGenerated.java @@ -185,6 +185,38 @@ public class IrJsTypeScriptExportTestGenerated extends AbstractIrJsTypeScriptExp } } + @Nested + @TestMetadata("js/js.translator/testData/typescript-export/excluded-exported-declarations") + @TestDataPath("$PROJECT_ROOT") + public class Excluded_exported_declarations { + @Test + public void testAllFilesPresentInExcluded_exported_declarations() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/excluded-exported-declarations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("excluded-exported-declarations.kt") + public void testExcluded_exported_declarations() throws Exception { + runTest("js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.kt"); + } + } + + @Nested + @TestMetadata("js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file") + @TestDataPath("$PROJECT_ROOT") + public class Excluded_exported_declarations_in_exported_file { + @Test + public void testAllFilesPresentInExcluded_exported_declarations_in_exported_file() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("excluded-exported-declarations.kt") + public void testExcluded_exported_declarations() throws Exception { + runTest("js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.kt"); + } + } + @Nested @TestMetadata("js/js.translator/testData/typescript-export/functions") @TestDataPath("$PROJECT_ROOT") @@ -497,6 +529,38 @@ public class IrJsTypeScriptExportTestGenerated extends AbstractIrJsTypeScriptExp } } + @Nested + @TestMetadata("js/js.translator/testData/typescript-export/not-exported-declarations") + @TestDataPath("$PROJECT_ROOT") + public class Not_exported_declarations { + @Test + public void testAllFilesPresentInNot_exported_declarations() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/not-exported-declarations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("not-exported-declarations.kt") + public void testNot_exported_declarations() throws Exception { + runTest("js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.kt"); + } + } + + @Nested + @TestMetadata("js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file") + @TestDataPath("$PROJECT_ROOT") + public class Not_exported_declarations_in_exported_file { + @Test + public void testAllFilesPresentInNot_exported_declarations_in_exported_file() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("not-exported-declarations.kt") + public void testNot_exported_declarations() throws Exception { + runTest("js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.kt"); + } + } + @Nested @TestMetadata("js/js.translator/testData/typescript-export/objects") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.translator/testData/box/export/excludeMembersFromExport.kt b/js/js.translator/testData/box/export/excludeMembersFromExport.kt new file mode 100644 index 00000000000..a26454ec8f8 --- /dev/null +++ b/js/js.translator/testData/box/export/excludeMembersFromExport.kt @@ -0,0 +1,52 @@ +// RUN_PLAIN_BOX_FUNCTION +// IGNORE_BACKEND: JS + +// MODULE: lib +// FILE: lib.kt +@JsExport +class Bar(val value: String) { + @JsExport.Ignore + constructor(): this("SECONDARY") + + @JsExport.Ignore + val excludedValue: Int = 42 + + fun foo(): String = "FOO" + + @JsExport.Ignore + fun excludedFun(): String = "EXCLUDED_FUN" + + class Nested + + @JsExport.Ignore + class ExcludedNested { + fun doSomething(): String = "SOMETHING" + } + + companion object { + fun baz(): String = "BAZ" + + @JsExport.Ignore + fun excludedFun(): String = "STATIC EXCLUDED_FUN" + } +} + +// FILE: main.js +function box() { + var Bar = this.lib.Bar; + var bar = new Bar("TEST"); + + if (bar.value !== "TEST") return "Error: exported property was not exported" + if (bar.excludedValue === 42) return "Error: not exported property was exported" + + if (bar.foo() !== "FOO") return "Error: exported function was not exported" + if (typeof bar.excludedFun === "function") return "Error: not exported function was exported" + + if (typeof Bar.Nested !== "function") return "Error: exported nested class was not exported" + if (typeof Bar.ExcludedNested === "function") return "Error: not exported nested class was exported" + + if (Bar.Companion.baz() !== "BAZ") return "Error: exported companion function was not exported" + if (typeof Bar.Companion.excludedFun === "function") return "Error: not exported companion function was exported" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/export/excludeTopLevelFromExport.kt b/js/js.translator/testData/box/export/excludeTopLevelFromExport.kt new file mode 100644 index 00000000000..d7bf59b5e38 --- /dev/null +++ b/js/js.translator/testData/box/export/excludeTopLevelFromExport.kt @@ -0,0 +1,49 @@ +// RUN_PLAIN_BOX_FUNCTION +// IGNORE_BACKEND: JS + +// MODULE: lib +// FILE: lib.kt +@file:JsExport + +val value: String = "TEST" + +@JsExport.Ignore +val excludedValue: Int = 42 + +fun foo(): String = "FOO" + +@JsExport.Ignore +fun excludedFun(): String = "EXCLUDED_FUN" + +class SomeClass + +@JsExport.Ignore +class ExcludedSomeClass { + fun doSomething(): String = "SOMETHING" +} + +object Companion { + fun baz(): String = "BAZ" + + @JsExport.Ignore + fun excludedFun(): String = "STATIC EXCLUDED_FUN" +} + +// FILE: main.js +function box() { + var lib = this.lib; + + if (lib.value !== "TEST") return "Error: exported property was not exported" + if (lib.excludedValue === 42) return "Error: not exported property was exported" + + if (lib.foo() !== "FOO") return "Error: exported function was not exported" + if (typeof lib.excludedFun === "function") return "Error: not exported function was exported" + + if (typeof lib.SomeClass !== "function") return "Error: exported nested class was not exported" + if (typeof lib.ExcludedSomeClass === "function") return "Error: not exported nested class was exported" + + if (lib.Companion.baz() !== "BAZ") return "Error: exported companion function was not exported" + if (typeof lib.Companion.excludedFun === "function") return "Error: not exported companion function was exported" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/export/excludeTopLevelFromExportWithoutFileJsExport.kt b/js/js.translator/testData/box/export/excludeTopLevelFromExportWithoutFileJsExport.kt new file mode 100644 index 00000000000..2250e44c804 --- /dev/null +++ b/js/js.translator/testData/box/export/excludeTopLevelFromExportWithoutFileJsExport.kt @@ -0,0 +1,55 @@ +// RUN_PLAIN_BOX_FUNCTION +// IGNORE_BACKEND: JS + +// MODULE: lib +// FILE: lib.kt + +@JsExport +val value: String = "TEST" + +@JsExport +@JsExport.Ignore +val excludedValue: Int = 42 + +@JsExport +fun foo(): String = "FOO" + +@JsExport +@JsExport.Ignore +fun excludedFun(): String = "EXCLUDED_FUN" + +@JsExport +class SomeClass + +@JsExport.Ignore +@JsExport +class ExcludedSomeClass { + fun doSomething(): String = "SOMETHING" +} + +@JsExport +object Companion { + fun baz(): String = "BAZ" + + @JsExport.Ignore + fun excludedFun(): String = "STATIC EXCLUDED_FUN" +} + +// FILE: main.js +function box() { + var lib = this.lib; + + if (lib.value !== "TEST") return "Error: exported property was not exported" + if (lib.excludedValue === 42) return "Error: not exported property was exported" + + if (lib.foo() !== "FOO") return "Error: exported function was not exported" + if (typeof lib.excludedFun === "function") return "Error: not exported function was exported" + + if (typeof lib.SomeClass !== "function") return "Error: exported nested class was not exported" + if (typeof lib.ExcludedSomeClass === "function") return "Error: not exported nested class was exported" + + if (lib.Companion.baz() !== "BAZ") return "Error: exported companion function was not exported" + if (typeof lib.Companion.excludedFun === "function") return "Error: not exported companion function was exported" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.d.ts b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.d.ts new file mode 100644 index 00000000000..b0570eb8ac2 --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.d.ts @@ -0,0 +1,7 @@ +declare namespace JS_TESTS { + type Nullable = T | null | undefined + namespace foo { + const foo: string; + function bar(): string; + } +} diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.kt b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.kt new file mode 100644 index 00000000000..5473bc82174 --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations.kt @@ -0,0 +1,63 @@ +/** This file is generated by {@link :js:js.test:generateJsExportOnFileTestFilesForTS} task. DO NOT MODIFY MANUALLY */ + +// CHECK_TYPESCRIPT_DECLARATIONS +// RUN_PLAIN_BOX_FUNCTION +// SKIP_MINIFICATION +// SKIP_NODE_JS +// INFER_MAIN_MODULE +// MODULE: JS_TESTS +// WITH_STDLIB +// FILE: declarations.kt + +@file:JsExport + +package foo + + +@JsExport.Ignore +val baz: String = "Baz" + + +@JsExport.Ignore +fun inter(): String = "inter" + + +@JsExport.Ignore +class NotExportableNestedInsideInterface + +@JsExport.Ignore + +object Comanion { + val foo: String ="FOO" +} + + +val foo: String = "Foo" + + +fun bar() = "Bar" + +@JsExport.Ignore + +inline fun A.notExportableReified(): Boolean = this is B + +@JsExport.Ignore + +suspend fun notExportableSuspend(): String = "SuspendResult" + + +@JsExport.Ignore +fun notExportableReturn(): List = listOf("1", "2") + + +@JsExport.Ignore +val String.notExportableExentsionProperty: String + get() = "notExportableExentsionProperty" + + +@JsExport.Ignore +annotation class NotExportableAnnotation + + +@JsExport.Ignore +value class NotExportableInlineClass(val value: Int) \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.js b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.js new file mode 100644 index 00000000000..fb89b9a148f --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.js @@ -0,0 +1,33 @@ +"use strict"; +var foo = JS_TESTS.foo; +function assert(condition, message) { + if (message === void 0) { message = "Assertion failed"; } + if (!condition) { + throw message; + } +} +function box() { + assert(foo.foo === "Foo", "Error in property 'foo'"); + assert(foo.bar() === "Bar", "Error in property 'bar'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.baz === undefined, "Error in property 'baz'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.inter === undefined, "Error in method 'inter'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableNestedInsideInterface === undefined, "Error in class 'NotExportableNestedInsideInterface'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.Companion === undefined, "Error in object 'Companion'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReified === undefined, "Error in method 'notExportableReified'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReturn === undefined, "Error in method 'notExportableReturn'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'"); + return "OK"; +} diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.ts b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.ts new file mode 100644 index 00000000000..f0f0cd7886b --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/excluded-exported-declarations__main.ts @@ -0,0 +1,36 @@ +import foo = JS_TESTS.foo; + + +function assert(condition: boolean, message: string = "Assertion failed") { + if (!condition) { + throw message; + } +} + +function box(): string { + assert(foo.foo === "Foo", "Error in property 'foo'") + assert(foo.bar() === "Bar", "Error in property 'bar'") + + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.baz === undefined, "Error in property 'baz'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.inter === undefined, "Error in method 'inter'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableNestedInsideInterface === undefined, "Error in class 'NotExportableNestedInsideInterface'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.Companion === undefined, "Error in object 'Companion'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReified === undefined, "Error in method 'notExportableReified'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReturn === undefined, "Error in method 'notExportableReturn'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'") + + return "OK"; +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/tsconfig.json b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/tsconfig.json new file mode 100644 index 00000000000..17612c56c9d --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations-in-exported-file/tsconfig.json @@ -0,0 +1,4 @@ +{ + "include": [ "./*" ], + "extends": "../common.tsconfig.json" +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.d.ts b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.d.ts new file mode 100644 index 00000000000..b0570eb8ac2 --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.d.ts @@ -0,0 +1,7 @@ +declare namespace JS_TESTS { + type Nullable = T | null | undefined + namespace foo { + const foo: string; + function bar(): string; + } +} diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.kt b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.kt new file mode 100644 index 00000000000..483f57e7c59 --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations.kt @@ -0,0 +1,59 @@ +// CHECK_TYPESCRIPT_DECLARATIONS +// RUN_PLAIN_BOX_FUNCTION +// SKIP_MINIFICATION +// SKIP_NODE_JS +// INFER_MAIN_MODULE +// MODULE: JS_TESTS +// WITH_STDLIB +// FILE: declarations.kt + +package foo + +@JsExport +@JsExport.Ignore +val baz: String = "Baz" + +@JsExport +@JsExport.Ignore +fun inter(): String = "inter" + +@JsExport +@JsExport.Ignore +class NotExportableNestedInsideInterface + +@JsExport.Ignore +@JsExport +object Comanion { + val foo: String ="FOO" +} + +@JsExport +val foo: String = "Foo" + +@JsExport +fun bar() = "Bar" + +@JsExport.Ignore +@JsExport +inline fun A.notExportableReified(): Boolean = this is B + +@JsExport.Ignore +@JsExport +suspend fun notExportableSuspend(): String = "SuspendResult" + +@JsExport +@JsExport.Ignore +fun notExportableReturn(): List = listOf("1", "2") + +@JsExport +@JsExport.Ignore +val String.notExportableExentsionProperty: String + get() = "notExportableExentsionProperty" + +@JsExport +@JsExport.Ignore +annotation class NotExportableAnnotation + +@JsExport +@JsExport.Ignore +value class NotExportableInlineClass(val value: Int) \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.js b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.js new file mode 100644 index 00000000000..fb89b9a148f --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.js @@ -0,0 +1,33 @@ +"use strict"; +var foo = JS_TESTS.foo; +function assert(condition, message) { + if (message === void 0) { message = "Assertion failed"; } + if (!condition) { + throw message; + } +} +function box() { + assert(foo.foo === "Foo", "Error in property 'foo'"); + assert(foo.bar() === "Bar", "Error in property 'bar'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.baz === undefined, "Error in property 'baz'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.inter === undefined, "Error in method 'inter'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableNestedInsideInterface === undefined, "Error in class 'NotExportableNestedInsideInterface'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.Companion === undefined, "Error in object 'Companion'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReified === undefined, "Error in method 'notExportableReified'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReturn === undefined, "Error in method 'notExportableReturn'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'"); + return "OK"; +} diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.ts b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.ts new file mode 100644 index 00000000000..f0f0cd7886b --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations/excluded-exported-declarations__main.ts @@ -0,0 +1,36 @@ +import foo = JS_TESTS.foo; + + +function assert(condition: boolean, message: string = "Assertion failed") { + if (!condition) { + throw message; + } +} + +function box(): string { + assert(foo.foo === "Foo", "Error in property 'foo'") + assert(foo.bar() === "Bar", "Error in property 'bar'") + + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.baz === undefined, "Error in property 'baz'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.inter === undefined, "Error in method 'inter'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableNestedInsideInterface === undefined, "Error in class 'NotExportableNestedInsideInterface'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.Companion === undefined, "Error in object 'Companion'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReified === undefined, "Error in method 'notExportableReified'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableReturn === undefined, "Error in method 'notExportableReturn'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(foo.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'") + + return "OK"; +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/excluded-exported-declarations/tsconfig.json b/js/js.translator/testData/typescript-export/excluded-exported-declarations/tsconfig.json new file mode 100644 index 00000000000..17612c56c9d --- /dev/null +++ b/js/js.translator/testData/typescript-export/excluded-exported-declarations/tsconfig.json @@ -0,0 +1,4 @@ +{ + "include": [ "./*" ], + "extends": "../common.tsconfig.json" +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.d.ts b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.d.ts new file mode 100644 index 00000000000..93de069b1ea --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.d.ts @@ -0,0 +1,15 @@ +declare namespace JS_TESTS { + type Nullable = T | null | undefined + namespace foo { + interface ExportedInterface { + readonly __doNotUseOrImplementIt: { + readonly "foo.ExportedInterface": unique symbol; + }; + } + class OnlyFooParamExported implements foo.ExportedInterface { + constructor(foo: string); + get foo(): string; + readonly __doNotUseOrImplementIt: foo.ExportedInterface["__doNotUseOrImplementIt"]; + } + } +} diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.kt b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.kt new file mode 100644 index 00000000000..6395e92b108 --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations.kt @@ -0,0 +1,63 @@ +/** This file is generated by {@link :js:js.test:generateJsExportOnFileTestFilesForTS} task. DO NOT MODIFY MANUALLY */ + +// CHECK_TYPESCRIPT_DECLARATIONS +// RUN_PLAIN_BOX_FUNCTION +// SKIP_MINIFICATION +// SKIP_NODE_JS +// INFER_MAIN_MODULE +// MODULE: JS_TESTS +// WITH_STDLIB +// FILE: declarations.kt + +@file:JsExport + +package foo + + +interface ExportedInterface { + @JsExport.Ignore + val baz: String + + @JsExport.Ignore + fun inter(): String + + @JsExport.Ignore + class NotExportableNestedInsideInterface + + @JsExport.Ignore + companion object { + val foo: String ="FOO" + } +} + + +class OnlyFooParamExported(val foo: String) : ExportedInterface { + @JsExport.Ignore + constructor() : this("TEST") + + override val baz = "Baz" + + override fun inter(): String = "Inter" + + @JsExport.Ignore + val bar = "Bar" + + @JsExport.Ignore + inline fun A.notExportableReified(): Boolean = this is B + + @JsExport.Ignore + suspend fun notExportableSuspend(): String = "SuspendResult" + + @JsExport.Ignore + fun notExportableReturn(): List = listOf("1", "2") + + @JsExport.Ignore + val String.notExportableExentsionProperty: String + get() = "notExportableExentsionProperty" + + @JsExport.Ignore + annotation class NotExportableAnnotation + + @JsExport.Ignore + value class NotExportableInlineClass(val value: Int) +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.js b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.js new file mode 100644 index 00000000000..5b412ebc49b --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.js @@ -0,0 +1,32 @@ +"use strict"; +var OnlyFooParamExported = JS_TESTS.foo.OnlyFooParamExported; +function assert(condition, message) { + if (message === void 0) { message = "Assertion failed"; } + if (!condition) { + throw message; + } +} +function box() { + var onlyFooParamExported = new OnlyFooParamExported("TEST"); + assert(OnlyFooParamExported.length === 1, "Error in constructor'"); + assert(onlyFooParamExported.foo === "TEST", "Error in property 'foo'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.bar === undefined, "Error in property 'bar'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.baz === undefined, "Error in property 'baz'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.inter === undefined, "Error in method 'inter'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReified === undefined, "Error in method 'notExportableReified'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReturn === undefined, "Error in method 'notExportableReturn'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'"); + return "OK"; +} diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.ts b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.ts new file mode 100644 index 00000000000..8ec01629bfd --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/not-exported-declarations__main.ts @@ -0,0 +1,35 @@ +import OnlyFooParamExported = JS_TESTS.foo.OnlyFooParamExported; + + +function assert(condition: boolean, message: string = "Assertion failed") { + if (!condition) { + throw message; + } +} + +function box(): string { + const onlyFooParamExported = new OnlyFooParamExported("TEST") + assert(OnlyFooParamExported.length === 1, "Error in constructor'") + assert(onlyFooParamExported.foo === "TEST", "Error in property 'foo'") + + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.bar === undefined, "Error in property 'bar'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.baz === undefined, "Error in property 'baz'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.inter === undefined, "Error in method 'inter'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReified === undefined, "Error in method 'notExportableReified'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReturn === undefined, "Error in method 'notExportableReturn'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'") + + return "OK"; +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/tsconfig.json b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/tsconfig.json new file mode 100644 index 00000000000..17612c56c9d --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations-in-exported-file/tsconfig.json @@ -0,0 +1,4 @@ +{ + "include": [ "./*" ], + "extends": "../common.tsconfig.json" +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.d.ts b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.d.ts new file mode 100644 index 00000000000..93de069b1ea --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.d.ts @@ -0,0 +1,15 @@ +declare namespace JS_TESTS { + type Nullable = T | null | undefined + namespace foo { + interface ExportedInterface { + readonly __doNotUseOrImplementIt: { + readonly "foo.ExportedInterface": unique symbol; + }; + } + class OnlyFooParamExported implements foo.ExportedInterface { + constructor(foo: string); + get foo(): string; + readonly __doNotUseOrImplementIt: foo.ExportedInterface["__doNotUseOrImplementIt"]; + } + } +} diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.kt b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.kt new file mode 100644 index 00000000000..de57dead443 --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations.kt @@ -0,0 +1,59 @@ +// CHECK_TYPESCRIPT_DECLARATIONS +// RUN_PLAIN_BOX_FUNCTION +// SKIP_MINIFICATION +// SKIP_NODE_JS +// INFER_MAIN_MODULE +// MODULE: JS_TESTS +// WITH_STDLIB +// FILE: declarations.kt + +package foo + +@JsExport +interface ExportedInterface { + @JsExport.Ignore + val baz: String + + @JsExport.Ignore + fun inter(): String + + @JsExport.Ignore + class NotExportableNestedInsideInterface + + @JsExport.Ignore + companion object { + val foo: String ="FOO" + } +} + +@JsExport +class OnlyFooParamExported(val foo: String) : ExportedInterface { + @JsExport.Ignore + constructor() : this("TEST") + + override val baz = "Baz" + + override fun inter(): String = "Inter" + + @JsExport.Ignore + val bar = "Bar" + + @JsExport.Ignore + inline fun A.notExportableReified(): Boolean = this is B + + @JsExport.Ignore + suspend fun notExportableSuspend(): String = "SuspendResult" + + @JsExport.Ignore + fun notExportableReturn(): List = listOf("1", "2") + + @JsExport.Ignore + val String.notExportableExentsionProperty: String + get() = "notExportableExentsionProperty" + + @JsExport.Ignore + annotation class NotExportableAnnotation + + @JsExport.Ignore + value class NotExportableInlineClass(val value: Int) +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.js b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.js new file mode 100644 index 00000000000..5b412ebc49b --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.js @@ -0,0 +1,32 @@ +"use strict"; +var OnlyFooParamExported = JS_TESTS.foo.OnlyFooParamExported; +function assert(condition, message) { + if (message === void 0) { message = "Assertion failed"; } + if (!condition) { + throw message; + } +} +function box() { + var onlyFooParamExported = new OnlyFooParamExported("TEST"); + assert(OnlyFooParamExported.length === 1, "Error in constructor'"); + assert(onlyFooParamExported.foo === "TEST", "Error in property 'foo'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.bar === undefined, "Error in property 'bar'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.baz === undefined, "Error in property 'baz'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.inter === undefined, "Error in method 'inter'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReified === undefined, "Error in method 'notExportableReified'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReturn === undefined, "Error in method 'notExportableReturn'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'"); + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'"); + return "OK"; +} diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.ts b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.ts new file mode 100644 index 00000000000..8ec01629bfd --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations/not-exported-declarations__main.ts @@ -0,0 +1,35 @@ +import OnlyFooParamExported = JS_TESTS.foo.OnlyFooParamExported; + + +function assert(condition: boolean, message: string = "Assertion failed") { + if (!condition) { + throw message; + } +} + +function box(): string { + const onlyFooParamExported = new OnlyFooParamExported("TEST") + assert(OnlyFooParamExported.length === 1, "Error in constructor'") + assert(onlyFooParamExported.foo === "TEST", "Error in property 'foo'") + + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.bar === undefined, "Error in property 'bar'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.baz === undefined, "Error in property 'baz'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.inter === undefined, "Error in method 'inter'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReified === undefined, "Error in method 'notExportableReified'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableSuspend === undefined, "Error in method 'notExportableSuspend'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableReturn === undefined, "Error in method 'notExportableReturn'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(onlyFooParamExported.notExportableExentsionProperty === undefined, "Error in method 'notExportableExentsionProperty'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableAnnotation === undefined, "Error in nested class 'NotExportableAnnotation'") + // @ts-expect-error "the param should not be exported either in TS, or in JS" + assert(OnlyFooParamExported.NotExportableInlineClass === undefined, "Error in nested class 'NotExportableInlineClass'") + + return "OK"; +} \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/not-exported-declarations/tsconfig.json b/js/js.translator/testData/typescript-export/not-exported-declarations/tsconfig.json new file mode 100644 index 00000000000..17612c56c9d --- /dev/null +++ b/js/js.translator/testData/typescript-export/not-exported-declarations/tsconfig.json @@ -0,0 +1,4 @@ +{ + "include": [ "./*" ], + "extends": "../common.tsconfig.json" +} \ No newline at end of file diff --git a/libraries/stdlib/api/js-v1/kotlin.js.kt b/libraries/stdlib/api/js-v1/kotlin.js.kt index 1be8e0e27ae..4416386650b 100644 --- a/libraries/stdlib/api/js-v1/kotlin.js.kt +++ b/libraries/stdlib/api/js-v1/kotlin.js.kt @@ -240,6 +240,14 @@ public external interface JsClass { @kotlin.SinceKotlin(version = "1.3") public final annotation class JsExport : kotlin.Annotation { public constructor JsExport() + + @kotlin.js.ExperimentalJsExport + @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) + @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR}) + @kotlin.SinceKotlin(version = "1.8") + public final annotation class Ignore : kotlin.Annotation { + public constructor Ignore() + } } @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) diff --git a/libraries/stdlib/api/js/kotlin.js.kt b/libraries/stdlib/api/js/kotlin.js.kt index 8152c55d2f3..b3f07c8bd01 100644 --- a/libraries/stdlib/api/js/kotlin.js.kt +++ b/libraries/stdlib/api/js/kotlin.js.kt @@ -239,6 +239,14 @@ public external interface JsClass { @kotlin.SinceKotlin(version = "1.3") public final annotation class JsExport : kotlin.Annotation { public constructor JsExport() + + @kotlin.js.ExperimentalJsExport + @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) + @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR}) + @kotlin.SinceKotlin(version = "1.8") + public final annotation class Ignore : kotlin.Annotation { + public constructor Ignore() + } } @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) diff --git a/libraries/stdlib/common/src/kotlin/JsAnnotationsH.kt b/libraries/stdlib/common/src/kotlin/JsAnnotationsH.kt index 18b98048dfa..b32bb3b4843 100644 --- a/libraries/stdlib/common/src/kotlin/JsAnnotationsH.kt +++ b/libraries/stdlib/common/src/kotlin/JsAnnotationsH.kt @@ -63,4 +63,18 @@ public annotation class ExperimentalJsExport @Target(CLASS, PROPERTY, FUNCTION, FILE) @SinceKotlin("1.4") @OptionalExpectation -public expect annotation class JsExport() \ No newline at end of file +public expect annotation class JsExport() { + /* + * The annotation prevents exporting the annotated member of an exported class. + * This annotation is experimental, meaning that the restrictions mentioned above are subject to change. + */ + @ExperimentalJsExport + @Retention(AnnotationRetention.BINARY) + @Target(CLASS, PROPERTY, FUNCTION) + @SinceKotlin("1.8") + // Suppress until bootstrapping + @Suppress("NESTED_OPTIONAL_EXPECTATION") + @OptionalExpectation + public annotation class Ignore() +} + diff --git a/libraries/stdlib/js/src/kotlin/annotations.kt b/libraries/stdlib/js/src/kotlin/annotations.kt index b43046a87e2..dfddd9e0c45 100644 --- a/libraries/stdlib/js/src/kotlin/annotations.kt +++ b/libraries/stdlib/js/src/kotlin/annotations.kt @@ -190,7 +190,18 @@ public annotation class JsQualifier(val value: String) @Retention(AnnotationRetention.BINARY) @Target(CLASS, PROPERTY, FUNCTION, FILE) @SinceKotlin("1.3") -public actual annotation class JsExport +public actual annotation class JsExport { + /* + * The annotation prevents exporting the annotated member of an exported class. + * This annotation is experimental, meaning that the restrictions mentioned above are subject to change. + */ + @ExperimentalJsExport + @Retention(AnnotationRetention.BINARY) + @Target(CLASS, PROPERTY, FUNCTION, CONSTRUCTOR) + @SinceKotlin("1.8") + public actual annotation class Ignore +} + /** * Forces a top-level property to be initialized eagerly, opposed to lazily on the first access to file and/or property. diff --git a/libraries/stdlib/wasm/src/kotlin/js/annotations.kt b/libraries/stdlib/wasm/src/kotlin/js/annotations.kt index e075105e945..29e0c38fd11 100644 --- a/libraries/stdlib/wasm/src/kotlin/js/annotations.kt +++ b/libraries/stdlib/wasm/src/kotlin/js/annotations.kt @@ -13,7 +13,17 @@ package kotlin.js @ExperimentalJsExport @Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.FUNCTION) -public actual annotation class JsExport +public actual annotation class JsExport { + @ExperimentalJsExport + @Retention(AnnotationRetention.BINARY) + @Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.CONSTRUCTOR, + ) + public actual annotation class Ignore +} /** * Specifies JavaScript name for external and imported declarations