Skip to content

refactor: make no-unused-modules no-op on ESLint 10 or later#457

Merged
SukkaW merged 6 commits intoun-ts:masterfrom
SukkaW:drop-no-unused-module
Mar 3, 2026
Merged

refactor: make no-unused-modules no-op on ESLint 10 or later#457
SukkaW merged 6 commits intoun-ts:masterfrom
SukkaW:drop-no-unused-module

Conversation

@SukkaW
Copy link
Copy Markdown
Collaborator

@SukkaW SukkaW commented Feb 20, 2026

Another step toward ESLint 10 support (#438).


Important

Refactor no-unused-modules rule to be a no-op on ESLint 10 or later, adding a suppressible warning for the removed FileEnumerator API.

  • Behavior:
    • no-unused-modules rule is now a no-op on ESLint 10 or later due to removal of FileEnumerator API.
    • Adds warning message about this behavior, suppressible with suppressMissingFileEnumeratorAPIWarning option.
  • Code Changes:
    • Moves FileEnumerator and shouldUseFlatConfig access inside listFilesUsingFileEnumerator() to avoid accessing removed APIs unless invoked.
    • Adds suppressMissingFileEnumeratorAPIWarning to Options in no-unused-modules.ts.
    • Logs warning in create() function if FileEnumerator is not present and suppression option is not set.

This description was created by Ellipsis for c815920. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • New Features

    • Added a configuration option to suppress informational warnings when running on ESLint 10+.
  • Bug Fixes

    • The unused-modules check now gracefully becomes a no-op on ESLint 10+ to avoid errors; emits an informational warning by default.
  • Documentation

    • Changelog and notices updated to document the runtime behavior, warning, and suppression option.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 20, 2026

🦋 Changeset detected

Latest commit: 8c91a7b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
eslint-plugin-import-x Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Defers access to ESLint's FileEnumerator to runtime, makes the no-unused-modules rule a no-op when that API is unavailable (ESLint 10+), emits a warning unless suppressed, and adds the suppressMissingFileEnumeratorAPIWarning option; also adds a changelog entry documenting this behavior.

Changes

Cohort / File(s) Summary
Changelog Entry
/.changeset/clever-meals-fly.md
Adds changelog describing ESLint 10+ behavior: rule becomes a no-op with a warning and documents suppressMissingFileEnumeratorAPIWarning option.
no-unused-modules rule
src/rules/no-unused-modules.ts
Moves top-level FileEnumerator/shouldUseFlatConfig access into listFilesUsingFileEnumerator, uses guarded/lazy access to (eslintUnsupportedApi as any).FileEnumerator, adds runtime check and one-time warning for missing API, expands Options and schema with suppressMissingFileEnumeratorAPIWarning?: boolean, and returns a no-op rule when API is absent.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant DevRule as "Rule (no-unused-modules)"
    participant ESLint as "ESLint Runtime"
    participant FileEnum as "FileEnumerator API"
    participant Logger as "Console/Logger"

    DevRule->>ESLint: rule created / config parsed
    ESLint->>DevRule: invoke rule factory
    DevRule->>FileEnum: attempt lazy access (guarded)
    alt FileEnumerator available
        FileEnum-->>DevRule: returns file list
        DevRule->>ESLint: perform unused-module checks
    else FileEnumerator missing (ESLint 10+)
        DevRule->>Logger: emit one-time warning (unless suppressed)
        DevRule-->>ESLint: return no-op rule (skip file enumeration)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

refactor

Suggested reviewers

  • 43081j
  • JounQin

Poem

🐰 I hopped through code with careful paws,
Tucked lazy guards in, avoided flaws.
If Enumerator’s gone, I softly warn,
Or silence the shout with an option born.
Nibbles, then back to the lawn — hooray! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: making the no-unused-modules rule a no-op on ESLint 10+, which is the primary objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci Bot commented Feb 20, 2026

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Feb 20, 2026

Open in StackBlitz

npm i https://pkg.pr.new/eslint-plugin-import-x@457

commit: 4f715c3

@SukkaW SukkaW requested review from 43081j and JounQin February 20, 2026 11:08
@SukkaW
Copy link
Copy Markdown
Collaborator Author

SukkaW commented Feb 20, 2026

@43081j @JounQin What do you think make no-unused-modules no-op on ESLint 10? This should fix the rule crashing on ESLint 10.

Technically, "ignoring" the potential rule violations may be a breaking change, but I want to include the ESLint 10 support in a minor release (so most of users can update).

@SukkaW SukkaW mentioned this pull request Feb 20, 2026
@43081j
Copy link
Copy Markdown
Collaborator

43081j commented Feb 21, 2026

What is it that causes the crash?

I think I'm missing the context here 👀

@SukkaW
Copy link
Copy Markdown
Collaborator Author

SukkaW commented Feb 21, 2026

What is it that causes the crash?

I think I'm missing the context here 👀

no-unused-modules relies on ESLint's FileEnumerator API to get the file list (the one used by ESLint). But this API had been broken with ESLint flat config since ESLint 8.56 and now removed by ESLint 10. Without this API, no-unused-modules can not work.

@SukkaW SukkaW force-pushed the drop-no-unused-module branch 4 times, most recently from 1ae11a6 to 4b25628 Compare February 22, 2026 18:54
@43081j
Copy link
Copy Markdown
Collaborator

43081j commented Feb 22, 2026

ok that makes sense.

in that case, i agree it should ultimately be removed but could temporarily be no-op until then

@SukkaW SukkaW force-pushed the drop-no-unused-module branch from 4b25628 to c815920 Compare February 22, 2026 19:03
@SukkaW
Copy link
Copy Markdown
Collaborator Author

SukkaW commented Feb 22, 2026

ok that makes sense.

in that case, i agree it should ultimately be removed but could temporarily be no-op until then

Technically, we can iterate over all the files ourselves, but I prefer not to do that. ESLint is really not great for cross-file linting for now. In the meantime let's just no-op it.

@SukkaW SukkaW marked this pull request as ready for review February 22, 2026 19:15
Copy link
Copy Markdown

@ellipsis-dev ellipsis-dev Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed everything up to c815920 in 10 seconds. Click for details.
  • Reviewed 87 lines of code in 2 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_FKF3xjB5ccFnWqj0

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/rules/no-unused-modules.ts (1)

29-32: Nit: comment grammar.

Line 30: "avoid access the removed APIs" → "avoid accessing the removed APIs".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/rules/no-unused-modules.ts` around lines 29 - 32, Update the inline
comment that currently reads "This allows us to avoid access the removed APIs as
long as the function is not invoked." to correct the grammar by changing "avoid
access" to "avoid accessing" (the surrounding comment references
shouldUseFlatConfig and FileEnumerator and should remain otherwise unchanged).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/clever-meals-fly.md:
- Line 5: Fix the stray extra quote in the config example: update the snippet
`['error', { suppressMissingFileEnumeratorAPIWarning: true }']` to `['error', {
suppressMissingFileEnumeratorAPIWarning: true }]` (or include the missing
closing quote only around the whole string as intended) wherever it appears —
specifically in the .changeset/clever-meals-fly.md text and in the console.warn
message in src/rules/no-unused-modules.ts (the warn at/around the place
referenced, previously line 559). Also search for any other occurrences of the
malformed snippet in the repo and correct them so the example is syntactically
valid when copy-pasted.

In `@src/rules/no-unused-modules.ts`:
- Around line 557-560: The warning string contains a stray quote in the embedded
config snippet (`import-x/no-unused-modules: ['error', {
suppressMissingFileEnumeratorAPIWarning: true }']`) — update that literal so the
snippet ends with `}]` (i.e., `import-x/no-unused-modules: ['error', {
suppressMissingFileEnumeratorAPIWarning: true }]`) so the shown config is
syntactically correct; locate the console.warn call that prints this message
(the string containing "suppressMissingFileEnumeratorAPIWarning") and fix the
trailing quote.
- Around line 554-563: The warning is printed once per file because create()
runs for each file; add a module-level boolean (e.g.,
warnedMissingFileEnumerator) near the top of the module (around the Options
interface or other module state) and change the FileEnumerator check in the
create() implementation to only call console.warn when the flag is false, then
set the flag to true after logging so subsequent create() calls do not emit the
same message; keep the existing suppressMissingFileEnumeratorAPIWarning option
check as-is to allow explicit suppression.

---

Nitpick comments:
In `@src/rules/no-unused-modules.ts`:
- Around line 29-32: Update the inline comment that currently reads "This allows
us to avoid access the removed APIs as long as the function is not invoked." to
correct the grammar by changing "avoid access" to "avoid accessing" (the
surrounding comment references shouldUseFlatConfig and FileEnumerator and should
remain otherwise unchanged).

Comment thread .changeset/clever-meals-fly.md Outdated
Comment thread src/rules/no-unused-modules.ts
Comment thread src/rules/no-unused-modules.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the no-unused-modules rule to gracefully handle ESLint 10+, where the FileEnumerator API has been removed. The rule becomes a no-op on ESLint 10+ and displays an optional warning to users about this behavior.

Changes:

  • Moved FileEnumerator and shouldUseFlatConfig access into listFilesUsingFileEnumerator() function to avoid accessing removed APIs at module load time
  • Added suppressMissingFileEnumeratorAPIWarning option to allow users to suppress the informational warning
  • Added ESLint 10 detection logic that returns early with an empty rule implementation when FileEnumerator is unavailable

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/rules/no-unused-modules.ts Refactored to lazily access FileEnumerator API and added ESLint 10 compatibility check with optional warning
.changeset/clever-meals-fly.md Added changeset documenting the patch-level change for ESLint 10 compatibility

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/rules/no-unused-modules.ts Outdated
Comment thread src/rules/no-unused-modules.ts
Comment thread src/rules/no-unused-modules.ts Outdated
Comment thread src/rules/no-unused-modules.ts
Comment thread src/rules/no-unused-modules.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/rules/no-unused-modules.ts (1)

554-562: ⚠️ Potential issue | 🟠 Major

Missing-API warning should be emitted once, not once per linted file.

Because create() runs per file, this prints the same warning repeatedly in large projects. Please gate the warning with a module-level flag.

🔧 Suggested fix
+let warnedAboutMissingFileEnumeratorAPI = false
+
 export interface Options {
   src?: string[]
   ignoreExports?: string[]
   missingExports?: true
@@
-    if (!('FileEnumerator' in eslintUnsupportedApi)) {
-      if (!suppressMissingFileEnumeratorAPIWarning) {
+    if (!('FileEnumerator' in eslintUnsupportedApi)) {
+      if (
+        !suppressMissingFileEnumeratorAPIWarning &&
+        !warnedAboutMissingFileEnumeratorAPI
+      ) {
+        warnedAboutMissingFileEnumeratorAPI = true
         console.warn(`
 ESLint removes the FileEnumerator API since ESLint 10, which is required by the "no-unused-modules" rule. Therefore, the "no-unused-modules" rule is no-op for now before we can implement an alternative.
 In the meantime, if you want to keep this rule enabled, you can suppress this warning with the "suppressMissingFileEnumeratorAPIWarning" rule option: \`import-x/no-unused-modules: ['error', { suppressMissingFileEnumeratorAPIWarning: true }]\`
 `)
       }
       return {}
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/rules/no-unused-modules.ts` around lines 554 - 562, The warning inside
the create() path is emitted per-file because create() is called for each linted
file; add a module-level flag (e.g., let missingFileEnumeratorWarningEmitted =
false) at top of src/rules/no-unused-modules.ts and wrap the console.warn block
with if (!missingFileEnumeratorWarningEmitted &&
!suppressMissingFileEnumeratorAPIWarning) { ...;
missingFileEnumeratorWarningEmitted = true; } so the message (controlled by
eslintUnsupportedApi and suppressMissingFileEnumeratorAPIWarning) is logged only
once across the process.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/rules/no-unused-modules.ts`:
- Line 559: Update the example config text for the "import-x/no-unused-modules"
rule so it satisfies the rule's options schema: include either "unusedExports:
true" or "missingExports: true" alongside
"suppressMissingFileEnumeratorAPIWarning". Locate the example that mentions
suppressMissingFileEnumeratorAPIWarning and change the suggested object to
include the required flag (e.g. add unusedExports: true) so the snippet becomes
a valid options object for the rule.

---

Duplicate comments:
In `@src/rules/no-unused-modules.ts`:
- Around line 554-562: The warning inside the create() path is emitted per-file
because create() is called for each linted file; add a module-level flag (e.g.,
let missingFileEnumeratorWarningEmitted = false) at top of
src/rules/no-unused-modules.ts and wrap the console.warn block with if
(!missingFileEnumeratorWarningEmitted &&
!suppressMissingFileEnumeratorAPIWarning) { ...;
missingFileEnumeratorWarningEmitted = true; } so the message (controlled by
eslintUnsupportedApi and suppressMissingFileEnumeratorAPIWarning) is logged only
once across the process.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d20115 and 45ef2a5.

📒 Files selected for processing (1)
  • src/rules/no-unused-modules.ts

Comment thread src/rules/no-unused-modules.ts
SukkaW and others added 4 commits March 1, 2026 23:10
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: JounQin <admin@1stg.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: JounQin <admin@1stg.me>
@SukkaW SukkaW force-pushed the drop-no-unused-module branch from f4c609b to dcd459f Compare March 1, 2026 15:10
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/rules/no-unused-modules.ts (1)

561-564: ⚠️ Potential issue | 🟡 Minor

The warning's config example doesn't satisfy this rule's schema.

The example shown in the warning message only includes suppressMissingFileEnumeratorAPIWarning: true, but the rule's schema (lines 512-537) requires either unusedExports: true or missingExports: true via the anyOf constraint. Users copying this example would get a schema validation error.

✏️ Suggested fix
-ESLint removes the FileEnumerator API since ESLint 10, which is required by the "no-unused-modules" rule. Therefore, the "no-unused-modules" rule is no-op for now before we can implement an alternative.
-In the meantime, if you want to keep this rule enabled, you can suppress this warning with the "suppressMissingFileEnumeratorAPIWarning" rule option: \`import-x/no-unused-modules: ['error', { suppressMissingFileEnumeratorAPIWarning: true }]\`
+ESLint removes the FileEnumerator API since ESLint 10, which is required by the "no-unused-modules" rule. Therefore, the "no-unused-modules" rule is no-op for now before we can implement an alternative.
+In the meantime, you can suppress this warning by adding "suppressMissingFileEnumeratorAPIWarning: true" to your existing rule config (e.g., \`import-x/no-unused-modules: ['error', { unusedExports: true, suppressMissingFileEnumeratorAPIWarning: true }]\`).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/rules/no-unused-modules.ts` around lines 561 - 564, The warning message
for the "no-unused-modules" rule shows a config example that violates the rule
schema by omitting the required anyOf option; update the example in the
console.warn block in src/rules/no-unused-modules.ts to include one of the
required options (either "unusedExports" or "missingExports") alongside
"suppressMissingFileEnumeratorAPIWarning" (for example: { unusedExports: true,
suppressMissingFileEnumeratorAPIWarning: true }) so a pasted config validates
against the rule schema; ensure the message string references the exact option
names "suppressMissingFileEnumeratorAPIWarning", "unusedExports", and
"missingExports".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/rules/no-unused-modules.ts`:
- Around line 561-564: The warning message for the "no-unused-modules" rule
shows a config example that violates the rule schema by omitting the required
anyOf option; update the example in the console.warn block in
src/rules/no-unused-modules.ts to include one of the required options (either
"unusedExports" or "missingExports") alongside
"suppressMissingFileEnumeratorAPIWarning" (for example: { unusedExports: true,
suppressMissingFileEnumeratorAPIWarning: true }) so a pasted config validates
against the rule schema; ensure the message string references the exact option
names "suppressMissingFileEnumeratorAPIWarning", "unusedExports", and
"missingExports".

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45ef2a5 and f4c609b.

📒 Files selected for processing (1)
  • src/rules/no-unused-modules.ts

@SukkaW SukkaW merged commit 1da4043 into un-ts:master Mar 3, 2026
45 checks passed
@SukkaW SukkaW deleted the drop-no-unused-module branch March 3, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants