[lexical] Chore: Upgrade ESLint 8 to ESLint 10 with flat configuration#8287
Merged
etrepum merged 21 commits intofacebook:mainfrom Apr 7, 2026
Merged
[lexical] Chore: Upgrade ESLint 8 to ESLint 10 with flat configuration#8287etrepum merged 21 commits intofacebook:mainfrom
etrepum merged 21 commits intofacebook:mainfrom
Conversation
- Replace .eslintrc.js and .eslintignore with eslint.config.mjs (ESM flat config) - Upgrade eslint from ^8.57.0 to ^10.0.0 - Replace eslint-config-fbjs with @eslint/js recommended + inlined rules - Replace eslint-plugin-import with eslint-plugin-import-x (ESLint 10 compat) - Replace @typescript-eslint/parser + @typescript-eslint/eslint-plugin with unified typescript-eslint package (^8.58.0, supports ESLint 10) - Add @eslint/compat to wrap legacy plugins (react, header, sort-keys-fix, etc.) - Add globals package to replace env configuration - Upgrade eslint-plugin-react-hooks from ^4.6.2 to ^5.2.0 - Upgrade eslint-plugin-react from ^7.34.1 to ^7.37.5 - Upgrade eslint-config-prettier from ^9.1.0 to ^10.0.0 - Remove eslint-config-fbjs, eslint-plugin-babel, eslint-plugin-ft-flow (no longer needed - project has migrated from Flow to TypeScript) - Remove @babel/eslint-parser (default espree parser handles all JS files) - Fix no-imports-from-self rule to resolve monorepo root dynamically instead of using fragile relative path - Fix unnecessary escape characters in e2e test template literals - Remove unused eslint-disable directives - Update Node engine requirement to >=20.19.0 (ESLint 10 requirement) https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Convert all source files from CommonJS (require/module.exports) to ES modules (import/export) - Add "type": "module" and "exports" field to package.json - Remove separate rules/index.js barrel file, inline into src/index.js - Replace __dirname with import.meta.url + fileURLToPath - Use createRequire for loading CJS dependency (PackageMetadata.js) - Simplify no-optional-chaining rule to use context.sourceCode directly (ESLint 10 only, no legacy context.getSourceCode() fallback needed) - Update eslint.config.mjs to use ESM import for internal plugin https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
- Revert auto-removal of eslint-disable comments by eslint --fix
- Keep no-console strictly enabled (no {allow}), use per-line disables
- Add eslint-disable-next-line no-console to source files that
intentionally use console.warn/console.error
- Restore no-constant-condition with {checkLoops: 'all'} to match
ESLint 8 behavior (ESLint 10 defaults to allExceptWhileTrue)
- Add no-shadow override for TS files with ignoreTypeValueShadow: false
to match old config behavior
- Disable strict rule for .mjs files (irrelevant for ESM)
- Keep devtools/playground no-console: OFF override for pre-existing usage
https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
…quire ESM import can natively load CJS modules via direct file paths, bypassing the package.json exports map (which points to non-existent built .mjs files in development). This removes one of the two createRequire usages. https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
- Set reportUnusedDisableDirectives: 'off' to prevent eslint --fix from stripping existing eslint-disable comments for rules that may not be active in the current config (stale guards, @typescript-eslint type-checked rules, proactive disables) - Restore no-inner-declarations with blockScopedFunctions: 'disallow' to match ESLint 8 behavior (ESLint 10 defaults to 'allow') - Remove blanket no-console: OFF overrides for devtools/playground; use per-line eslint-disable-next-line no-console instead - Add eslint-disable-next-line no-console to all source files that intentionally use console.warn/console.error - Add react/jsx-key rule (from react recommended config) and fix two pre-existing missing key prop errors - Restore all eslint-disable directives that were incorrectly stripped by eslint --fix in earlier commits https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
…directive warnings
- Change no-console to [error, {allow: ['warn', 'error']}] to match
the prior effective behavior (console.log is flagged, warn/error are not)
- Remove no-constant-condition override, use ESLint 10 default
(checkLoops: 'allExceptWhileTrue' — while(true) is now allowed)
- Remove no-inner-declarations override, use ESLint 10 default
(blockScopedFunctions: 'allow' — block-scoped functions are now allowed)
- Set reportUnusedDisableDirectives back to 'warn' (ESLint 10 default)
- Remove now-stale eslint-disable directives for no-console (console.warn
and console.error are allowed), no-constant-condition (while(true) is
allowed), and no-inner-declarations (block-scoped functions are allowed)
https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
- Restore files from main where the only diff was empty lines left behind by eslint --fix stripping unused directives - Allow console.time and console.timeEnd in no-console config - Restore inline comments in isQuestionDotToken explaining espree compat - Remove now-unnecessary eslint-disable comments for console.time/timeEnd https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
These comments were left behind after the eslint-disable-next-line react-hooks/exhaustive-deps directives they accompanied were removed. https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
The e2e tests use prettier's HTML parser at runtime (prettifyHTML). pnpm was resolving prettier@3.6.2 for some packages due to stale lockfile entries, causing 'Missing visitor keys' errors in the HTML parser. Pin prettier to 3.8.1 via pnpm overrides to ensure a single version is used throughout the monorepo. https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
Refactor rules-of-lexical.js and getParentAssignmentName.js to pass type checking with ESLint 10's stricter types: - Add null guards for Node.parent (nullable in ESLint 10's type defs) - Cast Definition.node to Rule.Node to access the parent property - Revert @ts-nocheck additions https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
The published @lexical/eslint-plugin may still be used with ESLint 8 by external consumers, and the integration tests verify this. Restore the context.sourceCode || context.getSourceCode() fallback with a @ts-expect-error for the removed type. https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
This is an externally published package — keep the broad peer dep range to avoid breaking existing consumers on older ESLint versions. https://claude.ai/code/session_01DxtHyfC26VYrRm1YKsWyTP
zurfyx
approved these changes
Apr 7, 2026
Merged
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.
Description
The monorepo was using ESLint 8.57.0 with the legacy
.eslintrc.jsconfiguration format, which is no longer supported in ESLint 10. This PR migrates the entire ESLint setup to ESLint 10 with the modern flat configuration format, and upgrades related tooling.(authored with claude)
ESLint migration:
.eslintrc.jsand.eslintignorewitheslint.config.mjs(ESM flat config)eslintfrom^8.57.0to^10.0.0eslint-config-fbjswith@eslint/jsrecommended + inlined rules (fbjs is abandoned, last published July 2022, no flat config support)eslint-plugin-importwitheslint-plugin-import-x(ESLint 10 compatible)@typescript-eslint/parser+@typescript-eslint/eslint-pluginwith unifiedtypescript-eslintpackage (^8.58.0, explicit ESLint 10 support)@eslint/compatto wrap legacy plugins that use removed ESLint APIs (eslint-plugin-react,eslint-plugin-header,eslint-plugin-sort-keys-fix,eslint-plugin-no-function-declare-after-return)globalspackage to replaceenvconfigurationno-consoleto allowwarn,error,time,timeEnd(matching prior effective behavior — onlyconsole.logis flagged)no-constant-condition(while(true)allowed) andno-inner-declarations(block-scoped functions allowed)react/jsx-keyrule and fix two pre-existing missing key prop errorseslint-disabledirectives for rules whose defaults changed>=20.19.0(ESLint 10 requirement)ESLint plugin changes:
peerDependencies.eslintfrom>=7.31.0to>=9for@lexical/eslint-plugin-internal(private, monorepo only)@lexical/eslint-plugin-internalfrom CJS to ESMno-imports-from-selfrule to resolve monorepo root dynamically instead of using a fragile relative path that broke under pnpm's hardlink structurerules-of-lexical.jsandgetParentAssignmentName.jsto pass type checking with ESLint 10's stricterNode.parentnullabilitygetSourceCode()fallback inrules-of-lexical.jsfor ESLint 8 backwards compatibilityRuleTesterconfig in unit tests to flat config format@lexical/eslint-pluginby direct file path ineslint.config.mjs(bypasses package.json exports map which points to non-existent built files in development)Module system modernization:
.lintstagedrc.jsto.lintstagedrc.mjs(ESM)Dependency upgrades:
eslint-config-prettierfrom^9.1.0to^10.0.0eslint-plugin-reactfrom^7.34.1to^7.37.5eslint-plugin-react-hooksfrom^4.6.2to^5.2.0eslint-plugin-jsx-a11yfrom^6.8.0to^6.10.2eslint-plugin-no-only-testsfrom^3.1.0to^3.3.0eslint-plugin-simple-import-sortfrom^12.1.0to^13.0.0prettierfrom^3.6.2to^3.8.1(pinned via pnpm override)lint-stagedfrom^11.1.0to^16.0.0huskyfrom^7.0.1to^9.1.7Dependencies removed:
eslint-config-fbjs,eslint-plugin-babel,eslint-plugin-ft-flow,eslint-plugin-import,@typescript-eslint/parser,@typescript-eslint/eslint-plugin,@babel/eslint-parser,@types/prettierTest plan
pnpm run ci-checkpasses (TypeScript, Flow, Prettier, ESLint)pnpm run test-unit— all 104 test suites pass (2737 tests)pnpm run test-eslint-integration— all 6 integration tests pass (ESLint 8 legacy fixtures + ESLint 10 flat config fixtures)