sync.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. var isCore = require('is-core-module');
  2. var fs = require('fs');
  3. var path = require('path');
  4. var $Error = require('es-errors');
  5. var $TypeError = require('es-errors/type');
  6. var getHomedir = require('./homedir');
  7. var caller = require('./caller');
  8. var nodeModulesPaths = require('./node-modules-paths');
  9. var normalizeOptions = require('./normalize-options');
  10. var realpathFS = process.platform !== 'win32' && fs.realpathSync && typeof fs.realpathSync.native === 'function' ? fs.realpathSync.native : fs.realpathSync;
  11. var relativePathRegex = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/;
  12. var windowsDriveRegex = /^\w:[/\\]*$/;
  13. var nodeModulesRegex = /[/\\]node_modules[/\\]*$/;
  14. var homedir = getHomedir();
  15. function defaultPaths() {
  16. if (!homedir) return [];
  17. return [
  18. path.join(homedir, '.node_modules'),
  19. path.join(homedir, '.node_libraries')
  20. ];
  21. }
  22. var defaultIsFile = function isFile(file) {
  23. try {
  24. var stat = fs.statSync(file, { throwIfNoEntry: false });
  25. } catch (e) {
  26. if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
  27. throw e;
  28. }
  29. return !!stat && (stat.isFile() || stat.isFIFO());
  30. };
  31. var defaultIsDir = function isDirectory(dir) {
  32. try {
  33. var stat = fs.statSync(dir, { throwIfNoEntry: false });
  34. } catch (e) {
  35. if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
  36. throw e;
  37. }
  38. return !!stat && stat.isDirectory();
  39. };
  40. var defaultRealpathSync = function realpathSync(x) {
  41. try {
  42. return realpathFS(x);
  43. } catch (realpathErr) {
  44. if (realpathErr.code !== 'ENOENT') {
  45. throw realpathErr;
  46. }
  47. }
  48. return x;
  49. };
  50. function maybeRealpathSync(realpathSync, x, opts) {
  51. if (opts && opts.preserveSymlinks === false) {
  52. return realpathSync(x);
  53. }
  54. return x;
  55. }
  56. function defaultReadPackageSync(readFileSync, pkgfile) {
  57. var body = readFileSync(pkgfile);
  58. try {
  59. var pkg = JSON.parse(body);
  60. return pkg;
  61. } catch (jsonErr) {}
  62. }
  63. function getPackageCandidates(x, start, opts) {
  64. var dirs = nodeModulesPaths(start, opts, x);
  65. for (var i = 0; i < dirs.length; i++) {
  66. dirs[i] = path.join(dirs[i], x);
  67. }
  68. return dirs;
  69. }
  70. module.exports = function resolveSync(x, options) {
  71. if (typeof x !== 'string') {
  72. throw new $TypeError('Path must be a string.');
  73. }
  74. var opts = normalizeOptions(x, options);
  75. var isFile = opts.isFile || defaultIsFile;
  76. var readFileSync = opts.readFileSync || fs.readFileSync;
  77. var isDirectory = opts.isDirectory || defaultIsDir;
  78. var realpathSync = opts.realpathSync || defaultRealpathSync;
  79. var readPackageSync = opts.readPackageSync || defaultReadPackageSync;
  80. if (opts.readFileSync && opts.readPackageSync) {
  81. throw new $TypeError('`readFileSync` and `readPackageSync` are mutually exclusive.');
  82. }
  83. var packageIterator = opts.packageIterator;
  84. var extensions = opts.extensions || ['.js'];
  85. var includeCoreModules = opts.includeCoreModules !== false;
  86. var basedir = opts.basedir || path.dirname(caller());
  87. var parent = opts.filename || basedir;
  88. opts.paths = opts.paths || defaultPaths();
  89. // ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory
  90. var absoluteStart = maybeRealpathSync(realpathSync, path.resolve(basedir), opts);
  91. if (relativePathRegex.test(x)) {
  92. var res = path.resolve(absoluteStart, x);
  93. if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/';
  94. var m = loadAsFileSync(res) || loadAsDirectorySync(res);
  95. if (m) return maybeRealpathSync(realpathSync, m, opts);
  96. } else if (includeCoreModules && isCore(x)) {
  97. return x;
  98. } else {
  99. var n = loadNodeModulesSync(x, absoluteStart);
  100. if (n) return maybeRealpathSync(realpathSync, n, opts);
  101. }
  102. var err = new $Error("Cannot find module '" + x + "' from '" + parent + "'");
  103. err.code = 'MODULE_NOT_FOUND';
  104. throw err;
  105. function loadAsFileSync(x) {
  106. var pkg = loadpkg(path.dirname(x));
  107. if (pkg && pkg.dir && pkg.pkg && opts.pathFilter) {
  108. var rfile = path.relative(pkg.dir, x);
  109. var r = opts.pathFilter(pkg.pkg, x, rfile);
  110. if (r) {
  111. x = path.resolve(pkg.dir, r); // eslint-disable-line no-param-reassign
  112. }
  113. }
  114. if (isFile(x)) {
  115. return x;
  116. }
  117. for (var i = 0; i < extensions.length; i++) {
  118. var file = x + extensions[i];
  119. if (isFile(file)) {
  120. return file;
  121. }
  122. }
  123. }
  124. function loadpkg(dir) {
  125. if (dir === '' || dir === '/') return;
  126. if (process.platform === 'win32' && windowsDriveRegex.test(dir)) {
  127. return;
  128. }
  129. if (nodeModulesRegex.test(dir)) return;
  130. var pkgfile = path.join(maybeRealpathSync(realpathSync, dir, opts), 'package.json');
  131. if (!isFile(pkgfile)) {
  132. return loadpkg(path.dirname(dir));
  133. }
  134. var pkg = readPackageSync(readFileSync, pkgfile);
  135. if (pkg && opts.packageFilter) {
  136. // v2 will pass pkgfile
  137. pkg = opts.packageFilter(pkg, /*pkgfile,*/ dir); // eslint-disable-line spaced-comment
  138. }
  139. return { pkg: pkg, dir: dir };
  140. }
  141. function loadAsDirectorySync(x) {
  142. var pkgfile = path.join(maybeRealpathSync(realpathSync, x, opts), '/package.json');
  143. if (isFile(pkgfile)) {
  144. try {
  145. var pkg = readPackageSync(readFileSync, pkgfile);
  146. } catch (e) {}
  147. if (pkg && opts.packageFilter) {
  148. // v2 will pass pkgfile
  149. pkg = opts.packageFilter(pkg, /*pkgfile,*/ x); // eslint-disable-line spaced-comment
  150. }
  151. if (pkg && pkg.main) {
  152. if (typeof pkg.main !== 'string') {
  153. var mainError = new $TypeError('package “' + pkg.name + '” `main` must be a string');
  154. mainError.code = 'INVALID_PACKAGE_MAIN';
  155. throw mainError;
  156. }
  157. if (pkg.main === '.' || pkg.main === './') {
  158. pkg.main = 'index';
  159. }
  160. try {
  161. var m = loadAsFileSync(path.resolve(x, pkg.main));
  162. if (m) return m;
  163. var n = loadAsDirectorySync(path.resolve(x, pkg.main));
  164. if (n) return n;
  165. } catch (e) {}
  166. }
  167. }
  168. return loadAsFileSync(path.join(x, '/index'));
  169. }
  170. function loadNodeModulesSync(x, start) {
  171. var thunk = function () { return getPackageCandidates(x, start, opts); };
  172. var dirs = packageIterator ? packageIterator(x, start, thunk, opts) : thunk();
  173. for (var i = 0; i < dirs.length; i++) {
  174. var dir = dirs[i];
  175. if (isDirectory(path.dirname(dir))) {
  176. var m = loadAsFileSync(dir);
  177. if (m) return m;
  178. var n = loadAsDirectorySync(dir);
  179. if (n) return n;
  180. }
  181. }
  182. }
  183. };