Skip to content

chore: migrate to ESLint 10 - #2442

Open
r0b1n wants to merge 7 commits into
mainfrom
chore/eslint-9-bump
Open

r0b1n wants to merge 7 commits into
mainfrom
chore/eslint-9-bump

Conversation

@r0b1n

@r0b1n r0b1n commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Pull request type

Dependency changes (any modification to dependencies in package.json)


Description

Migrates the repo to ESLint 10. ESLint 9 is now marked as deprecated/unsupported on npm.

Two plugins blocked the upgrade, so they are replaced with maintained alternatives that support ESLint 10:

  • eslint-plugin-react → @eslint-react/eslint-plugin: no ESLint 10 support upstream yet (jsx-eslint/eslint-plugin-react#3977). Uses the recommended-typescript preset. Rules we set explicitly keep their severity. Hooks rules stay with eslint-plugin-react-hooks, and the duplicate eslint-react hooks rules are turned off. jsx-boolean-value is replaced by a no-restricted-syntax selector, which no longer auto-fixes.
  • eslint-plugin-import → eslint-plugin-import-x: same rules, maintained fork. Rules and settings move from import/ to import-x/, so new disable comments need the import-x/ prefix.

Other changes:

  • Bump eslint to 10.x and @eslint/js to 10.x in the shared configs, automation/run-e2e, automation/snapshot-generator and web-actions. Bump the related plugins, globals and prettier to their latest versions.
  • Drop @babel/eslint-parser from @mendix/pluggable-widgets-tools through a root override. Only the tools package's unused legacy eslintrc config uses it, and it doesn't support ESLint 10. This follows the existing overrides for that package's other eslint dependencies.
  • Fix findings from rules newly enabled by ESLint 10 and eslint-react:
    • preserve-caught-error: rethrown errors now pass { cause } (html-element-web, automation/utils).
    • no-useless-assignment in rich-text-web's Indent.ts.
    • createRef → useRef in image-cropper-web's editor preview.
    • An inline disable for Floating UI's recommended flushSync usage in datagrid-web.
  • Fix google-tag-web's useDojoOnNavigation. It mutated module state during render and called useEffect conditionally (react-hooks/globals error, already on main). Both now happen in one unconditional effect.
  • Remove leftovers:
    • the Cypress configs, which point to a module that no longer exists since e2e moved to Playwright
    • barcode-scanner's old cypress/ folder
    • the unused eslint-plugin-cypress
    • the .eslintrc* files, which ESLint 9 already ignored

Lint results (all 58 widget/module packages, before → after): errors 1 → 0. The existing warnings are unchanged. New warnings come from eslint-react's recommended rules (for example naming-convention-ref-name, no-array-index-key, jsx-no-children-prop, use-state). They're advisory and can be cleaned up or tuned in follow-ups.

Note on @eslint-react/eslint-plugin: it's actively maintained, gets about 2.4M weekly downloads and has been released since 2023. It is mostly a single-maintainer project and ships major versions often, so it's pinned with ~5.24.8.

What should be covered while testing?

  • pnpm lint passes across packages. The tests for datagrid-web, image-cropper-web, html-element-web and rich-text-web pass.
  • google-tag-web: page-change tracking (dojo onNavigation) still works in a Mendix app, and the "window.dojo is not found" message is still logged once when dojo is missing.

@r0b1n
r0b1n requested a review from a team as a code owner September 29, 2026 12:53
@github-actions

This comment has been minimized.

gjulivan
gjulivan previously approved these changes Oct 5, 2026
r0b1n added 7 commits October 8, 2026 17:04
… to latest

Stays within ESLint 9 — eslint-plugin-react's latest stable (7.37.5)
only declares peer support up to eslint ^9.7, so a jump to ESLint 10
is blocked until that plugin catches up.

Bumped: eslint, @eslint/js, typescript-eslint, eslint-plugin-jest,
eslint-plugin-react-hooks, globals, prettier.
…tier to latest

Same treatment as eslint-config-web-widgets: keep eslint/@eslint/js/globals/prettier
current within their existing major versions. Left prettier-plugin-packagejson on 2.x
(latest is 3.x, a separate major bump) and @prettier/plugin-xml unchanged (already latest).
…slint-react/eslint-plugin

eslint-plugin-react has no ESLint 10 support, which blocks the ESLint upgrade.
Hooks rules stay with eslint-plugin-react-hooks; the overlapping eslint-react
hooks rules are turned off. jsx-boolean-value is replaced by a no-restricted-syntax
selector. Fixes the two new errors: createRef in a function component
(image-cropper preview) and a Floating UI flushSync false positive (datagrid).
…slint-plugin-import-x

eslint-plugin-import does not support ESLint 10; import-x is a maintained fork
with the same rules and ESLint 10 support. Rules and settings move to the
import-x/ prefix; lint results are unchanged.
Bumps eslint to 10.x and @eslint/js to 10.x across shared configs, automation
and web-actions. Fixes findings from rules newly enabled in eslint:recommended
(preserve-caught-error, no-useless-assignment). Drops @babel/eslint-parser from
pluggable-widgets-tools, as it is only used by its unused legacy eslintrc config
and does not support ESLint 10.
…DojoOnNavigation

The hook reassigned a module-level flag during render and called useEffect
conditionally. Both now happen inside a single unconditional effect.
E2E runs on Playwright; the cypress configs pointed at a module that no longer
exists. The .eslintrc files were already ignored since ESLint 9 and are not
supported by ESLint 10. eslint-plugin-cypress was not used by any config.
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

AI Code Review

⚠️ Approved with suggestions — low-severity items only, safe to merge


What was reviewed

File Change
packages/shared/eslint-config-web-widgets/widget-ts.mjs Core ESLint config migration: eslint-plugin-react → @eslint-react, eslint-plugin-import → eslint-plugin-import-x
packages/shared/eslint-config-web-widgets/package.json Replaced eslint-plugin-react, eslint-plugin-import, eslint-plugin-cypress; added @eslint-react/eslint-plugin; bumped eslint to 10.x
packages/shared/prettier-config-web-widgets/package.json Bumped eslint to 10.x, globals, prettier
packages/pluggableWidgets/google-tag-web/src/utils.ts Fixed useDojoOnNavigation: moved conditional useEffect call and render-time mutation into a single unconditional useEffect
packages/pluggableWidgets/image-cropper-web/src/ImageCropper.editorPreview.tsx createRef → useRef in functional component
packages/pluggableWidgets/rich-text-web/src/extensions/Indent.ts no-useless-assignment fix: let + reassign → const ternary
packages/pluggableWidgets/rich-text-web/src/components/toolbars/Toolbar.tsx Updated disable comments from import/order → import-x/order
packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx Added @eslint-react/dom-no-flush-sync inline disable for Floating UI pattern
packages/pluggableWidgets/html-element-web/src/utils/props-utils.ts { cause: e } added to rethrown Error
automation/utils/src/{fetch,github,jira,package-info}.ts { cause: error } propagation on rethrown Errors
automation/run-e2e/lib/dev.mjs Comment: cypress bin → playwright bin
automation/run-e2e/package.json @eslint/js bumped to ^10.0.1
automation/snapshot-generator/package.json @eslint/js bumped
packages/modules/web-actions/package.json @eslint/js bumped
package.json Added @babel/eslint-parser root override to drop it from pluggable-widgets-tools
.npmrc Removed *cypress* hoisting pattern
Deleted files automation/scripts/.eslintrc.json, packages/modules/web-actions/.eslintrc.js, packages/shared/prettier-config-web-widgets/.eslintrc.json, all cypress.config.cjs and cypress/ folders for barcode-scanner/calendar/events/signature widgets

Skipped (out of scope): pnpm-lock.yaml


Findings

⚠️ Low — google-tag-web runtime bug fix has no CHANGELOG entry

File: packages/pluggableWidgets/google-tag-web/src/utils.ts
Note: The fix to useDojoOnNavigation is a genuine behavioral bug fix (conditional useEffect call and render-time mutation), not just a lint cleanup. Per repo convention, widget runtime changes require a CHANGELOG.md entry. The PR description clearly explains the fix, so the content is already written — it just needs to land in the changelog.

Fix: run pnpm -w changelog from within packages/pluggableWidgets/google-tag-web and add a Fixed entry describing that useDojoOnNavigation no longer calls hooks conditionally.


⚠️ Low — React config scope expanded from *.tsx to *.ts

File: packages/shared/eslint-config-web-widgets/widget-ts.mjs line 482
Note: The original eslint-plugin-react config targeted ["**/*.tsx", "**/*.jsx"]. The new @eslint-react config targets ["**/*.ts", "**/*.tsx"]. This means recommended-typescript rules now run on all .ts utility and helper files. Most rules are JSX-aware and will stay silent, but advisory rules like naming-convention/use-state, no-array-index-key, and hooks-extra/* could generate new warnings on non-component .ts files over time. Intentional or not, worth a comment in the config so reviewers understand the scope choice.


Positives

  • The conditional-useEffect fix in google-tag-web addresses a real hooks rules violation (react-hooks/rules-of-hooks error already on main) cleanly — one unconditional useEffect covers both the error-logging and the navigation-subscribe paths without restructuring the API.
  • createRef → useRef in the editor preview is exactly right: createRef in a functional component allocates a new ref object on every render; useRef returns the same object across renders.
  • { cause: error } propagation across all automation/utils rethrows improves debuggability with no risk — original message is preserved and the root cause is now accessible via .cause.
  • Dead Cypress infrastructure (configs, specs, .eslintrc files) is cleanly removed in one pass — no partial leftovers.
  • @eslint-react/eslint-plugin pinned with ~ (patch-only range) is the right call for a single-maintainer package that ships breaking changes in minor versions.
  • The @babel/eslint-parser root override approach (drop it entirely from pluggable-widgets-tools via pnpm override "-") is consistent with the existing pattern for that package's other ESLint deps.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants