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