Skip to content

Commit

Permalink
[New] sync'/async: Implement 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 426c124 commit 0f698c6
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 9 deletions.
22 changes: 17 additions & 5 deletions lib/async.js
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 @@ -265,19 +274,18 @@ module.exports = function resolve(x, options, callback) {
if (dirs.length === 0) return cb(null, undefined);
var dir = dirs[0];

isDirectory(dir, isdir);
isDirectory(path.dirname(dir), isdir);

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);
loadAsFile(dir, opts.package, onfile);
}

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);
loadAsDirectory(dir, opts.package, ondir);
}

function ondir(err, n, pkg) {
Expand All @@ -287,6 +295,10 @@ module.exports = function resolve(x, options, callback) {
}
}
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
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 @@ -162,13 +171,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
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
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
@@ -1,3 +1,4 @@
{
"name": "baz",
"main": "quux.js"
}
15 changes: 15 additions & 0 deletions test/resolver_sync.js
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 0f698c6

Please sign in to comment.