1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', {
|
4 | value: true
|
5 | });
|
6 | Object.defineProperty(exports, 'ModuleMap', {
|
7 | enumerable: true,
|
8 | get: function () {
|
9 | return _ModuleMap.default;
|
10 | }
|
11 | });
|
12 | exports.DuplicateError = exports.default = void 0;
|
13 |
|
14 | function _child_process() {
|
15 | const data = require('child_process');
|
16 |
|
17 | _child_process = function () {
|
18 | return data;
|
19 | };
|
20 |
|
21 | return data;
|
22 | }
|
23 |
|
24 | function _crypto() {
|
25 | const data = require('crypto');
|
26 |
|
27 | _crypto = function () {
|
28 | return data;
|
29 | };
|
30 |
|
31 | return data;
|
32 | }
|
33 |
|
34 | function _events() {
|
35 | const data = require('events');
|
36 |
|
37 | _events = function () {
|
38 | return data;
|
39 | };
|
40 |
|
41 | return data;
|
42 | }
|
43 |
|
44 | function _os() {
|
45 | const data = require('os');
|
46 |
|
47 | _os = function () {
|
48 | return data;
|
49 | };
|
50 |
|
51 | return data;
|
52 | }
|
53 |
|
54 | function path() {
|
55 | const data = _interopRequireWildcard(require('path'));
|
56 |
|
57 | path = function () {
|
58 | return data;
|
59 | };
|
60 |
|
61 | return data;
|
62 | }
|
63 |
|
64 | function _jestRegexUtil() {
|
65 | const data = require('jest-regex-util');
|
66 |
|
67 | _jestRegexUtil = function () {
|
68 | return data;
|
69 | };
|
70 |
|
71 | return data;
|
72 | }
|
73 |
|
74 | function _jestSerializer() {
|
75 | const data = _interopRequireDefault(require('jest-serializer'));
|
76 |
|
77 | _jestSerializer = function () {
|
78 | return data;
|
79 | };
|
80 |
|
81 | return data;
|
82 | }
|
83 |
|
84 | function _jestWorker() {
|
85 | const data = require('jest-worker');
|
86 |
|
87 | _jestWorker = function () {
|
88 | return data;
|
89 | };
|
90 |
|
91 | return data;
|
92 | }
|
93 |
|
94 | var _HasteFS = _interopRequireDefault(require('./HasteFS'));
|
95 |
|
96 | var _ModuleMap = _interopRequireDefault(require('./ModuleMap'));
|
97 |
|
98 | var _constants = _interopRequireDefault(require('./constants'));
|
99 |
|
100 | var _node = _interopRequireDefault(require('./crawlers/node'));
|
101 |
|
102 | var _watchman = _interopRequireDefault(require('./crawlers/watchman'));
|
103 |
|
104 | var _getMockName = _interopRequireDefault(require('./getMockName'));
|
105 |
|
106 | var fastPath = _interopRequireWildcard(require('./lib/fast_path'));
|
107 |
|
108 | var _getPlatformExtension = _interopRequireDefault(
|
109 | require('./lib/getPlatformExtension')
|
110 | );
|
111 |
|
112 | var _normalizePathSep = _interopRequireDefault(
|
113 | require('./lib/normalizePathSep')
|
114 | );
|
115 |
|
116 | var _FSEventsWatcher = _interopRequireDefault(
|
117 | require('./watchers/FSEventsWatcher')
|
118 | );
|
119 |
|
120 | var _NodeWatcher = _interopRequireDefault(require('./watchers/NodeWatcher'));
|
121 |
|
122 | var _WatchmanWatcher = _interopRequireDefault(
|
123 | require('./watchers/WatchmanWatcher')
|
124 | );
|
125 |
|
126 | var _worker = require('./worker');
|
127 |
|
128 | function _interopRequireDefault(obj) {
|
129 | return obj && obj.__esModule ? obj : {default: obj};
|
130 | }
|
131 |
|
132 | function _getRequireWildcardCache(nodeInterop) {
|
133 | if (typeof WeakMap !== 'function') return null;
|
134 | var cacheBabelInterop = new WeakMap();
|
135 | var cacheNodeInterop = new WeakMap();
|
136 | return (_getRequireWildcardCache = function (nodeInterop) {
|
137 | return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
138 | })(nodeInterop);
|
139 | }
|
140 |
|
141 | function _interopRequireWildcard(obj, nodeInterop) {
|
142 | if (!nodeInterop && obj && obj.__esModule) {
|
143 | return obj;
|
144 | }
|
145 | if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
146 | return {default: obj};
|
147 | }
|
148 | var cache = _getRequireWildcardCache(nodeInterop);
|
149 | if (cache && cache.has(obj)) {
|
150 | return cache.get(obj);
|
151 | }
|
152 | var newObj = {};
|
153 | var hasPropertyDescriptor =
|
154 | Object.defineProperty && Object.getOwnPropertyDescriptor;
|
155 | for (var key in obj) {
|
156 | if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
157 | var desc = hasPropertyDescriptor
|
158 | ? Object.getOwnPropertyDescriptor(obj, key)
|
159 | : null;
|
160 | if (desc && (desc.get || desc.set)) {
|
161 | Object.defineProperty(newObj, key, desc);
|
162 | } else {
|
163 | newObj[key] = obj[key];
|
164 | }
|
165 | }
|
166 | }
|
167 | newObj.default = obj;
|
168 | if (cache) {
|
169 | cache.set(obj, newObj);
|
170 | }
|
171 | return newObj;
|
172 | }
|
173 |
|
174 | function _defineProperty(obj, key, value) {
|
175 | if (key in obj) {
|
176 | Object.defineProperty(obj, key, {
|
177 | value: value,
|
178 | enumerable: true,
|
179 | configurable: true,
|
180 | writable: true
|
181 | });
|
182 | } else {
|
183 | obj[key] = value;
|
184 | }
|
185 | return obj;
|
186 | }
|
187 |
|
188 |
|
189 |
|
190 | const {version: VERSION} = require('../package.json');
|
191 |
|
192 | const CHANGE_INTERVAL = 30;
|
193 | const MAX_WAIT_TIME = 240000;
|
194 | const NODE_MODULES = path().sep + 'node_modules' + path().sep;
|
195 | const PACKAGE_JSON = path().sep + 'package.json';
|
196 | const VCS_DIRECTORIES = ['.git', '.hg']
|
197 | .map(vcs =>
|
198 | (0, _jestRegexUtil().escapePathForRegex)(path().sep + vcs + path().sep)
|
199 | )
|
200 | .join('|');
|
201 |
|
202 | const canUseWatchman = (() => {
|
203 | try {
|
204 | (0, _child_process().execSync)('watchman --version', {
|
205 | stdio: ['ignore']
|
206 | });
|
207 | return true;
|
208 | } catch {}
|
209 |
|
210 | return false;
|
211 | })();
|
212 |
|
213 | function invariant(condition, message) {
|
214 | if (!condition) {
|
215 | throw new Error(message);
|
216 | }
|
217 | }
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 | class HasteMap extends _events().EventEmitter {
|
298 | static getStatic(config) {
|
299 | if (config.haste.hasteMapModulePath) {
|
300 | return require(config.haste.hasteMapModulePath);
|
301 | }
|
302 |
|
303 | return HasteMap;
|
304 | }
|
305 |
|
306 | static create(options) {
|
307 | if (options.hasteMapModulePath) {
|
308 | const CustomHasteMap = require(options.hasteMapModulePath);
|
309 |
|
310 | return new CustomHasteMap(options);
|
311 | }
|
312 |
|
313 | return new HasteMap(options);
|
314 | }
|
315 |
|
316 | constructor(options) {
|
317 | super();
|
318 |
|
319 | _defineProperty(this, '_buildPromise', void 0);
|
320 |
|
321 | _defineProperty(this, '_cachePath', void 0);
|
322 |
|
323 | _defineProperty(this, '_changeInterval', void 0);
|
324 |
|
325 | _defineProperty(this, '_console', void 0);
|
326 |
|
327 | _defineProperty(this, '_options', void 0);
|
328 |
|
329 | _defineProperty(this, '_watchers', void 0);
|
330 |
|
331 | _defineProperty(this, '_worker', void 0);
|
332 |
|
333 | this._options = {
|
334 | cacheDirectory: options.cacheDirectory || (0, _os().tmpdir)(),
|
335 | computeDependencies:
|
336 | options.computeDependencies === undefined
|
337 | ? true
|
338 | : options.computeDependencies,
|
339 | computeSha1: options.computeSha1 || false,
|
340 | dependencyExtractor: options.dependencyExtractor || null,
|
341 | enableSymlinks: options.enableSymlinks || false,
|
342 | extensions: options.extensions,
|
343 | forceNodeFilesystemAPI: !!options.forceNodeFilesystemAPI,
|
344 | hasteImplModulePath: options.hasteImplModulePath,
|
345 | maxWorkers: options.maxWorkers,
|
346 | mocksPattern: options.mocksPattern
|
347 | ? new RegExp(options.mocksPattern)
|
348 | : null,
|
349 | name: options.name,
|
350 | platforms: options.platforms,
|
351 | resetCache: options.resetCache,
|
352 | retainAllFiles: options.retainAllFiles,
|
353 | rootDir: options.rootDir,
|
354 | roots: Array.from(new Set(options.roots)),
|
355 | skipPackageJson: !!options.skipPackageJson,
|
356 | throwOnModuleCollision: !!options.throwOnModuleCollision,
|
357 | useWatchman: options.useWatchman == null ? true : options.useWatchman,
|
358 | watch: !!options.watch
|
359 | };
|
360 | this._console = options.console || global.console;
|
361 |
|
362 | if (options.ignorePattern) {
|
363 | if (options.ignorePattern instanceof RegExp) {
|
364 | this._options.ignorePattern = new RegExp(
|
365 | options.ignorePattern.source.concat('|' + VCS_DIRECTORIES),
|
366 | options.ignorePattern.flags
|
367 | );
|
368 | } else {
|
369 | throw new Error(
|
370 | 'jest-haste-map: the `ignorePattern` option must be a RegExp'
|
371 | );
|
372 | }
|
373 | } else {
|
374 | this._options.ignorePattern = new RegExp(VCS_DIRECTORIES);
|
375 | }
|
376 |
|
377 | if (this._options.enableSymlinks && this._options.useWatchman) {
|
378 | throw new Error(
|
379 | 'jest-haste-map: enableSymlinks config option was set, but ' +
|
380 | 'is incompatible with watchman.\n' +
|
381 | 'Set either `enableSymlinks` to false or `useWatchman` to false.'
|
382 | );
|
383 | }
|
384 |
|
385 | const rootDirHash = (0, _crypto().createHash)('md5')
|
386 | .update(options.rootDir)
|
387 | .digest('hex');
|
388 | let hasteImplHash = '';
|
389 | let dependencyExtractorHash = '';
|
390 |
|
391 | if (options.hasteImplModulePath) {
|
392 | const hasteImpl = require(options.hasteImplModulePath);
|
393 |
|
394 | if (hasteImpl.getCacheKey) {
|
395 | hasteImplHash = String(hasteImpl.getCacheKey());
|
396 | }
|
397 | }
|
398 |
|
399 | if (options.dependencyExtractor) {
|
400 | const dependencyExtractor = require(options.dependencyExtractor);
|
401 |
|
402 | if (dependencyExtractor.getCacheKey) {
|
403 | dependencyExtractorHash = String(dependencyExtractor.getCacheKey());
|
404 | }
|
405 | }
|
406 |
|
407 | this._cachePath = HasteMap.getCacheFilePath(
|
408 | this._options.cacheDirectory,
|
409 | `haste-map-${this._options.name}-${rootDirHash}`,
|
410 | VERSION,
|
411 | this._options.name,
|
412 | this._options.roots
|
413 | .map(root => fastPath.relative(options.rootDir, root))
|
414 | .join(':'),
|
415 | this._options.extensions.join(':'),
|
416 | this._options.platforms.join(':'),
|
417 | this._options.computeSha1.toString(),
|
418 | options.mocksPattern || '',
|
419 | (options.ignorePattern || '').toString(),
|
420 | hasteImplHash,
|
421 | dependencyExtractorHash,
|
422 | this._options.computeDependencies.toString()
|
423 | );
|
424 | this._buildPromise = null;
|
425 | this._watchers = [];
|
426 | this._worker = null;
|
427 | }
|
428 |
|
429 | static getCacheFilePath(tmpdir, name, ...extra) {
|
430 | const hash = (0, _crypto().createHash)('md5').update(extra.join(''));
|
431 | return path().join(
|
432 | tmpdir,
|
433 | name.replace(/\W/g, '-') + '-' + hash.digest('hex')
|
434 | );
|
435 | }
|
436 |
|
437 | static getModuleMapFromJSON(json) {
|
438 | return _ModuleMap.default.fromJSON(json);
|
439 | }
|
440 |
|
441 | getCacheFilePath() {
|
442 | return this._cachePath;
|
443 | }
|
444 |
|
445 | build() {
|
446 | if (!this._buildPromise) {
|
447 | this._buildPromise = (async () => {
|
448 | const data = await this._buildFileMap();
|
449 |
|
450 |
|
451 | let hasteMap;
|
452 |
|
453 | if (
|
454 | data.changedFiles === undefined ||
|
455 | data.changedFiles.size > 0 ||
|
456 | data.removedFiles.size > 0
|
457 | ) {
|
458 | hasteMap = await this._buildHasteMap(data);
|
459 |
|
460 | this._persist(hasteMap);
|
461 | } else {
|
462 | hasteMap = data.hasteMap;
|
463 | }
|
464 |
|
465 | const rootDir = this._options.rootDir;
|
466 | const hasteFS = new _HasteFS.default({
|
467 | files: hasteMap.files,
|
468 | rootDir
|
469 | });
|
470 | const moduleMap = new _ModuleMap.default({
|
471 | duplicates: hasteMap.duplicates,
|
472 | map: hasteMap.map,
|
473 | mocks: hasteMap.mocks,
|
474 | rootDir
|
475 | });
|
476 |
|
477 | const __hasteMapForTest =
|
478 | (process.env.NODE_ENV === 'test' && hasteMap) || null;
|
479 |
|
480 | await this._watch(hasteMap);
|
481 | return {
|
482 | __hasteMapForTest,
|
483 | hasteFS,
|
484 | moduleMap
|
485 | };
|
486 | })();
|
487 | }
|
488 |
|
489 | return this._buildPromise;
|
490 | }
|
491 | |
492 |
|
493 |
|
494 |
|
495 | read() {
|
496 | let hasteMap;
|
497 |
|
498 | try {
|
499 | hasteMap = _jestSerializer().default.readFileSync(this._cachePath);
|
500 | } catch {
|
501 | hasteMap = this._createEmptyMap();
|
502 | }
|
503 |
|
504 | return hasteMap;
|
505 | }
|
506 |
|
507 | readModuleMap() {
|
508 | const data = this.read();
|
509 | return new _ModuleMap.default({
|
510 | duplicates: data.duplicates,
|
511 | map: data.map,
|
512 | mocks: data.mocks,
|
513 | rootDir: this._options.rootDir
|
514 | });
|
515 | }
|
516 | |
517 |
|
518 |
|
519 |
|
520 | async _buildFileMap() {
|
521 | let hasteMap;
|
522 |
|
523 | try {
|
524 | const read = this._options.resetCache ? this._createEmptyMap : this.read;
|
525 | hasteMap = await read.call(this);
|
526 | } catch {
|
527 | hasteMap = this._createEmptyMap();
|
528 | }
|
529 |
|
530 | return this._crawl(hasteMap);
|
531 | }
|
532 | |
533 |
|
534 |
|
535 |
|
536 | _processFile(hasteMap, map, mocks, filePath, workerOptions) {
|
537 | const rootDir = this._options.rootDir;
|
538 |
|
539 | const setModule = (id, module) => {
|
540 | let moduleMap = map.get(id);
|
541 |
|
542 | if (!moduleMap) {
|
543 | moduleMap = Object.create(null);
|
544 | map.set(id, moduleMap);
|
545 | }
|
546 |
|
547 | const platform =
|
548 | (0, _getPlatformExtension.default)(
|
549 | module[_constants.default.PATH],
|
550 | this._options.platforms
|
551 | ) || _constants.default.GENERIC_PLATFORM;
|
552 |
|
553 | const existingModule = moduleMap[platform];
|
554 |
|
555 | if (
|
556 | existingModule &&
|
557 | existingModule[_constants.default.PATH] !==
|
558 | module[_constants.default.PATH]
|
559 | ) {
|
560 | const method = this._options.throwOnModuleCollision ? 'error' : 'warn';
|
561 |
|
562 | this._console[method](
|
563 | [
|
564 | 'jest-haste-map: Haste module naming collision: ' + id,
|
565 | ' The following files share their name; please adjust your hasteImpl:',
|
566 | ' * <rootDir>' +
|
567 | path().sep +
|
568 | existingModule[_constants.default.PATH],
|
569 | ' * <rootDir>' + path().sep + module[_constants.default.PATH],
|
570 | ''
|
571 | ].join('\n')
|
572 | );
|
573 |
|
574 | if (this._options.throwOnModuleCollision) {
|
575 | throw new DuplicateError(
|
576 | existingModule[_constants.default.PATH],
|
577 | module[_constants.default.PATH]
|
578 | );
|
579 | }
|
580 |
|
581 | delete moduleMap[platform];
|
582 |
|
583 | if (Object.keys(moduleMap).length === 1) {
|
584 | map.delete(id);
|
585 | }
|
586 |
|
587 | let dupsByPlatform = hasteMap.duplicates.get(id);
|
588 |
|
589 | if (dupsByPlatform == null) {
|
590 | dupsByPlatform = new Map();
|
591 | hasteMap.duplicates.set(id, dupsByPlatform);
|
592 | }
|
593 |
|
594 | const dups = new Map([
|
595 | [module[_constants.default.PATH], module[_constants.default.TYPE]],
|
596 | [
|
597 | existingModule[_constants.default.PATH],
|
598 | existingModule[_constants.default.TYPE]
|
599 | ]
|
600 | ]);
|
601 | dupsByPlatform.set(platform, dups);
|
602 | return;
|
603 | }
|
604 |
|
605 | const dupsByPlatform = hasteMap.duplicates.get(id);
|
606 |
|
607 | if (dupsByPlatform != null) {
|
608 | const dups = dupsByPlatform.get(platform);
|
609 |
|
610 | if (dups != null) {
|
611 | dups.set(
|
612 | module[_constants.default.PATH],
|
613 | module[_constants.default.TYPE]
|
614 | );
|
615 | }
|
616 |
|
617 | return;
|
618 | }
|
619 |
|
620 | moduleMap[platform] = module;
|
621 | };
|
622 |
|
623 | const relativeFilePath = fastPath.relative(rootDir, filePath);
|
624 | const fileMetadata = hasteMap.files.get(relativeFilePath);
|
625 |
|
626 | if (!fileMetadata) {
|
627 | throw new Error(
|
628 | 'jest-haste-map: File to process was not found in the haste map.'
|
629 | );
|
630 | }
|
631 |
|
632 | const moduleMetadata = hasteMap.map.get(
|
633 | fileMetadata[_constants.default.ID]
|
634 | );
|
635 | const computeSha1 =
|
636 | this._options.computeSha1 && !fileMetadata[_constants.default.SHA1];
|
637 |
|
638 | const workerReply = metadata => {
|
639 |
|
640 | fileMetadata[_constants.default.VISITED] = 1;
|
641 | const metadataId = metadata.id;
|
642 | const metadataModule = metadata.module;
|
643 |
|
644 | if (metadataId && metadataModule) {
|
645 | fileMetadata[_constants.default.ID] = metadataId;
|
646 | setModule(metadataId, metadataModule);
|
647 | }
|
648 |
|
649 | fileMetadata[_constants.default.DEPENDENCIES] = metadata.dependencies
|
650 | ? metadata.dependencies.join(_constants.default.DEPENDENCY_DELIM)
|
651 | : '';
|
652 |
|
653 | if (computeSha1) {
|
654 | fileMetadata[_constants.default.SHA1] = metadata.sha1;
|
655 | }
|
656 | };
|
657 |
|
658 | const workerError = error => {
|
659 | if (typeof error !== 'object' || !error.message || !error.stack) {
|
660 | error = new Error(error);
|
661 | error.stack = '';
|
662 | }
|
663 |
|
664 | if (!['ENOENT', 'EACCES'].includes(error.code)) {
|
665 | throw error;
|
666 | }
|
667 |
|
668 |
|
669 | hasteMap.files.delete(relativeFilePath);
|
670 | };
|
671 |
|
672 |
|
673 | if (this._options.retainAllFiles && filePath.includes(NODE_MODULES)) {
|
674 | if (computeSha1) {
|
675 | return this._getWorker(workerOptions)
|
676 | .getSha1({
|
677 | computeDependencies: this._options.computeDependencies,
|
678 | computeSha1,
|
679 | dependencyExtractor: this._options.dependencyExtractor,
|
680 | filePath,
|
681 | hasteImplModulePath: this._options.hasteImplModulePath,
|
682 | rootDir
|
683 | })
|
684 | .then(workerReply, workerError);
|
685 | }
|
686 |
|
687 | return null;
|
688 | }
|
689 |
|
690 | if (
|
691 | this._options.mocksPattern &&
|
692 | this._options.mocksPattern.test(filePath)
|
693 | ) {
|
694 | const mockPath = (0, _getMockName.default)(filePath);
|
695 | const existingMockPath = mocks.get(mockPath);
|
696 |
|
697 | if (existingMockPath) {
|
698 | const secondMockPath = fastPath.relative(rootDir, filePath);
|
699 |
|
700 | if (existingMockPath !== secondMockPath) {
|
701 | const method = this._options.throwOnModuleCollision
|
702 | ? 'error'
|
703 | : 'warn';
|
704 |
|
705 | this._console[method](
|
706 | [
|
707 | 'jest-haste-map: duplicate manual mock found: ' + mockPath,
|
708 | ' The following files share their name; please delete one of them:',
|
709 | ' * <rootDir>' + path().sep + existingMockPath,
|
710 | ' * <rootDir>' + path().sep + secondMockPath,
|
711 | ''
|
712 | ].join('\n')
|
713 | );
|
714 |
|
715 | if (this._options.throwOnModuleCollision) {
|
716 | throw new DuplicateError(existingMockPath, secondMockPath);
|
717 | }
|
718 | }
|
719 | }
|
720 |
|
721 | mocks.set(mockPath, relativeFilePath);
|
722 | }
|
723 |
|
724 | if (fileMetadata[_constants.default.VISITED]) {
|
725 | if (!fileMetadata[_constants.default.ID]) {
|
726 | return null;
|
727 | }
|
728 |
|
729 | if (moduleMetadata != null) {
|
730 | const platform =
|
731 | (0, _getPlatformExtension.default)(
|
732 | filePath,
|
733 | this._options.platforms
|
734 | ) || _constants.default.GENERIC_PLATFORM;
|
735 |
|
736 | const module = moduleMetadata[platform];
|
737 |
|
738 | if (module == null) {
|
739 | return null;
|
740 | }
|
741 |
|
742 | const moduleId = fileMetadata[_constants.default.ID];
|
743 | let modulesByPlatform = map.get(moduleId);
|
744 |
|
745 | if (!modulesByPlatform) {
|
746 | modulesByPlatform = Object.create(null);
|
747 | map.set(moduleId, modulesByPlatform);
|
748 | }
|
749 |
|
750 | modulesByPlatform[platform] = module;
|
751 | return null;
|
752 | }
|
753 | }
|
754 |
|
755 | return this._getWorker(workerOptions)
|
756 | .worker({
|
757 | computeDependencies: this._options.computeDependencies,
|
758 | computeSha1,
|
759 | dependencyExtractor: this._options.dependencyExtractor,
|
760 | filePath,
|
761 | hasteImplModulePath: this._options.hasteImplModulePath,
|
762 | rootDir
|
763 | })
|
764 | .then(workerReply, workerError);
|
765 | }
|
766 |
|
767 | _buildHasteMap(data) {
|
768 | const {removedFiles, changedFiles, hasteMap} = data;
|
769 |
|
770 |
|
771 | let map;
|
772 | let mocks;
|
773 | let filesToProcess;
|
774 |
|
775 | if (changedFiles === undefined || removedFiles.size) {
|
776 | map = new Map();
|
777 | mocks = new Map();
|
778 | filesToProcess = hasteMap.files;
|
779 | } else {
|
780 | map = hasteMap.map;
|
781 | mocks = hasteMap.mocks;
|
782 | filesToProcess = changedFiles;
|
783 | }
|
784 |
|
785 | for (const [relativeFilePath, fileMetadata] of removedFiles) {
|
786 | this._recoverDuplicates(
|
787 | hasteMap,
|
788 | relativeFilePath,
|
789 | fileMetadata[_constants.default.ID]
|
790 | );
|
791 | }
|
792 |
|
793 | const promises = [];
|
794 |
|
795 | for (const relativeFilePath of filesToProcess.keys()) {
|
796 | if (
|
797 | this._options.skipPackageJson &&
|
798 | relativeFilePath.endsWith(PACKAGE_JSON)
|
799 | ) {
|
800 | continue;
|
801 | }
|
802 |
|
803 | const filePath = fastPath.resolve(
|
804 | this._options.rootDir,
|
805 | relativeFilePath
|
806 | );
|
807 |
|
808 | const promise = this._processFile(hasteMap, map, mocks, filePath);
|
809 |
|
810 | if (promise) {
|
811 | promises.push(promise);
|
812 | }
|
813 | }
|
814 |
|
815 | return Promise.all(promises).then(
|
816 | () => {
|
817 | this._cleanup();
|
818 |
|
819 | hasteMap.map = map;
|
820 | hasteMap.mocks = mocks;
|
821 | return hasteMap;
|
822 | },
|
823 | error => {
|
824 | this._cleanup();
|
825 |
|
826 | throw error;
|
827 | }
|
828 | );
|
829 | }
|
830 |
|
831 | _cleanup() {
|
832 | const worker = this._worker;
|
833 |
|
834 | if (worker && typeof worker.end === 'function') {
|
835 |
|
836 | worker.end();
|
837 | }
|
838 |
|
839 | this._worker = null;
|
840 | }
|
841 | |
842 |
|
843 |
|
844 |
|
845 | _persist(hasteMap) {
|
846 | _jestSerializer().default.writeFileSync(this._cachePath, hasteMap);
|
847 | }
|
848 | |
849 |
|
850 |
|
851 |
|
852 | _getWorker(options) {
|
853 | if (!this._worker) {
|
854 | if ((options && options.forceInBand) || this._options.maxWorkers <= 1) {
|
855 | this._worker = {
|
856 | getSha1: _worker.getSha1,
|
857 | worker: _worker.worker
|
858 | };
|
859 | } else {
|
860 |
|
861 | this._worker = new (_jestWorker().Worker)(require.resolve('./worker'), {
|
862 | exposedMethods: ['getSha1', 'worker'],
|
863 | maxRetries: 3,
|
864 | numWorkers: this._options.maxWorkers
|
865 | });
|
866 | }
|
867 | }
|
868 |
|
869 | return this._worker;
|
870 | }
|
871 |
|
872 | _crawl(hasteMap) {
|
873 | const options = this._options;
|
874 |
|
875 | const ignore = this._ignore.bind(this);
|
876 |
|
877 | const crawl =
|
878 | canUseWatchman && this._options.useWatchman
|
879 | ? _watchman.default
|
880 | : _node.default;
|
881 | const crawlerOptions = {
|
882 | computeSha1: options.computeSha1,
|
883 | data: hasteMap,
|
884 | enableSymlinks: options.enableSymlinks,
|
885 | extensions: options.extensions,
|
886 | forceNodeFilesystemAPI: options.forceNodeFilesystemAPI,
|
887 | ignore,
|
888 | rootDir: options.rootDir,
|
889 | roots: options.roots
|
890 | };
|
891 |
|
892 | const retry = error => {
|
893 | if (crawl === _watchman.default) {
|
894 | this._console.warn(
|
895 | `jest-haste-map: Watchman crawl failed. Retrying once with node ` +
|
896 | `crawler.\n` +
|
897 | ` Usually this happens when watchman isn't running. Create an ` +
|
898 | `empty \`.watchmanconfig\` file in your project's root folder or ` +
|
899 | `initialize a git or hg repository in your project.\n` +
|
900 | ` ` +
|
901 | error
|
902 | );
|
903 |
|
904 | return (0, _node.default)(crawlerOptions).catch(e => {
|
905 | throw new Error(
|
906 | `Crawler retry failed:\n` +
|
907 | ` Original error: ${error.message}\n` +
|
908 | ` Retry error: ${e.message}\n`
|
909 | );
|
910 | });
|
911 | }
|
912 |
|
913 | throw error;
|
914 | };
|
915 |
|
916 | try {
|
917 | return crawl(crawlerOptions).catch(retry);
|
918 | } catch (error) {
|
919 | return retry(error);
|
920 | }
|
921 | }
|
922 | |
923 |
|
924 |
|
925 |
|
926 | _watch(hasteMap) {
|
927 | if (!this._options.watch) {
|
928 | return Promise.resolve();
|
929 | }
|
930 |
|
931 |
|
932 | this._options.throwOnModuleCollision = false;
|
933 | this._options.retainAllFiles = true;
|
934 |
|
935 | const Watcher =
|
936 | canUseWatchman && this._options.useWatchman
|
937 | ? _WatchmanWatcher.default
|
938 | : _FSEventsWatcher.default.isSupported()
|
939 | ? _FSEventsWatcher.default
|
940 | : _NodeWatcher.default;
|
941 | const extensions = this._options.extensions;
|
942 | const ignorePattern = this._options.ignorePattern;
|
943 | const rootDir = this._options.rootDir;
|
944 | let changeQueue = Promise.resolve();
|
945 | let eventsQueue = [];
|
946 |
|
947 | let mustCopy = true;
|
948 |
|
949 | const createWatcher = root => {
|
950 | const watcher = new Watcher(root, {
|
951 | dot: true,
|
952 | glob: extensions.map(extension => '**/*.' + extension),
|
953 | ignored: ignorePattern
|
954 | });
|
955 | return new Promise((resolve, reject) => {
|
956 | const rejectTimeout = setTimeout(
|
957 | () => reject(new Error('Failed to start watch mode.')),
|
958 | MAX_WAIT_TIME
|
959 | );
|
960 | watcher.once('ready', () => {
|
961 | clearTimeout(rejectTimeout);
|
962 | watcher.on('all', onChange);
|
963 | resolve(watcher);
|
964 | });
|
965 | });
|
966 | };
|
967 |
|
968 | const emitChange = () => {
|
969 | if (eventsQueue.length) {
|
970 | mustCopy = true;
|
971 | const changeEvent = {
|
972 | eventsQueue,
|
973 | hasteFS: new _HasteFS.default({
|
974 | files: hasteMap.files,
|
975 | rootDir
|
976 | }),
|
977 | moduleMap: new _ModuleMap.default({
|
978 | duplicates: hasteMap.duplicates,
|
979 | map: hasteMap.map,
|
980 | mocks: hasteMap.mocks,
|
981 | rootDir
|
982 | })
|
983 | };
|
984 | this.emit('change', changeEvent);
|
985 | eventsQueue = [];
|
986 | }
|
987 | };
|
988 |
|
989 | const onChange = (type, filePath, root, stat) => {
|
990 | filePath = path().join(root, (0, _normalizePathSep.default)(filePath));
|
991 |
|
992 | if (
|
993 | (stat && stat.isDirectory()) ||
|
994 | this._ignore(filePath) ||
|
995 | !extensions.some(extension => filePath.endsWith(extension))
|
996 | ) {
|
997 | return;
|
998 | }
|
999 |
|
1000 | const relativeFilePath = fastPath.relative(rootDir, filePath);
|
1001 | const fileMetadata = hasteMap.files.get(relativeFilePath);
|
1002 |
|
1003 | if (
|
1004 | type === 'change' &&
|
1005 | fileMetadata &&
|
1006 | stat &&
|
1007 | fileMetadata[_constants.default.MTIME] === stat.mtime.getTime()
|
1008 | ) {
|
1009 | return;
|
1010 | }
|
1011 |
|
1012 | changeQueue = changeQueue
|
1013 | .then(() => {
|
1014 |
|
1015 | if (
|
1016 | eventsQueue.find(
|
1017 | event =>
|
1018 | event.type === type &&
|
1019 | event.filePath === filePath &&
|
1020 | ((!event.stat && !stat) ||
|
1021 | (!!event.stat &&
|
1022 | !!stat &&
|
1023 | event.stat.mtime.getTime() === stat.mtime.getTime()))
|
1024 | )
|
1025 | ) {
|
1026 | return null;
|
1027 | }
|
1028 |
|
1029 | if (mustCopy) {
|
1030 | mustCopy = false;
|
1031 | hasteMap = {
|
1032 | clocks: new Map(hasteMap.clocks),
|
1033 | duplicates: new Map(hasteMap.duplicates),
|
1034 | files: new Map(hasteMap.files),
|
1035 | map: new Map(hasteMap.map),
|
1036 | mocks: new Map(hasteMap.mocks)
|
1037 | };
|
1038 | }
|
1039 |
|
1040 | const add = () => {
|
1041 | eventsQueue.push({
|
1042 | filePath,
|
1043 | stat,
|
1044 | type
|
1045 | });
|
1046 | return null;
|
1047 | };
|
1048 |
|
1049 | const fileMetadata = hasteMap.files.get(relativeFilePath);
|
1050 |
|
1051 | if (fileMetadata != null) {
|
1052 | const moduleName = fileMetadata[_constants.default.ID];
|
1053 |
|
1054 | const platform =
|
1055 | (0, _getPlatformExtension.default)(
|
1056 | filePath,
|
1057 | this._options.platforms
|
1058 | ) || _constants.default.GENERIC_PLATFORM;
|
1059 |
|
1060 | hasteMap.files.delete(relativeFilePath);
|
1061 | let moduleMap = hasteMap.map.get(moduleName);
|
1062 |
|
1063 | if (moduleMap != null) {
|
1064 |
|
1065 |
|
1066 | moduleMap = copy(moduleMap);
|
1067 | delete moduleMap[platform];
|
1068 |
|
1069 | if (Object.keys(moduleMap).length === 0) {
|
1070 | hasteMap.map.delete(moduleName);
|
1071 | } else {
|
1072 | hasteMap.map.set(moduleName, moduleMap);
|
1073 | }
|
1074 | }
|
1075 |
|
1076 | if (
|
1077 | this._options.mocksPattern &&
|
1078 | this._options.mocksPattern.test(filePath)
|
1079 | ) {
|
1080 | const mockName = (0, _getMockName.default)(filePath);
|
1081 | hasteMap.mocks.delete(mockName);
|
1082 | }
|
1083 |
|
1084 | this._recoverDuplicates(hasteMap, relativeFilePath, moduleName);
|
1085 | }
|
1086 |
|
1087 |
|
1088 | if (type === 'add' || type === 'change') {
|
1089 | invariant(
|
1090 | stat,
|
1091 | 'since the file exists or changed, it should have stats'
|
1092 | );
|
1093 | const fileMetadata = [
|
1094 | '',
|
1095 | stat.mtime.getTime(),
|
1096 | stat.size,
|
1097 | 0,
|
1098 | '',
|
1099 | null
|
1100 | ];
|
1101 | hasteMap.files.set(relativeFilePath, fileMetadata);
|
1102 |
|
1103 | const promise = this._processFile(
|
1104 | hasteMap,
|
1105 | hasteMap.map,
|
1106 | hasteMap.mocks,
|
1107 | filePath,
|
1108 | {
|
1109 | forceInBand: true
|
1110 | }
|
1111 | );
|
1112 |
|
1113 | this._cleanup();
|
1114 |
|
1115 | if (promise) {
|
1116 | return promise.then(add);
|
1117 | } else {
|
1118 |
|
1119 |
|
1120 | add();
|
1121 | }
|
1122 | } else {
|
1123 | add();
|
1124 | }
|
1125 |
|
1126 | return null;
|
1127 | })
|
1128 | .catch(error => {
|
1129 | this._console.error(
|
1130 | `jest-haste-map: watch error:\n ${error.stack}\n`
|
1131 | );
|
1132 | });
|
1133 | };
|
1134 |
|
1135 | this._changeInterval = setInterval(emitChange, CHANGE_INTERVAL);
|
1136 | return Promise.all(this._options.roots.map(createWatcher)).then(
|
1137 | watchers => {
|
1138 | this._watchers = watchers;
|
1139 | }
|
1140 | );
|
1141 | }
|
1142 | |
1143 |
|
1144 |
|
1145 |
|
1146 |
|
1147 |
|
1148 |
|
1149 |
|
1150 |
|
1151 | _recoverDuplicates(hasteMap, relativeFilePath, moduleName) {
|
1152 | let dupsByPlatform = hasteMap.duplicates.get(moduleName);
|
1153 |
|
1154 | if (dupsByPlatform == null) {
|
1155 | return;
|
1156 | }
|
1157 |
|
1158 | const platform =
|
1159 | (0, _getPlatformExtension.default)(
|
1160 | relativeFilePath,
|
1161 | this._options.platforms
|
1162 | ) || _constants.default.GENERIC_PLATFORM;
|
1163 |
|
1164 | let dups = dupsByPlatform.get(platform);
|
1165 |
|
1166 | if (dups == null) {
|
1167 | return;
|
1168 | }
|
1169 |
|
1170 | dupsByPlatform = copyMap(dupsByPlatform);
|
1171 | hasteMap.duplicates.set(moduleName, dupsByPlatform);
|
1172 | dups = copyMap(dups);
|
1173 | dupsByPlatform.set(platform, dups);
|
1174 | dups.delete(relativeFilePath);
|
1175 |
|
1176 | if (dups.size !== 1) {
|
1177 | return;
|
1178 | }
|
1179 |
|
1180 | const uniqueModule = dups.entries().next().value;
|
1181 |
|
1182 | if (!uniqueModule) {
|
1183 | return;
|
1184 | }
|
1185 |
|
1186 | let dedupMap = hasteMap.map.get(moduleName);
|
1187 |
|
1188 | if (dedupMap == null) {
|
1189 | dedupMap = Object.create(null);
|
1190 | hasteMap.map.set(moduleName, dedupMap);
|
1191 | }
|
1192 |
|
1193 | dedupMap[platform] = uniqueModule;
|
1194 | dupsByPlatform.delete(platform);
|
1195 |
|
1196 | if (dupsByPlatform.size === 0) {
|
1197 | hasteMap.duplicates.delete(moduleName);
|
1198 | }
|
1199 | }
|
1200 |
|
1201 | async end() {
|
1202 | if (this._changeInterval) {
|
1203 | clearInterval(this._changeInterval);
|
1204 | }
|
1205 |
|
1206 | if (!this._watchers.length) {
|
1207 | return;
|
1208 | }
|
1209 |
|
1210 | await Promise.all(this._watchers.map(watcher => watcher.close()));
|
1211 | this._watchers = [];
|
1212 | }
|
1213 | |
1214 |
|
1215 |
|
1216 |
|
1217 | _ignore(filePath) {
|
1218 | const ignorePattern = this._options.ignorePattern;
|
1219 | const ignoreMatched =
|
1220 | ignorePattern instanceof RegExp
|
1221 | ? ignorePattern.test(filePath)
|
1222 | : ignorePattern && ignorePattern(filePath);
|
1223 | return (
|
1224 | ignoreMatched ||
|
1225 | (!this._options.retainAllFiles && filePath.includes(NODE_MODULES))
|
1226 | );
|
1227 | }
|
1228 |
|
1229 | _createEmptyMap() {
|
1230 | return {
|
1231 | clocks: new Map(),
|
1232 | duplicates: new Map(),
|
1233 | files: new Map(),
|
1234 | map: new Map(),
|
1235 | mocks: new Map()
|
1236 | };
|
1237 | }
|
1238 | }
|
1239 |
|
1240 | exports.default = HasteMap;
|
1241 |
|
1242 | _defineProperty(HasteMap, 'H', _constants.default);
|
1243 |
|
1244 | class DuplicateError extends Error {
|
1245 | constructor(mockPath1, mockPath2) {
|
1246 | super('Duplicated files or mocks. Please check the console for more info');
|
1247 |
|
1248 | _defineProperty(this, 'mockPath1', void 0);
|
1249 |
|
1250 | _defineProperty(this, 'mockPath2', void 0);
|
1251 |
|
1252 | this.mockPath1 = mockPath1;
|
1253 | this.mockPath2 = mockPath2;
|
1254 | }
|
1255 | }
|
1256 |
|
1257 | exports.DuplicateError = DuplicateError;
|
1258 |
|
1259 | function copy(object) {
|
1260 | return Object.assign(Object.create(null), object);
|
1261 | }
|
1262 |
|
1263 | function copyMap(input) {
|
1264 | return new Map(input);
|
1265 | }
|