Skip to content

Commit 0f698c6

Browse files
arcanisljharb
authored andcommitted
[New] sync'/async: Implement packageIterator
1 parent 426c124 commit 0f698c6

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());
@@ -265,19 +274,18 @@ module.exports = function resolve(x, options, callback) {
265274
if (dirs.length === 0) return cb(null, undefined);
266275
var dir = dirs[0];
267276

268-
isDirectory(dir, isdir);
277+
isDirectory(path.dirname(dir), isdir);
269278

270279
function isdir(err, isdir) {
271280
if (err) return cb(err);
272281
if (!isdir) return processDirs(cb, dirs.slice(1));
273-
var file = path.join(dir, x);
274-
loadAsFile(file, opts.package, onfile);
282+
loadAsFile(dir, opts.package, onfile);
275283
}
276284

277285
function onfile(err, m, pkg) {
278286
if (err) return cb(err);
279287
if (m) return cb(null, m, pkg);
280-
loadAsDirectory(path.join(dir, x), opts.package, ondir);
288+
loadAsDirectory(dir, opts.package, ondir);
281289
}
282290

283291
function ondir(err, n, pkg) {
@@ -287,6 +295,10 @@ module.exports = function resolve(x, options, callback) {
287295
}
288296
}
289297
function loadNodeModules(x, start, cb) {
290-
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+
);
291303
}
292304
};

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());
@@ -162,13 +171,15 @@ module.exports = function (x, options) {
162171
}
163172

164173
function loadNodeModulesSync(x, start) {
165-
var dirs = nodeModulesPaths(start, opts, x);
174+
var thunk = function () { return getPackageCandidates(x, start, opts); };
175+
var dirs = packageIterator ? packageIterator(x, start, thunk, opts) : thunk();
176+
166177
for (var i = 0; i < dirs.length; i++) {
167178
var dir = dirs[i];
168-
if (isDirectory(dir)) {
169-
var m = loadAsFileSync(path.join(dir, '/', x));
179+
if (isDirectory(path.dirname(dir))) {
180+
var m = loadAsFileSync(dir);
170181
if (m) return m;
171-
var n = loadAsDirectorySync(path.join(dir, '/', x));
182+
var n = loadAsDirectorySync(dir);
172183
if (n) return n;
173184
}
174185
}

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)