[New] add requireResolve option to check require.resolve() paths#3264
Open
manzoorwanijk wants to merge 7 commits into
Open
[New] add requireResolve option to check require.resolve() paths#3264manzoorwanijk wants to merge 7 commits into
requireResolve option to check require.resolve() paths#3264manzoorwanijk wants to merge 7 commits into
Conversation
…ve()` paths
Adds an opt-in `requireResolve` boolean (default false) to the shared module
visitor and its options schema. When enabled, single- or multi-arg
`require.resolve("<literal>")` calls have their first string argument visited as
a `require` module path, so resolution-based rules can check it.
…solve` Resolves import-js#585. The shared `requireResolve` option (off by default) makes `no-unresolved` report unresolvable `require.resolve("./foo")` paths.
`require.resolve` computes a path without loading the module, so it cannot form a runtime dependency cycle. Skip it in the visitor so enabling `requireResolve` does not produce false cycle reports.
…ia `requireResolve`
Adds the `requireResolve` option to the rule schema and forwards it to the
module visitor, so a package pulled in via `require.resolve("pkg")` is flagged
when it is not a declared dependency.
…segments`, `no-internal-modules`: check `require.resolve()` paths via `requireResolve` Wires the opt-in `requireResolve` option into the remaining path-checking rules that resolve module specifiers, so each also inspects `require.resolve()` paths.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3264 +/- ##
===========================================
+ Coverage 80.95% 91.36% +10.40%
===========================================
Files 97 85 -12
Lines 4438 3753 -685
Branches 1535 1369 -166
===========================================
- Hits 3593 3429 -164
+ Misses 845 324 -521 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Author
|
@ljharb, a gentle request: is it possible to wrap this up before the next release? |
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.
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 wayrequire()does, but until now the resolution rules ignored it. This PR adds an opt-inrequireResolveboolean option (defaultfalse) to the sharedmoduleVisitor. When enabled, the first string-literal argument of arequire.resolve("<path>")call is visited as arequiremodule path, so the rules that resolve specifiers can check it too.Relation to #1217
This supersedes the earlier #1217, which also added a
requireResolveoption but stalled in review. The main differences here: the option is a plain boolean independent ofcommonjs(instead of theboolean | { commonjs }oneOf), the first argument is checked regardless of arity (per @ljharb's review feedback on that PR),no-cycleexplicitly ignoresrequire.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.resolveis sometimes used to resolve non-module assets (e.g. build-generated files) that a resolver can't find. The option therefore defaults tofalseand is independent ofcommonjs.Affected rules
The change lives in
moduleVisitor, so every resolution rule can opt in: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.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.resolveis often used specifically to resolve paths with an extension), andno-nodejs-modules(marginal value).Behaviour / edge cases
require.resolve(path, { paths })form (per @ljharb's Add requireResolve option #1217 review).require.resolve(...)member calls match;require['resolve'](...),require[resolve](...), andfoo.require.resolve(...)are ignored.moduleSystem: 'require', so resolvermoduleSystemconfiguration applies consistently withrequire().Checklist
docs/rules/*)Testing
npm run tests-onlyfor the affected suites — all passingeslint .,tsc --noEmit index.d.ts,npm run update:eslint-docs -- --check, andmarkdownlintall cleanAI 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.