Skip to content

ESLint v10 support#3230

Merged
ljharb merged 9 commits into
import-js:mainfrom
rasmi:eslint-update
Jun 29, 2026
Merged

ESLint v10 support#3230
ljharb merged 9 commits into
import-js:mainfrom
rasmi:eslint-update

Conversation

@rasmi

@rasmi rasmi commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Add ESLint v10 support while maintaining backward compatibility with ESLint v2–v9. The v10 compat changes in shipped code use feature detection (e.g. checking if context.languageOptions exists) rather than version checks.

Closes:

Split out into separate PRs (independent / pre-existing issues revealed during v10 update; this branch rebases onto them and becomes v10-only):

What changed

Removed API replacements

ESLint v10 removed several deprecated context properties and SourceCode methods. Each call site now feature-detects the new API and falls back to the old one:

  • context.parserOptionscontext.languageOptions.parserOptions (affects sourceType.js, childContext.js, typescript.js, scc.js, parse.js)
  • context.parserPathcontext.languageOptions used for cache hashing instead (scc.js)
  • context.getPhysicalFilename()context.physicalFilename property (contextCompat.js)
  • context.getScope() → already had a compat wrapper, but one call site in declaredScope.js bypassed it — now fixed
  • sourceCode.getTokenOrCommentAfter/Before()sourceCode.getTokenAfter/Before(node, { includeComments: true }) (order.js)

no-unused-modules file enumeration fallback

ESLint v10 removed FileEnumerator and the internal glob-utils module. The existing cascade (FileEnumerator → legacy glob-utils) now has a third tier: a Node.js fs + minimatch fallback that walks directories and matches globs.

  • Only reached when both prior methods throw MODULE_NOT_FOUND or ERR_PACKAGE_PATH_NOT_EXPORTED
  • Uses minimatch and is-glob (existing direct dependencies)
  • On v10, this resolves #3079 (flat config requiring a dummy .eslintrc) since FileEnumerator is no longer used. The issue remains on v9.

Test infrastructure (test files only)

On v10, the unmaintained babel-eslint (Babel 6) is replaced with @babel/eslint-parser v8 for test coverage. This restores ~475 babel-related tests that would otherwise be skipped on v10.

Dependency changes

Package Change Why
eslint || ^10 added to peerDeps and devDeps v10 support

v10-specific parser deps are installed via dep-time-travel.sh (not in devDeps) to avoid peer dep conflicts with typescript@4.5.5 during npm install:

  • @typescript-eslint/parser@8 — on all ESLint 10 Node versions
    -@angular-eslint/template-parser@21 — on all ESLint 10 Node versions (v13 does not support ESLint 10)
  • @babel/eslint-parser@8 + @babel/core@8 (ESM, RC) — on Node >= 20
  • No babel parser on Node 18/19/21 (v8 is ESM-only, engines ^20.19.0 || >=22.12.0; v7 will not get ESLint 10 support). Babel tests are skipped; all other tests run.

CI changes

  • eslint-8+.yml: added ESLint 10 to the matrix, excluded Node < 18
  • dep-time-travel.sh: installs v10-specific parser deps (@typescript-eslint/parser@8 and @angular-eslint/template-parser@21 on all nodes, @babel/eslint-parser@8 on Node >= 20 only)
  • See also Fix resolve install in old npm version on CI. #3237 to fix tests failing in main.

@codecov

codecov Bot commented Feb 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 26.66667% with 88 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.95%. Comparing base (b3cf7e1) to head (99d5a50).
⚠️ Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
src/core/listFilesToProcess.js 10.41% 43 Missing ⚠️
src/core/listFilesWithNodeFs.js 31.91% 32 Missing ⚠️
src/core/getTokenOrComment.js 0.00% 8 Missing ⚠️
src/exportMap/typescript.js 28.57% 5 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (b3cf7e1) and HEAD (99d5a50). Click for more details.

