Open lucono opened 7 years ago
@lucono does the following not work:
import some.other.modul { exports { myData } }
If not, then yeah, I think we should make it work.
@gavinking No, that doesn't work.
Well what is the error?
There's no error, just that it's undefined.
It seems Ceylon doesn't make the entire CommonJS module.exports
value available through the Ceylon import
statement. Instead, if module.exports
is an object, then Ceylon provides access (with Ceylon import
statement) to only the properties under that object, with the additional special case handling described here - https://github.com/ceylon/ceylon/wiki/NPM-and-Ceylon-JS#non-standard-modules.
@chochos WDYT?
Didn't we already have the special require
that checked if the returned object was really just a function or something and if so, put it inside an object so that it was a standard thing?
I remember bumping into this before, but I'm not sure what we did about it, if anything.
@chochos I think what you ended up doing is what's described at the bottom of the page here, under the section Non-standard Modules.
Basically, some special handling was implemented for when the returned "object" is really just a function, but that special handling is also relevant for certain cases where the returned object is indeed a regular object.
So, Ceylon JS could benefit from a generalization of that handling, as I described earlier above, where the (entire) returned value from the export is made accessible under a special name in the package import. In the special handling you implemented for when the export is a function, that special name is the name of the module, but a set name such as exports
could also be used. This of course would only be relevant to JavaScript/npm modules imported in a Ceylon module.
CommonJS JavaScript module:
// my-module.js
var someData = {
a: "one",
b: "two",
c: "three"
};
module.exports = someData; // Note that not: module.exports.someData = someData;
And in Ceylon:
// uses the JS module's name "myModule" to import the entire export value
import my.module { myModule, a, b, c }
dynamic {
print(JSON.stringify(myModule)); // { "a":"one", "b":"two", "c":"three" }
print(a); // "one"
print(b); // "two"
print(c); // "three"
}
OR:
// uses special name "exports" to import the entire export value
import my.module { myModule = exports, a, b, c }
dynamic {
print(JSON.stringify(myModule)); // { "a":"one", "b":"two", "c":"three" }
print(a); // "one"
print(b); // "two"
print(c); // "three"
}
I imagine the choice of name to use for the import of the entire export value should be one that has the least likely chance of collision given common practices in real life modules. It could also be something that could not possibly be a field name in most JavaScript modules, such as the JS keyword export
(except of course if doing something like module['export'] = someData
), but not a Ceylon keyword, allowing something like this:
// uses special name "export", a JS keyword but not a Ceylon keyword
import my.module { myModule = export, a, b, c }
dynamic {
print(JSON.stringify(myModule)); // { "a":"one", "b":"two", "c":"three" }
print(a); // "one"
print(b); // "two"
print(c); // "three"
}
In either case, the examples above use import aliasing to alias it to a more meaningful name in the Ceylon file.
There are many JavaScript libraries where the exported item is exported as the "exports" property of "module", ie:
For these, there should be a way in Ceylon to get a reference to the entire exports object (basically, get a handle on "module.exports" object) using Ceylon's
import
statement rather thanrequire
-ing the module in adynamic
block.Basically, if I had a library that does this:
Then, there should be a way to obtain
myData
in Ceylon, using theimport
statement, something like this:Rather than having to do this:
Ceylon already has some special handling for "Non-standard modules" described here, which accounts for cases where the main module export is a function that is directly exported over
module.exports
, but doesn't account for the case where the main export is an object that is directly exported overmodule.exports
.In its current special handling, Ceylon will provide access to the entire
exports
object with Ceylon'simport
statement only if it finds that it's a function, but I don't see any reason why this scheme couldn't be generalized for all situations - that the module name always imports whatever is the value ofmodule.exports
.This would allow it to work for both functions and objects (or anything else) exported over
module.exports
, while allowing for backward compatibility with applications already using the module name to import functions exported this way in Ceylon's current special handling of the case.