Skip to content

feat(linter): add setup-oxlint-bridge generator for ESLint/Oxlint coexistence#35114

Open
benpsnyder wants to merge 3 commits intonrwl:masterfrom
benpsnyder:feat/oxlint-bridge
Open

feat(linter): add setup-oxlint-bridge generator for ESLint/Oxlint coexistence#35114
benpsnyder wants to merge 3 commits intonrwl:masterfrom
benpsnyder:feat/oxlint-bridge

Conversation

@benpsnyder
Copy link
Copy Markdown
Contributor

@benpsnyder benpsnyder commented Apr 1, 2026

Current Behavior

When migrating from ESLint to Oxlint in an Nx workspace, there is no built-in way to make ESLint aware of which rules Oxlint already covers. Users must manually configure eslint-plugin-oxlint, set up JITI to load TypeScript-based oxlint.config.ts from ESLint's .mjs config, disable reportUnusedDisableDirectives, and use buildFromOxlintConfig() instead of the less precise flat/recommended preset. This is error-prone and undocumented in Nx.

Expected Behavior

A new generator nx g @nx/eslint:setup-oxlint-bridge automates the ESLint-side setup for Oxlint coexistence:

  • Installs eslint-plugin-oxlint and jiti as devDependencies
  • Injects the JITI bridge into eslint.config.mjs (or .cjs) so ESLint can load oxlint.config.ts at runtime
  • Adds reportUnusedDisableDirectives: 'off' to prevent false warnings from oxlint's eslint-disable comments
  • Appends ...oxlint.buildFromOxlintConfig(oxlintConfig) to precisely disable only the ESLint rules that oxlint already handles
  • Supports custom --oxlintConfigPath for non-standard config locations

This follows the community-standard pattern used by AnalogJS alpha and documented by eslint-plugin-oxlint. It complements the @nx/oxlint plugin work in #34838 and nx-labs#441 — those PRs build the Oxlint side, this PR builds the ESLint bridge for coexistence during migration.

Changes

  • packages/eslint/generators.json — Register setup-oxlint-bridge generator
  • packages/eslint/src/utils/versions.ts — Add eslintPluginOxlintVersion (^1.57.0) and jitiVersion (^2.6.1)
  • packages/eslint/src/generators/setup-oxlint-bridge/ — Generator implementation, schema, types, and 12 unit tests covering ESM/CJS injection, idempotency, error cases, and config preservation

Related Issue(s)

Complements #34838 and nx-labs#441
#35111

…xistence

Add a new generator `@nx/eslint:setup-oxlint-bridge` that injects the
JITI bridge into existing ESLint flat configs, enabling eslint-plugin-oxlint
to dynamically disable ESLint rules already handled by Oxlint.

The generator:
- Installs eslint-plugin-oxlint and jiti as devDependencies
- Injects JITI-based loading of oxlint.config.ts into eslint.config.mjs/cjs
- Adds reportUnusedDisableDirectives: 'off' to prevent false warnings
- Appends ...oxlint.buildFromOxlintConfig() for precise rule deduplication
- Supports both ESM and CJS flat config formats

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@benpsnyder benpsnyder requested a review from a team as a code owner April 1, 2026 04:08
@benpsnyder benpsnyder requested a review from AgentEnder April 1, 2026 04:08
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 1, 2026

Deploy Preview for nx-docs canceled.

Name Link
🔨 Latest commit d8e306d
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/69da8d339c68bd000809816e

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 1, 2026

Deploy Preview for nx-dev canceled.

Name Link
🔨 Latest commit d8e306d
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/69da8d33d02fc4000898e094

`const { createJiti } = require('jiti');`,
'',
`const jiti = createJiti(__filename);`,
`const oxlintConfig = jiti.import('${oxlintConfigPath}', { default: true });`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid JITI API usage in CJS path. The jiti.import() method does not accept { default: true } as a second parameter to extract the default export. This will cause a runtime error when the generator is run on a CJS ESLint config.

The ESM version (lines 115-117) correctly uses .default to extract the default export:

const oxlintConfig = (await jiti.import('${oxlintConfigPath}')).default;

The CJS version should match this pattern:

const oxlintConfig = jiti.import('${oxlintConfigPath}').default;

This bug will break the generator for any workspace using CommonJS ESLint configs (eslint.config.cjs).

Suggested change
`const oxlintConfig = jiti.import('${oxlintConfigPath}', { default: true });`,
`const oxlintConfig = jiti.import('${oxlintConfigPath}').default;`,

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@FrozenPandaz FrozenPandaz added the priority: low Low Priority (does not affect many people or not severely or has an easy workaround) label Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: low Low Priority (does not affect many people or not severely or has an easy workaround)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants