UNPKG

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