Skip to content

Commit 4591469

Browse files
waliscXhmikosR
andauthored
Resolving local/nested node_modules folder correctly (#162)
* catering for nested/local node_modules * reconstructing path appropriately --------- Co-authored-by: XhmikosR <[email protected]>
1 parent 8b6ad1b commit 4591469

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

index.js

+24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const fs = require('node:fs');
4+
const path = require('node:path');
45
const { debuglog } = require('node:util');
56
const cabinet = require('filing-cabinet');
67
const precinct = require('precinct');
@@ -162,6 +163,7 @@ function traverse(config = {}) {
162163
for (const dependency of dependencies) {
163164
const localConfig = config.clone();
164165
localConfig.filename = dependency;
166+
localConfig.directory = getDirectory(localConfig);
165167

166168
if (localConfig.isListForm) {
167169
for (const item of traverse(localConfig)) {
@@ -193,3 +195,25 @@ function dedupeNonExistent(nonExistent) {
193195
i++;
194196
}
195197
}
198+
199+
// If the file is in a node module, use the root directory of the module
200+
function getDirectory(localConfig) {
201+
if (!localConfig.filename.includes('node_modules')) {
202+
return localConfig.directory;
203+
}
204+
205+
return getProjectPath(path.dirname(localConfig.filename)) || localConfig.directory;
206+
}
207+
208+
function getProjectPath(filename) {
209+
try {
210+
const nodeModuleParts = filename.split('node_modules');
211+
const packageSubPathPath = nodeModuleParts.pop().split(path.sep).filter(Boolean);
212+
const packageName = packageSubPathPath[0].startsWith('@') ? `${packageSubPathPath[0]}${path.sep}${packageSubPathPath[1]}` : packageSubPathPath[0];
213+
214+
return path.normalize([...nodeModuleParts, `${path.sep}${packageName}`].join('node_modules'));
215+
} catch {
216+
debug(`Could not determine the root directory of package file ${filename}. Using default`);
217+
return null;
218+
}
219+
}

test/test.mjs

+71
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,77 @@ describe('dependencyTree', () => {
472472
});
473473
});
474474

475+
describe('it uses package specific node_module directory when resolving package dependencies', () => {
476+
testTreesForFormat('commonjs');
477+
478+
it('it can find sub package in node module package', () => {
479+
mockfs({
480+
[path.join(__dirname, '/es6')]: {
481+
'module.entry.js': 'import * as module from "parent_module_a"',
482+
node_modules: {
483+
parent_module_a: {
484+
'index.main.js': 'import * as child_module from "child_node_module"; module.exports = child_module;',
485+
'package.json': '{ "main": "index.main.js"}',
486+
node_modules: {
487+
child_node_module: {
488+
'index.main.js': 'module.exports = "child_node_module_of_parent_a"',
489+
'package.json': '{ "main": "index.main.js"}'
490+
}
491+
}
492+
}
493+
}
494+
}
495+
});
496+
497+
const directory = path.join(__dirname, '/es6');
498+
const filename = path.normalize(`${directory}/module.entry.js`);
499+
500+
const treeList = dependencyTree({
501+
filename,
502+
directory,
503+
isListForm: true
504+
});
505+
506+
assert.ok(treeList.includes(path.normalize(`${directory}/node_modules/parent_module_a/node_modules/child_node_module/index.main.js`)));
507+
});
508+
509+
it('it uses correct version of sub package in node module package', () => {
510+
mockfs({
511+
[path.join(__dirname, '/es6')]: {
512+
'module.entry.js': 'import * as module from "parent_module_a"',
513+
node_modules: {
514+
child_node_module: {
515+
'index.main.js': 'module.exports = "child_node_module"',
516+
'package.json': '{ "main": "index.main.js", "version": "2.0.0"}'
517+
},
518+
parent_module_a: {
519+
'index.main.js': 'import * as child_module from "child_node_module"; module.exports = child_module;',
520+
'package.json': '{ "main": "index.main.js"}',
521+
node_modules: {
522+
child_node_module: {
523+
'index.main.js': 'module.exports = "child_node_module_of_parent_a"',
524+
'package.json': '{ "main": "index.main.js", "version": "1.0.0"}'
525+
}
526+
}
527+
}
528+
}
529+
}
530+
});
531+
532+
const directory = path.join(__dirname, '/es6');
533+
const filename = path.normalize(`${directory}/module.entry.js`);
534+
535+
const treeList = dependencyTree({
536+
filename,
537+
directory,
538+
isListForm: true
539+
});
540+
541+
assert.ok(!treeList.includes(path.normalize(`${directory}/node_modules/child_node_module/index.main.js`)));
542+
assert.ok(treeList.includes(path.normalize(`${directory}/node_modules/parent_module_a/node_modules/child_node_module/index.main.js`)));
543+
});
544+
});
545+
475546
describe('module formats', () => {
476547
describe('amd', () => {
477548
testTreesForFormat('amd');

0 commit comments

Comments
 (0)