Skip to content

Commit b192e97

Browse files
arcanisljharb
authored andcommitted
Implements packageIterator
1 parent 6f57476 commit b192e97

File tree

6 files changed

+97
-23
lines changed

6 files changed

+97
-23
lines changed

lib/async.js

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts, cb) {
3636
}
3737
};
3838

39+
var getPackageCandidates = function getPackageCandidates(x, start, opts) {
40+
var dirs = nodeModulesPaths(start, opts, x);
41+
for (var i = 0; i < dirs.length; i++) {
42+
dirs[i] = path.join(dirs[i], x);
43+
}
44+
return dirs;
45+
};
46+
3947
module.exports = function resolve(x, options, callback) {
4048
var cb = callback;
4149
var opts = options;
@@ -55,6 +63,7 @@ module.exports = function resolve(x, options, callback) {
5563
var isFile = opts.isFile || defaultIsFile;
5664
var isDirectory = opts.isDirectory || defaultIsDir;
5765
var readFile = opts.readFile || fs.readFile;
66+
var packageIterator = opts.packageIterator;
5867

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

263272
function processDirs(cb, dirs) {
264-
if (dirs.length === 0) return cb(null, undefined);
265-
var dir = dirs[0];
273+
iterate(0);
266274

267-
isDirectory(dir, isdir);
275+
function iterate(i) {
276+
if (i === dirs.length) return cb(null, undefined);
277+
var dir = dirs[i];
268278

269-
function isdir(err, isdir) {
270-
if (err) return cb(err);
271-
if (!isdir) return processDirs(cb, dirs.slice(1));
272-
var file = path.join(dir, x);
273-
loadAsFile(file, opts.package, onfile);
274-
}
279+
isDirectory(path.dirname(dir), function (err, status) {
280+
if (err) return cb(err);
281+
if (!status) return iterate(i + 1);
275282

276-
function onfile(err, m, pkg) {
277-
if (err) return cb(err);
278-
if (m) return cb(null, m, pkg);
279-
loadAsDirectory(path.join(dir, x), opts.package, ondir);
280-
}
283+
loadAsFile(dir, opts.package, function (err, m, pkg) {
284+
if (err) return cb(err);
285+
if (m) return cb(null, m, pkg);
286+
287+
loadAsDirectory(dir, opts.package, function (err, n, pkg) {
288+
if (err) return cb(err);
289+
if (n) return cb(null, n, pkg);
281290

282-
function ondir(err, n, pkg) {
283-
if (err) return cb(err);
284-
if (n) return cb(null, n, pkg);
285-
processDirs(cb, dirs.slice(1));
291+
iterate(i + 1);
292+
});
293+
});
294+
});
286295
}
287296
}
288297
function loadNodeModules(x, start, cb) {
289-
processDirs(cb, nodeModulesPaths(start, opts, x));
298+
var thunk = function () { return getPackageCandidates(x, start, opts); };
299+
processDirs(
300+
cb,
301+
packageIterator ? packageIterator(x, start, thunk, opts) : thunk()
302+
);
290303
}
291304
};

lib/sync.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts) {
3838
return x;
3939
};
4040

41+
var getPackageCandidates = function getPackageCandidates(x, start, opts) {
42+
var dirs = nodeModulesPaths(start, opts, x);
43+
for (var i = 0; i < dirs.length; i++) {
44+
dirs[i] = path.join(dirs[i], x);
45+
}
46+
return dirs;
47+
};
48+
4149
module.exports = function (x, options) {
4250
if (typeof x !== 'string') {
4351
throw new TypeError('Path must be a string.');
@@ -47,6 +55,7 @@ module.exports = function (x, options) {
4755
var isFile = opts.isFile || defaultIsFile;
4856
var isDirectory = opts.isDirectory || defaultIsDir;
4957
var readFileSync = opts.readFileSync || fs.readFileSync;
58+
var packageIterator = opts.packageIterator;
5059

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

166175
function loadNodeModulesSync(x, start) {
167-
var dirs = nodeModulesPaths(start, opts, x);
176+
var thunk = function () { return getPackageCandidates(x, start, opts); };
177+
var dirs = packageIterator ? packageIterator(x, start, thunk, opts) : thunk();
178+
168179
for (var i = 0; i < dirs.length; i++) {
169180
var dir = dirs[i];
170-
if (isDirectory(dir)) {
171-
var m = loadAsFileSync(path.join(dir, '/', x));
181+
if (isDirectory(path.dirname(dir))) {
182+
var m = loadAsFileSync(dir);
172183
if (m) return m;
173-
var n = loadAsDirectorySync(path.join(dir, '/', x));
184+
var n = loadAsDirectorySync(dir);
174185
if (n) return n;
175186
}
176187
}

readme.markdown

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ options are:
8080
* getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
8181
* opts - the resolution options
8282

83+
* `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this)
84+
* request - the import specifier being resolved
85+
* start - lookup path
86+
* getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
87+
* opts - the resolution options
88+
8389
* opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"`
8490

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

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

155+
For advanced users, `paths` can also be a `opts.paths(request, start, opts)` function
156+
* request - the import specifier being resolved
157+
* start - lookup path
158+
* getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
159+
* opts - the resolution options
160+
161+
* `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this)
162+
* request - the import specifier being resolved
163+
* start - lookup path
164+
* getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
165+
* opts - the resolution options
166+
149167
* opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"`
150168

151169
* opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving.

test/resolver.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,22 @@ test('other path', function (t) {
256256
});
257257
});
258258

259+
test('path iterator', function (t) {
260+
t.plan(2);
261+
262+
var resolverDir = path.join(__dirname, 'resolver');
263+
264+
var exactIterator = function (x, start, getPackageCandidates, opts) {
265+
return [path.join(resolverDir, x)];
266+
};
267+
268+
resolve('baz', { packageIterator: exactIterator }, function (err, res, pkg) {
269+
if (err) t.fail(err);
270+
t.equal(res, path.join(resolverDir, 'baz/quux.js'));
271+
t.equal(pkg && pkg.name, 'baz');
272+
});
273+
});
274+
259275
test('incorrect main', function (t) {
260276
t.plan(1);
261277

test/resolver/baz/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2+
"name": "baz",
23
"main": "quux.js"
34
}

test/resolver_sync.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,21 @@ test('other path', function (t) {
172172
t.end();
173173
});
174174

175+
test('path iterator', function (t) {
176+
var resolverDir = path.join(__dirname, 'resolver');
177+
178+
var exactIterator = function (x, start, getPackageCandidates, opts) {
179+
return [path.join(resolverDir, x)];
180+
};
181+
182+
t.equal(
183+
resolve.sync('baz', { packageIterator: exactIterator }),
184+
path.join(resolverDir, 'baz/quux.js')
185+
);
186+
187+
t.end();
188+
});
189+
175190
test('incorrect main', function (t) {
176191
var resolverDir = path.join(__dirname, 'resolver');
177192
var dir = path.join(resolverDir, 'incorrect_main');

0 commit comments

Comments
 (0)