index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. 'use strict';
  2. var _fs;
  3. function _load_fs() {
  4. return _fs = _interopRequireDefault(require('fs'));
  5. }
  6. var _path;
  7. function _load_path() {
  8. return _path = _interopRequireDefault(require('path'));
  9. }
  10. var _node_modules_paths;
  11. function _load_node_modules_paths() {
  12. return _node_modules_paths = _interopRequireDefault(require('./node_modules_paths'));
  13. }
  14. var _is_builtin_module;
  15. function _load_is_builtin_module() {
  16. return _is_builtin_module = _interopRequireDefault(require('./is_builtin_module'));
  17. }
  18. var _default_resolver;
  19. function _load_default_resolver() {
  20. return _default_resolver = _interopRequireDefault(require('./default_resolver.js'));
  21. }
  22. var _chalk;
  23. function _load_chalk() {
  24. return _chalk = _interopRequireDefault(require('chalk'));
  25. }
  26. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  27. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } /**
  28. * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  29. *
  30. * This source code is licensed under the MIT license found in the
  31. * LICENSE file in the root directory of this source tree.
  32. *
  33. *
  34. */
  35. const NATIVE_PLATFORM = 'native';
  36. // We might be inside a symlink.
  37. const cwd = process.cwd();
  38. const resolvedCwd = (_fs || _load_fs()).default.realpathSync(cwd) || cwd;
  39. const nodePaths = process.env.NODE_PATH ? process.env.NODE_PATH.split((_path || _load_path()).default.delimiter).filter(Boolean)
  40. // The resolver expects absolute paths.
  41. .map(p => (_path || _load_path()).default.resolve(resolvedCwd, p)) : null;
  42. class Resolver {
  43. constructor(moduleMap, options) {
  44. this._options = {
  45. browser: options.browser,
  46. defaultPlatform: options.defaultPlatform,
  47. extensions: options.extensions,
  48. hasCoreModules: options.hasCoreModules === undefined ? true : options.hasCoreModules,
  49. moduleDirectories: options.moduleDirectories || ['node_modules'],
  50. moduleNameMapper: options.moduleNameMapper,
  51. modulePaths: options.modulePaths,
  52. platforms: options.platforms,
  53. resolver: options.resolver,
  54. rootDir: options.rootDir
  55. };
  56. this._moduleMap = moduleMap;
  57. this._moduleIDCache = Object.create(null);
  58. this._moduleNameCache = Object.create(null);
  59. this._modulePathCache = Object.create(null);
  60. }
  61. static findNodeModule(path, options) {
  62. const resolver = options.resolver ? /* $FlowFixMe */
  63. require(options.resolver) : (_default_resolver || _load_default_resolver()).default;
  64. const paths = options.paths;
  65. try {
  66. return resolver(path, {
  67. basedir: options.basedir,
  68. browser: options.browser,
  69. extensions: options.extensions,
  70. moduleDirectory: options.moduleDirectory,
  71. paths: paths ? (nodePaths || []).concat(paths) : nodePaths,
  72. rootDir: options.rootDir
  73. });
  74. } catch (e) {}
  75. return null;
  76. }
  77. resolveModule(from, moduleName, options) {
  78. const dirname = (_path || _load_path()).default.dirname(from);
  79. const paths = this._options.modulePaths;
  80. const moduleDirectory = this._options.moduleDirectories;
  81. const key = dirname + (_path || _load_path()).default.delimiter + moduleName;
  82. const defaultPlatform = this._options.defaultPlatform;
  83. const extensions = this._options.extensions.slice();
  84. if (this._supportsNativePlatform()) {
  85. extensions.unshift.apply(extensions, _toConsumableArray(this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext)));
  86. }
  87. if (defaultPlatform) {
  88. extensions.unshift.apply(extensions, _toConsumableArray(this._options.extensions.map(ext => '.' + defaultPlatform + ext)));
  89. }
  90. // 0. If we have already resolved this module for this directory name,
  91. // return a value from the cache.
  92. if (this._moduleNameCache[key]) {
  93. return this._moduleNameCache[key];
  94. }
  95. // 1. Check if the module is a haste module.
  96. let module = this.getModule(moduleName);
  97. if (module) {
  98. return this._moduleNameCache[key] = module;
  99. }
  100. // 2. Check if the module is a node module and resolve it based on
  101. // the node module resolution algorithm.
  102. // If skipNodeResolution is given we ignore all modules that look like
  103. // node modules (ie. are not relative requires). This enables us to speed
  104. // up resolution when we build a dependency graph because we don't have
  105. // to look at modules that may not exist and aren't mocked.
  106. const skipResolution = options && options.skipNodeResolution && !moduleName.includes((_path || _load_path()).default.sep);
  107. const resolveNodeModule = name => {
  108. return Resolver.findNodeModule(name, {
  109. basedir: dirname,
  110. browser: this._options.browser,
  111. extensions,
  112. moduleDirectory,
  113. paths,
  114. resolver: this._options.resolver,
  115. rootDir: this._options.rootDir
  116. });
  117. };
  118. if (!skipResolution) {
  119. module = resolveNodeModule(moduleName);
  120. if (module) {
  121. return this._moduleNameCache[key] = module;
  122. }
  123. }
  124. // 3. Resolve "haste packages" which are `package.json` files outside of
  125. // `node_modules` folders anywhere in the file system.
  126. const parts = moduleName.split('/');
  127. const hastePackage = this.getPackage(parts.shift());
  128. if (hastePackage) {
  129. try {
  130. const module = (_path || _load_path()).default.join.apply((_path || _load_path()).default, [(_path || _load_path()).default.dirname(hastePackage)].concat(parts));
  131. // try resolving with custom resolver first to support extensions,
  132. // then fallback to require.resolve
  133. return this._moduleNameCache[key] = resolveNodeModule(module) || require.resolve(module);
  134. } catch (ignoredError) {}
  135. }
  136. // 4. Throw an error if the module could not be found. `resolve.sync`
  137. // only produces an error based on the dirname but we have the actual
  138. // current module name available.
  139. const relativePath = (_path || _load_path()).default.relative(dirname, from);
  140. const err = new Error(`Cannot find module '${moduleName}' from '${relativePath || '.'}'`);
  141. err.code = 'MODULE_NOT_FOUND';
  142. throw err;
  143. }
  144. isCoreModule(moduleName) {
  145. return this._options.hasCoreModules && (0, (_is_builtin_module || _load_is_builtin_module()).default)(moduleName);
  146. }
  147. getModule(name) {
  148. return this._moduleMap.getModule(name, this._options.defaultPlatform, this._supportsNativePlatform());
  149. }
  150. getModulePath(from, moduleName) {
  151. if (moduleName[0] !== '.' || (_path || _load_path()).default.isAbsolute(moduleName)) {
  152. return moduleName;
  153. }
  154. return (_path || _load_path()).default.normalize((_path || _load_path()).default.dirname(from) + '/' + moduleName);
  155. }
  156. getPackage(name) {
  157. return this._moduleMap.getPackage(name, this._options.defaultPlatform, this._supportsNativePlatform());
  158. }
  159. getMockModule(from, name) {
  160. const mock = this._moduleMap.getMockModule(name);
  161. if (mock) {
  162. return mock;
  163. } else {
  164. const moduleName = this._resolveStubModuleName(from, name);
  165. if (moduleName) {
  166. return this.getModule(moduleName) || moduleName;
  167. }
  168. }
  169. return null;
  170. }
  171. getModulePaths(from) {
  172. if (!this._modulePathCache[from]) {
  173. const moduleDirectory = this._options.moduleDirectories;
  174. const paths = (0, (_node_modules_paths || _load_node_modules_paths()).default)(from, { moduleDirectory });
  175. if (paths[paths.length - 1] === undefined) {
  176. // circumvent node-resolve bug that adds `undefined` as last item.
  177. paths.pop();
  178. }
  179. this._modulePathCache[from] = paths;
  180. }
  181. return this._modulePathCache[from];
  182. }
  183. getModuleID(virtualMocks, from, _moduleName) {
  184. const moduleName = _moduleName || '';
  185. const key = from + (_path || _load_path()).default.delimiter + moduleName;
  186. if (this._moduleIDCache[key]) {
  187. return this._moduleIDCache[key];
  188. }
  189. const moduleType = this._getModuleType(moduleName);
  190. const absolutePath = this._getAbsolutPath(virtualMocks, from, moduleName);
  191. const mockPath = this._getMockPath(from, moduleName);
  192. const sep = (_path || _load_path()).default.delimiter;
  193. const id = moduleType + sep + (absolutePath ? absolutePath + sep : '') + (mockPath ? mockPath + sep : '');
  194. return this._moduleIDCache[key] = id;
  195. }
  196. _getModuleType(moduleName) {
  197. return this.isCoreModule(moduleName) ? 'node' : 'user';
  198. }
  199. _getAbsolutPath(virtualMocks, from, moduleName) {
  200. if (this.isCoreModule(moduleName)) {
  201. return moduleName;
  202. }
  203. return this._isModuleResolved(from, moduleName) ? this.getModule(moduleName) : this._getVirtualMockPath(virtualMocks, from, moduleName);
  204. }
  205. _getMockPath(from, moduleName) {
  206. return !this.isCoreModule(moduleName) ? this.getMockModule(from, moduleName) : null;
  207. }
  208. _getVirtualMockPath(virtualMocks, from, moduleName) {
  209. const virtualMockPath = this.getModulePath(from, moduleName);
  210. return virtualMocks[virtualMockPath] ? virtualMockPath : moduleName ? this.resolveModule(from, moduleName) : from;
  211. }
  212. _isModuleResolved(from, moduleName) {
  213. return !!(this.getModule(moduleName) || this.getMockModule(from, moduleName));
  214. }
  215. _resolveStubModuleName(from, moduleName) {
  216. const dirname = (_path || _load_path()).default.dirname(from);
  217. const paths = this._options.modulePaths;
  218. const extensions = this._options.extensions;
  219. const moduleDirectory = this._options.moduleDirectories;
  220. const moduleNameMapper = this._options.moduleNameMapper;
  221. const resolver = this._options.resolver;
  222. if (moduleNameMapper) {
  223. for (const _ref of moduleNameMapper) {
  224. const mappedModuleName = _ref.moduleName;
  225. const regex = _ref.regex;
  226. if (regex.test(moduleName)) {
  227. // Note: once a moduleNameMapper matches the name, it must result
  228. // in a module, or else an error is thrown.
  229. const matches = moduleName.match(regex);
  230. const updatedName = matches ? mappedModuleName.replace(/\$([0-9]+)/g, (_, index) => matches[parseInt(index, 10)]) : mappedModuleName;
  231. const module = this.getModule(updatedName) || Resolver.findNodeModule(updatedName, {
  232. basedir: dirname,
  233. browser: this._options.browser,
  234. extensions,
  235. moduleDirectory,
  236. paths,
  237. resolver,
  238. rootDir: this._options.rootDir
  239. });
  240. if (!module) {
  241. const error = new Error((_chalk || _load_chalk()).default.red(`${(_chalk || _load_chalk()).default.bold('Configuration error')}:
  242. Could not locate module ${(_chalk || _load_chalk()).default.bold(moduleName)} (mapped as ${(_chalk || _load_chalk()).default.bold(updatedName)})
  243. Please check:
  244. "moduleNameMapper": {
  245. "${regex.toString()}": "${(_chalk || _load_chalk()).default.bold(mappedModuleName)}"
  246. },
  247. "resolver": ${(_chalk || _load_chalk()).default.bold(resolver)}`));
  248. error.stack = '';
  249. throw error;
  250. }
  251. return module;
  252. }
  253. }
  254. }
  255. if (resolver) {
  256. // if moduleNameMapper didn't match anything, fallback to just the
  257. // regular resolver
  258. const module = this.getModule(moduleName) || Resolver.findNodeModule(moduleName, {
  259. basedir: dirname,
  260. browser: this._options.browser,
  261. extensions,
  262. moduleDirectory,
  263. paths,
  264. resolver,
  265. rootDir: this._options.rootDir
  266. });
  267. return module;
  268. }
  269. return null;
  270. }
  271. _supportsNativePlatform() {
  272. return (this._options.platforms || []).indexOf(NATIVE_PLATFORM) !== -1;
  273. }
  274. }
  275. module.exports = Resolver;