Pull Request Overview
- Opened on June 30, 2026
- Status Stale Open
- Commit count 7 with first commit June 30, 2026
Total Delta
Open Days
Test Delta
How long has this pull request spent in each phase of its lifecycle?
| Fraction of total time | Business days | Phase |
|---|---|---|
|
|
0.0 days | Authoring 7 commits before pull request opened for review |
|
|
0.1 days | Awaiting first review |
|
|
58.1 days | Revising work with 0 commits in response to 0 reviews that left 1 comment |
Total time for pull request still awaiting merge (longer than repo's target): 58.2 business days
[New] add `requireResolve` option to check `require.resolve()` paths
Closes #585. Supersedes #1217.
Motivation
While working on a PR in Gutenberg (which powers the WordPress block editor), I noticed that require.resolve() calls are not considered by these rules. Looking for existing discussion I found #585, so this PR implements it.
Summary
require.resolve() resolves a module path the same way require() does, but until now the resolution rules ignored it. This PR adds an opt-in requireResolve boolean option (default false) to the shared moduleVisitor. When enabled, the first string-literal argument of a require.resolve("<path>") call is visited as a require module path, so the rules that resolve specifiers can check it too.
/*eslint import/no-unresolved: [2, { requireResolve: true }]*/
const x = require.resolve('./foo'); // reported if './foo' is not found
require.resolve('./foo', { paths: [__dirname] }); // first argument still checked
require.resolve(0); // ignored (non-string)
require['resolve']('./foo'); // ignored (computed access)
Relation to #1217
This supersedes the earlier #1217, which also added a requireResolve option but stalled in review. The main differences here: the option is a plain boolean independent of commonjs (instead of the boolean | { commonjs } oneOf), the first argument is checked regardless of arity (per @ljharb's review feedback on that PR), no-cycle explicitly ignores require.resolve, and the option is wired into several additional resolution rules β all with tests and docs.
Why opt-in (off by default)
This mirrors the conclusion of the earlier attempts (#1216 / #1217): emitting new warnings on existing code is a breaking change, and require.resolve is sometimes used to resolve non-module assets (e.g. build-generated files) that a resolver can't find. The option therefore defaults to false and is independent of commonjs.
Note on
require.resolve(0): likerequire()andimport(), the visitor only forwards static string paths, so non-string / dynamic arguments are skipped rather than reported. (In the #1217 review @ljharb noted a warning there could be useful; that is arguably a separate "invalid argument type" concern and is intentionally left out of scope here.)
Affected rules
The change lives in moduleVisitor, so every resolution rule can opt in:
-
Enabled via the shared options schema (no rule change needed): [no-unresolved], [no-absolute-path], [no-relative-packages], [no-relative-parent-imports]. -
[no-cycle]: explicitly ignoresrequire.resolveβ it computes a path without loading the module, so it cannot form a runtime cycle. This prevents false cycle reports when the option is enabled elsewhere. -
Explicitly wired (these have their own schema and/or hardcode the visitor options): [no-extraneous-dependencies], [no-self-import], [no-webpack-loader-syntax], [no-useless-path-segments], [no-internal-modules].
Deliberately not wired: max-dependencies (a resolved path is not a load-time dependency edge), extensions (require.resolve is often used specifically to resolve paths with an extension), and no-nodejs-modules (marginal value).
Behaviour / edge cases
- Arity is not restricted: the first argument is checked even in the 2-arg
require.resolve(path, { paths })form (per @ljharb's #1217 review). - Only non-computed
require.resolve(...)member calls match;require['resolve'](...),require[resolve](...), andfoo.require.resolve(...)are ignored. - Non-string / dynamic first arguments are ignored.
- The visitor reports with
moduleSystem: 'require', so resolvermoduleSystemconfiguration applies consistently withrequire().
Checklist
- [x] write tests β valid (off-by-default) and invalid (option-on) cases for every wired rule, across the existing parser matrix where applicable
- [x] implement feature
- [x] update docs (
docs/rules/*) - [x] make a note in the change log
Testing
-
npm run tests-onlyfor the affected suites β all passing -
eslint .,tsc --noEmit index.d.ts,npm run update:eslint-docs -- --check, andmarkdownlintall clean
AI tool disclosure
This change was prepared with AI assistance. The plan, implementation, tests, and docs were drafted with Claude Code, and the plan and final diff were independently reviewed with Codex. All output was reviewed by me before submission, and I take responsibility for the contents of this PR.
Comments Threads Pending Resolution
Resolved Comment Threads
No resolved comments have been left on this PR.