From 671b8064f98d36cfd0c6bd1ced40c447b7b19407 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:51:59 +0000 Subject: [PATCH 1/4] linter: introduce `oxlint-plugin-eslint` package Co-Authored-By: overlookmotel <557937+overlookmotel@users.noreply.github.com> --- .github/workflows/release_apps.yml | 8 +++ apps/oxlint/.gitignore | 2 + apps/oxlint/scripts/build.ts | 19 +++++- apps/oxlint/scripts/generate-plugin-eslint.ts | 67 +++++++++++++++++++ apps/oxlint/src-js/plugin-eslint/index.ts | 8 +++ apps/oxlint/tsdown.config.ts | 43 ++++++++++++ npm/oxlint-plugin-eslint/CHANGELOG.md | 3 + npm/oxlint-plugin-eslint/README.md | 39 +++++++++++ npm/oxlint-plugin-eslint/package.json | 47 +++++++++++++ oxc_release.toml | 1 + pnpm-lock.yaml | 6 ++ 11 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 apps/oxlint/scripts/generate-plugin-eslint.ts create mode 100644 apps/oxlint/src-js/plugin-eslint/index.ts create mode 100644 npm/oxlint-plugin-eslint/CHANGELOG.md create mode 100644 npm/oxlint-plugin-eslint/README.md create mode 100644 npm/oxlint-plugin-eslint/package.json diff --git a/.github/workflows/release_apps.yml b/.github/workflows/release_apps.yml index 4d4cb178c4186..0c4a1164e2767 100644 --- a/.github/workflows/release_apps.yml +++ b/.github/workflows/release_apps.yml @@ -274,6 +274,7 @@ jobs: env: package_path: npm/oxlint plugins_package_path: npm/oxlint-plugins + plugin_eslint_package_path: npm/oxlint-plugin-eslint npm_dir: npm/oxlint-release PUBLISH_FLAGS: "--provenance --access public --no-git-checks" steps: @@ -303,12 +304,17 @@ jobs: run: | cp apps/oxlint/dist-pkg-plugins/* ${plugins_package_path}/ + - name: Copy dist files to oxlint-plugin-eslint npm package + run: | + cp -r apps/oxlint/dist-pkg-plugin-eslint/. ${plugin_eslint_package_path}/ + - run: npm install -g npm@latest # For trusted publishing support - name: Check Publish run: | node .github/scripts/check-npm-packages.js "${npm_dir}/*" "${package_path}" node .github/scripts/check-npm-packages.js "${plugins_package_path}" + node .github/scripts/check-npm-packages.js "${plugin_eslint_package_path}" - name: Trusted Publish run: | @@ -319,6 +325,8 @@ jobs: pnpm publish ${package_path}/ ${PUBLISH_FLAGS} # Publish `@oxlint/plugins` package pnpm publish ${plugins_package_path}/ ${PUBLISH_FLAGS} + # Publish `oxlint-plugin-eslint` package + pnpm publish ${plugin_eslint_package_path}/ ${PUBLISH_FLAGS} build-oxfmt: needs: check diff --git a/apps/oxlint/.gitignore b/apps/oxlint/.gitignore index 8b33a8b91eb50..e1e1120765b11 100644 --- a/apps/oxlint/.gitignore +++ b/apps/oxlint/.gitignore @@ -1,4 +1,6 @@ /node_modules/ /dist/ /dist-pkg-plugins/ +/dist-pkg-plugin-eslint/ +/src-js/generated/plugin-eslint/ *.node diff --git a/apps/oxlint/scripts/build.ts b/apps/oxlint/scripts/build.ts index d47b5afa9c627..16741e60dad5a 100755 --- a/apps/oxlint/scripts/build.ts +++ b/apps/oxlint/scripts/build.ts @@ -7,12 +7,25 @@ import { join } from "node:path"; const oxlintDirPath = join(import.meta.dirname, ".."), srcDirPath = join(oxlintDirPath, "src-js"), distDirPath = join(oxlintDirPath, "dist"), - distPkgPluginsDirPath = join(oxlintDirPath, "dist-pkg-plugins"); + distPkgPluginsDirPath = join(oxlintDirPath, "dist-pkg-plugins"), + distPkgPluginEslintDirPath = join(oxlintDirPath, "dist-pkg-plugin-eslint"), + generatedPluginEslintDirPath = join(oxlintDirPath, "src-js", "generated", "plugin-eslint"); // Delete `dist-pkg-plugins` directory console.log("Deleting `dist-pkg-plugins` directory..."); rmSync(distPkgPluginsDirPath, { recursive: true, force: true }); +// Delete `dist-pkg-plugin-eslint` directory +console.log("Deleting `dist-pkg-plugin-eslint` directory..."); +rmSync(distPkgPluginEslintDirPath, { recursive: true, force: true }); + +// Generate plugin-eslint files +console.log("Generating plugin-eslint files..."); +execSync("node scripts/generate-plugin-eslint.ts", { + stdio: "inherit", + cwd: oxlintDirPath, +}); + // Build with tsdown console.log("Building with tsdown..."); execSync("pnpm tsdown", { stdio: "inherit", cwd: oxlintDirPath }); @@ -21,6 +34,10 @@ execSync("pnpm tsdown", { stdio: "inherit", cwd: oxlintDirPath }); console.log("Deleting cli.d.ts..."); rmSync(join(distDirPath, "cli.d.ts")); +// Delete generated `plugin-eslint` directory (no longer needed after build) +console.log("Deleting generated `plugin-eslint` directory..."); +rmSync(generatedPluginEslintDirPath, { recursive: true, force: true }); + // Copy native `.node` files from `src-js` console.log("Copying `.node` files..."); for (const filename of readdirSync(srcDirPath)) { diff --git a/apps/oxlint/scripts/generate-plugin-eslint.ts b/apps/oxlint/scripts/generate-plugin-eslint.ts new file mode 100644 index 0000000000000..b0650b8b89074 --- /dev/null +++ b/apps/oxlint/scripts/generate-plugin-eslint.ts @@ -0,0 +1,67 @@ +// oxlint-disable no-console + +import { readdirSync, mkdirSync, writeFileSync } from "node:fs"; +import { join, basename } from "node:path"; +import { createRequire } from "node:module"; + +const require = createRequire(import.meta.url); + +const oxlintDirPath = join(import.meta.dirname, ".."); +const eslintRulesDir = join(require.resolve("eslint/package.json"), "..", "lib", "rules"); +const generatedDirPath = join(oxlintDirPath, "src-js", "generated", "plugin-eslint"); +const generatedRulesDirPath = join(generatedDirPath, "rules"); + +// Get all ESLint rule names (exclude index.js which is the registry, not a rule) +const ruleNames = readdirSync(eslintRulesDir) + .filter((f) => f.endsWith(".js") && f !== "index.js") + .map((f) => basename(f, ".js")) + .sort(); + +console.log(`Found ${ruleNames.length} ESLint rules`); + +// Create generated directories +mkdirSync(generatedRulesDirPath, { recursive: true }); + +// Generate a CJS wrapper file for each rule. +// Uses createRequire with eslint's package.json path to bypass ESLint 9's exports map restrictions +// (which block access to `eslint/lib/rules/*` from outside the package). +// createRequire(path) creates a require that resolves relative paths from `path`'s directory, +// so `./lib/rules/...` resolves to `/lib/rules/...`. +for (const ruleName of ruleNames) { + const content = [ + `const { createRequire } = require("node:module");`, + `// createRequire resolves relative paths from eslint's package root, bypassing its exports map.`, + `const _require = createRequire(require.resolve("eslint/package.json"));`, + `module.exports = _require("./lib/rules/${ruleName}.js");`, + ``, + ].join("\n"); + writeFileSync(join(generatedRulesDirPath, `${ruleName}.cjs`), content); +} + +// Generate the plugin rules index (ESM with lazy getters) +const indexLines = [ + `import { createRequire } from "node:module";`, + `const require = createRequire(import.meta.url);`, + ``, + `export default {`, +]; +for (const ruleName of ruleNames) { + indexLines.push( + ` get ${JSON.stringify(ruleName)}() { return require("./rules/${ruleName}.cjs"); },`, + ); +} +indexLines.push(`};`, ``); + +writeFileSync(join(generatedDirPath, "index.js"), indexLines.join("\n")); + +// Generate the rule_names.ts file for use in tsdown config +const ruleNamesLines = [ + `export default [`, + ...ruleNames.map((name) => ` ${JSON.stringify(name)},`), + `] as const;`, + ``, +]; + +writeFileSync(join(generatedDirPath, "rule_names.ts"), ruleNamesLines.join("\n")); + +console.log("Generated plugin-eslint files."); diff --git a/apps/oxlint/src-js/plugin-eslint/index.ts b/apps/oxlint/src-js/plugin-eslint/index.ts new file mode 100644 index 0000000000000..02b10232c7a63 --- /dev/null +++ b/apps/oxlint/src-js/plugin-eslint/index.ts @@ -0,0 +1,8 @@ +import rules from "../generated/plugin-eslint/index.js"; + +export default { + meta: { + name: "eslint-js", + }, + rules, +}; diff --git a/apps/oxlint/tsdown.config.ts b/apps/oxlint/tsdown.config.ts index 6bed83260437c..22264ffa49c79 100644 --- a/apps/oxlint/tsdown.config.ts +++ b/apps/oxlint/tsdown.config.ts @@ -4,6 +4,7 @@ import { defineConfig } from "tsdown"; import { parseSync, Visitor } from "oxc-parser"; import type { Plugin } from "rolldown"; +import ruleNames from "./src-js/generated/plugin-eslint/rule_names.ts"; const { env } = process; const isEnabled = (env: string | undefined) => env === "true" || env === "1"; @@ -63,6 +64,26 @@ const pluginsPkgConfig = defineConfig({ define: definedGlobals, }); +// Build entries for `oxlint-plugin-eslint` rule files. +// Each rule is a separate CJS file, lazy-loaded on demand. +const pluginEslintRulesEntry: Record = {}; +for (const ruleName of ruleNames) { + pluginEslintRulesEntry[`rules/${ruleName}`] = + `src-js/generated/plugin-eslint/rules/${ruleName}.cjs`; +} + +// Base config for `oxlint-plugin-eslint` package. +// "node12" target to match `engines` field of last ESLint 8 release (8.57.1). +const pluginEslintPkgConfig = defineConfig({ + ...commonConfig, + outDir: "dist-pkg-plugin-eslint", + // `build.ts` deletes the directory before TSDown runs. + // This allows generating the ESM and CommonJS builds in the same directory. + clean: false, + target: "node12", + external: ["eslint", /^eslint\//], +}); + // Plugins. // Only remove debug assertions in release build. const plugins = [createReplaceGlobalsPlugin()]; @@ -103,6 +124,28 @@ export default defineConfig([ format: "commonjs", dts: false, }, + + // `oxlint-plugin-eslint` package - main entry ESM. + { + ...pluginEslintPkgConfig, + entry: { index: "src-js/plugin-eslint/index.ts" }, + format: "esm", + dts: true, + }, + // `oxlint-plugin-eslint` package - main entry CJS. + { + ...pluginEslintPkgConfig, + entry: { index: "src-js/plugin-eslint/index.ts" }, + format: "commonjs", + dts: false, + }, + // `oxlint-plugin-eslint` package - individual rule files CJS. + { + ...pluginEslintPkgConfig, + entry: pluginEslintRulesEntry, + format: "commonjs", + dts: false, + }, ]); /** diff --git a/npm/oxlint-plugin-eslint/CHANGELOG.md b/npm/oxlint-plugin-eslint/CHANGELOG.md new file mode 100644 index 0000000000000..e30b69168493c --- /dev/null +++ b/npm/oxlint-plugin-eslint/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +All notable changes to this package will be documented in this file. diff --git a/npm/oxlint-plugin-eslint/README.md b/npm/oxlint-plugin-eslint/README.md new file mode 100644 index 0000000000000..344360d3b634d --- /dev/null +++ b/npm/oxlint-plugin-eslint/README.md @@ -0,0 +1,39 @@ +# oxlint-plugin-eslint + +ESLint's built-in rules as an Oxlint plugin. + +This package exports all of ESLint's built-in rules as a JS plugin that Oxlint users can use. + +## Usage + +Install the package: + +```sh +npm install --save-dev oxlint-plugin-eslint eslint +``` + +Add to your Oxlint config: + +```json +{ + "jsPlugins": ["oxlint-plugin-eslint"], + "rules": { + "eslint-js/no-unused-vars": "error" + } +} +``` + +The plugin's `meta.name` is `eslint-js`, so all rules are prefixed with `eslint-js/`. + +## Why? + +This package is useful when: + +1. You want to use an ESLint rule that Oxlint doesn't implement natively yet. +2. You encounter a bug in Oxlint's native implementation of an ESLint rule and need a temporary fix. + +All rules from ESLint are included, even those that Oxlint already implements natively. You can switch to the JS plugin version as a "hotfix" if needed. + +## License + +MIT diff --git a/npm/oxlint-plugin-eslint/package.json b/npm/oxlint-plugin-eslint/package.json new file mode 100644 index 0000000000000..2bcbf499aa7ef --- /dev/null +++ b/npm/oxlint-plugin-eslint/package.json @@ -0,0 +1,47 @@ +{ + "name": "oxlint-plugin-eslint", + "version": "1.50.0", + "description": "ESLint's built-in rules as an Oxlint plugin", + "keywords": [ + "eslint", + "linter", + "oxlint", + "plugin" + ], + "homepage": "https://oxc.rs/docs/guide/usage/linter/js-plugins", + "bugs": "https://github.com/oxc-project/oxc/issues", + "license": "MIT", + "author": "Boshen and oxc contributors", + "repository": { + "type": "git", + "url": "git+https://github.com/oxc-project/oxc.git", + "directory": "npm/oxlint-plugin-eslint" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "files": [ + "index.js", + "index.cjs", + "index.d.ts", + "rules", + "README.md" + ], + "type": "module", + "main": "index.js", + "types": "index.d.ts", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./index.js", + "require": "./index.cjs", + "default": "./index.js" + } + }, + "peerDependencies": { + "eslint": ">=8.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } +} diff --git a/oxc_release.toml b/oxc_release.toml index b2fc598852416..7ecfa2259b077 100644 --- a/oxc_release.toml +++ b/oxc_release.toml @@ -21,6 +21,7 @@ versioned_files = [ "apps/oxlint/package.json", "crates/oxc_linter/Cargo.toml", "npm/oxlint/package.json", + "npm/oxlint-plugin-eslint/package.json", "npm/oxlint-plugins/package.json", ] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9542efc9ae646..0168a004d1395 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -284,6 +284,12 @@ importers: specifier: '>=0.15.0' version: 0.16.0 + npm/oxlint-plugin-eslint: + dependencies: + eslint: + specifier: '>=8.0.0' + version: 9.39.2(jiti@2.6.1) + npm/oxlint-plugins: {} npm/runtime: {} From 082df3c885f284fc459dce096f52178d20188c2c Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Tue, 3 Mar 2026 02:43:41 +0000 Subject: [PATCH 2/4] fix --- apps/oxlint/scripts/build.ts | 7 +----- apps/oxlint/scripts/generate-plugin-eslint.ts | 24 ++++++------------- apps/oxlint/src-js/plugin-eslint/index.ts | 2 +- apps/oxlint/tsdown.config.ts | 23 +++++------------- 4 files changed, 15 insertions(+), 41 deletions(-) diff --git a/apps/oxlint/scripts/build.ts b/apps/oxlint/scripts/build.ts index 16741e60dad5a..a7eb1e5a89f38 100755 --- a/apps/oxlint/scripts/build.ts +++ b/apps/oxlint/scripts/build.ts @@ -8,8 +8,7 @@ const oxlintDirPath = join(import.meta.dirname, ".."), srcDirPath = join(oxlintDirPath, "src-js"), distDirPath = join(oxlintDirPath, "dist"), distPkgPluginsDirPath = join(oxlintDirPath, "dist-pkg-plugins"), - distPkgPluginEslintDirPath = join(oxlintDirPath, "dist-pkg-plugin-eslint"), - generatedPluginEslintDirPath = join(oxlintDirPath, "src-js", "generated", "plugin-eslint"); + distPkgPluginEslintDirPath = join(oxlintDirPath, "dist-pkg-plugin-eslint"); // Delete `dist-pkg-plugins` directory console.log("Deleting `dist-pkg-plugins` directory..."); @@ -34,10 +33,6 @@ execSync("pnpm tsdown", { stdio: "inherit", cwd: oxlintDirPath }); console.log("Deleting cli.d.ts..."); rmSync(join(distDirPath, "cli.d.ts")); -// Delete generated `plugin-eslint` directory (no longer needed after build) -console.log("Deleting generated `plugin-eslint` directory..."); -rmSync(generatedPluginEslintDirPath, { recursive: true, force: true }); - // Copy native `.node` files from `src-js` console.log("Copying `.node` files..."); for (const filename of readdirSync(srcDirPath)) { diff --git a/apps/oxlint/scripts/generate-plugin-eslint.ts b/apps/oxlint/scripts/generate-plugin-eslint.ts index b0650b8b89074..89129e88a046b 100644 --- a/apps/oxlint/scripts/generate-plugin-eslint.ts +++ b/apps/oxlint/scripts/generate-plugin-eslint.ts @@ -1,5 +1,3 @@ -// oxlint-disable no-console - import { readdirSync, mkdirSync, writeFileSync } from "node:fs"; import { join, basename } from "node:path"; import { createRequire } from "node:module"; @@ -7,8 +5,8 @@ import { createRequire } from "node:module"; const require = createRequire(import.meta.url); const oxlintDirPath = join(import.meta.dirname, ".."); -const eslintRulesDir = join(require.resolve("eslint/package.json"), "..", "lib", "rules"); -const generatedDirPath = join(oxlintDirPath, "src-js", "generated", "plugin-eslint"); +const eslintRulesDir = join(require.resolve("eslint/package.json"), "../lib/rules"); +const generatedDirPath = join(oxlintDirPath, "src-js/generated/plugin-eslint"); const generatedRulesDirPath = join(generatedDirPath, "rules"); // Get all ESLint rule names (exclude index.js which is the registry, not a rule) @@ -17,24 +15,15 @@ const ruleNames = readdirSync(eslintRulesDir) .map((f) => basename(f, ".js")) .sort(); +// oxlint-disable-next-line no-console console.log(`Found ${ruleNames.length} ESLint rules`); // Create generated directories mkdirSync(generatedRulesDirPath, { recursive: true }); -// Generate a CJS wrapper file for each rule. -// Uses createRequire with eslint's package.json path to bypass ESLint 9's exports map restrictions -// (which block access to `eslint/lib/rules/*` from outside the package). -// createRequire(path) creates a require that resolves relative paths from `path`'s directory, -// so `./lib/rules/...` resolves to `/lib/rules/...`. +// Generate a CJS wrapper file for each rule for (const ruleName of ruleNames) { - const content = [ - `const { createRequire } = require("node:module");`, - `// createRequire resolves relative paths from eslint's package root, bypassing its exports map.`, - `const _require = createRequire(require.resolve("eslint/package.json"));`, - `module.exports = _require("./lib/rules/${ruleName}.js");`, - ``, - ].join("\n"); + const content = `module.exports = require("../../../../node_modules/eslint/lib/rules/${ruleName}.js");`; writeFileSync(join(generatedRulesDirPath, `${ruleName}.cjs`), content); } @@ -52,7 +41,7 @@ for (const ruleName of ruleNames) { } indexLines.push(`};`, ``); -writeFileSync(join(generatedDirPath, "index.js"), indexLines.join("\n")); +writeFileSync(join(generatedDirPath, "index.ts"), indexLines.join("\n")); // Generate the rule_names.ts file for use in tsdown config const ruleNamesLines = [ @@ -64,4 +53,5 @@ const ruleNamesLines = [ writeFileSync(join(generatedDirPath, "rule_names.ts"), ruleNamesLines.join("\n")); +// oxlint-disable-next-line no-console console.log("Generated plugin-eslint files."); diff --git a/apps/oxlint/src-js/plugin-eslint/index.ts b/apps/oxlint/src-js/plugin-eslint/index.ts index 02b10232c7a63..d0665a1d76e80 100644 --- a/apps/oxlint/src-js/plugin-eslint/index.ts +++ b/apps/oxlint/src-js/plugin-eslint/index.ts @@ -1,4 +1,4 @@ -import rules from "../generated/plugin-eslint/index.js"; +import rules from "../generated/plugin-eslint/index.ts"; export default { meta: { diff --git a/apps/oxlint/tsdown.config.ts b/apps/oxlint/tsdown.config.ts index 22264ffa49c79..be3d5219de016 100644 --- a/apps/oxlint/tsdown.config.ts +++ b/apps/oxlint/tsdown.config.ts @@ -2,9 +2,9 @@ import fs from "node:fs"; import { join as pathJoin, relative as pathRelative, dirname } from "node:path"; import { defineConfig } from "tsdown"; import { parseSync, Visitor } from "oxc-parser"; +import ruleNames from "./src-js/generated/plugin-eslint/rule_names.ts"; import type { Plugin } from "rolldown"; -import ruleNames from "./src-js/generated/plugin-eslint/rule_names.ts"; const { env } = process; const isEnabled = (env: string | undefined) => env === "true" || env === "1"; @@ -66,9 +66,9 @@ const pluginsPkgConfig = defineConfig({ // Build entries for `oxlint-plugin-eslint` rule files. // Each rule is a separate CJS file, lazy-loaded on demand. -const pluginEslintRulesEntry: Record = {}; +const pluginEslintRulesEntries: Record = {}; for (const ruleName of ruleNames) { - pluginEslintRulesEntry[`rules/${ruleName}`] = + pluginEslintRulesEntries[`rules/${ruleName}`] = `src-js/generated/plugin-eslint/rules/${ruleName}.cjs`; } @@ -80,8 +80,7 @@ const pluginEslintPkgConfig = defineConfig({ // `build.ts` deletes the directory before TSDown runs. // This allows generating the ESM and CommonJS builds in the same directory. clean: false, - target: "node12", - external: ["eslint", /^eslint\//], + dts: false, }); // Plugins. @@ -125,26 +124,16 @@ export default defineConfig([ dts: false, }, - // `oxlint-plugin-eslint` package - main entry ESM. + // `oxlint-plugin-eslint` package { ...pluginEslintPkgConfig, entry: { index: "src-js/plugin-eslint/index.ts" }, format: "esm", - dts: true, }, - // `oxlint-plugin-eslint` package - main entry CJS. { ...pluginEslintPkgConfig, - entry: { index: "src-js/plugin-eslint/index.ts" }, + entry: pluginEslintRulesEntries, format: "commonjs", - dts: false, - }, - // `oxlint-plugin-eslint` package - individual rule files CJS. - { - ...pluginEslintPkgConfig, - entry: pluginEslintRulesEntry, - format: "commonjs", - dts: false, }, ]); From 2f7023d75df807f27783edd2362dd847a89cc0eb Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Tue, 3 Mar 2026 02:46:43 +0000 Subject: [PATCH 3/4] fix --- npm/oxlint-plugin-eslint/package.json | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/npm/oxlint-plugin-eslint/package.json b/npm/oxlint-plugin-eslint/package.json index 2bcbf499aa7ef..419cb29dea939 100644 --- a/npm/oxlint-plugin-eslint/package.json +++ b/npm/oxlint-plugin-eslint/package.json @@ -1,6 +1,6 @@ { "name": "oxlint-plugin-eslint", - "version": "1.50.0", + "version": "1.51.0", "description": "ESLint's built-in rules as an Oxlint plugin", "keywords": [ "eslint", @@ -22,26 +22,12 @@ }, "files": [ "index.js", - "index.cjs", - "index.d.ts", "rules", "README.md" ], "type": "module", "main": "index.js", - "types": "index.d.ts", - "exports": { - ".": { - "types": "./index.d.ts", - "import": "./index.js", - "require": "./index.cjs", - "default": "./index.js" - } - }, - "peerDependencies": { - "eslint": ">=8.0.0" - }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" } } From 4d9c1a24950d9a8598aee4b9450db63dd0c6c371 Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Tue, 3 Mar 2026 02:54:19 +0000 Subject: [PATCH 4/4] README --- npm/oxlint-plugin-eslint/README.md | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/npm/oxlint-plugin-eslint/README.md b/npm/oxlint-plugin-eslint/README.md index 344360d3b634d..ca33d382bc18b 100644 --- a/npm/oxlint-plugin-eslint/README.md +++ b/npm/oxlint-plugin-eslint/README.md @@ -4,12 +4,16 @@ ESLint's built-in rules as an Oxlint plugin. This package exports all of ESLint's built-in rules as a JS plugin that Oxlint users can use. +Allows using ESLint rules that Oxlint doesn't implement natively yet. + +More details in [Oxlint docs](https://oxc.rs/docs/guide/usage/linter/js-plugins). + ## Usage Install the package: ```sh -npm install --save-dev oxlint-plugin-eslint eslint +npm install --save-dev oxlint-plugin-eslint ``` Add to your Oxlint config: @@ -18,22 +22,16 @@ Add to your Oxlint config: { "jsPlugins": ["oxlint-plugin-eslint"], "rules": { - "eslint-js/no-unused-vars": "error" + "eslint-js/no-restricted-syntax": [ + "error", + { + "selector": "ThrowStatement > CallExpression[callee.name=/Error$/]", + "message": "Use `new` keyword when throwing an `Error`." + } + ] } } ``` -The plugin's `meta.name` is `eslint-js`, so all rules are prefixed with `eslint-js/`. - -## Why? - -This package is useful when: - -1. You want to use an ESLint rule that Oxlint doesn't implement natively yet. -2. You encounter a bug in Oxlint's native implementation of an ESLint rule and need a temporary fix. - -All rules from ESLint are included, even those that Oxlint already implements natively. You can switch to the JS plugin version as a "hotfix" if needed. - -## License - -MIT +All rules are prefixed with `eslint-js/`, to distinguish them from the native implementation of many ESLint rules +in Oxlint.