Skip to content

Commit

Permalink
Resolving local/nested node_modules folder correctly (#162)
Browse files Browse the repository at this point in the history
* catering for nested/local node_modules

* reconstructing path appropriately

---------

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
  • Loading branch information
walisc and XhmikosR authored Feb 8, 2025
1 parent 8b6ad1b commit 4591469
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
24 changes: 24 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const fs = require('node:fs');
const path = require('node:path');
const { debuglog } = require('node:util');
const cabinet = require('filing-cabinet');
const precinct = require('precinct');
Expand Down Expand Up @@ -162,6 +163,7 @@ function traverse(config = {}) {
for (const dependency of dependencies) {
const localConfig = config.clone();
localConfig.filename = dependency;
localConfig.directory = getDirectory(localConfig);

if (localConfig.isListForm) {
for (const item of traverse(localConfig)) {
Expand Down Expand Up @@ -193,3 +195,25 @@ function dedupeNonExistent(nonExistent) {
i++;
}
}

// If the file is in a node module, use the root directory of the module
function getDirectory(localConfig) {
if (!localConfig.filename.includes('node_modules')) {
return localConfig.directory;
}

return getProjectPath(path.dirname(localConfig.filename)) || localConfig.directory;
}

function getProjectPath(filename) {
try {
const nodeModuleParts = filename.split('node_modules');
const packageSubPathPath = nodeModuleParts.pop().split(path.sep).filter(Boolean);
const packageName = packageSubPathPath[0].startsWith('@') ? `${packageSubPathPath[0]}${path.sep}${packageSubPathPath[1]}` : packageSubPathPath[0];

return path.normalize([...nodeModuleParts, `${path.sep}${packageName}`].join('node_modules'));
} catch {
debug(`Could not determine the root directory of package file ${filename}. Using default`);
return null;
}
}
71 changes: 71 additions & 0 deletions test/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,77 @@ describe('dependencyTree', () => {
});
});

describe('it uses package specific node_module directory when resolving package dependencies', () => {
testTreesForFormat('commonjs');

it('it can find sub package in node module package', () => {
mockfs({
[path.join(__dirname, '/es6')]: {
'module.entry.js': 'import * as module from "parent_module_a"',
node_modules: {
parent_module_a: {
'index.main.js': 'import * as child_module from "child_node_module"; module.exports = child_module;',
'package.json': '{ "main": "index.main.js"}',
node_modules: {
child_node_module: {
'index.main.js': 'module.exports = "child_node_module_of_parent_a"',
'package.json': '{ "main": "index.main.js"}'
}
}
}
}
}
});

const directory = path.join(__dirname, '/es6');
const filename = path.normalize(`${directory}/module.entry.js`);

const treeList = dependencyTree({
filename,
directory,
isListForm: true
});

assert.ok(treeList.includes(path.normalize(`${directory}/node_modules/parent_module_a/node_modules/child_node_module/index.main.js`)));
});

it('it uses correct version of sub package in node module package', () => {
mockfs({
[path.join(__dirname, '/es6')]: {
'module.entry.js': 'import * as module from "parent_module_a"',
node_modules: {
child_node_module: {
'index.main.js': 'module.exports = "child_node_module"',
'package.json': '{ "main": "index.main.js", "version": "2.0.0"}'
},
parent_module_a: {
'index.main.js': 'import * as child_module from "child_node_module"; module.exports = child_module;',
'package.json': '{ "main": "index.main.js"}',
node_modules: {
child_node_module: {
'index.main.js': 'module.exports = "child_node_module_of_parent_a"',
'package.json': '{ "main": "index.main.js", "version": "1.0.0"}'
}
}
}
}
}
});

const directory = path.join(__dirname, '/es6');
const filename = path.normalize(`${directory}/module.entry.js`);

const treeList = dependencyTree({
filename,
directory,
isListForm: true
});

assert.ok(!treeList.includes(path.normalize(`${directory}/node_modules/child_node_module/index.main.js`)));
assert.ok(treeList.includes(path.normalize(`${directory}/node_modules/parent_module_a/node_modules/child_node_module/index.main.js`)));
});
});

describe('module formats', () => {
describe('amd', () => {
testTreesForFormat('amd');
Expand Down

0 comments on commit 4591469

Please sign in to comment.