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 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_QUALIFIER_ANNOTATION = new FqName("kotlin.js.JsQualifier");
|
||||
|
||||
private AnnotationsUtils() {
|
||||
}
|
||||
@@ -197,21 +198,34 @@ public final class AnnotationsUtils {
|
||||
@Nullable
|
||||
public static String getModuleName(@NotNull DeclarationDescriptor declaration) {
|
||||
AnnotationDescriptor annotation = declaration.getAnnotations().findAnnotation(JS_MODULE_ANNOTATION);
|
||||
return annotation != null ? extractJsModuleName(annotation) : null;
|
||||
return annotation != null ? extractSingleStringArgument(annotation) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
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)) {
|
||||
DeclarationDescriptor annotationType = annotation.getType().getConstructor().getDeclarationDescriptor();
|
||||
if (annotationType == null) continue;
|
||||
|
||||
FqNameUnsafe fqName = DescriptorUtils.getFqName(annotation.getType().getConstructor().getDeclarationDescriptor());
|
||||
if (fqName.equals(JS_MODULE_ANNOTATION.toUnsafe())) {
|
||||
return extractJsModuleName(annotation);
|
||||
if (fqName.equals(annotationFqName.toUnsafe())) {
|
||||
return extractSingleStringArgument(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -237,7 +251,7 @@ public final class AnnotationsUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String extractJsModuleName(@NotNull AnnotationDescriptor annotation) {
|
||||
private static String extractSingleStringArgument(@NotNull AnnotationDescriptor annotation) {
|
||||
if (annotation.getAllValueArguments().isEmpty()) return null;
|
||||
|
||||
ConstantValue<?> importValue = annotation.getAllValueArguments().values().iterator().next();
|
||||
|
||||
@@ -54,4 +54,8 @@ annotation class JsModule(val import: String)
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@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)
|
||||
|
||||
writeFun(KotlinJavascriptSerializedResourcePaths.getFileListFilePath(fqName),
|
||||
serializeFiles(fileRegistry, bindingContext, AnnotationSerializer(serializer.stringTable)))
|
||||
|
||||
val packageStream = ByteArrayOutputStream()
|
||||
val fragments = packageView.fragments
|
||||
val members = fragments
|
||||
@@ -158,6 +155,9 @@ object KotlinJavascriptSerializationUtil {
|
||||
writeFun(KotlinJavascriptSerializedResourcePaths.getPackageFilePath(fqName), packageStream.toByteArray())
|
||||
}
|
||||
|
||||
writeFun(KotlinJavascriptSerializedResourcePaths.getFileListFilePath(fqName),
|
||||
serializeFiles(fileRegistry, bindingContext, AnnotationSerializer(serializer.stringTable)))
|
||||
|
||||
val strings = serializerExtension.stringTable
|
||||
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")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@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.Maps;
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -287,7 +288,14 @@ public final class StaticContext {
|
||||
String fileModuleName = AnnotationsUtils.getFileModuleName(getBindingContext(), suggested.getDescriptor());
|
||||
if (fileModuleName != null) {
|
||||
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