Open negora opened 7 years ago
I've been thinking about this issue and the issue #319 thoroughly, and I've came to the conclusion there are 2 different situations that cause import errors:
Importing a module that represents a namespace and contains a class/function with the same name that the namespace. Example: namespace foo
and function foo.foo
. This belongs to the issue #318 (this issue).
Importing a module that represents, at the same time, a namespace and a class/function. Example: namespace foo
and function foo
. This belongs to the issue #319.
In the first case, to avoid a conflict of names, the right import generated by JSweet could be something like this:
import foo_ns = require ("foo");
import foo = foo_ns.foo; // This avoids causing a circular "import foo = foo.foo;"
import bar = foo_ns.bar;
...
foo ();
And, in the second case:
import foo_ns = require ("foo");
import foo = foo_ns; // An extra import, to clarify that "foo" also exports a function/class.
import bar = foo_ns.bar;
...
foo ();
The namespace foo_ns
would be generated combining the original name of the namespace (not the package name, as it happens nowadays), plus the "_ns" suffix.
In the last case, I know that the code could just import the module as foo
and use it directly as a function, without that extra import. But I believe that using this nomenclature could make things more homogeneous and avoid some confusion.
In other words, JSweet could treat all the imports made with require()
as namespaces. And then, depending on whether the namespace also represents a class/function or not, it would add that extra import or not.
Just today I've found another bug under the same conditions: when the module exports a namespace and a class that have the same name, and both are in the same level of the package tree. But this bug happens only if you import the class alone, without any class from the namespace. In that case, no require()
statement is generated by the transpiler.
Why does it happen? I believe that it's because the @jsweet.lang.Module
annotation is declared in the package that represents the namespace, but the class is out of it. So, when the transpiler checks the package where the class is located, it doesn't find any @Module
annotation, and doesn't generate the require()
statement.
There is an ugly workaround, which consists in copying the @Module
annotation from the package-info.java
that represents the namespace to the package-info.java
that contains the class, which is the one marked with @jsweet.lang.Root
. That way, when the transpiler scans the package of the class, it will find the annotation and will add the require()
statement. I said "ugly workaround" because the root package is not the module and shouldn't be annotated like that. But... It's the only way of making it work.
Thank you!
It looks like your issues would probably require to re-think how JSweet handles modules... maybe there is a general solution, or maybe there are limitations and we can live this it :) Definitely not the right time for version 2.0.0.
I can manage with it for now ;) . Anyway, if I faced a new problem, I think it wouldn't be traumatic to switch to bundles instead of modules. Thank you.
I've found a run-time error when a namespace and a class share the same name. I'm using the 2.0.0-SNAPSHOT version of JSweet.
I've a candy with the following structure:
The file
def/foo/package-info.java
contains this:The file
def/foo/foo/package-info.java
contains this:I've done this so that the package "def.foo.foo" is transpiled as the namespace "Foo", which has the same name that the class "Foo". This way, both, the namespace and class, are exported as a single module. This is the resulting
bundle.d.ts
:The result is right. However, the problem appears when I use this candy in a class of another JSweet project, and I enable the creation of AMD modules. This is the resulting TypeScript of the class (abbreviated):
The
Bar
class is correctly imported. However, theFoo
class isn't imported. Thetsc
compiler doesn't complain, because thebundle.d.ts
file generated by JSweet first declares the "Foo" class in the global scope, before exporting it with the module. Sotsc
recognises it as an existing class, although it's not imported. But anyway, the code fails at run-time, when invokingnew Foo();
.I guess that, instead, the JSweet transpiler should create something like this:
A real life example is the Pikaday library. This JavaScript library declares a class called
Pikaday
that, at the same time, is used as a namespace for thePikadayOptions
andPikadayI18nConfig
classes.Thank you!