HEAD has 19 uploads less than BASE
Flag BASE (b3cf7e1) HEAD (99d5a50)
40 21
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #3230       +/-   ##
===========================================
- Coverage   95.82%   80.95%   -14.88%     
===========================================
  Files          83       97       +14     
  Lines        3741     4438      +697     
  Branches     1355     1535      +180     
===========================================
+ Hits         3585     3593        +8     
- Misses        156      845      +689     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@StephanTLavavej

Copy link
Copy Markdown

@rasmi Do you want to disclose your usage of LLMs to generate this PR description and/or PR, which @ljharb objected to in another repo jsx-eslint/eslint-plugin-jsx-a11y#1077 ?

@rasmi

rasmi commented Feb 19, 2026

Copy link
Copy Markdown
Contributor Author

Was not aware, thanks @StephanTLavavej! It is a bit disappointing, as I spent a few hours of my day working on this, even with LLM tools. I will close this PR regardless out of respect for the maintainer (I just want to make sure the tests pass for my own edification).

@rasmi rasmi force-pushed the eslint-update branch 3 times, most recently from efa4b8b to 069a70f Compare February 19, 2026 02:07
@rasmi rasmi closed this Feb 19, 2026
@dirkluijk

dirkluijk commented Feb 19, 2026

Copy link
Copy Markdown

Just curious (and with all respect), what is the real issue of LLM-generated code? What matters is the code, right?

If the PR is too big, or too hard to review, we could just improve that?

@ljharb

ljharb commented Feb 19, 2026

Copy link
Copy Markdown
Member

@StephanTLavavej please do not take it upon yourself to act as if you're a maintainer. Each project can have different policies regardless of who's maintaining them. Please do not attempt to police projects you aren't even a significant contributor to.

@rasmi if you're using an LLM to automate applying changes you're writing, I'm fine with that - however if you're just prompting one to "add eslint v10 support", i have my own LLM subscription for that kind of thing :-)

@dirkluijk no, "what matters" has never been, and never will be, just "the code". Any code contribution represents a legal assignment of rights, as well as an eternal maintenance burden on that code, and as such, the human contributor is an important factor.

@rasmi

rasmi commented Feb 19, 2026

Copy link
Copy Markdown
Contributor Author

@ljharb -- point well-taken! I did go through a more rigorous process here -- it really did take me hours of focused work, thinking about implementation approaches, iterating, fixing tests, etc. It is not my intention to submit slop, I wanted to submit a PR that I hoped would meet the standard of the library, at least as a first pass. I lack decision-making insight/context on things like "Is it okay to just use glob, if not let's do a custom file search" and "exactly how should node vs. eslint-parser vs. core library version compatibility be handled" -- but this is what the review process is for!

I also understand that big changes like this may be simpler for the maintainer to just take on directly, as you have all the proper context and expertise on all the nuances of the library and ecosystem, to say the least. Apologies again, I didn't mean to burden you at all, I know it is hard to maintain core libraries like this. Please do with this what you wish!

Comment thread tests/src/cli.js Outdated
@A-Loot

A-Loot commented Mar 7, 2026

Copy link
Copy Markdown

What is the current status of this PR?

@rasmi

rasmi commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

Hi @ljharb -- let me know if you have any feedback / next steps on this that I can address. Sorry to ping you, but there is quite a crowd on this PR and #3227. If the issue is codecoverage, I can add new test coverage. I think my main concern was whether some of the design decisions are appropriate for the project. (just rebasing onto main & force-pushing now)

Comment thread .github/workflows/eslint-8+.yml
@rasmi

rasmi commented Mar 12, 2026

Copy link
Copy Markdown
Contributor Author

#3237 should fix the tests currently failing in main.

