Skip to content

fix: complete ESLint 10 compatibility - #4022

Open
plthomasva wants to merge 26 commits into
jsx-eslint:masterfrom
plthomasva:update-deprecated-calls-v8
Open

fix: complete ESLint 10 compatibility#4022
plthomasva wants to merge 26 commits into
jsx-eslint:masterfrom
plthomasva:update-deprecated-calls-v8

Conversation

@plthomasva

@plthomasva plthomasva commented Jul 30, 2026

Copy link
Copy Markdown

This PR brings ESLint v10 compatibility to eslint-plugin-react.

It consolidates and builds upon the work of several contributors across the history of #3979 to create a fully-green patch branch that resolves all unit test failures and CI matrix issues under ESLint 10.

History & Summary of Integrated Changes

  1. RuleContext & getFilename API adaptations (by @ledsun & @tylermumford):

    • Replaced deprecated/removed context.getFilename() calls with eslintUtil.getFilename(context).
  2. RuleTester type: property stripping (by @captaindonald in [Tests] drop ESLint-10-incompatible 'type:' property from RuleTester error assertions #4006):

    • Added helper in tests/helpers/ruleTester.js to strip type: from expected error objects when running on ESLint >= 10.
  3. Matrix & Spacing API updates (from @Trott's patch-1 branch):

    • CI Matrix: Added typescript@5 installation to ESLint 9+ test matrices so modern TS parsers don't fail against old matrix TypeScript versions.
    • isSpaceBetween Fallback: Added eslintUtil.isSpaceBetween helper in lib/util/eslint.js replacing the removed sourceCode.isSpaceBetweenTokens.
    • RuleTester Valid Cases: Stripped invalid output and errors fields from valid test cases in jsx-indent-props, jsx-indent, jsx-no-bind, and require-optimization.

Breaking Changes

  • Dropped Support: Formally dropped support for Node 4 and ESLint 3 and 4 as they lack the newer SourceCode APIs required by these changes.

Fixes & AST Migration:

  • JSDoc Comment Fallback (lib/util/componentUtil.js): Added a fallback checking sourceCode.getCommentsBefore(node) when the removed sourceCode.getJSDocComment is unavailable on ESLint 10. This fixes JSDoc @extends React.Component detection for no-typos and prop-types.
  • AST Node Migration: Migrated other deprecated/removed v3/v4 AST nodes to modern sourceCode equivalents to resolve AST fallback failures on newer versions.
  • Canary Parser Support (tests/helpers/parsers.js): Passed { includePrerelease: true } to semver.satisfies so canary/prerelease versions of @typescript-eslint/parser are matched correctly. Fixes failures in jsx-uses-react.
  • no-undef JSX Comment Override (tests/lib/rules/jsx-no-undef.js): Added a test code map replacing /*eslint no-undef:1*/ with /*eslint no-undef:0*/ on ESLint >= 10, preventing ESLint 10's native JSX no-undef tracking from producing duplicate errors.
  • Windows Path Resolution (lib/util/version.js): Added ENOENT handling alongside ENOTDIR in resolveBasedir for virtual file paths on Windows.
  • CI Fixes: Prevented strict peer dependency failures by stripping typescript and eslint-doc-generator from devDependencies dynamically during test matrix runs, bumped ls-engines validation to Node >= 14, and properly excluded ESLint 10 from running on unsupported Node versions (18, 19, 21, 23).
  • SonarQube: Addressed quality gate issues in scripts/audit.js.

Related Issues

Dependency Overrides for ESLint 10

To pass CI on modern npm versions (which strictly enforce peer dependencies), temporary "overrides" have been added to package.json for several dev dependencies that do not yet officially support ESLint 10. These overrides can be removed once the following upstream issues are resolved:

@socket-security

socket-security Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​eslint@​10.8.09710010095100

View full report

ljharb and others added 13 commits July 30, 2026 08:12
Use isSpaceBetween when isSpaceBetweenTokens is unavailable, while
preserving legacy JSXText whitespace behavior for older ESLint versions.
ESLint 10 rejects output and errors properties on valid test cases.
These properties were ignored by older RuleTester versions.
Exclude Node 18, 19, 21, and 23 for ESLint 10, properly quoting node versions to avoid type mismatch in GitHub Actions matrix exclusions.

Dynamically remove eslint-doc-generator before installing eslint 9+ to prevent EBADENGINE failures due to commander@14 requiring Node >=20.

Format CHANGELOG.md to place removed support under a ### Breaking heading as per v7.0.0 conventions.
@plthomasva
plthomasva force-pushed the update-deprecated-calls-v8 branch from 25d08f4 to 355177c Compare July 30, 2026 12:15
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.36066% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 97.73%. Comparing base (f16ce0d) to head (8f873f7).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
lib/util/componentUtil.js 94.11% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4022      +/-   ##
==========================================
+ Coverage   97.60%   97.73%   +0.12%     
==========================================
  Files         137      137              
  Lines       10188    10189       +1     
  Branches     3797     3792       -5     
==========================================
+ Hits         9944     9958      +14     
+ Misses        244      231      -13     

☔ 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.

@plthomasva plthomasva mentioned this pull request Jul 30, 2026
2 tasks
@jfredyromero

Copy link
Copy Markdown

Approved

@plthomasva

Copy link
Copy Markdown
Author

@ljharb I think this is over to you when you get a chance.

@jtzingsheim1

Copy link
Copy Markdown

Adding independent validation ahead of maintainer review:

Behavioral parity on a production Next.js 16 / React 19 / TypeScript app

Result: with this branch, ESLint 10.8.1 output is identical to the ESLint 9.39.4 baseline — on both the app's real eslint-config-next config and an all-rules harness (1,229 findings, 18 rules). The single difference traces to an intentional unreleased master change, not this PR.

Since most reports of the ESLint 10 crash come through eslint-config-next (vercel/next.js#89764), I tested this branch (b73f110) against a production Next.js codebase to check output parity with the last release on real code, complementing the existing unit tests and edge-case review.

Setup: Next.js 16.3.0 / React 19.2.8 / TypeScript strict, flat config via eslint-config-next 16.2.12, Node 22.22.2. Branch installed via npm pack + npm overrides, verified to replace the copy nested under eslint-config-next. Two configs, each run on ESLint 9.39.4 + released 7.37.5 (baseline) and ESLint 10.8.1 + this branch: the app's own preset (61 files, 17 react/* rules), and a harness applying configs.flat.all with settings.react.version: "detect" over the TS/TSX sources (54 files) — chosen so React version detection, where the release crashes, runs on every rule.

Details:

  1. Control: ESLint 10.8.1 + released 7.37.5 crashes on both configs with the known TypeError: … contextOrFilename.getFilename is not a function.
  2. Preset run: completes, exit code and findings identical to baseline. For readers from the Next.js issue: the rest of the preset's plugin stack ran fine under ESLint 10 — this plugin was the only crash, so this PR alone unblocks that path.
  3. All-rules run: 17 of 18 firing rules identical in count and location. The one difference (react/react-in-jsx-scope, 189 → 0) is the unreleased master change gating the rule off for React >= 19 (on master at c99d3b2, before this PR). That gate calls testReactVersion, so the migrated version-detection path demonstrably resolves the React version correctly on real code — not just avoids crashing.
  4. Install: the widened peer range resolves alongside eslint@10 without --legacy-peer-deps; the release requires it.

Caveats: one codebase; TS-only sources; React 19; rules with zero findings in both runs are smoke-tested but not behaviorally compared; prop-types machinery largely unexercised. Offered as whole-codebase parity evidence alongside the unit tests and earlier edge-case review, not as a substitute for either.

tjarrier added a commit to Triathlon-Club-Nantais/data-triathlon that referenced this pull request Aug 17, 2026
ESLint 10 casse toutes les règles react/* : eslint-plugin-react (peer
« ^9.7 », tiré transitivement par eslint-config-next) appelle encore
context.getFilename(), retiré en ESLint 10. Le job frontend sortait en
code 2 dès le premier fichier :

    TypeError: Error while loading rule 'react/display-name':
      contextOrFilename.getFilename is not a function

Aucune version publiée ne corrige : eslint-plugin-react s'arrête à
7.37.5 et eslint-config-next 16.3.1 dépend toujours de « ^7.37.0 ». Le
correctif amont (jsx-eslint/eslint-plugin-react#4022) est encore ouvert.

Cette PR annule donc son propre bump et pose l'ignore à la place, pour
que Dependabot cesse de reproposer une montée non installable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tjarrier added a commit to Triathlon-Club-Nantais/data-triathlon that referenced this pull request Aug 18, 2026
ESLint 10 casse toutes les règles react/* : eslint-plugin-react (peer
« ^9.7 », tiré transitivement par eslint-config-next) appelle encore
context.getFilename(), retiré en ESLint 10. Le job frontend sortait en
code 2 dès le premier fichier :

    TypeError: Error while loading rule 'react/display-name':
      contextOrFilename.getFilename is not a function

Aucune version publiée ne corrige : eslint-plugin-react s'arrête à
7.37.5 et eslint-config-next 16.3.1 dépend toujours de « ^7.37.0 ». Le
correctif amont (jsx-eslint/eslint-plugin-react#4022) est encore ouvert.

Cette PR annule donc son propre bump et pose l'ignore à la place, pour
que Dependabot cesse de reproposer une montée non installable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tjarrier added a commit to Triathlon-Club-Nantais/data-triathlon that referenced this pull request Aug 18, 2026
ESLint 10 casse toutes les règles react/* : eslint-plugin-react (peer
« ^9.7 », tiré transitivement par eslint-config-next) appelle encore
context.getFilename(), retiré en ESLint 10. Le job frontend sortait en
code 2 dès le premier fichier :

    TypeError: Error while loading rule 'react/display-name':
      contextOrFilename.getFilename is not a function

Aucune version publiée ne corrige : eslint-plugin-react s'arrête à
7.37.5 et eslint-config-next 16.3.1 dépend toujours de « ^7.37.0 ». Le
correctif amont (jsx-eslint/eslint-plugin-react#4022) est encore ouvert.

Cette PR pose donc l'ignore, pour que Dependabot cesse de reproposer une
montée non installable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jimisola added a commit to Malmo-Skyttegille-Pistolsektionen/rotation_target that referenced this pull request Aug 20, 2026
eslint-plugin-react@7.37.5 is the only package in webapp/ that rejects
ESLint 10 (peer `eslint ... || ^9.7`), so the bump in the parent commit
cannot install. The peer range is accurate rather than conservative: with
an override forcing the install, the plugin throws on the first file --
`lib/util/version.js` calls `context.getFilename()`, removed in ESLint 10.
Upstream has had no release since 7.37.5 (2025-04-03) and the ESLint 10
compatibility PR (jsx-eslint/eslint-plugin-react#4022) is still open.

@eslint-react/eslint-plugin is maintained, ESLint-10 clean, and needs no
type-aware linting (its `recommended` and `recommended-typescript` presets
are identical). eslint-plugin-react-hooks stays the authority for the dozen
rules the two plugins both implement.

Three findings the new preset surfaced were worth acting on rather than
silencing: `<SettingsContext.Provider>` and `useContext` are the pre-React-19
spellings, and a ref was not named for what it is.

This is a deliberate lint-policy change, not part of the version bump, hence
its own commit.

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
@ternaus ternaus mentioned this pull request Aug 21, 2026
jimisola added a commit to Malmo-Skyttegille-Pistolsektionen/rotation_target that referenced this pull request Aug 21, 2026
eslint-plugin-react@7.37.5 is the only package in webapp/ that rejects
ESLint 10 (peer `eslint ... || ^9.7`), so the bump in the parent commit
cannot install. The peer range is accurate rather than conservative: with
an override forcing the install, the plugin throws on the first file --
`lib/util/version.js` calls `context.getFilename()`, removed in ESLint 10.
Upstream has had no release since 7.37.5 (2025-04-03) and the ESLint 10
compatibility PR (jsx-eslint/eslint-plugin-react#4022) is still open.

@eslint-react/eslint-plugin is maintained, ESLint-10 clean, and needs no
type-aware linting (its `recommended` and `recommended-typescript` presets
are identical). eslint-plugin-react-hooks stays the authority for the dozen
rules the two plugins both implement.

Three findings the new preset surfaced were worth acting on rather than
silencing: `<SettingsContext.Provider>` and `useContext` are the pre-React-19
spellings, and a ref was not named for what it is.

This is a deliberate lint-policy change, not part of the version bump, hence
its own commit.

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola added a commit to Malmo-Skyttegille-Pistolsektionen/rotation_target that referenced this pull request Aug 21, 2026
* chore(npm): update eslint monorepo to v10

* fix(webapp): replace eslint-plugin-react with @eslint-react

eslint-plugin-react@7.37.5 is the only package in webapp/ that rejects
ESLint 10 (peer `eslint ... || ^9.7`), so the bump in the parent commit
cannot install. The peer range is accurate rather than conservative: with
an override forcing the install, the plugin throws on the first file --
`lib/util/version.js` calls `context.getFilename()`, removed in ESLint 10.
Upstream has had no release since 7.37.5 (2025-04-03) and the ESLint 10
compatibility PR (jsx-eslint/eslint-plugin-react#4022) is still open.

@eslint-react/eslint-plugin is maintained, ESLint-10 clean, and needs no
type-aware linting (its `recommended` and `recommended-typescript` presets
are identical). eslint-plugin-react-hooks stays the authority for the dozen
rules the two plugins both implement.

Three findings the new preset surfaced were worth acting on rather than
silencing: `<SettingsContext.Provider>` and `useContext` are the pre-React-19
spellings, and a ref was not named for what it is.

This is a deliberate lint-policy change, not part of the version bump, hence
its own commit.

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>

---------

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola added a commit to Malmo-Skyttegille-Pistolsektionen/rotation_target that referenced this pull request Aug 22, 2026
* chore(npm): update eslint monorepo to v10

* fix(webapp): replace eslint-plugin-react with @eslint-react

eslint-plugin-react@7.37.5 is the only package in webapp/ that rejects
ESLint 10 (peer `eslint ... || ^9.7`), so the bump in the parent commit
cannot install. The peer range is accurate rather than conservative: with
an override forcing the install, the plugin throws on the first file --
`lib/util/version.js` calls `context.getFilename()`, removed in ESLint 10.
Upstream has had no release since 7.37.5 (2025-04-03) and the ESLint 10
compatibility PR (jsx-eslint/eslint-plugin-react#4022) is still open.

@eslint-react/eslint-plugin is maintained, ESLint-10 clean, and needs no
type-aware linting (its `recommended` and `recommended-typescript` presets
are identical). eslint-plugin-react-hooks stays the authority for the dozen
rules the two plugins both implement.

Three findings the new preset surfaced were worth acting on rather than
silencing: `<SettingsContext.Provider>` and `useContext` are the pre-React-19
spellings, and a ref was not named for what it is.

This is a deliberate lint-policy change, not part of the version bump, hence
its own commit.

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>

---------

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jimisola Laursen <jimisola@jimisola.com>
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.

ESLint v10 compatibility

7 participants