|
| 1 | +/* eslint-disable max-lines */ |
1 | 2 | var fs = require('fs');
|
2 | 3 | var path = require('path');
|
3 | 4 | var caller = require('./caller.js');
|
4 | 5 | var nodeModulesPaths = require('./node-modules-paths.js');
|
5 | 6 | var normalizeOptions = require('./normalize-options.js');
|
6 | 7 | var isCore = require('./is-core');
|
| 8 | +var resolveExports = require('./resolve-exports.js'); |
7 | 9 |
|
8 | 10 | var realpathFS = fs.realpath && typeof fs.realpath.native === 'function' ? fs.realpath.native : fs.realpath;
|
9 | 11 |
|
@@ -75,6 +77,7 @@ module.exports = function resolve(x, options, callback) {
|
75 | 77 | var extensions = opts.extensions || ['.js'];
|
76 | 78 | var basedir = opts.basedir || path.dirname(caller());
|
77 | 79 | var parent = opts.filename || basedir;
|
| 80 | + var env = opts.ignoreExportsField === false ? ['require', 'node'] : []; |
78 | 81 |
|
79 | 82 | opts.paths = opts.paths || [];
|
80 | 83 |
|
@@ -278,35 +281,104 @@ module.exports = function resolve(x, options, callback) {
|
278 | 281 | });
|
279 | 282 | }
|
280 | 283 |
|
281 |
| - function processDirs(cb, dirs) { |
| 284 | + function loadManifestInDir(dir, cb) { |
| 285 | + maybeRealpath(realpath, dir, opts, function (err, pkgdir) { |
| 286 | + if (err) return cb(null); |
| 287 | + |
| 288 | + var pkgfile = path.join(pkgdir, 'package.json'); |
| 289 | + isFile(pkgfile, function (err, ex) { |
| 290 | + // on err, ex is false |
| 291 | + if (!ex) return cb(null); |
| 292 | + |
| 293 | + readFile(pkgfile, function (err, body) { |
| 294 | + if (err) cb(err); |
| 295 | + try { var pkg = JSON.parse(body); } catch (jsonErr) {} |
| 296 | + |
| 297 | + if (pkg && opts.packageFilter) { |
| 298 | + pkg = opts.packageFilter(pkg, pkgfile, dir); |
| 299 | + } |
| 300 | + cb(pkg); |
| 301 | + }); |
| 302 | + }); |
| 303 | + }); |
| 304 | + } |
| 305 | + |
| 306 | + function processDirs(cb, dirs, subpath, endsWithSubpath) { |
282 | 307 | if (dirs.length === 0) return cb(null, undefined);
|
283 | 308 | var dir = dirs[0];
|
284 | 309 |
|
285 |
| - isDirectory(path.dirname(dir), isdir); |
286 |
| - |
287 |
| - function isdir(err, isdir) { |
288 |
| - if (err) return cb(err); |
289 |
| - if (!isdir) return processDirs(cb, dirs.slice(1)); |
290 |
| - loadAsFile(dir, opts.package, onfile); |
| 310 | + if (env.length > 0 && endsWithSubpath(dir)) { |
| 311 | + var pkgDir = dir.slice(0, dir.length - subpath.length); |
| 312 | + loadManifestInDir(pkgDir, onmanifestWithExports); |
| 313 | + } else { |
| 314 | + onmanifest(true); |
291 | 315 | }
|
292 | 316 |
|
293 |
| - function onfile(err, m, pkg) { |
294 |
| - if (err) return cb(err); |
295 |
| - if (m) return cb(null, m, pkg); |
296 |
| - loadAsDirectory(dir, opts.package, ondir); |
| 317 | + function onmanifestWithExports(pkg) { |
| 318 | + var tryLoadAsDirectory = true; |
| 319 | + if (pkg && pkg.exports) { |
| 320 | + try { |
| 321 | + var resolvedExport = resolveExports(pkgDir, parent, subpath, pkg.exports, env); |
| 322 | + } catch (resolveErr) { |
| 323 | + return cb(resolveErr); |
| 324 | + } |
| 325 | + |
| 326 | + if (resolvedExport) { |
| 327 | + dir = resolvedExport.path; |
| 328 | + tryLoadAsDirectory = resolvedExport.tryLoadAsDirectory; |
| 329 | + } |
| 330 | + } |
| 331 | + |
| 332 | + onmanifest(tryLoadAsDirectory); |
297 | 333 | }
|
298 | 334 |
|
299 |
| - function ondir(err, n, pkg) { |
300 |
| - if (err) return cb(err); |
301 |
| - if (n) return cb(null, n, pkg); |
302 |
| - processDirs(cb, dirs.slice(1)); |
| 335 | + function onmanifest(tryLoadAsDirectory) { |
| 336 | + isDirectory(path.dirname(dir), isdir); |
| 337 | + |
| 338 | + function isdir(err, isdir) { |
| 339 | + if (err) return cb(err); |
| 340 | + if (!isdir) return processDirs(cb, dirs.slice(1), subpath, endsWithSubpath); |
| 341 | + loadAsFile(dir, opts.package, onfile); |
| 342 | + } |
| 343 | + |
| 344 | + function onfile(err, m, pkg) { |
| 345 | + if (err) return cb(err); |
| 346 | + if (m) return cb(null, m, pkg); |
| 347 | + if (!tryLoadAsDirectory) return processDirs(cb, dirs.slice(1), subpath, endsWithSubpath); |
| 348 | + loadAsDirectory(dir, opts.package, ondir); |
| 349 | + } |
| 350 | + |
| 351 | + function ondir(err, n, pkg) { |
| 352 | + if (err) return cb(err); |
| 353 | + if (n) return cb(null, n, pkg); |
| 354 | + processDirs(cb, dirs.slice(1), subpath, endsWithSubpath); |
| 355 | + } |
303 | 356 | }
|
| 357 | + |
304 | 358 | }
|
305 | 359 | function loadNodeModules(x, start, cb) {
|
| 360 | + var subpathIndex = x.indexOf('/'); |
| 361 | + if (x[0] === '@') { |
| 362 | + subpathIndex = x.indexOf('/', subpathIndex + 1); |
| 363 | + } |
| 364 | + var subpath; |
| 365 | + if (subpathIndex === -1) { |
| 366 | + subpath = ''; |
| 367 | + } else { |
| 368 | + subpath = x.slice(subpathIndex); |
| 369 | + } |
| 370 | + |
306 | 371 | var thunk = function () { return getPackageCandidates(x, start, opts); };
|
| 372 | + var endsWithSubpath = function (dir) { |
| 373 | + var endOfDir = dir.slice(dir.length - subpath.length); |
| 374 | + |
| 375 | + return endOfDir === subpath || endOfDir.replace(/\\/g, '/') === subpath; |
| 376 | + }; |
307 | 377 | processDirs(
|
308 | 378 | cb,
|
309 |
| - packageIterator ? packageIterator(x, start, thunk, opts) : thunk() |
| 379 | + packageIterator ? packageIterator(x, start, thunk, opts) : thunk(), |
| 380 | + subpath, |
| 381 | + endsWithSubpath |
310 | 382 | );
|
311 | 383 | }
|
312 | 384 | };
|
0 commit comments