index.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. 'use strict';
  2. function _path() {
  3. const data = _interopRequireDefault(require('path'));
  4. _path = function _path() {
  5. return data;
  6. };
  7. return data;
  8. }
  9. function _realpathNative() {
  10. const data = require('realpath-native');
  11. _realpathNative = function _realpathNative() {
  12. return data;
  13. };
  14. return data;
  15. }
  16. function _chalk() {
  17. const data = _interopRequireDefault(require('chalk'));
  18. _chalk = function _chalk() {
  19. return data;
  20. };
  21. return data;
  22. }
  23. var _nodeModulesPaths = _interopRequireDefault(require('./nodeModulesPaths'));
  24. var _isBuiltinModule = _interopRequireDefault(require('./isBuiltinModule'));
  25. var _defaultResolver = _interopRequireWildcard(require('./defaultResolver'));
  26. function _interopRequireWildcard(obj) {
  27. if (obj && obj.__esModule) {
  28. return obj;
  29. } else {
  30. var newObj = {};
  31. if (obj != null) {
  32. for (var key in obj) {
  33. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  34. var desc =
  35. Object.defineProperty && Object.getOwnPropertyDescriptor
  36. ? Object.getOwnPropertyDescriptor(obj, key)
  37. : {};
  38. if (desc.get || desc.set) {
  39. Object.defineProperty(newObj, key, desc);
  40. } else {
  41. newObj[key] = obj[key];
  42. }
  43. }
  44. }
  45. }
  46. newObj.default = obj;
  47. return newObj;
  48. }
  49. }
  50. function _interopRequireDefault(obj) {
  51. return obj && obj.__esModule ? obj : {default: obj};
  52. }
  53. function _defineProperty(obj, key, value) {
  54. if (key in obj) {
  55. Object.defineProperty(obj, key, {
  56. value: value,
  57. enumerable: true,
  58. configurable: true,
  59. writable: true
  60. });
  61. } else {
  62. obj[key] = value;
  63. }
  64. return obj;
  65. }
  66. const NATIVE_PLATFORM = 'native'; // We might be inside a symlink.
  67. const cwd = process.cwd();
  68. const resolvedCwd = (0, _realpathNative().sync)(cwd) || cwd;
  69. const NODE_PATH = process.env.NODE_PATH;
  70. const nodePaths = NODE_PATH
  71. ? NODE_PATH.split(_path().default.delimiter)
  72. .filter(Boolean) // The resolver expects absolute paths.
  73. .map(p => _path().default.resolve(resolvedCwd, p))
  74. : undefined;
  75. /* eslint-disable-next-line no-redeclare */
  76. class Resolver {
  77. constructor(moduleMap, options) {
  78. _defineProperty(this, '_options', void 0);
  79. _defineProperty(this, '_moduleMap', void 0);
  80. _defineProperty(this, '_moduleIDCache', void 0);
  81. _defineProperty(this, '_moduleNameCache', void 0);
  82. _defineProperty(this, '_modulePathCache', void 0);
  83. _defineProperty(this, '_supportsNativePlatform', void 0);
  84. this._options = {
  85. browser: options.browser,
  86. defaultPlatform: options.defaultPlatform,
  87. extensions: options.extensions,
  88. hasCoreModules:
  89. options.hasCoreModules === undefined ? true : options.hasCoreModules,
  90. moduleDirectories: options.moduleDirectories || ['node_modules'],
  91. moduleNameMapper: options.moduleNameMapper,
  92. modulePaths: options.modulePaths,
  93. platforms: options.platforms,
  94. resolver: options.resolver,
  95. rootDir: options.rootDir
  96. };
  97. this._supportsNativePlatform = options.platforms
  98. ? options.platforms.includes(NATIVE_PLATFORM)
  99. : false;
  100. this._moduleMap = moduleMap;
  101. this._moduleIDCache = new Map();
  102. this._moduleNameCache = new Map();
  103. this._modulePathCache = new Map();
  104. }
  105. static clearDefaultResolverCache() {
  106. (0, _defaultResolver.clearDefaultResolverCache)();
  107. }
  108. static findNodeModule(path, options) {
  109. const resolver = options.resolver
  110. ? require(options.resolver)
  111. : _defaultResolver.default;
  112. const paths = options.paths;
  113. try {
  114. return resolver(path, {
  115. basedir: options.basedir,
  116. browser: options.browser,
  117. defaultResolver: _defaultResolver.default,
  118. extensions: options.extensions,
  119. moduleDirectory: options.moduleDirectory,
  120. paths: paths ? (nodePaths || []).concat(paths) : nodePaths,
  121. rootDir: options.rootDir
  122. });
  123. } catch (e) {}
  124. return null;
  125. }
  126. resolveModuleFromDirIfExists(dirname, moduleName, options) {
  127. const paths = (options && options.paths) || this._options.modulePaths;
  128. const moduleDirectory = this._options.moduleDirectories;
  129. const key = dirname + _path().default.delimiter + moduleName;
  130. const defaultPlatform = this._options.defaultPlatform;
  131. const extensions = this._options.extensions.slice();
  132. let module;
  133. if (this._supportsNativePlatform) {
  134. extensions.unshift(
  135. ...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext)
  136. );
  137. }
  138. if (defaultPlatform) {
  139. extensions.unshift(
  140. ...this._options.extensions.map(ext => '.' + defaultPlatform + ext)
  141. );
  142. } // 1. If we have already resolved this module for this directory name,
  143. // return a value from the cache.
  144. const cacheResult = this._moduleNameCache.get(key);
  145. if (cacheResult) {
  146. return cacheResult;
  147. } // 2. Check if the module is a haste module.
  148. module = this.getModule(moduleName);
  149. if (module) {
  150. this._moduleNameCache.set(key, module);
  151. return module;
  152. } // 3. Check if the module is a node module and resolve it based on
  153. // the node module resolution algorithm. If skipNodeResolution is given we
  154. // ignore all modules that look like node modules (ie. are not relative
  155. // requires). This enables us to speed up resolution when we build a
  156. // dependency graph because we don't have to look at modules that may not
  157. // exist and aren't mocked.
  158. const skipResolution =
  159. options &&
  160. options.skipNodeResolution &&
  161. !moduleName.includes(_path().default.sep);
  162. const resolveNodeModule = name =>
  163. Resolver.findNodeModule(name, {
  164. basedir: dirname,
  165. browser: this._options.browser,
  166. extensions,
  167. moduleDirectory,
  168. paths,
  169. resolver: this._options.resolver,
  170. rootDir: this._options.rootDir
  171. });
  172. if (!skipResolution) {
  173. module = resolveNodeModule(moduleName);
  174. if (module) {
  175. this._moduleNameCache.set(key, module);
  176. return module;
  177. }
  178. } // 4. Resolve "haste packages" which are `package.json` files outside of
  179. // `node_modules` folders anywhere in the file system.
  180. const parts = moduleName.split('/');
  181. const hastePackage = this.getPackage(parts.shift());
  182. if (hastePackage) {
  183. try {
  184. const module = _path().default.join.apply(
  185. _path().default,
  186. [_path().default.dirname(hastePackage)].concat(parts)
  187. ); // try resolving with custom resolver first to support extensions,
  188. // then fallback to require.resolve
  189. const resolvedModule =
  190. resolveNodeModule(module) || require.resolve(module);
  191. this._moduleNameCache.set(key, resolvedModule);
  192. return resolvedModule;
  193. } catch (ignoredError) {}
  194. }
  195. return null;
  196. }
  197. resolveModule(from, moduleName, options) {
  198. const dirname = _path().default.dirname(from);
  199. const module =
  200. this.resolveStubModuleName(from, moduleName) ||
  201. this.resolveModuleFromDirIfExists(dirname, moduleName, options);
  202. if (module) return module; // 5. Throw an error if the module could not be found. `resolve.sync` only
  203. // produces an error based on the dirname but we have the actual current
  204. // module name available.
  205. const relativePath = _path().default.relative(dirname, from);
  206. const err = new Error(
  207. `Cannot find module '${moduleName}' from '${relativePath || '.'}'`
  208. );
  209. err.code = 'MODULE_NOT_FOUND';
  210. throw err;
  211. }
  212. isCoreModule(moduleName) {
  213. return (
  214. this._options.hasCoreModules && (0, _isBuiltinModule.default)(moduleName)
  215. );
  216. }
  217. getModule(name) {
  218. return this._moduleMap.getModule(
  219. name,
  220. this._options.defaultPlatform,
  221. this._supportsNativePlatform
  222. );
  223. }
  224. getModulePath(from, moduleName) {
  225. if (moduleName[0] !== '.' || _path().default.isAbsolute(moduleName)) {
  226. return moduleName;
  227. }
  228. return _path().default.normalize(
  229. _path().default.dirname(from) + '/' + moduleName
  230. );
  231. }
  232. getPackage(name) {
  233. return this._moduleMap.getPackage(
  234. name,
  235. this._options.defaultPlatform,
  236. this._supportsNativePlatform
  237. );
  238. }
  239. getMockModule(from, name) {
  240. const mock = this._moduleMap.getMockModule(name);
  241. if (mock) {
  242. return mock;
  243. } else {
  244. const moduleName = this.resolveStubModuleName(from, name);
  245. if (moduleName) {
  246. return this.getModule(moduleName) || moduleName;
  247. }
  248. }
  249. return null;
  250. }
  251. getModulePaths(from) {
  252. const cachedModule = this._modulePathCache.get(from);
  253. if (cachedModule) {
  254. return cachedModule;
  255. }
  256. const moduleDirectory = this._options.moduleDirectories;
  257. const paths = (0, _nodeModulesPaths.default)(from, {
  258. moduleDirectory
  259. });
  260. if (paths[paths.length - 1] === undefined) {
  261. // circumvent node-resolve bug that adds `undefined` as last item.
  262. paths.pop();
  263. }
  264. this._modulePathCache.set(from, paths);
  265. return paths;
  266. }
  267. getModuleID(virtualMocks, from, _moduleName) {
  268. const moduleName = _moduleName || '';
  269. const key = from + _path().default.delimiter + moduleName;
  270. const cachedModuleID = this._moduleIDCache.get(key);
  271. if (cachedModuleID) {
  272. return cachedModuleID;
  273. }
  274. const moduleType = this._getModuleType(moduleName);
  275. const absolutePath = this._getAbsolutePath(virtualMocks, from, moduleName);
  276. const mockPath = this._getMockPath(from, moduleName);
  277. const sep = _path().default.delimiter;
  278. const id =
  279. moduleType +
  280. sep +
  281. (absolutePath ? absolutePath + sep : '') +
  282. (mockPath ? mockPath + sep : '');
  283. this._moduleIDCache.set(key, id);
  284. return id;
  285. }
  286. _getModuleType(moduleName) {
  287. return this.isCoreModule(moduleName) ? 'node' : 'user';
  288. }
  289. _getAbsolutePath(virtualMocks, from, moduleName) {
  290. if (this.isCoreModule(moduleName)) {
  291. return moduleName;
  292. }
  293. return this._isModuleResolved(from, moduleName)
  294. ? this.getModule(moduleName)
  295. : this._getVirtualMockPath(virtualMocks, from, moduleName);
  296. }
  297. _getMockPath(from, moduleName) {
  298. return !this.isCoreModule(moduleName)
  299. ? this.getMockModule(from, moduleName)
  300. : null;
  301. }
  302. _getVirtualMockPath(virtualMocks, from, moduleName) {
  303. const virtualMockPath = this.getModulePath(from, moduleName);
  304. return virtualMocks[virtualMockPath]
  305. ? virtualMockPath
  306. : moduleName
  307. ? this.resolveModule(from, moduleName)
  308. : from;
  309. }
  310. _isModuleResolved(from, moduleName) {
  311. return !!(
  312. this.getModule(moduleName) || this.getMockModule(from, moduleName)
  313. );
  314. }
  315. resolveStubModuleName(from, moduleName) {
  316. const dirname = _path().default.dirname(from);
  317. const paths = this._options.modulePaths;
  318. const extensions = this._options.extensions.slice();
  319. const moduleDirectory = this._options.moduleDirectories;
  320. const moduleNameMapper = this._options.moduleNameMapper;
  321. const resolver = this._options.resolver;
  322. const defaultPlatform = this._options.defaultPlatform;
  323. if (this._supportsNativePlatform) {
  324. extensions.unshift(
  325. ...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext)
  326. );
  327. }
  328. if (defaultPlatform) {
  329. extensions.unshift(
  330. ...this._options.extensions.map(ext => '.' + defaultPlatform + ext)
  331. );
  332. }
  333. if (moduleNameMapper) {
  334. var _iteratorNormalCompletion = true;
  335. var _didIteratorError = false;
  336. var _iteratorError = undefined;
  337. try {
  338. for (
  339. var _iterator = moduleNameMapper[Symbol.iterator](), _step;
  340. !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
  341. _iteratorNormalCompletion = true
  342. ) {
  343. const _step$value = _step.value,
  344. mappedModuleName = _step$value.moduleName,
  345. regex = _step$value.regex;
  346. if (regex.test(moduleName)) {
  347. // Note: once a moduleNameMapper matches the name, it must result
  348. // in a module, or else an error is thrown.
  349. const matches = moduleName.match(regex);
  350. const updatedName = matches
  351. ? mappedModuleName.replace(
  352. /\$([0-9]+)/g,
  353. (_, index) => matches[parseInt(index, 10)]
  354. )
  355. : mappedModuleName;
  356. const module =
  357. this.getModule(updatedName) ||
  358. Resolver.findNodeModule(updatedName, {
  359. basedir: dirname,
  360. browser: this._options.browser,
  361. extensions,
  362. moduleDirectory,
  363. paths,
  364. resolver,
  365. rootDir: this._options.rootDir
  366. });
  367. if (!module) {
  368. throw createNoMappedModuleFoundError(
  369. moduleName,
  370. updatedName,
  371. mappedModuleName,
  372. regex,
  373. resolver
  374. );
  375. }
  376. return module;
  377. }
  378. }
  379. } catch (err) {
  380. _didIteratorError = true;
  381. _iteratorError = err;
  382. } finally {
  383. try {
  384. if (!_iteratorNormalCompletion && _iterator.return != null) {
  385. _iterator.return();
  386. }
  387. } finally {
  388. if (_didIteratorError) {
  389. throw _iteratorError;
  390. }
  391. }
  392. }
  393. }
  394. return null;
  395. }
  396. }
  397. const createNoMappedModuleFoundError = (
  398. moduleName,
  399. updatedName,
  400. mappedModuleName,
  401. regex,
  402. resolver
  403. ) => {
  404. const error = new Error(
  405. _chalk().default.red(`${_chalk().default.bold('Configuration error')}:
  406. Could not locate module ${_chalk().default.bold(moduleName)} mapped as:
  407. ${_chalk().default.bold(updatedName)}.
  408. Please check your configuration for these entries:
  409. {
  410. "moduleNameMapper": {
  411. "${regex.toString()}": "${_chalk().default.bold(mappedModuleName)}"
  412. },
  413. "resolver": ${_chalk().default.bold(String(resolver))}
  414. }`)
  415. );
  416. error.name = '';
  417. return error;
  418. };
  419. module.exports = Resolver;