UNPKG

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