JS: add support of JsQualifier annotation. See KT-15905
This commit is contained in:
@@ -42,6 +42,7 @@ public final class AnnotationsUtils {
|
|||||||
private static final String JS_NAME = "kotlin.js.JsName";
|
private static final String JS_NAME = "kotlin.js.JsName";
|
||||||
private static final FqName JS_MODULE_ANNOTATION = new FqName("kotlin.js.JsModule");
|
private static final FqName JS_MODULE_ANNOTATION = new FqName("kotlin.js.JsModule");
|
||||||
private static final FqName JS_NON_MODULE_ANNOTATION = new FqName("kotlin.js.JsNonModule");
|
private static final FqName JS_NON_MODULE_ANNOTATION = new FqName("kotlin.js.JsNonModule");
|
||||||
|
private static final FqName JS_QUALIFIER_ANNOTATION = new FqName("kotlin.js.JsQualifier");
|
||||||
|
|
||||||
private AnnotationsUtils() {
|
private AnnotationsUtils() {
|
||||||
}
|
}
|
||||||
@@ -197,21 +198,34 @@ public final class AnnotationsUtils {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public static String getModuleName(@NotNull DeclarationDescriptor declaration) {
|
public static String getModuleName(@NotNull DeclarationDescriptor declaration) {
|
||||||
AnnotationDescriptor annotation = declaration.getAnnotations().findAnnotation(JS_MODULE_ANNOTATION);
|
AnnotationDescriptor annotation = declaration.getAnnotations().findAnnotation(JS_MODULE_ANNOTATION);
|
||||||
return annotation != null ? extractJsModuleName(annotation) : null;
|
return annotation != null ? extractSingleStringArgument(annotation) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getFileModuleName(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor declaration) {
|
public static String getFileModuleName(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor declaration) {
|
||||||
|
return getSingleStringAnnotationArgument(bindingContext, declaration, JS_MODULE_ANNOTATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getFileQualifier(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor declaration) {
|
||||||
|
return getSingleStringAnnotationArgument(bindingContext, declaration, JS_QUALIFIER_ANNOTATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String getSingleStringAnnotationArgument(
|
||||||
|
@NotNull BindingContext bindingContext,
|
||||||
|
@NotNull DeclarationDescriptor declaration,
|
||||||
|
@NotNull FqName annotationFqName
|
||||||
|
) {
|
||||||
for (AnnotationDescriptor annotation : getContainingFileAnnotations(bindingContext, declaration)) {
|
for (AnnotationDescriptor annotation : getContainingFileAnnotations(bindingContext, declaration)) {
|
||||||
DeclarationDescriptor annotationType = annotation.getType().getConstructor().getDeclarationDescriptor();
|
DeclarationDescriptor annotationType = annotation.getType().getConstructor().getDeclarationDescriptor();
|
||||||
if (annotationType == null) continue;
|
if (annotationType == null) continue;
|
||||||
|
|
||||||
FqNameUnsafe fqName = DescriptorUtils.getFqName(annotation.getType().getConstructor().getDeclarationDescriptor());
|
FqNameUnsafe fqName = DescriptorUtils.getFqName(annotation.getType().getConstructor().getDeclarationDescriptor());
|
||||||
if (fqName.equals(JS_MODULE_ANNOTATION.toUnsafe())) {
|
if (fqName.equals(annotationFqName.toUnsafe())) {
|
||||||
return extractJsModuleName(annotation);
|
return extractSingleStringArgument(annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +251,7 @@ public final class AnnotationsUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String extractJsModuleName(@NotNull AnnotationDescriptor annotation) {
|
private static String extractSingleStringArgument(@NotNull AnnotationDescriptor annotation) {
|
||||||
if (annotation.getAllValueArguments().isEmpty()) return null;
|
if (annotation.getAllValueArguments().isEmpty()) return null;
|
||||||
|
|
||||||
ConstantValue<?> importValue = annotation.getAllValueArguments().values().iterator().next();
|
ConstantValue<?> importValue = annotation.getAllValueArguments().values().iterator().next();
|
||||||
|
|||||||
@@ -54,4 +54,8 @@ annotation class JsModule(val import: String)
|
|||||||
|
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
@Target(CLASS, PROPERTY, FUNCTION, FILE)
|
@Target(CLASS, PROPERTY, FUNCTION, FILE)
|
||||||
annotation class JsNonModule
|
annotation class JsNonModule
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@Target(AnnotationTarget.FILE)
|
||||||
|
annotation class JsQualifier(val value: String)
|
||||||
+3
-3
@@ -144,9 +144,6 @@ object KotlinJavascriptSerializationUtil {
|
|||||||
}
|
}
|
||||||
}, skip)
|
}, skip)
|
||||||
|
|
||||||
writeFun(KotlinJavascriptSerializedResourcePaths.getFileListFilePath(fqName),
|
|
||||||
serializeFiles(fileRegistry, bindingContext, AnnotationSerializer(serializer.stringTable)))
|
|
||||||
|
|
||||||
val packageStream = ByteArrayOutputStream()
|
val packageStream = ByteArrayOutputStream()
|
||||||
val fragments = packageView.fragments
|
val fragments = packageView.fragments
|
||||||
val members = fragments
|
val members = fragments
|
||||||
@@ -158,6 +155,9 @@ object KotlinJavascriptSerializationUtil {
|
|||||||
writeFun(KotlinJavascriptSerializedResourcePaths.getPackageFilePath(fqName), packageStream.toByteArray())
|
writeFun(KotlinJavascriptSerializedResourcePaths.getPackageFilePath(fqName), packageStream.toByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeFun(KotlinJavascriptSerializedResourcePaths.getFileListFilePath(fqName),
|
||||||
|
serializeFiles(fileRegistry, bindingContext, AnnotationSerializer(serializer.stringTable)))
|
||||||
|
|
||||||
val strings = serializerExtension.stringTable
|
val strings = serializerExtension.stringTable
|
||||||
serializeClassNamesInPackage(fqName, fragments, strings, skip, writeFun)
|
serializeClassNamesInPackage(fqName, fragments, strings, skip, writeFun)
|
||||||
|
|
||||||
|
|||||||
@@ -5238,6 +5238,39 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("js/js.translator/testData/box/jsQualifier")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JsQualifier extends AbstractBoxJsTest {
|
||||||
|
public void testAllFilesPresentInJsQualifier() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/jsQualifier"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classes.kt")
|
||||||
|
public void testClasses() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/jsQualifier/classes.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/jsQualifier/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("umdFallback.kt")
|
||||||
|
public void testUmdFallback() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/jsQualifier/umdFallback.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withModule.kt")
|
||||||
|
public void testWithModule() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/jsQualifier/withModule.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("js/js.translator/testData/box/labels")
|
@TestMetadata("js/js.translator/testData/box/labels")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.translate.context;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.intellij.openapi.util.Factory;
|
import com.intellij.openapi.util.Factory;
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -287,7 +288,14 @@ public final class StaticContext {
|
|||||||
String fileModuleName = AnnotationsUtils.getFileModuleName(getBindingContext(), suggested.getDescriptor());
|
String fileModuleName = AnnotationsUtils.getFileModuleName(getBindingContext(), suggested.getDescriptor());
|
||||||
if (fileModuleName != null) {
|
if (fileModuleName != null) {
|
||||||
JsName moduleJsName = getImportedModule(fileModuleName, null).internalName;
|
JsName moduleJsName = getImportedModule(fileModuleName, null).internalName;
|
||||||
expression = pureFqn(moduleJsName, null);
|
expression = pureFqn(moduleJsName, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
String qualifier = AnnotationsUtils.getFileQualifier(getBindingContext(), suggested.getDescriptor());
|
||||||
|
if (qualifier != null) {
|
||||||
|
for (String qualifierPart : StringUtil.split(qualifier, ".")) {
|
||||||
|
expression = pureFqn(qualifierPart, expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
var pkg = function() {
|
||||||
|
function C() {
|
||||||
|
}
|
||||||
|
C.prototype.o = function() {
|
||||||
|
return "O";
|
||||||
|
};
|
||||||
|
function D() {
|
||||||
|
}
|
||||||
|
D.prototype.k = function() {
|
||||||
|
return "K";
|
||||||
|
};
|
||||||
|
C.D = D;
|
||||||
|
return {
|
||||||
|
C: C
|
||||||
|
};
|
||||||
|
}();
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
@file:JsQualifier("pkg")
|
||||||
|
external class C {
|
||||||
|
fun o(): String
|
||||||
|
|
||||||
|
class D {
|
||||||
|
fun k(): String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
fun box() = C().o() + C.D().k()
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
var a = {
|
||||||
|
b: {
|
||||||
|
c: function() {
|
||||||
|
return "O";
|
||||||
|
},
|
||||||
|
d: "K"
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
@file:JsQualifier("a.b")
|
||||||
|
package ab
|
||||||
|
|
||||||
|
external fun c(): String
|
||||||
|
|
||||||
|
external val d: String
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
fun box() = ab.c() + ab.d
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
var foo = {
|
||||||
|
bar: function() {
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
// MODULE_KIND: UMD
|
||||||
|
// NO_JS_MODULE_SYSTEM
|
||||||
|
@file:JsQualifier("foo")
|
||||||
|
|
||||||
|
external fun bar(): String
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
// MODULE_KIND: UMD
|
||||||
|
// NO_JS_MODULE_SYSTEM
|
||||||
|
fun box() = bar()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
define("libjs", ["exports"], function(exports) {
|
||||||
|
exports.a = {
|
||||||
|
b: {
|
||||||
|
c: function () {
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
// MODULE_KIND: AMD
|
||||||
|
@file:JsQualifier("a.b")
|
||||||
|
@file:JsModule("libjs")
|
||||||
|
package ab
|
||||||
|
|
||||||
|
external fun c(): String
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
// MODULE_KIND: AMD
|
||||||
|
package main
|
||||||
|
|
||||||
|
fun box() = ab.c()
|
||||||
Reference in New Issue
Block a user