Skip to content

Commit

Permalink
Implements packageIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
arcanis authored and ljharb committed Jan 3, 2020
1 parent 6f57476 commit b192e97
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 23 deletions.
51 changes: 32 additions & 19 deletions lib/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts, cb) {
}
};

var getPackageCandidates = function getPackageCandidates(x, start, opts) {
var dirs = nodeModulesPaths(start, opts, x);
for (var i = 0; i < dirs.length; i++) {
dirs[i] = path.join(dirs[i], x);
}
return dirs;
};

module.exports = function resolve(x, options, callback) {
var cb = callback;
var opts = options;
Expand All @@ -55,6 +63,7 @@ module.exports = function resolve(x, options, callback) {
var isFile = opts.isFile || defaultIsFile;
var isDirectory = opts.isDirectory || defaultIsDir;
var readFile = opts.readFile || fs.readFile;
var packageIterator = opts.packageIterator;

var extensions = opts.extensions || ['.js'];
var basedir = opts.basedir || path.dirname(caller());
Expand Down Expand Up @@ -261,31 +270,35 @@ module.exports = function resolve(x, options, callback) {
}

function processDirs(cb, dirs) {
if (dirs.length === 0) return cb(null, undefined);
var dir = dirs[0];
iterate(0);

isDirectory(dir, isdir);
function iterate(i) {
if (i === dirs.length) return cb(null, undefined);
var dir = dirs[i];

function isdir(err, isdir) {
if (err) return cb(err);
if (!isdir) return processDirs(cb, dirs.slice(1));
var file = path.join(dir, x);
loadAsFile(file, opts.package, onfile);
}
isDirectory(path.dirname(dir), function (err, status) {
if (err) return cb(err);
if (!status) return iterate(i + 1);

function onfile(err, m, pkg) {
if (err) return cb(err);
if (m) return cb(null, m, pkg);
loadAsDirectory(path.join(dir, x), opts.package, ondir);
}
loadAsFile(dir, opts.package, function (err, m, pkg) {
if (err) return cb(err);
if (m) return cb(null, m, pkg);

loadAsDirectory(dir, opts.package, function (err, n, pkg) {
if (err) return cb(err);
if (n) return cb(null, n, pkg);

function ondir(err, n, pkg) {
if (err) return cb(err);
if (n) return cb(null, n, pkg);
processDirs(cb, dirs.slice(1));
iterate(i + 1);
});
});
});
}
}
function loadNodeModules(x, start, cb) {
processDirs(cb, nodeModulesPaths(start, opts, x));
var thunk = function () { return getPackageCandidates(x, start, opts); };
processDirs(
cb,
packageIterator ? packageIterator(x, start, thunk, opts) : thunk()
);
}
};
19 changes: 15 additions & 4 deletions lib/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts) {
return x;
};

var getPackageCandidates = function getPackageCandidates(x, start, opts) {
var dirs = nodeModulesPaths(start, opts, x);
for (var i = 0; i < dirs.length; i++) {
dirs[i] = path.join(dirs[i], x);
}
return dirs;
};

module.exports = function (x, options) {
if (typeof x !== 'string') {
throw new TypeError('Path must be a string.');
Expand All @@ -47,6 +55,7 @@ module.exports = function (x, options) {
var isFile = opts.isFile || defaultIsFile;
var isDirectory = opts.isDirectory || defaultIsDir;
var readFileSync = opts.readFileSync || fs.readFileSync;
var packageIterator = opts.packageIterator;

var extensions = opts.extensions || ['.js'];
var basedir = opts.basedir || path.dirname(caller());
Expand Down Expand Up @@ -164,13 +173,15 @@ module.exports = function (x, options) {
}

function loadNodeModulesSync(x, start) {
var dirs = nodeModulesPaths(start, opts, x);
var thunk = function () { return getPackageCandidates(x, start, opts); };
var dirs = packageIterator ? packageIterator(x, start, thunk, opts) : thunk();

for (var i = 0; i < dirs.length; i++) {
var dir = dirs[i];
if (isDirectory(dir)) {
var m = loadAsFileSync(path.join(dir, '/', x));
if (isDirectory(path.dirname(dir))) {
var m = loadAsFileSync(dir);
if (m) return m;
var n = loadAsDirectorySync(path.join(dir, '/', x));
var n = loadAsDirectorySync(dir);
if (n) return n;
}
}
Expand Down
18 changes: 18 additions & 0 deletions readme.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ options are:
* getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
* opts - the resolution options

* `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this)
* request - the import specifier being resolved
* start - lookup path
* getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
* opts - the resolution options

* opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"`

* opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving.
Expand Down Expand Up @@ -146,6 +152,18 @@ options are:

* opts.paths - require.paths array to use if nothing is found on the normal `node_modules` recursive walk (probably don't use this)

For advanced users, `paths` can also be a `opts.paths(request, start, opts)` function
* request - the import specifier being resolved
* start - lookup path
* getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
* opts - the resolution options

* `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this)
* request - the import specifier being resolved
* start - lookup path
* getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
* opts - the resolution options

* opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"`

* opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving.
Expand Down
16 changes: 16 additions & 0 deletions test/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,22 @@ test('other path', function (t) {
});
});

test('path iterator', function (t) {
t.plan(2);

var resolverDir = path.join(__dirname, 'resolver');

var exactIterator = function (x, start, getPackageCandidates, opts) {
return [path.join(resolverDir, x)];
};

resolve('baz', { packageIterator: exactIterator }, function (err, res, pkg) {
if (err) t.fail(err);
t.equal(res, path.join(resolverDir, 'baz/quux.js'));
t.equal(pkg && pkg.name, 'baz');
});
});

test('incorrect main', function (t) {
t.plan(1);

Expand Down
1 change: 1 addition & 0 deletions test/resolver/baz/package.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"name": "baz",
"main": "quux.js"
}
15 changes: 15 additions & 0 deletions test/resolver_sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@ test('other path', function (t) {
t.end();
});

test('path iterator', function (t) {
var resolverDir = path.join(__dirname, 'resolver');

var exactIterator = function (x, start, getPackageCandidates, opts) {
return [path.join(resolverDir, x)];
};

t.equal(
resolve.sync('baz', { packageIterator: exactIterator }),
path.join(resolverDir, 'baz/quux.js')
);

t.end();
});

test('incorrect main', function (t) {
var resolverDir = path.join(__dirname, 'resolver');
var dir = path.join(resolverDir, 'incorrect_main');
Expand Down

0 comments on commit b192e97

Please sign in to comment.