diff --git a/core-lib/es5/src/main/java/jsweet/lang/Name.java b/core-lib/es5/src/main/java/jsweet/lang/Name.java
index 77ccc54f..c3a9cbef 100644
--- a/core-lib/es5/src/main/java/jsweet/lang/Name.java
+++ b/core-lib/es5/src/main/java/jsweet/lang/Name.java
@@ -27,20 +27,20 @@ import java.lang.annotation.Target;
* final generated code (rather than the Java name).
*
*
- * This needs to be used when the name of an element is not a valid Java
- * identifier. By convention, JSweet implements a built-in convention to save
- * the use of @Name annotations:
+ * It can be used when the name of an element is not a valid Java identifier. By
+ * convention, JSweet implements a built-in convention to save the use of @Name
+ * annotations:
*
*
* - Convention:
Keyword in Java transpiles to
- * keyword, when keyword is a Java keyword (such as catch, finaly,
+ * keyword, when keyword is a Java keyword (such as catch, finally,
* int, long, and so forth)
*
*
* @author Renaud Pawlak
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PACKAGE })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PACKAGE })
@Documented
public @interface Name {
diff --git a/core-lib/es6/src/main/java/jsweet/lang/Name.java b/core-lib/es6/src/main/java/jsweet/lang/Name.java
index f6e6ee1d..f91ef816 100644
--- a/core-lib/es6/src/main/java/jsweet/lang/Name.java
+++ b/core-lib/es6/src/main/java/jsweet/lang/Name.java
@@ -27,20 +27,20 @@ import java.lang.annotation.Target;
* final generated code (rather than the Java name).
*
*
- * This needs to be used when the name of an element is not a valid Java
- * identifier. By convention, JSweet implements a built-in convention to save
- * the use of @Name annotations:
+ * It can be used when the name of an element is not a valid Java identifier. By
+ * convention, JSweet implements a built-in convention to save the use of @Name
+ * annotations:
*
*
* - Convention:
Keyword in Java transpiles to
- * keyword, when keyword is a Java keyword (such as catch, finaly,
+ * keyword, when keyword is a Java keyword (such as catch, finally,
* int, long, and so forth)
*
*
* @author Renaud Pawlak
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PACKAGE })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PACKAGE })
@Documented
public @interface Name {
diff --git a/transpiler/src/main/java/org/jsweet/transpiler/JSweetProblem.java b/transpiler/src/main/java/org/jsweet/transpiler/JSweetProblem.java
index 325497e4..fd722be2 100644
--- a/transpiler/src/main/java/org/jsweet/transpiler/JSweetProblem.java
+++ b/transpiler/src/main/java/org/jsweet/transpiler/JSweetProblem.java
@@ -302,9 +302,16 @@ public enum JSweetProblem {
/**
* Raised when a template literal is not used properly.
*/
- MISUSED_TEMPLATE_MACRO(Severity.ERROR);
+ MISUSED_TEMPLATE_MACRO(Severity.ERROR),
+ /**
+ * Raised when a mixin does not have the same name as its target.
+ */
+ WRONG_MIXIN_NAME(Severity.ERROR),
+ /**
+ * Raised when a mixin targets itself.
+ */
+ SELF_MIXIN_TARGET(Severity.ERROR);
-
private Severity severity;
/**
@@ -334,11 +341,15 @@ public enum JSweetProblem {
case MAPPED_TSC_ERROR:
return String.format("%s", params);
case NODE_CANNOT_START:
- return String.format("cannot find Node.js: install first and make sure that the 'node' command is in your execution path", params);
+ return String.format(
+ "cannot find Node.js: install first and make sure that the 'node' command is in your execution path",
+ params);
case NODE_OBSOLETE_VERSION:
return String.format("Node.js should be upgraded: %s < %s (recommended)", params);
case TSC_CANNOT_START:
- return String.format("cannot find TypeScript compiler: install first and make sure that the 'tsc' command is in your execution path", params);
+ return String.format(
+ "cannot find TypeScript compiler: install first and make sure that the 'tsc' command is in your execution path",
+ params);
case JDK_TYPE:
return String.format("invalid access to JDK type '%s' from JSweet", params);
case JDK_METHOD:
@@ -360,12 +371,16 @@ public enum JSweetProblem {
case UNINITIALIZED_FIELD:
return String.format("field '%s' is not optional (see @Optional) but has not been initialized", params);
case USELESS_OPTIONAL_ANNOTATION:
- return String.format("useless @Optional field %s (fields are optional by default in classes, use @Interface to define %s as an interface)", params);
- case JS_KEYWORD_CONFLICT:
- return String.format("local variable name '%s' is not allowed and is automatically generated to '" + JSweetConfig.JS_KEYWORD_PREFIX + "%s'",
+ return String.format(
+ "useless @Optional field %s (fields are optional by default in classes, use @Interface to define %s as an interface)",
params);
+ case JS_KEYWORD_CONFLICT:
+ return String.format("local variable name '%s' is not allowed and is automatically generated to '"
+ + JSweetConfig.JS_KEYWORD_PREFIX + "%s'", params);
case INVALID_METHOD_BODY_IN_INTERFACE:
- return String.format("method '%s' cannot define a body in interface '%s' (try 'abstract' or 'native' modifiers)", params);
+ return String.format(
+ "method '%s' cannot define a body in interface '%s' (try 'abstract' or 'native' modifiers)",
+ params);
case INVALID_PRIVATE_IN_INTERFACE:
return String.format("member '%s' cannot be private in interface '%s'", params);
case INVALID_FIELD_INITIALIZER_IN_INTERFACE:
@@ -421,16 +436,22 @@ public enum JSweetProblem {
case WILDCARD_IMPORT:
return String.format("imports cannot use * wildcards: please import a specific element", params);
case ENCLOSED_ROOT_PACKAGES:
- return String.format("invalid package hierarchy: @Root package '%s' cannot be enclosed in @Root package '%s'", params);
+ return String.format(
+ "invalid package hierarchy: @Root package '%s' cannot be enclosed in @Root package '%s'", params);
case MULTIPLE_ROOT_PACKAGES_NOT_ALLOWED_WITH_MODULES:
- return String.format("multipe @Root packages (including the default 'null' package) are not allowed when using modules, found packages: %s",
+ return String.format(
+ "multipe @Root packages (including the default 'null' package) are not allowed when using modules, found packages: %s",
params);
case CLASS_OUT_OF_ROOT_PACKAGE_SCOPE:
- return String.format("invalid package hierarchy: type '%s' is declared in a parent of @Root package '%s'", params);
+ return String.format("invalid package hierarchy: type '%s' is declared in a parent of @Root package '%s'",
+ params);
case WRONG_USE_OF_AMBIENT:
- return String.format("wrong use of @Ambient on '%s': only types and globals can be declared as ambients", params);
+ return String.format("wrong use of @Ambient on '%s': only types and globals can be declared as ambients",
+ params);
case CANDY_VERSION_DISCREPANCY:
- return String.format("candy %s:%s was generated for a different version of the transpiler (current:%s, candy:%s)", params);
+ return String.format(
+ "candy %s:%s was generated for a different version of the transpiler (current:%s, candy:%s)",
+ params);
case GLOBALS_CAN_ONLY_HAVE_STATIC_MEMBERS:
return String.format("globals classes can only define static members", params);
case GLOBALS_CLASS_CANNOT_HAVE_SUPERCLASS:
@@ -438,21 +459,31 @@ public enum JSweetProblem {
case GLOBALS_CLASS_CANNOT_BE_SUBCLASSED:
return String.format("globals classes cannot be subclassed", params);
case CANNOT_ACCESS_THIS:
- return String.format("'this' isn't defined in scope of %s", params);
+ return String.format("'this' isn't defined in scope of '%s'", params);
case CANNOT_ACCESS_STATIC_MEMBER_ON_THIS:
return String.format("member '%s' is static and cannot be accessed on 'this'", params);
case UNTYPED_OBJECT_ODD_PARAMETER_COUNT:
- return String.format("wrong parameter count: method '$object' expects a list of key/value pairs as parameters", params);
+ return String.format(
+ "wrong parameter count: method '$object' expects a list of key/value pairs as parameters", params);
case UNTYPED_OBJECT_WRONG_KEY:
- return String.format("wrong key: method '$object' expects a list of key/value pairs as parameters, where keys are string literals", params);
+ return String.format(
+ "wrong key: method '$object' expects a list of key/value pairs as parameters, where keys are string literals",
+ params);
case CYCLE_IN_STATIC_INITIALIZER_DEPENDENCIES:
return String.format("a cycle was detected in static intializers involving '%s'", params);
case INTERNAL_TRANSPILER_ERROR:
return String.format("internal transpiler error");
case MISUSED_INSERT_MACRO:
- return String.format("the %s macro argument must be a raw string literal");
+ return String.format("the '%s' macro argument must be a raw string literal", params);
case MISUSED_TEMPLATE_MACRO:
- return String.format("the %s macro last argument must be a raw string literal");
+ return String.format("the '%s' macro last argument must be a raw string literal", params);
+ case WRONG_MIXIN_NAME:
+ return String.format("the '%s' mixin must have the same root-relative name as its target ('%s')", params);
+ case SELF_MIXIN_TARGET:
+ return String.format(
+ "the '%s' mixin targets itself but should target another interface/declaration of the same name",
+ params);
+
}
return null;
}
diff --git a/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java b/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java
index 80f0c259..b68fc98f 100644
--- a/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java
+++ b/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java
@@ -174,7 +174,7 @@ public class JSweetTranspiler implements JSweetOptions {
private boolean interfaceTracking = true;
private boolean supportGetClass = true;
private boolean supportSaticLazyInitialization = true;
- private boolean generateDefinitions = false;
+ private boolean generateDefinitions = true;
private ArrayList jsLibFiles = new ArrayList<>();
private File sourceRoot = null;
private boolean ignoreTypeScriptErrors = false;
diff --git a/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java b/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java
index d2866f84..a0da408a 100644
--- a/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java
+++ b/transpiler/src/main/java/org/jsweet/transpiler/Java2TypeScriptTranslator.java
@@ -75,6 +75,8 @@ import org.jsweet.transpiler.util.JSDoc;
import org.jsweet.transpiler.util.Util;
import com.sun.source.tree.Tree.Kind;
+import com.sun.tools.javac.code.Attribute;
+import com.sun.tools.javac.code.Attribute.Compound;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
@@ -1184,6 +1186,19 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
String mixin = null;
if (context.hasAnnotationType(classdecl.sym, JSweetConfig.ANNOTATION_MIXIN)) {
mixin = context.getAnnotationValue(classdecl.sym, JSweetConfig.ANNOTATION_MIXIN, null);
+ for (Compound c : classdecl.sym.getAnnotationMirrors()) {
+ if (JSweetConfig.ANNOTATION_MIXIN.equals(c.type.toString())) {
+ String targetName = getRootRelativeName(((Attribute.Class)c.values.head.snd).classType.tsym);
+ String mixinName = getRootRelativeName(classdecl.sym);
+ if(!mixinName.equals(targetName)) {
+ report(classdecl, JSweetProblem.WRONG_MIXIN_NAME, mixinName, targetName);
+ } else {
+ if(((Attribute.Class)c.values.head.snd).classType.tsym.equals(classdecl.sym)) {
+ report(classdecl, JSweetProblem.SELF_MIXIN_TARGET, mixinName);
+ }
+ }
+ }
+ }
}
boolean extendsInterface = false;
diff --git a/transpiler/src/test/java/def/test/JQuery.java b/transpiler/src/test/java/def/test/JQuery.java
index ee3760b7..e244fee6 100644
--- a/transpiler/src/test/java/def/test/JQuery.java
+++ b/transpiler/src/test/java/def/test/JQuery.java
@@ -8,6 +8,9 @@ public class JQuery extends def.jquery.JQuery {
public native void modal(String action);
- public native void material_select();
+ public native JQuery material_select();
+
+ public native JQuery myExtension();
+
}
diff --git a/transpiler/src/test/java/def/test2/ExtendedJQuery.java b/transpiler/src/test/java/def/test2/ExtendedJQuery.java
new file mode 100644
index 00000000..5f76c0d1
--- /dev/null
+++ b/transpiler/src/test/java/def/test2/ExtendedJQuery.java
@@ -0,0 +1,17 @@
+package def.test2;
+
+import jsweet.lang.Mixin;
+import jsweet.lang.Name;
+
+@Mixin(target = def.jquery.JQuery.class)
+public class ExtendedJQuery extends def.jquery.JQuery {
+ public native void modal();
+
+ public native void modal(String action);
+
+ public native ExtendedJQuery material_select();
+
+ @Name("EXT")
+ public native ExtendedJQuery myExtension();
+
+}
diff --git a/transpiler/src/test/java/def/test2/Globals.java b/transpiler/src/test/java/def/test2/Globals.java
new file mode 100644
index 00000000..743b5172
--- /dev/null
+++ b/transpiler/src/test/java/def/test2/Globals.java
@@ -0,0 +1,8 @@
+package def.test2;
+
+import jsweet.lang.Erased;
+
+public class Globals {
+ @Erased
+ public static native ExtendedJQuery $(CharSequence query);
+}
diff --git a/transpiler/src/test/java/def/test3/JQuery.java b/transpiler/src/test/java/def/test3/JQuery.java
new file mode 100644
index 00000000..ddf7e8c5
--- /dev/null
+++ b/transpiler/src/test/java/def/test3/JQuery.java
@@ -0,0 +1,8 @@
+package def.test3;
+
+import jsweet.lang.Mixin;
+
+@Mixin(target=JQuery.class)
+public class JQuery extends def.jquery.JQuery {
+
+}
diff --git a/transpiler/src/test/java/org/jsweet/test/transpiler/TypingTests.java b/transpiler/src/test/java/org/jsweet/test/transpiler/TypingTests.java
index eca5b95a..571efdbd 100644
--- a/transpiler/src/test/java/org/jsweet/test/transpiler/TypingTests.java
+++ b/transpiler/src/test/java/org/jsweet/test/transpiler/TypingTests.java
@@ -23,6 +23,7 @@ import org.junit.Test;
import def.test.Globals;
import def.test.JQuery;
+import def.test2.ExtendedJQuery;
import source.typing.ArraysOfLambdas;
import source.typing.ClassTypeAsFunction;
import source.typing.ClassTypeAsTypeOf;
@@ -31,6 +32,7 @@ import source.typing.CustomStringTypes;
import source.typing.InvalidIndexedAccesses;
import source.typing.Lambdas;
import source.typing.MixinsWithDefs;
+import source.typing.MixinsWithDefsAndOtherName;
import source.typing.Numbers;
import source.typing.StringTypesUsage;
import source.typing.Tuples;
@@ -161,4 +163,13 @@ public class TypingTests extends AbstractTest {
}, getSourceFile(MixinsWithDefs.class), getSourceFile(Globals.class), getSourceFile(JQuery.class));
}
+ @Test
+ public void testWrongMixins() {
+ transpile(ModuleKind.none, logHandler -> {
+ Assert.assertTrue(logHandler.reportedProblems.contains(JSweetProblem.WRONG_MIXIN_NAME)
+ && logHandler.reportedProblems.contains(JSweetProblem.SELF_MIXIN_TARGET));
+ }, getSourceFile(MixinsWithDefsAndOtherName.class), getSourceFile(def.test2.Globals.class),
+ getSourceFile(ExtendedJQuery.class), getSourceFile(def.test3.JQuery.class));
+ }
+
}
diff --git a/transpiler/src/test/java/source/typing/MixinsWithDefs.java b/transpiler/src/test/java/source/typing/MixinsWithDefs.java
index ff3c56f1..b36c8d63 100644
--- a/transpiler/src/test/java/source/typing/MixinsWithDefs.java
+++ b/transpiler/src/test/java/source/typing/MixinsWithDefs.java
@@ -1,14 +1,19 @@
package source.typing;
-import def.test.Globals;
import static def.test.Globals.$;
+import def.test.Globals;
+import def.test.JQuery;
+
public class MixinsWithDefs {
public static void main(String[] args) {
$(".modal").modal();
- $("select").material_select();
+ $("select").material_select().addClass("animated");
Globals.$("test").modal("");
- $("test").animate("test");
+ $("test").animate("test").addClass("animated");
$(".modal").attr("class");
+ JQuery extendedJQuery = $("test").myExtension();
+ extendedJQuery.addClass("test");
+
}
}
diff --git a/transpiler/src/test/java/source/typing/MixinsWithDefsAndOtherName.java b/transpiler/src/test/java/source/typing/MixinsWithDefsAndOtherName.java
new file mode 100644
index 00000000..eec5964f
--- /dev/null
+++ b/transpiler/src/test/java/source/typing/MixinsWithDefsAndOtherName.java
@@ -0,0 +1,18 @@
+package source.typing;
+
+import static def.test2.Globals.$;
+
+import def.test2.ExtendedJQuery;
+import def.test2.Globals;
+
+public class MixinsWithDefsAndOtherName {
+ public static void main(String[] args) {
+ $(".modal").modal();
+ $("select").material_select().addClass("animated");
+ Globals.$("test").modal("");
+ $("test").animate("test").addClass("animated");
+ $(".modal").attr("class");
+ ExtendedJQuery extendedJQuery = $("test").myExtension();
+ extendedJQuery.addClass("test");
+ }
+}