Skip to content

Commit ccbb463

Browse files
hefangshicjihrig
authored andcommitted
module: fix node_modules search path in edge case
The `p < nmLen` condition will fail when a module's name is end with `node_modules` like `foo_node_modules`. The old logic will miss the `foo_node_modules/node_modules` in node_modules paths. TL;TR, a module named like `foo_node_modules` can't require any module in the node_modules folder. Fixes: #6679 PR-URL: #6670 Reviewed-By: Evan Lucas <[email protected]>
1 parent 3f46b5c commit ccbb463

File tree

2 files changed

+119
-19
lines changed

2 files changed

+119
-19
lines changed

‎lib/module.js‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,29 @@ if (process.platform === 'win32'){
221221
// note: this approach *only* works when the path is guaranteed
222222
// to be absolute. Doing a fully-edge-case-correct path.split
223223
// that works on both Windows and Posix is non-trivial.
224+
225+
// return root node_modules when path is 'D:\\'.
226+
// path.resolve will make sure from.length >=3 in Windows.
227+
if(from.charCodeAt(from.length-1)===92/*\*/&&
228+
from.charCodeAt(from.length-2)===58/*:*/)
229+
return[from+'node_modules'];
230+
224231
constpaths=[];
225232
varp=0;
226233
varlast=from.length;
227234
for(vari=from.length-1;i>=0;--i){
228235
constcode=from.charCodeAt(i);
229-
if(code===92/*\*/||code===47/*/*/){
236+
// The path segment separator check ('\' and '/') was used to get
237+
// node_modules path for every path segment.
238+
// Use colon as an extra condition since we can get node_modules
239+
// path for dirver root like 'C:\node_modules' and don't need to
240+
// parse driver name.
241+
if(code===92/*\*/||code===47/*/*/||code===58/*:*/){
230242
if(p!==nmLen)
231243
paths.push(from.slice(0,last)+'\\node_modules');
232244
last=i;
233245
p=0;
234-
}elseif(p!==-1&&p<nmLen){
246+
}elseif(p!==-1){
235247
if(nmChars[p]===code){
236248
++p;
237249
}else{
@@ -265,7 +277,7 @@ if (process.platform === 'win32'){
265277
paths.push(from.slice(0,last)+'/node_modules');
266278
last=i;
267279
p=0;
268-
}elseif(p!==-1&&p<nmLen){
280+
}elseif(p!==-1){
269281
if(nmChars[p]===code){
270282
++p;
271283
}else{
@@ -274,6 +286,9 @@ if (process.platform === 'win32'){
274286
}
275287
}
276288

289+
// Append /node_modules to handle root paths.
290+
paths.push('/node_modules');
291+
277292
returnpaths;
278293
};
279294
}
Lines changed: 101 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,105 @@
11
'use strict';
2-
varcommon=require('../common');
3-
varassert=require('assert');
42

5-
varmodule=require('module');
3+
constcommon=require('../common');
4+
constassert=require('assert');
5+
const_module=require('module');
66

7-
varfile,delimiter,paths;
7+
constcases={
8+
'WIN': [{
9+
file: 'C:\\Users\\hefangshi\\AppData\\Roaming\
10+
\\npm\\node_modules\\npm\\node_modules\\minimatch',
11+
expect: [
12+
'C:\\Users\\hefangshi\\AppData\\Roaming\
13+
\\npm\\node_modules\\npm\\node_modules\\minimatch\\node_modules',
14+
'C:\\Users\\hefangshi\\AppData\\Roaming\
15+
\\npm\\node_modules\\npm\\node_modules',
16+
'C:\\Users\\hefangshi\\AppData\\Roaming\\npm\\node_modules',
17+
'C:\\Users\\hefangshi\\AppData\\Roaming\\node_modules',
18+
'C:\\Users\\hefangshi\\AppData\\node_modules',
19+
'C:\\Users\\hefangshi\\node_modules',
20+
'C:\\Users\\node_modules',
21+
'C:\\node_modules'
22+
]
23+
},{
24+
file: 'C:\\Users\\Rocko Artischocko\\node_stuff\\foo',
25+
expect: [
26+
'C:\\Users\\Rocko Artischocko\\node_stuff\\foo\\node_modules',
27+
'C:\\Users\\Rocko Artischocko\\node_stuff\\node_modules',
28+
'C:\\Users\\Rocko Artischocko\\node_modules',
29+
'C:\\Users\\node_modules',
30+
'C:\\node_modules'
31+
]
32+
},{
33+
file: 'C:\\Users\\Rocko Artischocko\\node_stuff\\foo_node_modules',
34+
expect: [
35+
'C:\\Users\\Rocko \
36+
Artischocko\\node_stuff\\foo_node_modules\\node_modules',
37+
'C:\\Users\\Rocko Artischocko\\node_stuff\\node_modules',
38+
'C:\\Users\\Rocko Artischocko\\node_modules',
39+
'C:\\Users\\node_modules',
40+
'C:\\node_modules'
41+
]
42+
},{
43+
file: 'C:\\node_modules',
44+
expect: [
45+
'C:\\node_modules'
46+
]
47+
},{
48+
file: 'C:\\',
49+
expect: [
50+
'C:\\node_modules'
51+
]
52+
}],
53+
'POSIX': [{
54+
file: '/usr/lib/node_modules/npm/node_modules/\
55+
node-gyp/node_modules/glob/node_modules/minimatch',
56+
expect: [
57+
'/usr/lib/node_modules/npm/node_modules/\
58+
node-gyp/node_modules/glob/node_modules/minimatch/node_modules',
59+
'/usr/lib/node_modules/npm/node_modules/\
60+
node-gyp/node_modules/glob/node_modules',
61+
'/usr/lib/node_modules/npm/node_modules/node-gyp/node_modules',
62+
'/usr/lib/node_modules/npm/node_modules',
63+
'/usr/lib/node_modules',
64+
'/usr/node_modules',
65+
'/node_modules'
66+
]
67+
},{
68+
file: '/usr/test/lib/node_modules/npm/foo',
69+
expect: [
70+
'/usr/test/lib/node_modules/npm/foo/node_modules',
71+
'/usr/test/lib/node_modules/npm/node_modules',
72+
'/usr/test/lib/node_modules',
73+
'/usr/test/node_modules',
74+
'/usr/node_modules',
75+
'/node_modules'
76+
]
77+
},{
78+
file: '/usr/test/lib/node_modules/npm/foo_node_modules',
79+
expect: [
80+
'/usr/test/lib/node_modules/npm/foo_node_modules/node_modules',
81+
'/usr/test/lib/node_modules/npm/node_modules',
82+
'/usr/test/lib/node_modules',
83+
'/usr/test/node_modules',
84+
'/usr/node_modules',
85+
'/node_modules'
86+
]
87+
},{
88+
file: '/node_modules',
89+
expect: [
90+
'/node_modules'
91+
]
92+
},{
93+
file: '/',
94+
expect: [
95+
'/node_modules'
96+
]
97+
}]
98+
};
899

9-
if(common.isWindows){
10-
file='C:\\Users\\Rocko Artischocko\\node_stuff\\foo';
11-
delimiter='\\';
12-
}else{
13-
file='/usr/test/lib/node_modules/npm/foo';
14-
delimiter='/';
15-
}
16-
17-
paths=module._nodeModulePaths(file);
18-
19-
assert.ok(paths.indexOf(file+delimiter+'node_modules')!==-1);
20-
assert.ok(Array.isArray(paths));
100+
constplatformCases=common.isWindows ? cases.WIN : cases.POSIX;
101+
platformCases.forEach((c)=>{
102+
constpaths=_module._nodeModulePaths(c.file);
103+
assert.deepStrictEqual(c.expect,paths,'case '+c.file+
104+
' failed, actual paths is '+JSON.stringify(paths));
105+
});

0 commit comments

Comments
(0)