You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,6 +15,7 @@
15
15
### Chore & Maintenance
16
16
17
17
-`[jest-haste-map]` Refactor massive class into multiple files ([#16180](https://github.com/jestjs/jest/pull/16180))
18
+
-`[jest-haste-map]` Drop `walker` dependency; replace hand-rolled directory recursion in the JS crawler and watcher startup with `fdir` ([#16187](https://github.com/jestjs/jest/pull/16187))
18
19
-`[jest-runtime]` Avoid magical `null` value in ESM loader ([#16160](https://github.com/jestjs/jest/pull/16160))
-`lib/CacheManager.ts` — v8 serialize/deserialize for the on-disk cache. **Sync I/O is intentional** — at haste-map's scale, async overhead adds no value and switching to `fs.promises` is not a free win.
11
+
- `lib/walk.ts` — shared `fdir`-backed directory walker used by the node crawler (`crawlers/node.ts` `find`), `FSEventsWatcher.ts` startup, and `NodeWatcher.js` startup (via `watchers/common.js` `recReaddir`). Exports `walk(opts, done): void` (callback-based) and `WalkOptions`, `WalkEntryKind`. Uses `fdir`'s `.withCallback()` API with a bounded callback-driven `lstat` pool (default `Math.max(os.availableParallelism() * 4, 32)` inflight). `fdir` is constructed with `new Fdir({fs})` so it uses `graceful-fs` for `readdir` — mock `graceful-fs.readdir` in tests to control directory traversal. `WalkOptions.statCache` is an optional `Map<string, Stats>` passed by callers that invoke `walk()` multiple times (e.g. once per root): a path already in the map skips its `lstat` call. **The cache must not be stored on watcher instances or passed to runtime (post-startup) walks** — stale stats would be returned for files changed after startup. `find()` and `WatcherDriver.start()` each create a fresh cache, use it for all per-root startup walks, then discard it.
11
12
-`watchers/ChangeQueue.ts` — 30 ms debounce, O(1) mtime-dedup via `Set<string>`, copy-on-write for the live map, file-processing dispatch.
12
-
-`crawlers/watchman.ts` — fb-watchman with clock-based incremental updates. `crawlers/node.ts` — pure Node.js fallback.
13
-
-`watchers/types.ts` — `IWatcher`, `WatcherOptions`, `WatcherCtor`, `WatcherBackend`. New backends must implement `IWatcher` and accept `(root: string, opts: WatcherOptions)`.
-`crawlers/watchman.ts` — fb-watchman with clock-based incremental updates. `crawlers/node.ts` — `findNative` (`find(1)` shell-out) + `find` (`fdir` via `lib/walk`); `forceNodeFilesystemAPI` gates shell-out vs `fdir`.
14
+
-`watchers/types.ts` — `IWatcher`, `WatcherOptions`, `WatcherCtor`. New backends must implement `IWatcher` and accept `(root: string, opts: WatcherOptions)`.
15
+
-`watchers/WatchmanWatcher.js` — macOS/Linux watchman. `FSEventsWatcher.ts` — macOS native (startup walk via `lib/walk`). `NodeWatcher.js` — cross-platform fallback.
15
16
16
17
## Data model
17
18
@@ -40,6 +41,8 @@ Key files to know:
40
41
41
42
**`enableSymlinks` guard** fires when `enableSymlinks && useWatchman`.
42
43
44
+
**`enableSymlinks` symlink semantics.** When `false` (default), symlinks are excluded by all walkers. When `true`: `find` (fdir path) passes `enableSymlinks` to `walk()`, which sets `excludeSymlinks: false` and keeps `resolveSymlinks: false` (fdir mode 2) — symlinks are included at their **original link path** (not realpath); `walk()` then calls `fs.stat` (follows the link) to get target stats (mtime/size). This preserves the path Jest uses to `require` the file while reporting the target's metadata. `findNative` (shell `find` path) uses `( -type f -o -type l )` when `enableSymlinks` is true to include symlinks, then `fs.stat`s each result. Do NOT set fdir's `resolveSymlinks: true` — it calls `realpath` and returns the resolved path, which would cause haste-map to track files under the wrong path.
45
+
43
46
**Config wiring from jest-config to jest-haste-map:**`HasteMap.Options` fields come from two places in `ProjectConfig`: `haste.enableSymlinks` → `enableSymlinks`, `haste.forceNodeFilesystemAPI` → `forceNodeFilesystemAPI`. The `useWatchman` field comes from the caller (e.g. `jest-runtime` passes `options?.watchman`; `jest-core` passes `globalConfig.watchman`). If you add a new `haste.*` config key that needs to reach `HasteMap`, add it to `HasteConfig` in `jest-types/src/Config.ts`, `HasteConfig` schema in `jest-schemas/src/raw-types.ts`, `Defaults.ts` (if it has a default), `ValidConfig.ts` (both `initialOptions.haste` and `initialProjectOptions.haste`), and the `HasteMap.create(...)` call in `jest-runtime/src/index.ts`.
0 commit comments