chore(haste-map): replace walker and hand-rolled traversal with fdir#16187
Merged
Conversation
Introduces a shared `lib/walk.ts` that replaces the two hand-rolled directory walkers in jest-haste-map: - `crawlers/node.ts` `find()` — recursive readdir with activeCalls counter - `watchers/common.js` `recReaddir` — wraps the `walker` npm dep Both walk a tree and stat per entry. `walk` uses fdir's async crawl (which fans readdir out across libuv's threadpool) plus a bounded callback-based lstat pool (fdir's `.withCallback()` API, keeping all internals callback-driven with a single Promise at the outer boundary) that avoids Promise-per-file overhead on million-file trees. Call sites are converted in follow-up commits.
Replace the hand-rolled fs.readdir recursive walker in crawlers/node.ts with the new lib/walk helper. The find(1) shell-out path (findNative) is unchanged; only the JS fallback path (used when find is unavailable or forceNodeFilesystemAPI is true) is replaced.
Replace `walker` npm dep usage in `watchers/common.js` and the private `recReaddir` in `FSEventsWatcher.ts` with the shared `lib/walk` helper.
- Fix "This options" → "This option" in enableSymlinks JSDoc (jest-types, jest-schemas, docs) - Fix inaccurate test comment in watchers/__tests__/index.test.ts — the ready-timeout is what triggers the rejection, not monkey-patching - Delete unused WatcherBackend union from watchers/types.ts - Add test for shouldUseWatchman(true) when isWatchmanInstalled() returns false - Fix README: forceNodeFilesystemAPI, hasteImplModulePath, hasteMapModulePath, skipPackageJson, throwOnModuleCollision are all optional with sane defaults - Note: HasteMapOptions.watchman is intentionally required (breaking change from the PR 16186 rewrite; callers must be explicit)
✅ Deploy Preview for jestjs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
Replaces jest-haste-map's hand-rolled directory walkers (the recursive fs.readdir loop in crawlers/node.ts and the walker npm dep used by FSEventsWatcher startup and watchers/common.js recReaddir) with a single shared helper at lib/walk.ts backed by fdir. The walker dependency is dropped from the package.
Changes:
- New
lib/walk.tswrapsfdir.crawl().withCallback()with a bounded callback-drivenlstatpool and exposes a smallwalk(opts, done)API; covered by a newwalk.test.ts. crawlers/node.tsfindandwatchers/{FSEventsWatcher,common.js}switch towalk;findNativeis simplified.- Misc cleanup: drops unused
WatcherBackendtype, fixes "This options" typo in three places, expands README defaults, adds CHANGELOG entry and updatesCLAUDE.md.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/jest-haste-map/src/lib/walk.ts | New fdir-backed walker with bounded lstat pool. |
| packages/jest-haste-map/src/lib/tests/walk.test.ts | Tests for the new helper. |
| packages/jest-haste-map/src/crawlers/node.ts | Rewrites find on top of walk; drops enableSymlinks plumbing and simplifies findNative. |
| packages/jest-haste-map/src/crawlers/tests/node.test.js | Adjusts the graceful-fs mock for fdir (adds isFile, readdirSync, realpath, trailing-slash normalization). |
| packages/jest-haste-map/src/watchers/FSEventsWatcher.ts | Replaces walker-based startup walk with walk; drops local recReaddir/normalizeProxy. |
| packages/jest-haste-map/src/watchers/common.js | recReaddir now uses walk. |
| packages/jest-haste-map/src/watchers/types.ts | Removes unused WatcherBackend export. |
| packages/jest-haste-map/src/watchers/tests/index.test.ts | Tightens shouldUseWatchman tests; clarifies a comment. |
| packages/jest-haste-map/package.json | Adds fdir, removes walker. |
| packages/jest-haste-map/README.md | Marks several options as not required and documents defaults. |
| packages/jest-haste-map/CLAUDE.md | Documents lib/walk.ts and updates crawler/watcher notes. |
| packages/jest-types/src/Config.ts, packages/jest-schemas/src/raw-types.ts, docs/Configuration.md | Fixes "This options" → "This option" typo. |
| yarn.lock | Reflects added fdir and dropped walker resolutions. |
| CHANGELOG.md | Adds entry under Chore & Maintenance. |
babel-jest
babel-plugin-jest-hoist
babel-preset-jest
create-jest
@jest/diff-sequences
expect
@jest/expect-utils
jest
jest-changed-files
jest-circus
jest-cli
jest-config
@jest/console
@jest/core
@jest/create-cache-key-function
jest-diff
jest-docblock
jest-each
@jest/environment
jest-environment-jsdom
@jest/environment-jsdom-abstract
jest-environment-node
@jest/expect
@jest/fake-timers
@jest/get-type
@jest/globals
jest-haste-map
jest-jasmine2
jest-leak-detector
jest-matcher-utils
jest-message-util
jest-mock
@jest/pattern
jest-phabricator
jest-regex-util
@jest/reporters
jest-resolve
jest-resolve-dependencies
jest-runner
jest-runtime
@jest/schemas
jest-snapshot
@jest/snapshot-utils
@jest/source-map
@jest/test-result
@jest/test-sequencer
@jest/transform
@jest/types
jest-util
jest-validate
jest-watcher
jest-worker
pretty-format
commit: |
SimenB
commented
May 16, 2026
SimenB
commented
May 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
jest-haste-maphas two hand-rolled directory walkers:crawlers/node.ts— a recursivefs.readdirloop with a manualactiveCallscounter, used as the JS fallback whenfind(1)is unavailable orforceNodeFilesystemAPIis set.watchers/common.jsrecReaddirandFSEventsWatcher.ts— both wrap thewalkernpm dep to enumerate the initial file tree at watcher startup.Both walk a tree and
lstateach entry. This PR replaces them with a single shared helper atlib/walk.ts, backed byfdir.fdirfansreaddircalls out across libuv's threadpool natively. Thelstatphase uses a bounded callback pool (noPromise-per-file overhead) — the pool size defaults toMath.max(os.availableParallelism() * 4, 32)so the threadpool stays saturated on large trees without queuing all callbacks at once.What's unchanged:
findNative(thefind(1)shell-out incrawlers/node.ts) — still the fastest path on large POSIX trees; still gated behindhasNativeFindSupport.forceNodeFilesystemAPI— still functional; now forces the fdir path instead of the oldfs.readdirrecursion.WatchmanWatcherand the watchman crawler — untouched.Test plan
yarn build:js yarn jest packages/jest-haste-map # 154 tests, all pass yarn typecheck:tests yarn lint yarn check-changelog yarn constraints yarn dedupe --check