Skip to content

Commit 80cb8e1

Browse files
committed
feat: replace sane with chokidar
1 parent ddccb79 commit 80cb8e1

8 files changed

Lines changed: 52 additions & 277 deletions

File tree

.eslintrc.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ module.exports = {
9595
'packages/jest-core/src/plugins/UpdateSnapshotsInteractive.ts',
9696
'packages/jest-fake-timers/src/legacyFakeTimers.ts',
9797
'packages/jest-haste-map/src/index.ts',
98-
'packages/jest-haste-map/src/lib/FSEventsWatcher.ts',
9998
'packages/jest-jasmine2/src/jasmine/SpyStrategy.ts',
10099
'packages/jest-jasmine2/src/jasmine/Suite.ts',
101100
'packages/jest-leak-detector/src/index.ts',

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
### Fixes
99

10+
- `[jest-haste-map]` Replace `sane` with `chokidar` ([#10048](https://github.com/facebook/jest/pull/10048))
1011
- `[jest-runtime]` [**BREAKING**] Do not inject `global` variable into module wrapper ([#10644](https://github.com/facebook/jest/pull/10644))
1112
- `[jest-transform]` Show enhanced `SyntaxError` message for all `SyntaxError`s ([#10749](https://github.com/facebook/jest/pull/10749))
1213
- `[jest-transform]` [**BREAKING**] Refactor API to pass an options bag around rather than multiple boolean options ([#10753](https://github.com/facebook/jest/pull/10753))

packages/jest-haste-map/package.json

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,22 @@
1717
"@jest/types": "^26.6.2",
1818
"@types/graceful-fs": "^4.1.2",
1919
"@types/node": "*",
20-
"anymatch": "^3.0.3",
20+
"chokidar": "^3.4.2",
2121
"fb-watchman": "^2.0.0",
2222
"graceful-fs": "^4.2.4",
2323
"jest-regex-util": "^26.0.0",
2424
"jest-serializer": "^26.6.2",
2525
"jest-util": "^26.6.2",
2626
"jest-worker": "^26.6.2",
27-
"micromatch": "^4.0.2",
28-
"sane": "^4.0.3",
29-
"walker": "^1.0.7"
27+
"micromatch": "^4.0.2"
3028
},
3129
"devDependencies": {
3230
"@jest/test-utils": "^26.6.2",
33-
"@types/anymatch": "^1.3.1",
3431
"@types/fb-watchman": "^2.0.0",
3532
"@types/micromatch": "^4.0.0",
36-
"@types/sane": "^2.0.0",
3733
"jest-snapshot-serializer-raw": "^1.1.0",
3834
"slash": "^3.0.0"
3935
},
40-
"optionalDependencies": {
41-
"fsevents": "^2.1.2"
42-
},
4336
"engines": {
4437
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
4538
},

packages/jest-haste-map/src/__tests__/index.test.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,13 @@ jest.mock('../crawlers/watchman', () =>
7272
const mockWatcherConstructor = jest.fn(root => {
7373
const EventEmitter = require('events').EventEmitter;
7474
mockEmitters[root] = new EventEmitter();
75-
mockEmitters[root].close = jest.fn(callback => callback());
75+
mockEmitters[root].close = jest.fn();
7676
setTimeout(() => mockEmitters[root].emit('ready'), 0);
7777
return mockEmitters[root];
7878
});
7979

80-
jest.mock('sane', () => ({
81-
NodeWatcher: mockWatcherConstructor,
82-
WatchmanWatcher: mockWatcherConstructor,
80+
jest.mock('chokidar', () => ({
81+
watch: jest.fn((patten, opts) => mockWatcherConstructor(opts.cwd)),
8382
}));
8483

8584
jest.mock('../lib/WatchmanWatcher', () => mockWatcherConstructor);

packages/jest-haste-map/src/index.ts

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import {createHash} from 'crypto';
1212
import {EventEmitter} from 'events';
1313
import {tmpdir} from 'os';
1414
import * as path from 'path';
15+
import {FSWatcher as ChokidarFsWatcher, watch as chokidarWatch} from 'chokidar';
1516
import type {Stats} from 'graceful-fs';
16-
import {NodeWatcher, Watcher as SaneWatcher} from 'sane';
1717
import type {Config} from '@jest/types';
1818
import {escapePathForRegex} from 'jest-regex-util';
1919
import serializer from 'jest-serializer';
@@ -101,7 +101,7 @@ type InternalOptions = {
101101
};
102102

103103
type Watcher = {
104-
close(callback: () => void): void;
104+
close(): Promise<void>;
105105
};
106106

107107
type WorkerInterface = {worker: typeof worker; getSha1: typeof getSha1};
@@ -788,14 +788,6 @@ class HasteMap extends EventEmitter {
788788
this._options.throwOnModuleCollision = false;
789789
this._options.retainAllFiles = true;
790790

791-
// WatchmanWatcher > FSEventsWatcher > sane.NodeWatcher
792-
const Watcher: SaneWatcher =
793-
canUseWatchman && this._options.useWatchman
794-
? WatchmanWatcher
795-
: FSEventsWatcher.isSupported()
796-
? FSEventsWatcher
797-
: NodeWatcher;
798-
799791
const extensions = this._options.extensions;
800792
const ignorePattern = this._options.ignorePattern;
801793
const rootDir = this._options.rootDir;
@@ -806,12 +798,21 @@ class HasteMap extends EventEmitter {
806798
let mustCopy = true;
807799

808800
const createWatcher = (root: Config.Path): Promise<Watcher> => {
809-
// @ts-expect-error: TODO how? "Cannot use 'new' with an expression whose type lacks a call or construct signature."
810-
const watcher = new Watcher(root, {
811-
dot: true,
812-
glob: extensions.map(extension => '**/*.' + extension),
813-
ignored: ignorePattern,
814-
});
801+
const useWatchman = canUseWatchman && this._options.useWatchman;
802+
const patterns = extensions.map(extension => '**/*.' + extension);
803+
// Prefer Watchman over Chokidar
804+
const watcher = useWatchman
805+
? new WatchmanWatcher(root, {
806+
dot: true,
807+
glob: patterns,
808+
ignored: ignorePattern,
809+
})
810+
: chokidarWatch(patterns, {
811+
alwaysStat: true,
812+
cwd: root,
813+
ignoreInitial: true,
814+
ignored: ignorePattern,
815+
});
815816

816817
return new Promise((resolve, reject) => {
817818
const rejectTimeout = setTimeout(
@@ -821,7 +822,14 @@ class HasteMap extends EventEmitter {
821822

822823
watcher.once('ready', () => {
823824
clearTimeout(rejectTimeout);
824-
watcher.on('all', onChange);
825+
826+
if (useWatchman) {
827+
watcher.on('all', onChange);
828+
} else {
829+
(watcher as ChokidarFsWatcher).on('all', (type, filePath, stat) => {
830+
onChange(type, filePath, root, stat);
831+
});
832+
}
825833
resolve(watcher);
826834
});
827835
});
@@ -832,10 +840,7 @@ class HasteMap extends EventEmitter {
832840
mustCopy = true;
833841
const changeEvent: ChangeEvent = {
834842
eventsQueue,
835-
hasteFS: new HasteFS({
836-
files: hasteMap.files,
837-
rootDir,
838-
}),
843+
hasteFS: new HasteFS({files: hasteMap.files, rootDir}),
839844
moduleMap: new HasteModuleMap({
840845
duplicates: hasteMap.duplicates,
841846
map: hasteMap.map,
@@ -1051,20 +1056,16 @@ class HasteMap extends EventEmitter {
10511056
}
10521057
}
10531058

1054-
end(): Promise<void> {
1059+
async end(): Promise<void> {
10551060
// @ts-expect-error: TODO TS cannot decide if `setInterval` and `clearInterval` comes from NodeJS or the DOM
10561061
clearInterval(this._changeInterval);
10571062
if (!this._watchers.length) {
1058-
return Promise.resolve();
1063+
return;
10591064
}
10601065

1061-
return Promise.all(
1062-
this._watchers.map(
1063-
watcher => new Promise(resolve => watcher.close(resolve)),
1064-
),
1065-
).then(() => {
1066-
this._watchers = [];
1067-
});
1066+
await Promise.all(this._watchers.map(watcher => watcher.close()));
1067+
1068+
this._watchers = [];
10681069
}
10691070

10701071
/**

packages/jest-haste-map/src/lib/FSEventsWatcher.ts

Lines changed: 0 additions & 192 deletions
This file was deleted.

packages/jest-haste-map/src/lib/WatchmanWatcher.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,14 +278,12 @@ WatchmanWatcher.prototype.emitEvent = function (
278278
/**
279279
* Closes the watcher.
280280
*
281-
* @param {function} callback
282-
* @private
283281
*/
284282

285-
WatchmanWatcher.prototype.close = function (callback) {
283+
WatchmanWatcher.prototype.close = function () {
286284
this.client.removeAllListeners();
287285
this.client.end();
288-
callback && callback(null, true);
286+
return Promise.resolve();
289287
};
290288

291289
/**

0 commit comments

Comments
 (0)