resolve.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. /**
  4. * @license
  5. * Copyright Google Inc. All Rights Reserved.
  6. *
  7. * Use of this source code is governed by an MIT-style license that can be
  8. * found in the LICENSE file at https://angular.io/license
  9. */
  10. const fs = require("fs");
  11. const path = require("path");
  12. const src_1 = require("../src");
  13. const fs_1 = require("./fs");
  14. /**
  15. * Exception thrown when a module could not be resolved.
  16. * @deprecated since version 8. Use `MODULE_NOT_FOUND` Node error code instead.
  17. */
  18. class ModuleNotFoundException extends src_1.BaseException {
  19. constructor(moduleName, basePath) {
  20. super(`Could not find module ${JSON.stringify(moduleName)} from ${JSON.stringify(basePath)}.`);
  21. this.moduleName = moduleName;
  22. this.basePath = basePath;
  23. this.code = 'MODULE_NOT_FOUND';
  24. }
  25. }
  26. exports.ModuleNotFoundException = ModuleNotFoundException;
  27. /**
  28. * Returns a list of all the callers from the resolve() call.
  29. * @returns {string[]}
  30. * @private
  31. */
  32. function _caller() {
  33. // see https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
  34. const error = Error;
  35. const origPrepareStackTrace = error.prepareStackTrace;
  36. error.prepareStackTrace = (_, stack) => stack;
  37. const stack = (new Error()).stack;
  38. error.prepareStackTrace = origPrepareStackTrace;
  39. return stack ? stack.map(x => x.getFileName()).filter(x => !!x) : [];
  40. }
  41. /**
  42. * Get the global directory for node_modules. This is based on NPM code itself, and may be subject
  43. * to change, but is relatively stable.
  44. * @returns {string} The path to node_modules itself.
  45. * @private
  46. */
  47. function _getGlobalNodeModules() {
  48. let globalPrefix;
  49. if (process.env.PREFIX) {
  50. globalPrefix = process.env.PREFIX;
  51. }
  52. else if (process.platform === 'win32') {
  53. // c:\node\node.exe --> prefix=c:\node\
  54. globalPrefix = path.dirname(process.execPath);
  55. }
  56. else {
  57. // /usr/local/bin/node --> prefix=/usr/local
  58. globalPrefix = path.dirname(path.dirname(process.execPath));
  59. // destdir only is respected on Unix
  60. const destdir = process.env.DESTDIR;
  61. if (destdir) {
  62. globalPrefix = path.join(destdir, globalPrefix);
  63. }
  64. }
  65. return (process.platform !== 'win32')
  66. ? path.resolve(globalPrefix || '', 'lib', 'node_modules')
  67. : path.resolve(globalPrefix || '', 'node_modules');
  68. }
  69. let _resolveHook = null;
  70. /** @deprecated since version 8. Use `require.resolve` instead. */
  71. function setResolveHook(hook) {
  72. _resolveHook = hook;
  73. }
  74. exports.setResolveHook = setResolveHook;
  75. /**
  76. * Resolve a package using a logic similar to npm require.resolve, but with more options.
  77. * @param packageName The package name to resolve.
  78. * @param options A list of options. See documentation of those options.
  79. * @returns {string} Path to the index to include, or if `resolvePackageJson` option was
  80. * passed, a path to that file.
  81. * @throws {ModuleNotFoundException} If no module with that name was found anywhere.
  82. * @deprecated since version 8. Use `require.resolve` instead.
  83. */
  84. function resolve(packageName, options) {
  85. if (_resolveHook) {
  86. const maybe = _resolveHook(packageName, options);
  87. if (maybe) {
  88. return maybe;
  89. }
  90. }
  91. const readFileSync = fs.readFileSync;
  92. const extensions = options.extensions || Object.keys(require.extensions);
  93. const basePath = options.basedir;
  94. options.paths = options.paths || [];
  95. if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\/\\])/.test(packageName)) {
  96. let res = path.resolve(basePath, packageName);
  97. if (packageName === '..' || packageName.slice(-1) === '/') {
  98. res += '/';
  99. }
  100. const m = loadAsFileSync(res) || loadAsDirectorySync(res);
  101. if (m) {
  102. return m;
  103. }
  104. }
  105. else {
  106. const n = loadNodeModulesSync(packageName, basePath);
  107. if (n) {
  108. return n;
  109. }
  110. }
  111. // Fallback to checking the local (callee) node modules.
  112. if (options.checkLocal) {
  113. const callers = _caller();
  114. for (const caller of callers) {
  115. const localDir = path.dirname(caller);
  116. if (localDir !== options.basedir) {
  117. try {
  118. return resolve(packageName, {
  119. ...options,
  120. checkLocal: false,
  121. checkGlobal: false,
  122. basedir: localDir,
  123. });
  124. }
  125. catch (e) {
  126. // Just swap the basePath with the original call one.
  127. if (!(e instanceof ModuleNotFoundException)) {
  128. throw e;
  129. }
  130. }
  131. }
  132. }
  133. }
  134. // Fallback to checking the global node modules.
  135. if (options.checkGlobal) {
  136. const globalDir = path.dirname(_getGlobalNodeModules());
  137. if (globalDir !== options.basedir) {
  138. try {
  139. return resolve(packageName, {
  140. ...options,
  141. checkLocal: false,
  142. checkGlobal: false,
  143. basedir: globalDir,
  144. });
  145. }
  146. catch (e) {
  147. // Just swap the basePath with the original call one.
  148. if (!(e instanceof ModuleNotFoundException)) {
  149. throw e;
  150. }
  151. }
  152. }
  153. }
  154. throw new ModuleNotFoundException(packageName, basePath);
  155. function loadAsFileSync(x) {
  156. if (fs_1.isFile(x)) {
  157. return x;
  158. }
  159. return extensions.map(ex => x + ex).find(f => fs_1.isFile(f)) || null;
  160. }
  161. function loadAsDirectorySync(x) {
  162. const pkgfile = path.join(x, 'package.json');
  163. if (fs_1.isFile(pkgfile)) {
  164. if (options.resolvePackageJson) {
  165. return pkgfile;
  166. }
  167. try {
  168. const body = readFileSync(pkgfile, 'UTF8');
  169. const pkg = JSON.parse(body);
  170. if (pkg['main']) {
  171. if (pkg['main'] === '.' || pkg['main'] === './') {
  172. pkg['main'] = 'index';
  173. }
  174. const m = loadAsFileSync(path.resolve(x, pkg['main']));
  175. if (m) {
  176. return m;
  177. }
  178. const n = loadAsDirectorySync(path.resolve(x, pkg['main']));
  179. if (n) {
  180. return n;
  181. }
  182. }
  183. }
  184. catch (_a) { }
  185. }
  186. return loadAsFileSync(path.join(x, '/index'));
  187. }
  188. function loadNodeModulesSync(x, start) {
  189. const dirs = nodeModulesPaths(start, options);
  190. for (const dir of dirs) {
  191. const m = loadAsFileSync(path.join(dir, x));
  192. if (m) {
  193. return m;
  194. }
  195. const n = loadAsDirectorySync(path.join(dir, x));
  196. if (n) {
  197. return n;
  198. }
  199. }
  200. return null;
  201. }
  202. function nodeModulesPaths(start, opts) {
  203. const modules = ['node_modules'];
  204. if (process.env.BAZEL_TARGET) {
  205. // When running test under Bazel, node_modules have to be resolved
  206. // differently. node_modules are installed in the `npm` workspace.
  207. // For more info, see `yarn_install` rule in WORKSPACE file.
  208. modules.push(path.join('npm', 'node_modules'));
  209. }
  210. // ensure that `start` is an absolute path at this point,
  211. // resolving against the process' current working directory
  212. let absoluteStart = path.resolve(start);
  213. if (opts && opts.preserveSymlinks === false) {
  214. try {
  215. absoluteStart = fs.realpathSync(absoluteStart);
  216. }
  217. catch (err) {
  218. if (err.code !== 'ENOENT') {
  219. throw err;
  220. }
  221. }
  222. }
  223. let prefix = '/';
  224. if (/^([A-Za-z]:)/.test(absoluteStart)) {
  225. prefix = '';
  226. }
  227. else if (/^\\\\/.test(absoluteStart)) {
  228. prefix = '\\\\';
  229. }
  230. const paths = [absoluteStart];
  231. let parsed = path.parse(absoluteStart);
  232. while (parsed.dir !== paths[paths.length - 1]) {
  233. paths.push(parsed.dir);
  234. parsed = path.parse(parsed.dir);
  235. }
  236. const dirs = paths.reduce((dirs, aPath) => {
  237. return dirs.concat(modules.map(function (moduleDir) {
  238. return path.join(prefix, aPath, moduleDir);
  239. }));
  240. }, []);
  241. if (process.env.NG_TEMP_MODULES_DIR) {
  242. // When running from a temporary installations, node_modules have to be resolved
  243. // differently and they should be prefered over others.
  244. dirs.unshift(process.env.NG_TEMP_MODULES_DIR);
  245. }
  246. return opts && opts.paths ? dirs.concat(opts.paths) : dirs;
  247. }
  248. }
  249. exports.resolve = resolve;