Skip to content
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

Resolve symlinked modules correctly #92

Merged
merged 9 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
language: node_js
node_js:
- "0.8"
- "0.10"
- "4"
- "5"
- "6"
- "8"
- "10"
- "12"
20 changes: 19 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ function build_resolve_opts(opts, base) {
return opts;
}

function resolve(id, opts, cb) {
function resolve(id, opts, callback) {

// opts.filename
// opts.paths
Expand All @@ -216,6 +216,24 @@ function resolve(id, opts, cb) {
opts = opts || {};
opts.filename = opts.filename || '';

var cb = function(err, path, pkg) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this set of nested functions trying to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. if it's a module name, resolve to it
  2. if it's something in the filesystem, then
    2a) if it's a regular file, resolve to it
    2b) if it's a symlink, resolve to its realpath

fs.stat(path, function(notPath) {
if (notPath) {
callback(err, path, pkg);
}
else {
fs.realpath(path, function(notReal, real) {
if (notReal) {
callback(err, path, pkg);
}
else {
callback(err, real, pkg);
}
});
}
});
}

var base = path.dirname(opts.filename);

if (opts.basedir) {
Expand Down
136 changes: 136 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"empty.js"
],
"scripts": {
"test": "mocha --reporter list test/*.js"
"test": "node scripts/setup-symlinks.js && mocha --reporter list test/*.js"
},
"repository": {
"type": "git",
Expand Down
10 changes: 10 additions & 0 deletions scripts/setup-symlinks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
var fs = require('fs');

try {
fs.mkdirSync(__dirname + '/../test/fixtures/node_modules/linker/node_modules');
} catch (e) {}
process.chdir(__dirname + '/../test/fixtures/node_modules/linker/node_modules');
try {
fs.unlinkSync('linked');
} catch (e) {}
fs.symlinkSync('../../../linked', 'linked', 'dir');
1 change: 1 addition & 0 deletions test/fixtures/linked/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// dummy
1 change: 1 addition & 0 deletions test/fixtures/node_modules/linker/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions test/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,25 @@ test('not fail on accessing path name defined in Object.prototype', function (do
done();
});
});

test('respect symlinks', function (done) {
// some systems (e.g. rush, pnpm) use symlinks to create a recursive dependency graph
// instead of relying on the hoisting aspect of the node module resolution algorithm (like npm and yarn do)
// in these cases, we want to resolve to the real path of a module, so that the tree structure below
// only ever tries to run the `x` module once (rather than once on each module that depends on it)
//
// - node_modules
// - a
// - node_modules
// - symlink to x
// - b
// - node_modules
// - symlink to x
//
resolve('linked', { paths: [ fixtures_dir + '/linker/node_modules' ], package: { main: 'fixtures' } }, function(err, path, pkg) {
assert.ifError(err);
assert.equal(path, require.resolve('./fixtures/linked/index'));
assert.strictEqual(pkg, undefined);
done();
});
});