refactor: migrate from ESLint to oxlint#716
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
💤 Files with no reviewable changes (1)
✅ Files skipped from review due to trivial changes (3)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughReplaces ESLint with Oxlint across the repo: adds Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.oxlintrc.json:
- Around line 3-15: The plugins array in .oxlintrc.json currently overwrites
Oxlint's defaults and omits the built-in ESLint and Oxc plugins so core ESLint
rules like "no-unreachable" are effectively disabled; update the "plugins" field
to include the default entries ("eslint" and "oxc") alongside the existing ones
(e.g., "react", "unicorn", "typescript", "node") so Oxlint will load ESLint core
rules and the explicit "no-unreachable" rule will take effect.
In `@package.json`:
- Around line 23-24: The workflow still calls the old script name "lint:eslint"
while package.json now defines "lint:oxlint"; either restore a compatibility
alias or update the workflow: add a new npm script "lint:eslint" that simply
runs the existing "lint:oxlint" (e.g., make "lint:eslint" invoke "npm run
lint:oxlint"), or edit the .github/workflows code-quality job to call "npm run
lint:oxlint" (replace any "lint:eslint" references) so both the CI and local
scripts stay in sync.
- Around line 23-24: The package.json script "lint:oxlint" currently runs
"oxlint --fix .", which causes the top-level "lint" entrypoint to auto-fix
files; change "lint:oxlint" to a read-only verification (e.g., "oxlint .") so
pnpm lint remains non-mutating, and add a separate fixer script (e.g.,
"lint:oxlint:fix" or "lint:fix") that runs "oxlint --fix ." for local developer
use; update the scripts keys "lint" and "lint:oxlint" (and add the fixer script
name you choose) accordingly so pre-push CI uses the read-only check and
developers can run the explicit fix script when needed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 7ad4e1d7-aac4-4a65-a0c0-0c4c372f815f
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
.oxlintrc.jsoneslint.config.tslefthook.ymlpackage.jsonprisma/seed/book.ts
💤 Files with no reviewable changes (1)
- eslint.config.ts
| "plugins": ["react", "unicorn", "typescript", "node"], | ||
| "jsPlugins": [ | ||
| "@tanstack/eslint-plugin-query", | ||
| "@tanstack/eslint-plugin-router", | ||
| "eslint-plugin-simple-import-sort", | ||
| "eslint-plugin-sonarjs", | ||
| "eslint-plugin-storybook" | ||
| ], | ||
| "categories": { | ||
| "correctness": "error" | ||
| }, | ||
| "rules": { | ||
| "no-unreachable": "error", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and inspect the .oxlintrc.json file
find . -name ".oxlintrc.json" -type fRepository: BearStudio/start-ui-web
Length of output: 83
🏁 Script executed:
# Check if there's any documentation or config files related to oxlint
git ls-files | grep -i oxlintRepository: BearStudio/start-ui-web
Length of output: 81
🌐 Web query:
oxlint default plugins configuration eslint oxc
💡 Result:
Oxlint has built-in “plugins” (named rule groups, mostly ports of popular ESLint plugin rule sets). By default, these built-in plugins are enabled: eslint, typescript, unicorn, and oxc. Others (e.g. react, import, jsx-a11y, jest, nextjs, etc.) are off by default. [1]
Configure default vs extra plugins
-
Config file (
.oxlintrc.jsonoroxlint.config.ts)- Using the
pluginsfield overwrites the default plugin set, so you must list everything you want enabled (including defaults you want to keep). [2][1] - Example: enable
reactandimportwhile keeping defaults:{ "plugins": ["eslint", "typescript", "unicorn", "oxc", "react", "import"] } - Disable all default plugins:
[1]
{ "plugins": [] }
- Using the
-
CLI
- Enable a plugin:
oxlint --import-plugin(similar flags exist per plugin). [1] - Disable a default plugin:
oxlint --disable-unicorn-plugin(only works for plugins that are on by default). [1]
- Enable a plugin:
ESLint naming note
When configuring rules, Oxlint uses ESLint-like namespacing (e.g. eslint/no-unused-vars, oxc/...), and if an ESLint core rule name is unique you can omit the eslint/ prefix (e.g. no-console == eslint/no-console). [2]
Sources: Oxlint built-in plugins + defaults [1], Oxlint config behavior (plugins overwrites defaults) and rule naming [2].
[1] https://oxc.rs/docs/guide/usage/linter/plugins
[2] https://oxc.rs/docs/guide/usage/linter/config.html
🌐 Web query:
oxlint plugins config override defaults no-unreachable rule
💡 Result:
pluginsdoes not merge with Oxlint’s defaults — it overwrites the default plugin set. So if you addplugins, you must list every plugin you want enabled (including the default ones). (oxc.rs)To disable all default plugins:{ "plugins": ["eslint", "typescript", "unicorn", "oxc", "import"] }{ "plugins": [] } ``` ([oxc.rs](https://oxc.rs/docs/guide/usage/linter/plugins.html))- Override the
no-unreachablerule explicitly inrules(this is independent ofplugins, since it’s an ESLint-core rule in Oxlint’seslintplugin). (oxc.rs)
Enable:Disable/override:{ "rules": { "no-unreachable": "error" } }{ "rules": { "no-unreachable": "off" } } ``` ([oxc.rs](https://oxc.rs/docs/guide/usage/linter/config))
Citations:
- 1: https://oxc.rs/docs/guide/usage/linter/plugins.html
- 2: https://oxc.rs/docs/guide/usage/linter/plugins.html
- 3: https://oxc.rs/docs/guide/usage/linter/config
- 4: https://oxc.rs/docs/guide/usage/linter/config
🏁 Script executed:
cat .oxlintrc.jsonRepository: BearStudio/start-ui-web
Length of output: 3111
🌐 Web query:
oxlint rule disabled plugin configuration no-unreachable not in plugins list
💡 Result:
That error happens when your config overrides plugins and the rule you’re trying to disable belongs to a plugin you didn’t include.
In Oxlint, no-unreachable is an ESLint core rule, provided by the built-in eslint plugin. The eslint plugin is default = yes, but as soon as you set plugins, you overwrite the defaults—so eslint may no longer be enabled. [1], [2]
Fix options
Option A (recommended): include eslint in your plugins list
{
"plugins": ["eslint", "typescript", "unicorn", "oxc"],
"rules": {
"no-unreachable": "off"
}
}(Include whatever other plugins you actually use.) [1], [2]
Option B: don’t set plugins at all (keep default plugins), and just disable the rule:
{
"rules": {
"no-unreachable": "off"
}
}[1], [2]
Option C: explicitly namespace it
{
"plugins": ["eslint"],
"rules": {
"eslint/no-unreachable": "off"
}
}[1], [2]
Sources: Oxlint configuration docs [1] and built-in plugins docs (shows eslint is a default plugin and that plugins overwrites defaults) [2].
🌐 Web query:
oxlint how to use eslint plugin rules explicit rule configuration
💡 Result:
To use Oxlint with ESLint-style plugin rules and explicitly configure which rules are on, you do two things in your Oxlint config (.oxlintrc.json or oxlint.config.ts):
- Load the plugin (native Rust plugin via
plugins, or JS/ESLint plugin viajsPlugins) - Explicitly enable rules under
rulesusing thepluginName/ruleNamekey format
A) Native (Rust) plugins: plugins + explicit rules
// .oxlintrc.json
{
"plugins": ["typescript", "unicorn", "oxc"],
"rules": {
"typescript/no-explicit-any": "error",
"unicorn/filename-case": "warn"
}
}Oxlint’s plugins list controls which built-in rule namespaces are available; you still turn rules on/off explicitly in rules. [1]
B) Use an actual ESLint plugin: jsPlugins + explicit rules
// .oxlintrc.json
{
"jsPlugins": ["eslint-plugin-playwright"],
"rules": {
"playwright/no-focused-test": "error"
}
}JS plugins are declared in jsPlugins, and then you enable their rules in rules using pluginName/ruleName. [2]
C) If the plugin name is “reserved”, alias it (avoids collisions with native plugins)
Some plugin names can’t be used directly for JS plugins because Oxlint implements those natively; in that case, give the JS plugin a custom name and reference rules via that alias: [1][3]
{
"plugins": ["import"],
"jsPlugins": [{ "name": "import-js", "specifier": "eslint-plugin-import" }],
"rules": {
"import/no-cycle": "error",
"import-js/no-unresolved": "warn"
}
}Sources: Oxlint configuration (plugins/jsPlugins/overrides) [1], Oxlint JS plugins usage [2], Oxlint config file reference (reserved names + aliasing example) [3].
Restore the default eslint and oxc plugins to enable built-in ESLint rules.
The plugins field overwrites Oxlint's default plugins (eslint, typescript, unicorn, oxc), and the current config omits eslint and oxc. This disables all ESLint core rules, including no-unreachable—the explicit configuration of that rule in the rules section will not take effect without the eslint plugin enabled. Restore the missing defaults to restore ESLint rule coverage:
Suggested change
- "plugins": ["react", "unicorn", "typescript", "node"],
+ "plugins": ["eslint", "oxc", "react", "unicorn", "typescript", "node"],🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.oxlintrc.json around lines 3 - 15, The plugins array in .oxlintrc.json
currently overwrites Oxlint's defaults and omits the built-in ESLint and Oxc
plugins so core ESLint rules like "no-unreachable" are effectively disabled;
update the "plugins" field to include the default entries ("eslint" and "oxc")
alongside the existing ones (e.g., "react", "unicorn", "typescript", "node") so
Oxlint will load ESLint core rules and the explicit "no-unreachable" rule will
take effect.
- Replace eslint.config.ts with .oxlintrc.json using oxlint's native react/unicorn/typescript/node plugins and jsPlugins for @tanstack/eslint-plugin-query, @tanstack/eslint-plugin-router, eslint-plugin-simple-import-sort, eslint-plugin-sonarjs, and eslint-plugin-storybook - Remove ESLint-only packages: @eslint-react/eslint-plugin and its sub-plugins, eslint-plugin-unicorn - Add --fix flag to lint:oxlint script and lefthook pre-commit oxlint command
246f6f6 to
33ee5e5
Compare
|



Summary
eslint.config.tswith.oxlintrc.jsonusing oxlint's nativereact,unicorn,typescript, andnodeplugins, plusjsPluginsfor ESLint plugins without native oxlint equivalents@eslint-react/eslint-pluginand sub-plugins,eslint-plugin-unicorn)--fixflag tolint:oxlintscript and lefthook pre-commitoxlintcommandjsPlugins used
@tanstack/eslint-plugin-query@tanstack/eslint-plugin-routereslint-plugin-simple-import-sorteslint-plugin-sonarjseslint-plugin-storybookNotes
sonarjs.configs.recommendedis not replicated — only the 3 explicitly configured rules are kept (cognitive-complexity,prefer-immediate-return,todo-tag). Broad correctness coverage is handled by oxlint's nativecorrectnesscategory.no-restricted-syntax(blocking directimport.meta.envaccess) has no oxlint equivalent and was dropped.Summary by CodeRabbit