Skip to content

Commit 163f9da

Browse files
arcanisljharb
authored andcommitted
[New] sync'/async: Implement packageIterator (#205)
1 parent fca4013 commit 163f9da

File tree

6 files changed

+82
-9
lines changed

6 files changed

+82
-9
lines changed

lib/async.js

Lines changed: 17 additions & 5 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());
@@ -251,19 +260,18 @@ module.exports = function resolve(x, options, callback) {
251260
if (dirs.length === 0) return cb(null, undefined);
252261
var dir = dirs[0];
253262

254-
isDirectory(dir, isdir);
263+
isDirectory(path.dirname(dir), isdir);
255264

256265
function isdir(err, isdir) {
257266
if (err) return cb(err);
258267
if (!isdir) return processDirs(cb, dirs.slice(1));
259-
var file = path.join(dir, x);
260-
loadAsFile(file, opts.package, onfile);
268+
loadAsFile(dir, opts.package, onfile);
261269
}
262270

263271
function onfile(err, m, pkg) {
264272
if (err) return cb(err);
265273
if (m) return cb(null, m, pkg);
266-
loadAsDirectory(path.join(dir, x), opts.package, ondir);
274+
loadAsDirectory(dir, opts.package, ondir);
267275
}
268276

269277
function ondir(err, n, pkg) {
@@ -273,6 +281,10 @@ module.exports = function resolve(x, options, callback) {
273281
}
274282
}
275283
function loadNodeModules(x, start, cb) {
276-
processDirs(cb, nodeModulesPaths(start, opts, x));
284+
var thunk = function () { return getPackageCandidates(x, start, opts); };
285+
processDirs(
286+
cb,
287+
packageIterator ? packageIterator(x, start, thunk, opts) : thunk()
288+
);
277289
}
278290
};

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 readFileSync = opts.readFileSync || fs.readFileSync;
4957
var isDirectory = opts.isDirectory || defaultIsDir;
58+
var packageIterator = opts.packageIterator;
5059

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

160169
function loadNodeModulesSync(x, start) {
161-
var dirs = nodeModulesPaths(start, opts, x);
170+
var thunk = function () { return getPackageCandidates(x, start, opts); };
171+
var dirs = packageIterator ? packageIterator(x, start, thunk, opts) : thunk();
172+
162173
for (var i = 0; i < dirs.length; i++) {
163174
var dir = dirs[i];
164-
if (isDirectory(dir)) {
165-
var m = loadAsFileSync(path.join(dir, '/', x));
175+
if (isDirectory(path.dirname(dir))) {
176+
var m = loadAsFileSync(dir);
166177
if (m) return m;
167-
var n = loadAsDirectorySync(path.join(dir, '/', x));
178+
var n = loadAsDirectorySync(dir);
168179
if (n) return n;
169180
}
170181
}

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.
@@ -147,6 +153,18 @@ options are:
147153

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

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

152170
* 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)