feat(@JsExport for interfaces): add ability to export interfaces in TypeScript.
This commit is contained in:
@@ -106,7 +106,7 @@ sealed class ExportedType {
|
|||||||
val returnType: ExportedType
|
val returnType: ExportedType
|
||||||
) : ExportedType()
|
) : ExportedType()
|
||||||
|
|
||||||
class ClassType(val name: String, val arguments: List<ExportedType>) : ExportedType()
|
class ClassType(val name: String, val arguments: List<ExportedType>, val ir: IrClass) : ExportedType()
|
||||||
class TypeParameter(val name: String) : ExportedType()
|
class TypeParameter(val name: String) : ExportedType()
|
||||||
class Nullable(val baseType: ExportedType) : ExportedType()
|
class Nullable(val baseType: ExportedType) : ExportedType()
|
||||||
class ErrorType(val comment: String) : ExportedType()
|
class ErrorType(val comment: String) : ExportedType()
|
||||||
|
|||||||
+2
-1
@@ -483,7 +483,8 @@ class ExportModelGenerator(
|
|||||||
ClassKind.ENUM_CLASS,
|
ClassKind.ENUM_CLASS,
|
||||||
ClassKind.INTERFACE -> ExportedType.ClassType(
|
ClassKind.INTERFACE -> ExportedType.ClassType(
|
||||||
name,
|
name,
|
||||||
type.arguments.map { exportTypeArgument(it) }
|
type.arguments.map { exportTypeArgument(it) },
|
||||||
|
klass
|
||||||
)
|
)
|
||||||
}.withImplicitlyExported(isImplicitlyExported)
|
}.withImplicitlyExported(isImplicitlyExported)
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-8
@@ -19,7 +19,15 @@ fun ExportedModule.toTypeScript(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun wrapTypeScript(name: String, moduleKind: ModuleKind, dts: String): String {
|
fun wrapTypeScript(name: String, moduleKind: ModuleKind, dts: String): String {
|
||||||
val types = "${moduleKind.indent}type Nullable<T> = T | null | undefined\n"
|
val declareKeyword = when (moduleKind) {
|
||||||
|
ModuleKind.PLAIN -> ""
|
||||||
|
else -> "declare "
|
||||||
|
}
|
||||||
|
val types = """
|
||||||
|
type Nullable<T> = T | null | undefined
|
||||||
|
${declareKeyword}const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
|
""".trimIndent().prependIndent(moduleKind.indent) + "\n"
|
||||||
|
|
||||||
val declarationsDts = types + dts
|
val declarationsDts = types + dts
|
||||||
|
|
||||||
@@ -117,14 +125,16 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin
|
|||||||
val superClassClause = superClass?.let { it.toExtendsClause(indent) } ?: ""
|
val superClassClause = superClass?.let { it.toExtendsClause(indent) } ?: ""
|
||||||
val superInterfacesClause = superInterfaces.toImplementsClause(superInterfacesKeyword, indent)
|
val superInterfacesClause = superInterfaces.toImplementsClause(superInterfacesKeyword, indent)
|
||||||
|
|
||||||
val members = members.map {
|
val members = members
|
||||||
if (!ir.isInner || it !is ExportedFunction || !it.isStatic) {
|
.let { if (shouldNotBeImplemented()) it.withMagicProperty() else it }
|
||||||
it
|
.map {
|
||||||
} else {
|
if (!ir.isInner || it !is ExportedFunction || !it.isStatic) {
|
||||||
// Remove $outer argument from secondary constructors of inner classes
|
it
|
||||||
it.copy(parameters = it.parameters.drop(1))
|
} else {
|
||||||
|
// Remove $outer argument from secondary constructors of inner classes
|
||||||
|
it.copy(parameters = it.parameters.drop(1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val (innerClasses, nonInnerClasses) = nestedClasses.partition { it.ir.isInner }
|
val (innerClasses, nonInnerClasses) = nestedClasses.partition { it.ir.isInner }
|
||||||
val innerClassesProperties = innerClasses.map { it.toReadonlyProperty() }
|
val innerClassesProperties = innerClasses.map { it.toReadonlyProperty() }
|
||||||
@@ -179,6 +189,26 @@ fun List<ExportedType>.toImplementsClause(superInterfacesKeyword: String, indent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ExportedClass.shouldNotBeImplemented(): Boolean {
|
||||||
|
return (isInterface && !ir.isExternal) || superInterfaces.any { it is ExportedType.ClassType && !it.ir.isExternal }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<ExportedDeclaration>.withMagicProperty(): List<ExportedDeclaration> {
|
||||||
|
return plus(
|
||||||
|
ExportedProperty(
|
||||||
|
"__doNotUseIt",
|
||||||
|
ExportedType.TypeParameter("__doNotImplementIt"),
|
||||||
|
mutable = false,
|
||||||
|
isMember = true,
|
||||||
|
isStatic = false,
|
||||||
|
isAbstract = false,
|
||||||
|
isProtected = false,
|
||||||
|
irGetter = null,
|
||||||
|
irSetter = null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun IrClass.asNestedClassAccess(): String {
|
fun IrClass.asNestedClassAccess(): String {
|
||||||
val name = getJsNameOrKotlinName().identifier
|
val name = getJsNameOrKotlinName().identifier
|
||||||
if (parent !is IrClass) return name
|
if (parent !is IrClass) return name
|
||||||
|
|||||||
+51
-31
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isEnumFakeOverriddenDeclaration
|
import org.jetbrains.kotlin.ir.backend.js.export.isEnumFakeOverriddenDeclaration
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||||
@@ -125,24 +126,21 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrSimpleFunction.accessorRef(): JsNameRef? =
|
val overriddenSymbols = property.getter?.overriddenSymbols.orEmpty()
|
||||||
when (visibility) {
|
|
||||||
DescriptorVisibilities.PRIVATE -> null
|
|
||||||
else -> JsNameRef(
|
|
||||||
context.getNameForMemberFunction(this),
|
|
||||||
classPrototypeRef
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't generate `defineProperty` if the property overrides a property from an exported class,
|
// Don't generate `defineProperty` if the property overrides a property from an exported class,
|
||||||
// because we've already generated `defineProperty` for the base class property.
|
// because we've already generated `defineProperty` for the base class property.
|
||||||
// In other words, we only want to generate `defineProperty` once for each property.
|
// In other words, we only want to generate `defineProperty` once for each property.
|
||||||
// The exception is case when we override val with var,
|
// The exception is case when we override val with var,
|
||||||
// so we need regenerate `defineProperty` with setter.
|
// so we need regenerate `defineProperty` with setter.
|
||||||
val noOverriddenGetter = property.getter?.overriddenSymbols?.isEmpty() == true
|
// P.S. If the overridden property is owned by an interface - we should generate defineProperty
|
||||||
|
// for overridden property in the first class which override those properties
|
||||||
|
val hasOverriddenExportedInterfaceProperties = overriddenSymbols.any { it.owner.parentClassOrNull.isExportedInterface() }
|
||||||
|
&& !overriddenSymbols.any { it.owner.parentClassOrNull.isExportedClass() }
|
||||||
|
|
||||||
val overriddenExportedGetter = (property.getter?.overriddenSymbols?.isNotEmpty() == true &&
|
val getterOverridesExternal = property.getter?.overridesExternal() == true
|
||||||
property.getter?.isOverriddenExported(context.staticContext.backendContext) == true)
|
val overriddenExportedGetter = !property.getter?.overriddenSymbols.isNullOrEmpty() &&
|
||||||
|
property.getter?.isOverriddenExported(context.staticContext.backendContext) == true
|
||||||
|
|
||||||
val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false
|
val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false
|
||||||
|
|
||||||
@@ -150,8 +148,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext)
|
property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext)
|
||||||
|
|
||||||
if (irClass.isExported(context.staticContext.backendContext) &&
|
if (irClass.isExported(context.staticContext.backendContext) &&
|
||||||
(noOverriddenGetter || needsOverride) ||
|
(overriddenSymbols.isEmpty() || needsOverride) ||
|
||||||
property.getter?.overridesExternal() == true ||
|
hasOverriddenExportedInterfaceProperties ||
|
||||||
|
getterOverridesExternal ||
|
||||||
property.getJsName() != null
|
property.getJsName() != null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -168,31 +167,24 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
// set: Foo.prototype._set_prop__a4enbm_k$
|
// set: Foo.prototype._set_prop__a4enbm_k$
|
||||||
// });
|
// });
|
||||||
|
|
||||||
val getterForwarder = if (property.getter?.modality == Modality.FINAL) property.getter?.accessorRef()
|
val getterForwarder = property.getter
|
||||||
else {
|
.takeIf { it.shouldExportAccessor() }
|
||||||
property.getter?.propertyAccessorForwarder("getter forwarder") { getterRef ->
|
.getOrGenerateIfFinal {
|
||||||
JsReturn(
|
propertyAccessorForwarder("getter forwarder") {
|
||||||
JsInvocation(
|
JsReturn(JsInvocation(it))
|
||||||
getterRef
|
}
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val setterForwarder = if (property.setter?.modality == Modality.FINAL) property.setter?.accessorRef()
|
val setterForwarder = property.setter
|
||||||
else {
|
.takeIf { it.shouldExportAccessor() }
|
||||||
property.setter?.let {
|
.getOrGenerateIfFinal {
|
||||||
val setterArgName = JsName("value", false)
|
val setterArgName = JsName("value", false)
|
||||||
it.propertyAccessorForwarder("setter forwarder") { setterRef ->
|
propertyAccessorForwarder("setter forwarder") {
|
||||||
JsInvocation(
|
JsInvocation(it, JsNameRef(setterArgName)).makeStmt()
|
||||||
setterRef,
|
|
||||||
JsNameRef(setterArgName)
|
|
||||||
).makeStmt()
|
|
||||||
}?.apply {
|
}?.apply {
|
||||||
parameters.add(JsParameter(setterArgName))
|
parameters.add(JsParameter(setterArgName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
classBlock.statements += JsExpressionStatement(
|
classBlock.statements += JsExpressionStatement(
|
||||||
defineProperty(
|
defineProperty(
|
||||||
@@ -209,6 +201,34 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
return classBlock
|
return classBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline fun IrSimpleFunction?.getOrGenerateIfFinal(generateFunc: IrSimpleFunction.() -> JsFunction?): JsExpression? {
|
||||||
|
if (this == null) return null
|
||||||
|
return if (modality == Modality.FINAL) accessorRef() else generateFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrSimpleFunction?.shouldExportAccessor(): Boolean {
|
||||||
|
if (this == null) return false
|
||||||
|
|
||||||
|
if (parentAsClass.isExported(context.staticContext.backendContext)) return true
|
||||||
|
|
||||||
|
val property = correspondingPropertySymbol!!.owner
|
||||||
|
|
||||||
|
if (property.isOverriddenExported(context.staticContext.backendContext)) {
|
||||||
|
return isOverriddenExported(context.staticContext.backendContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
return overridesExternal() || property.getJsName() != null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrSimpleFunction.accessorRef(): JsNameRef? =
|
||||||
|
when (visibility) {
|
||||||
|
DescriptorVisibilities.PRIVATE -> null
|
||||||
|
else -> JsNameRef(
|
||||||
|
context.getNameForMemberFunction(this),
|
||||||
|
classPrototypeRef
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrSimpleFunction.generateAssignmentIfMangled(memberRef: JsExpression) {
|
private fun IrSimpleFunction.generateAssignmentIfMangled(memberRef: JsExpression) {
|
||||||
if (
|
if (
|
||||||
irClass.isExported(context.staticContext.backendContext) &&
|
irClass.isExported(context.staticContext.backendContext) &&
|
||||||
|
|||||||
+6
-3
@@ -143,11 +143,14 @@ fun translateCall(
|
|||||||
val jsExtensionReceiver = expression.extensionReceiver?.accept(transformer, context)
|
val jsExtensionReceiver = expression.extensionReceiver?.accept(transformer, context)
|
||||||
val arguments = translateCallArguments(expression, context, transformer)
|
val arguments = translateCallArguments(expression, context, transformer)
|
||||||
|
|
||||||
// Transform external property accessor call
|
// Transform external and interface's property accessor call
|
||||||
// @JsName-annotated external property accessors are translated as function calls
|
// @JsName-annotated external and interface's property accessors are translated as function calls
|
||||||
if (function.getJsName() == null) {
|
if (function.getJsName() == null) {
|
||||||
val property = function.correspondingPropertySymbol?.owner
|
val property = function.correspondingPropertySymbol?.owner
|
||||||
if (property != null && property.isEffectivelyExternal()) {
|
if (
|
||||||
|
property != null &&
|
||||||
|
(property.isEffectivelyExternal() || property.isExportedInterfaceMember())
|
||||||
|
) {
|
||||||
val propertyName = context.getNameForProperty(property)
|
val propertyName = context.getNameForProperty(property)
|
||||||
val nameRef = when (jsDispatchReceiver) {
|
val nameRef = when (jsDispatchReceiver) {
|
||||||
null -> jsGlobalVarRef(JsNameRef(propertyName))
|
null -> jsGlobalVarRef(JsNameRef(propertyName))
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.isInterface
|
||||||
|
import org.jetbrains.kotlin.descriptors.isClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||||
|
|
||||||
|
fun IrDeclaration?.isExportedClass() =
|
||||||
|
this is IrClass && kind.isClass && isJsExport()
|
||||||
|
|
||||||
|
fun IrDeclaration?.isExportedInterface() =
|
||||||
|
this is IrClass && kind.isInterface && isJsExport()
|
||||||
|
|
||||||
|
fun IrDeclaration.isExportedInterfaceMember() =
|
||||||
|
parentClassOrNull.isExportedInterface()
|
||||||
+1
-1
@@ -20,7 +20,7 @@ open class ExportedGenericClass<T>
|
|||||||
class <!NON_EXPORTABLE_TYPE("super; ExportedGenericClass<NonExportedClass>")!>ExportedClass3<!> : ExportedGenericClass<NonExportedClass>()
|
class <!NON_EXPORTABLE_TYPE("super; ExportedGenericClass<NonExportedClass>")!>ExportedClass3<!> : ExportedGenericClass<NonExportedClass>()
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
interface <!WRONG_EXPORTED_DECLARATION!>ExportedGenericInterface<!><T>
|
interface ExportedGenericInterface<T>
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
class <!NON_EXPORTABLE_TYPE("super; ExportedGenericInterface<NonExportedClass>")!>ExportedClass4<!> : ExportedGenericInterface<NonExportedClass>
|
class <!NON_EXPORTABLE_TYPE("super; ExportedGenericInterface<NonExportedClass>")!>ExportedClass4<!> : ExportedGenericInterface<NonExportedClass>
|
||||||
|
|||||||
Vendored
+1
-1
@@ -14,4 +14,4 @@ fun <<!NON_EXPORTABLE_TYPE("upper bound; C")!>T : C<!>>foo() { }
|
|||||||
class A<<!NON_EXPORTABLE_TYPE("upper bound; C")!>T : C<!>, <!NON_EXPORTABLE_TYPE("upper bound; I")!>S: I<!>>
|
class A<<!NON_EXPORTABLE_TYPE("upper bound; C")!>T : C<!>, <!NON_EXPORTABLE_TYPE("upper bound; I")!>S: I<!>>
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
interface <!WRONG_EXPORTED_DECLARATION!>I2<!><<!NON_EXPORTABLE_TYPE("upper bound; C"), NON_EXPORTABLE_TYPE("upper bound; I")!>T<!>> where T : C, T : I
|
interface I2<<!NON_EXPORTABLE_TYPE("upper bound; C"), NON_EXPORTABLE_TYPE("upper bound; I")!>T<!>> where T : C, T : I
|
||||||
|
|||||||
+13
-1
@@ -18,11 +18,23 @@ val String.extensionProperty<!>
|
|||||||
annotation class <!WRONG_EXPORTED_DECLARATION("annotation class")!>AnnotationClass<!>
|
annotation class <!WRONG_EXPORTED_DECLARATION("annotation class")!>AnnotationClass<!>
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
interface <!WRONG_EXPORTED_DECLARATION("interface")!>SomeInterface<!>
|
interface SomeInterface
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
external interface GoodInterface
|
external interface GoodInterface
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
interface InterfaceWithCompanion {
|
||||||
|
companion <!WRONG_EXPORTED_DECLARATION("companion object inside exported interface")!>object<!> {
|
||||||
|
fun foo() = 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
interface OuterInterface {
|
||||||
|
class <!WRONG_EXPORTED_DECLARATION("nested class inside exported interface")!>Nested<!>
|
||||||
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
value class <!WRONG_EXPORTED_DECLARATION("value class")!>A(val a: Int)<!>
|
value class <!WRONG_EXPORTED_DECLARATION("value class")!>A(val a: Int)<!>
|
||||||
|
|
||||||
|
|||||||
+27
@@ -50,6 +50,33 @@ package foo {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.js.JsExport public interface InterfaceWithCompanion {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
public companion object Companion {
|
||||||
|
private constructor Companion()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun foo(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.js.JsExport public interface OuterInterface {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
public final class Nested {
|
||||||
|
public constructor Nested()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@kotlin.js.JsExport public interface SomeInterface {
|
@kotlin.js.JsExport public interface SomeInterface {
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
|||||||
@@ -32,3 +32,6 @@ inline val ClassKind.isInterface: Boolean
|
|||||||
|
|
||||||
inline val ClassKind.isEnumClass: Boolean
|
inline val ClassKind.isEnumClass: Boolean
|
||||||
get() = this == ClassKind.ENUM_CLASS
|
get() = this == ClassKind.ENUM_CLASS
|
||||||
|
|
||||||
|
inline val ClassKind.isClass: Boolean
|
||||||
|
get() = this == ClassKind.CLASS
|
||||||
@@ -136,6 +136,11 @@ val DeclarationDescriptor.isInsidePrivateClass: Boolean
|
|||||||
return parent != null && DescriptorVisibilities.isPrivate(parent.visibility)
|
return parent != null && DescriptorVisibilities.isPrivate(parent.visibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val DeclarationDescriptor.isInsideInterface: Boolean
|
||||||
|
get() {
|
||||||
|
val parent = containingDeclaration as? ClassDescriptor
|
||||||
|
return parent != null && parent.kind.isInterface
|
||||||
|
}
|
||||||
|
|
||||||
fun ClassDescriptor.getSuperClassNotAny(): ClassDescriptor? {
|
fun ClassDescriptor.getSuperClassNotAny(): ClassDescriptor? {
|
||||||
for (supertype in defaultType.constructor.supertypes) {
|
for (supertype in defaultType.constructor.supertypes) {
|
||||||
|
|||||||
+8
-4
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
|||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isInsideInterface
|
||||||
import org.jetbrains.kotlin.resolve.inline.isInlineWithReified
|
import org.jetbrains.kotlin.resolve.inline.isInlineWithReified
|
||||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -109,12 +110,15 @@ object JsExportDeclarationChecker : DeclarationChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val wrongDeclaration: String? = when (descriptor.kind) {
|
val wrongDeclaration: String? = when (descriptor.kind) {
|
||||||
INTERFACE -> if (descriptor.isExternal) null else "interface"
|
|
||||||
ANNOTATION_CLASS -> "annotation class"
|
ANNOTATION_CLASS -> "annotation class"
|
||||||
CLASS -> if (descriptor.isInlineClass()) {
|
CLASS -> when {
|
||||||
"${if (descriptor.isInline) "inline " else ""}${if (descriptor.isValue) "value " else ""}class"
|
descriptor.isInsideInterface -> "nested class inside exported interface"
|
||||||
|
descriptor.isInlineClass() -> "${if (descriptor.isInline) "inline " else ""}${if (descriptor.isValue) "value " else ""}class"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
else -> if (descriptor.isInsideInterface) {
|
||||||
|
"${if (descriptor.isCompanionObject) "companion object" else "nested/inner declaration"} inside exported interface"
|
||||||
} else null
|
} else null
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wrongDeclaration != null) {
|
if (wrongDeclaration != null) {
|
||||||
|
|||||||
@@ -2070,6 +2070,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/export/exportEnumClass.kt");
|
runTest("js/js.translator/testData/box/export/exportEnumClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("exportInterface.kt")
|
||||||
|
public void testExportInterface() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/export/exportInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("exportNestedClass.kt")
|
@TestMetadata("exportNestedClass.kt")
|
||||||
public void testExportNestedClass() throws Exception {
|
public void testExportNestedClass() throws Exception {
|
||||||
|
|||||||
+6
@@ -2460,6 +2460,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/export/exportEnumClass.kt");
|
runTest("js/js.translator/testData/box/export/exportEnumClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("exportInterface.kt")
|
||||||
|
public void testExportInterface() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/export/exportInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("exportNestedClass.kt")
|
@TestMetadata("exportNestedClass.kt")
|
||||||
public void testExportNestedClass() throws Exception {
|
public void testExportNestedClass() throws Exception {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// EXPECTED_REACHABLE_NODES: 1288
|
// EXPECTED_REACHABLE_NODES: 1288
|
||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
// IGNORE_BACKEND: JS_IR_ES6
|
||||||
|
@JsExport
|
||||||
interface I {
|
interface I {
|
||||||
val a: Char
|
val a: Char
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// IGNORE_BACKEND: JS
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
|
||||||
|
// MODULE: export_interface
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
interface I {
|
||||||
|
val value: Int
|
||||||
|
var variable: Int
|
||||||
|
fun foo(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
open class NotExportedClass(override var value: Int) : I {
|
||||||
|
override var variable: Int = value
|
||||||
|
override open fun foo(): String = "Not Exported"
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
class ExportedClass(override val value: Int) : I {
|
||||||
|
override var variable: Int = value
|
||||||
|
override fun foo(): String = "Exported"
|
||||||
|
}
|
||||||
|
|
||||||
|
@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: test.js
|
||||||
|
function box() {
|
||||||
|
const { I, ExportedClass, AnotherOne, generateNotExported, consume } = this["export_interface"]
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
notExported.value = 42
|
||||||
|
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"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
class TestInner {
|
class TestInner {
|
||||||
constructor(a: string);
|
constructor(a: string);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
class ClassWithDefaultCtor {
|
class ClassWithDefaultCtor {
|
||||||
constructor();
|
constructor();
|
||||||
readonly x: string;
|
readonly x: string;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
const _val: number;
|
const _val: number;
|
||||||
let _var: number;
|
let _var: number;
|
||||||
@@ -123,5 +125,17 @@ declare namespace JS_TESTS {
|
|||||||
readonly prop: string;
|
readonly prop: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
interface TestInterface {
|
||||||
|
readonly value: string;
|
||||||
|
getOwnerName(): string;
|
||||||
|
readonly __doNotUseIt: __doNotImplementIt;
|
||||||
|
}
|
||||||
|
class TestInterfaceImpl implements foo.TestInterface {
|
||||||
|
constructor(value: string);
|
||||||
|
readonly value: string;
|
||||||
|
getOwnerName(): string;
|
||||||
|
readonly __doNotUseIt: __doNotImplementIt;
|
||||||
|
}
|
||||||
|
function processInterface(test: foo.TestInterface): string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,4 +179,21 @@ enum class TestEnumClass(val constructorParameter: String) {
|
|||||||
class Nested {
|
class Nested {
|
||||||
val prop: String = "hello2"
|
val prop: String = "hello2"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
interface TestInterface {
|
||||||
|
val value: String
|
||||||
|
fun getOwnerName(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
class TestInterfaceImpl(override val value: String) : TestInterface {
|
||||||
|
override fun getOwnerName() = "TestInterfaceImpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun processInterface(test: TestInterface): String {
|
||||||
|
return "Owner ${test.getOwnerName()} has value '${test.value}'"
|
||||||
}
|
}
|
||||||
+5
@@ -27,6 +27,8 @@ var TestSealed = JS_TESTS.foo.TestSealed;
|
|||||||
var TestAbstract = JS_TESTS.foo.TestAbstract;
|
var TestAbstract = JS_TESTS.foo.TestAbstract;
|
||||||
var TestDataClass = JS_TESTS.foo.TestDataClass;
|
var TestDataClass = JS_TESTS.foo.TestDataClass;
|
||||||
var TestEnumClass = JS_TESTS.foo.TestEnumClass;
|
var TestEnumClass = JS_TESTS.foo.TestEnumClass;
|
||||||
|
var TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
|
||||||
|
var processInterface = JS_TESTS.foo.processInterface;
|
||||||
function assert(condition) {
|
function assert(condition) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw "Assertion failed";
|
throw "Assertion failed";
|
||||||
@@ -112,5 +114,8 @@ function box() {
|
|||||||
assert(TestEnumClass.A.ordinal === 0);
|
assert(TestEnumClass.A.ordinal === 0);
|
||||||
assert(TestEnumClass.B.ordinal === 1);
|
assert(TestEnumClass.B.ordinal === 1);
|
||||||
assert(new TestEnumClass.Nested().prop == "hello2");
|
assert(new TestEnumClass.Nested().prop == "hello2");
|
||||||
|
assert(processInterface(new TestInterfaceImpl("bar")) == "Owner TestInterfaceImpl has value 'bar'");
|
||||||
|
// @ts-expect-error "Just test that this code will throw compilation error for a user"
|
||||||
|
assert(processInterface({ value: "bar", getOwnerName: function () { return "RandomObject"; } }) == "Owner RandomObject has value 'bar'");
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -27,6 +27,8 @@ import TestSealed = JS_TESTS.foo.TestSealed;
|
|||||||
import TestAbstract = JS_TESTS.foo.TestAbstract;
|
import TestAbstract = JS_TESTS.foo.TestAbstract;
|
||||||
import TestDataClass = JS_TESTS.foo.TestDataClass;
|
import TestDataClass = JS_TESTS.foo.TestDataClass;
|
||||||
import TestEnumClass = JS_TESTS.foo.TestEnumClass;
|
import TestEnumClass = JS_TESTS.foo.TestEnumClass;
|
||||||
|
import TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
|
||||||
|
import processInterface = JS_TESTS.foo.processInterface;
|
||||||
|
|
||||||
function assert(condition: boolean) {
|
function assert(condition: boolean) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
@@ -133,5 +135,10 @@ function box(): string {
|
|||||||
|
|
||||||
assert(new TestEnumClass.Nested().prop == "hello2")
|
assert(new TestEnumClass.Nested().prop == "hello2")
|
||||||
|
|
||||||
|
assert(processInterface(new TestInterfaceImpl("bar")) == "Owner TestInterfaceImpl has value 'bar'")
|
||||||
|
|
||||||
|
// @ts-expect-error "Just test that this code will throw compilation error for a user"
|
||||||
|
assert(processInterface({ value: "bar", getOwnerName: () => "RandomObject" }) == "Owner RandomObject has value 'bar'")
|
||||||
|
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
+2
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
|
interface ExportedInterface {
|
||||||
|
readonly __doNotUseIt: __doNotImplementIt;
|
||||||
|
}
|
||||||
function producer(value: number): any/* foo.NonExportedType */;
|
function producer(value: number): any/* foo.NonExportedType */;
|
||||||
function consumer(value: any/* foo.NonExportedType */): number;
|
function consumer(value: any/* foo.NonExportedType */): number;
|
||||||
class A {
|
class A {
|
||||||
@@ -14,5 +19,16 @@ declare namespace JS_TESTS {
|
|||||||
class C /* implements foo.NonExportedInterface */ {
|
class C /* implements foo.NonExportedInterface */ {
|
||||||
constructor();
|
constructor();
|
||||||
}
|
}
|
||||||
|
class D implements foo.ExportedInterface/*, foo.NonExportedInterface */ {
|
||||||
|
constructor();
|
||||||
|
readonly __doNotUseIt: __doNotImplementIt;
|
||||||
|
}
|
||||||
|
class E /* extends foo.NonExportedType */ implements foo.ExportedInterface {
|
||||||
|
constructor();
|
||||||
|
readonly __doNotUseIt: __doNotImplementIt;
|
||||||
|
}
|
||||||
|
class F extends foo.A /* implements foo.NonExportedInterface */ {
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+14
-2
@@ -11,6 +11,9 @@ package foo
|
|||||||
interface NonExportedInterface
|
interface NonExportedInterface
|
||||||
open class NonExportedType(val value: Int)
|
open class NonExportedType(val value: Int)
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
interface ExportedInterface
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
fun producer(value: Int): NonExportedType {
|
fun producer(value: Int): NonExportedType {
|
||||||
return NonExportedType(value)
|
return NonExportedType(value)
|
||||||
@@ -22,7 +25,7 @@ fun consumer(value: NonExportedType): Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
class A(var value: NonExportedType) {
|
open class A(var value: NonExportedType) {
|
||||||
fun <T: NonExportedType> increment(t: T): NonExportedType {
|
fun <T: NonExportedType> increment(t: T): NonExportedType {
|
||||||
return NonExportedType(value = t.value + 1)
|
return NonExportedType(value = t.value + 1)
|
||||||
}
|
}
|
||||||
@@ -32,4 +35,13 @@ class A(var value: NonExportedType) {
|
|||||||
class B(v: Int) : NonExportedType(v)
|
class B(v: Int) : NonExportedType(v)
|
||||||
|
|
||||||
@JsExport
|
@JsExport
|
||||||
class C : NonExportedInterface
|
class C : NonExportedInterface
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
class D : NonExportedInterface, ExportedInterface
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
class E : NonExportedType(42), ExportedInterface
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
class F : A(NonExportedType(42)), NonExportedInterface
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface I<T, S, U> {
|
interface I<T, S, U> {
|
||||||
x: T;
|
x: T;
|
||||||
|
|||||||
+2
-2
@@ -26,12 +26,12 @@ var Impl = /** @class */ (function (_super) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(Impl.prototype, "acAbstractProp", {
|
Object.defineProperty(Impl.prototype, "acAbstractProp", {
|
||||||
get: function () { return "Impl"; },
|
get: function () { return "Impl"; },
|
||||||
enumerable: true,
|
enumerable: false,
|
||||||
configurable: true
|
configurable: true
|
||||||
});
|
});
|
||||||
Object.defineProperty(Impl.prototype, "y", {
|
Object.defineProperty(Impl.prototype, "y", {
|
||||||
get: function () { return true; },
|
get: function () { return true; },
|
||||||
enumerable: true,
|
enumerable: false,
|
||||||
configurable: true
|
configurable: true
|
||||||
});
|
});
|
||||||
return Impl;
|
return Impl;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
declare const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
export namespace foo {
|
export namespace foo {
|
||||||
const prop: number;
|
const prop: number;
|
||||||
class C {
|
class C {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
const prop: number;
|
const prop: number;
|
||||||
class C {
|
class C {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
declare const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
export namespace foo {
|
export namespace foo {
|
||||||
const prop: number;
|
const prop: number;
|
||||||
class C {
|
class C {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo.bar.baz {
|
namespace foo.bar.baz {
|
||||||
class C1 {
|
class C1 {
|
||||||
constructor(value: string);
|
constructor(value: string);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
const _any: any;
|
const _any: any;
|
||||||
const _throwable: Error;
|
const _throwable: Error;
|
||||||
|
|||||||
+2
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface ExportedInternalInterface {
|
interface ExportedInternalInterface {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
const __doNotImplementIt: unique symbol
|
||||||
|
type __doNotImplementIt = typeof __doNotImplementIt
|
||||||
interface publicInterface {
|
interface publicInterface {
|
||||||
}
|
}
|
||||||
const publicVal: number;
|
const publicVal: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user