index.js 15 KB

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