-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
module: fix inconsistency between load and _findPath #22382
module: fix inconsistency between load and _findPath #22382
Conversation
lib/internal/modules/cjs/loader.js
Outdated
@@ -216,6 +216,11 @@ function tryExtensions(p, exts, isMain) { | |||
return false; | |||
} | |||
|
|||
function readExtensions() { | |||
return Object.keys(Module._extensions) | |||
.map((ext) => path.extname(ext) || ext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid the functional array methods and use a regular loop instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not against this but imo this looks much better than regular loop would. As for the performance implications this is not a hot code and also in the newest v8 AFAIK functional operations have the same or at least similar performance to regular loops.
Though if you want I'll change it. I think it will be as follows.
const exts = Object.keys(Module._extensions);
const result = new Array(exts.length);
for (let i = 0; i < exts.length; ++i)
result[i] = path.extname(exts[i]) || exts[i];
return result;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could simplify if further and make it even more efficient than a straight conversion with:
const exts = Object.keys(Module._extensions);
for (let i = 0; i < exts.length; ++i)
exts[i] = path.extname(exts[i]) || exts[i];
return exts;
or avoid reassigning the same value:
const exts = Object.keys(Module._extensions);
for (let i = 0; i < exts.length; ++i) {
const extName = path.extname(exts[i]);
if (extName)
exts[i] = extName;
}
return exts;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah. Functional thinking got too far =). Though I think the first method you suggested should be fine already.
6dd03d6
to
9a0ad77
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
lib/internal/modules/cjs/loader.js
Outdated
for (var i = 0; i < exts.length; ++i) | ||
exts[i] = path.extname(exts[i]) || exts[i]; | ||
return exts; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the example case of require.extensions
of .foo.bar
and .bar
this will return an array of ['.bar', '.bar]
?
So if you delete require.extensions[".bar"]
files like test-extensions.foo.bar
will still be found but their compiler at require.extensions[".foo.bar"]
won't be used for the module since _compile
will use extname(filename)
to and get .bar
which doesn't exist on require.extensions
and so will default to .js
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, though I'm not sure what's the correct behavior here. I'd say to just filter-out all extensions that path.extname() !== ''
and use the remaining ones, as they shouldn't be used anyway, wdyt?
9a0ad77
to
991cacf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This patch makes additions like require.extensions[".foo.bar"]
findable but not runnable as it defaults to require.extensions[".js"]
since the extname(filename)
is ".bar"
and does not have an entry in require.extensions
. This means this PR isn't really finished. Finding a module is great but it needs to use the correct compiler too.
Files with multiple extensions are not handled by require-module system therefore if you have file 'file.foo.bar' and require('./file') it won't be found even while using require.extensions['foo.bar'] but before this commit if you have require.extensions['foo.bar'] and require.extensions['bar'] set then the latter will be called if you do require('./file') but if you remove the former the former ('foo.bar') property it will fail. This commit makes it always fail in such cases. Fixes: nodejs#4778
991cacf
to
b009708
Compare
@jdalton PTAL #22382 (comment), I've changed the implementation to ignore multiple-extensions-type (as this is from what I understand compiler does via https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L597). The idea of this PR is to forbid what was previously accepted but is incorrect (if you have I've also added the test for the use-case you've described (have |
@lundibundi Do you want to land this? It seems ready to me. :) |
@addaleax thanks for reminding I kinda forgot =) |
Resume CI: https://ci.nodejs.org/job/node-test-pull-request/16959/ (:heavy_check_mark:) |
On and on: https://ci.nodejs.org/job/node-test-pull-request/16979/ (:heavy_check_mark:) |
@lundibundi I’m not sure I understand – all of the last three CIs (16959, 16973, 16979) were good…? |
Oh, I kind of didn't check that the failed test was with node help options. 🙃 Though I wanted to land this already, but EDIT: Okay, I guess the issues are not going anywhere, I kind of don't want to land when my npm/node/git is in such state. I'll try to debug them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but I’m adding semver-major
since it sounds like there’s a small chance of breakage, feel free to remove the label if I’m mistaken
Landed in 1b92214 |
Files with multiple extensions are not handled by require-module system therefore if you have file 'file.foo.bar' and require('./file') it won't be found even while using require.extensions['foo.bar'] but before this commit if you have require.extensions['foo.bar'] and require.extensions['bar'] set then the latter will be called if you do require('./file') but if you remove the former the former ('foo.bar') property it will fail. This commit makes it always fail in such cases. Fixes: #4778 PR-URL: #22382 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: John-David Dalton <john.david.dalton@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Files with multiple extensions are not handled by require-module system
therefore if you have file 'file.foo.bar' and require('./file') it won't
be found even while using require.extensions['foo.bar'] but before this
commit if you have require.extensions['foo.bar'] and
require.extensions['bar'] set then the latter will be called if you do
require('./file') but if you remove the former ('foo.bar')
property it will fail.
This commit makes it always fail in such cases.
Fixes: #4778
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes