async.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. var core = require('./core');
  2. var fs = require('fs');
  3. var path = require('path');
  4. var caller = require('./caller.js');
  5. var nodeModulesPaths = require('./node-modules-paths.js');
  6. module.exports = function resolve(x, options, callback) {
  7. var cb = callback;
  8. var opts = options || {};
  9. if (typeof opts === 'function') {
  10. cb = opts;
  11. opts = {};
  12. }
  13. if (typeof x !== 'string') {
  14. var err = new TypeError('Path must be a string.');
  15. return process.nextTick(function () {
  16. cb(err);
  17. });
  18. }
  19. var isFile = opts.isFile || function (file, cb) {
  20. fs.stat(file, function (err, stat) {
  21. if (!err) {
  22. return cb(null, stat.isFile() || stat.isFIFO());
  23. }
  24. if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
  25. return cb(err);
  26. });
  27. };
  28. var readFile = opts.readFile || fs.readFile;
  29. var extensions = opts.extensions || ['.js'];
  30. var y = opts.basedir || path.dirname(caller());
  31. opts.paths = opts.paths || [];
  32. if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/.test(x)) {
  33. var res = path.resolve(y, x);
  34. if (x === '..' || x.slice(-1) === '/') res += '/';
  35. if (/\/$/.test(x) && res === y) {
  36. loadAsDirectory(res, opts.package, onfile);
  37. } else loadAsFile(res, opts.package, onfile);
  38. } else loadNodeModules(x, y, function (err, n, pkg) {
  39. if (err) cb(err);
  40. else if (n) cb(null, n, pkg);
  41. else if (core[x]) return cb(null, x);
  42. else {
  43. var moduleError = new Error("Cannot find module '" + x + "' from '" + y + "'");
  44. moduleError.code = 'MODULE_NOT_FOUND';
  45. cb(moduleError);
  46. }
  47. });
  48. function onfile(err, m, pkg) {
  49. if (err) cb(err);
  50. else if (m) cb(null, m, pkg);
  51. else loadAsDirectory(res, function (err, d, pkg) {
  52. if (err) cb(err);
  53. else if (d) cb(null, d, pkg);
  54. else {
  55. var moduleError = new Error("Cannot find module '" + x + "' from '" + y + "'");
  56. moduleError.code = 'MODULE_NOT_FOUND';
  57. cb(moduleError);
  58. }
  59. });
  60. }
  61. function loadAsFile(x, thePackage, callback) {
  62. var loadAsFilePackage = thePackage;
  63. var cb = callback;
  64. if (typeof loadAsFilePackage === 'function') {
  65. cb = loadAsFilePackage;
  66. loadAsFilePackage = undefined;
  67. }
  68. var exts = [''].concat(extensions);
  69. load(exts, x, loadAsFilePackage);
  70. function load(exts, x, loadPackage) {
  71. if (exts.length === 0) return cb(null, undefined, loadPackage);
  72. var file = x + exts[0];
  73. var pkg = loadPackage;
  74. if (pkg) onpkg(null, pkg);
  75. else loadpkg(path.dirname(file), onpkg);
  76. function onpkg(err, pkg_, dir) {
  77. pkg = pkg_;
  78. if (err) return cb(err);
  79. if (dir && pkg && opts.pathFilter) {
  80. var rfile = path.relative(dir, file);
  81. var rel = rfile.slice(0, rfile.length - exts[0].length);
  82. var r = opts.pathFilter(pkg, x, rel);
  83. if (r) return load(
  84. [''].concat(extensions.slice()),
  85. path.resolve(dir, r),
  86. pkg
  87. );
  88. }
  89. isFile(file, onex);
  90. }
  91. function onex(err, ex) {
  92. if (err) return cb(err);
  93. if (ex) return cb(null, file, pkg);
  94. load(exts.slice(1), x, pkg);
  95. }
  96. }
  97. }
  98. function loadpkg(dir, cb) {
  99. if (dir === '' || dir === '/') return cb(null);
  100. if (process.platform === 'win32' && (/^\w:[/\\]*$/).test(dir)) {
  101. return cb(null);
  102. }
  103. if (/[/\\]node_modules[/\\]*$/.test(dir)) return cb(null);
  104. var pkgfile = path.join(dir, 'package.json');
  105. isFile(pkgfile, function (err, ex) {
  106. // on err, ex is false
  107. if (!ex) return loadpkg(path.dirname(dir), cb);
  108. readFile(pkgfile, function (err, body) {
  109. if (err) cb(err);
  110. try { var pkg = JSON.parse(body); } catch (jsonErr) {}
  111. if (pkg && opts.packageFilter) {
  112. pkg = opts.packageFilter(pkg, pkgfile);
  113. }
  114. cb(null, pkg, dir);
  115. });
  116. });
  117. }
  118. function loadAsDirectory(x, loadAsDirectoryPackage, callback) {
  119. var cb = callback;
  120. var fpkg = loadAsDirectoryPackage;
  121. if (typeof fpkg === 'function') {
  122. cb = fpkg;
  123. fpkg = opts.package;
  124. }
  125. var pkgfile = path.join(x, 'package.json');
  126. isFile(pkgfile, function (err, ex) {
  127. if (err) return cb(err);
  128. if (!ex) return loadAsFile(path.join(x, 'index'), fpkg, cb);
  129. readFile(pkgfile, function (err, body) {
  130. if (err) return cb(err);
  131. try {
  132. var pkg = JSON.parse(body);
  133. } catch (jsonErr) {}
  134. if (opts.packageFilter) {
  135. pkg = opts.packageFilter(pkg, pkgfile);
  136. }
  137. if (pkg.main) {
  138. if (pkg.main === '.' || pkg.main === './') {
  139. pkg.main = 'index';
  140. }
  141. loadAsFile(path.resolve(x, pkg.main), pkg, function (err, m, pkg) {
  142. if (err) return cb(err);
  143. if (m) return cb(null, m, pkg);
  144. if (!pkg) return loadAsFile(path.join(x, 'index'), pkg, cb);
  145. var dir = path.resolve(x, pkg.main);
  146. loadAsDirectory(dir, pkg, function (err, n, pkg) {
  147. if (err) return cb(err);
  148. if (n) return cb(null, n, pkg);
  149. loadAsFile(path.join(x, 'index'), pkg, cb);
  150. });
  151. });
  152. return;
  153. }
  154. loadAsFile(path.join(x, '/index'), pkg, cb);
  155. });
  156. });
  157. }
  158. function processDirs(cb, dirs) {
  159. if (dirs.length === 0) return cb(null, undefined);
  160. var dir = dirs[0];
  161. var file = path.join(dir, x);
  162. loadAsFile(file, undefined, onfile);
  163. function onfile(err, m, pkg) {
  164. if (err) return cb(err);
  165. if (m) return cb(null, m, pkg);
  166. loadAsDirectory(path.join(dir, x), undefined, ondir);
  167. }
  168. function ondir(err, n, pkg) {
  169. if (err) return cb(err);
  170. if (n) return cb(null, n, pkg);
  171. processDirs(cb, dirs.slice(1));
  172. }
  173. }
  174. function loadNodeModules(x, start, cb) {
  175. processDirs(cb, nodeModulesPaths(start, opts));
  176. }
  177. };