Comment thread tests/src/utils.js Outdated
Move the `getTokenOrComment{Before,After}`
feature-detection shims out of the rule and into
`src/core/getTokenOrComment.js` so both the legacy and the
`getToken{Before,After}({ includeComments: true })`
branches can be unit-tested directly.
They cannot be exported from the rule module:
the plugin loads rules via `require`,
which only yields the rule object while the file has a single default export.
…fallbacks

Exercise both branches of the `getTokenOrComment{Before,After}` shims,
and the `listFilesToProcess` fallback to
`listFilesWithNodeFs` when the legacy `glob-utils` module is no longer exported
(`ERR_PACKAGE_PATH_NOT_EXPORTED`, eslint 10)
in addition to the existing `MODULE_NOT_FOUND` case.
@captaindonald

Copy link
Copy Markdown
Contributor

@ljharb I opened rasmi/eslint-plugin-import#1 against @rasmi's eslint-update to clear the failing codecov/patch + codevov/project here - no targets, thresholds, or ignores changed, just covers the two new v10 spots that were uncovered: the getTokenOrComment feature-detect arms in order, and the ERR_PACKAGE_PATH_NOT_EXPORTED fallback in listFilesToProcess. Merge it into the branch, or pull the commits straight into this PR - whichever is easier.

captaindonald added a commit to captaindonald/eslint-plugin-import that referenced this pull request Jun 27, 2026
`v3.1.5` is the last v3 release. v4 made the upload token effectively
required and broke tokenless coverage uploads from fork PRs of public
repos, which is the reason this action was pinned back. v5 restored
reliable tokenless fork-PR uploads; v7 is the current release.

Fork PRs cannot read repository secrets, so they have always relied on
tokenless uploads. Against the sunset v3 endpoint those uploads were
frequently rate-limited/dropped, so version-specific code covered only
by certain matrix jobs appeared uncovered in the merged head report
(~19 upload sessions on the head vs ~40 on the base in import-js#3230). Upgrading
makes uploads reliable without lowering any coverage target or adding
`flags`/`ignore`.
…branches

Exercise both the modern (ESLint 8+) and the deprecated fallback branch of each compat shim
- `getSourceCode`, `getScope`, `getAncestors`, `getDeclaredVariables`, `getFilename`, and `getPhysicalFilename`
- with stub contexts.

These modern branches were previously only hit incidentally by rule tests on particular eslint versions.
A glob whose base directory does not exist now exercises the `readdirSync` failure branch.
@captaindonald

Copy link
Copy Markdown
Contributor

Ok, this one should clear that -0.04%.

rasmi#2

@captaindonald

Copy link
Copy Markdown
Contributor

Codecov being codecov again. Failed uploads.

@ljharb

ljharb commented Jun 29, 2026

Copy link
Copy Markdown
Member

Codecov isn't a blocker, don't worry.

@ljharb ljharb merged commit 99d5a50 into import-js:main Jun 29, 2026
420 of 422 checks passed
@manzoorwanijk

Copy link
Copy Markdown

Thank you @ljharb

captaindonald added a commit to captaindonald/eslint-plugin-import that referenced this pull request Jun 29, 2026
`v3.1.5` is the last v3 release. v4 made the upload token effectively
required and broke tokenless coverage uploads from fork PRs of public
repos, which is the reason this action was pinned back. v5 restored
reliable tokenless fork-PR uploads; v7 is the current release.

Fork PRs cannot read repository secrets, so they have always relied on
tokenless uploads. Against the sunset v3 endpoint those uploads were
frequently rate-limited/dropped, so version-specific code covered only
by certain matrix jobs appeared uncovered in the merged head report
(~19 upload sessions on the head vs ~40 on the base in import-js#3230). Upgrading
makes uploads reliable without lowering any coverage target or adding
`flags`/`ignore`.
@TheGiraffe3

Copy link
Copy Markdown

And thanks @captaindonald!

@ThomasAFink

Copy link
Copy Markdown

Thank you for this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade to ESLint v10 Following the ESLint 9 support, import/no-unused-modules only works in flat config if an .eslintrc file exists as well