Best effort Module Resolution Algorithm implementation based on Node.js 25.2.1 - #971
Conversation
|
Thank you for your pull request and welcome to our community! To contribute, please sign the Oracle Contributor Agreement (OCA).
To sign the OCA, please create an Oracle account and sign the OCA in Oracle's Contributor Agreement Application. When signing the OCA, please provide your GitHub username. After signing the OCA and getting an OCA approval from Oracle, this PR will be automatically updated. If you are an Oracle employee, please make sure that you are a member of the main Oracle GitHub organization, and your membership in this organization is public. |
|
Hello, any update on this PR? |
|
@imakira thank you for your contribution! We'll try to review this PR soon, but we'll need the OCA check to be cleared first. |
|
@woess Thanks for you reply! |
|
Thank you for signing the OCA. |
Speaking of useful |
| private URI packageImportsResolve(String specifier, URI parentURL, List<String> conditions, TruffleLanguage.Env env) { | ||
| // 1. Assert: specifier begins with "#". | ||
| // 2. If specifier is exactly equal to "#" or starts with "#/", then | ||
| if(!specifier.startsWith("#") || specifier.equals("#") || specifier.equals("#/")){ |
There was a problem hiding this comment.
There is no need to check for !specifier.startsWith("#"). packageImportsResolve() is always called with a specifier that begins with # (as the first step of this method says).
It seems that you can also remove the check for #/ that is not part of the algorithm (anymore?).
| } else if(exports instanceof JSDynamicObject exportsObj && | ||
| exportsObj.hasOwnProperty(constant(DOT))){ | ||
| // 2.3.1 Set mainExport to exports["."]. | ||
| mainExport = JSObject.get(exportsObj, constant(DOT)); |
There was a problem hiding this comment.
You can use Strings.DOT instead of constant(DOT) here (and two lines above).
| } | ||
|
|
||
| private static int countChar(String s, char c){ | ||
| return s.length() - s.replace(String.valueOf(c), "").length(); |
There was a problem hiding this comment.
This method is always used to check whether there is exactly one occurrence of c in s. This can be implemented more efficiently. For example:
private static boolean containsOnlyOne(String s, char c) {
int first = s.indexOf(c);
return (first != -1) && (first == s.lastIndexOf(c));
}
| // 2.1 If target contains any index property keys, as defined in ECMA-262 6.1.7 Array | ||
| // Index, throw an Invalid Package Configuration error. | ||
| for (var key : targetObj.ownPropertyKeys()) { | ||
| if (!(key instanceof TruffleString)) { |
There was a problem hiding this comment.
This condition should check for index property keys. These are keys that are strings but can be parsed as array indices. So, the current check is incorrect. JSRuntime.isArrayIndex(key) is more appropriate here.
| // throw an Invalid Package Configuration error. | ||
| boolean hasStartingWithDot = false; | ||
| if(exports instanceof JSDynamicObject exportsObj){ | ||
| List<TruffleString> keys = JSObject.enumerableOwnNames(exportsObj); |
There was a problem hiding this comment.
There is no need to check for enumerability. You can use ownPropertyKeys() instead of enumerableOwnNames()
|
Thank you for your contribution. We will be happy to integrate it into |
If a module `package.json` specifies `exports`, GraalJs will now read them and prefer exports over standard resolution; export types can be registered by the developer as preferred. In lieu of these types (and as a default), the following export types are preferred, in order: - `graaljs` - `import` (in ESM) - `require` - `default` Fixes and closes oracle#903 Relates-to: oracle#903 Signed-off-by: Sam Gammon <sam@elide.dev>
64b283e to
849f318
Compare
|
@iamstolis Thanks for pointing out the parts I have missed! I have made the changes you suggested, formatted the code, fixed one unit test I somehow missed last time (unsupportedUrl test, about error message), and rebased the PR against the master branch. Let me know if there's some thing I'm still missing. |
|
@imakira, thank you again for your contribution. The PR has been merged into |
Best effort Module Resolution Algorithm implementation based on Node.js 25.2.1 as documented in https://nodejs.org/api/esm.html#resolution-and-loading-algorithm.
The following features are not implemented:
This patch breaks one unit test:
The previous behavoir with regard to using
importwith CommonJS modules was:import()can't import a commonjs module with.jsextension, in a package not marked with"type"="module"import()can import a commonjs module with.cjsextension.import()can import a commonjs module with.jsextension but not in a packageAs import/import() can be used to load JavaScript CommonJS modules stated in packages.html.
I believe it is fair to expect
import/import()to be able to import CommonJS modules.In this patch,
importcan import a commonjs module with acjsextension, or with ajsextension and in a package not marked with"type"="module".I couldn't get WebAssemblySimpleTestSuite working correctly (error: WebAssembly API enabled but "wasm" language cannot be accessed! Make sure the "wasm" l
anguage is found on the module path and one of the permitted languages when creating the Context). All other tests are running correctly.
Another thing to note:
In this patch, if
esmResolvereturns a result andesmFileFormatreturnsCommonJs, it will pass the resoluted path directly totryLoadingAsCommonjsModule. Instead of the originalspecifier.I don't know if this is the best way to do it, but at least we can import a CommonJs module exported in
exportsusingimportnow (ideally we should makerequirealso support it).This patch is based on #904