diff --git a/scripts/traverse-rules.ts b/scripts/traverse-rules.ts index ffae7c4..9d916cb 100644 --- a/scripts/traverse-rules.ts +++ b/scripts/traverse-rules.ts @@ -4,6 +4,7 @@ import { aliasPluginNames, reactHookRulesInsideReactScope, typescriptRulesExtendEslintRules, + unicornRulesExtendEslintRules, viteTestCompatibleRules, } from '../src/constants.js'; @@ -76,6 +77,17 @@ function getAliasRules(rule: Rule): Rule | undefined { category: rule.category, }; } + + if ( + rule.scope === 'eslint' && + unicornRulesExtendEslintRules.includes(rule.value) + ) { + return { + value: `unicorn/${rule.value}`, + scope: 'unicorn', + category: rule.category, + }; + } } export function traverseRules(): Rule[] { diff --git a/src/__snapshots__/configs.spec.ts.snap b/src/__snapshots__/configs.spec.ts.snap index a000a0d..1449efe 100644 --- a/src/__snapshots__/configs.spec.ts.snap +++ b/src/__snapshots__/configs.spec.ts.snap @@ -1263,6 +1263,9 @@ exports[`contains all the oxlint rules 1`] = ` "unicorn/no-magic-array-flat-depth": [ 0, ], + "unicorn/no-negated-condition": [ + 0, + ], "unicorn/no-negation-in-equality-check": [ 0, ], diff --git a/src/build-from-oxlint-config.spec.ts b/src/build-from-oxlint-config.spec.ts index fd1cadb..ab0a887 100644 --- a/src/build-from-oxlint-config.spec.ts +++ b/src/build-from-oxlint-config.spec.ts @@ -8,6 +8,7 @@ import { execSync } from 'node:child_process'; import type { Linter } from 'eslint'; import { typescriptRulesExtendEslintRules, + unicornRulesExtendEslintRules, viteTestCompatibleRules, } from './constants.js'; @@ -204,6 +205,22 @@ describe('buildFromOxlintConfig', () => { }); } + for (const alias of unicornRulesExtendEslintRules) { + it(`disables unicorn eslint alias rules for ${alias}`, () => { + for (const rule of [`unicorn/${alias}`, alias]) { + const configs = buildFromOxlintConfig({ + rules: { + [rule]: 'warn', + }, + }); + + expect(configs.length).toBe(1); + expect(configs[0].rules).not.toBeUndefined(); + expect(rule in configs[0].rules!).toBe(true); + } + }); + } + describe('ignorePattern Property', () => { it('should append ignorePatterns to eslint v9 ignore property', () => { const configs = buildFromOxlintConfig({ @@ -506,6 +523,13 @@ describe('integration test with oxlint', () => { ).length; } + // special mapping for unicorn alias rules + if (config.plugins === undefined || config.plugins.includes('unicorn')) { + expectedCount += unicornRulesExtendEslintRules.filter( + (aliasRule) => `unicorn/${aliasRule}` in configs[0].rules! + ).length; + } + expect(Object.keys(configs[0].rules!).length).toBe(expectedCount); }); } diff --git a/src/constants.ts b/src/constants.ts index b11f720..505c3f0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -76,6 +76,8 @@ export const viteTestCompatibleRules = [ 'valid-expect', ]; +export const unicornRulesExtendEslintRules = ['no-negated-condition']; + // All rules from `eslint-plugin-react-hooks` // Since oxlint supports these rules under react/*, we need to remap them. export const reactHookRulesInsideReactScope = [ diff --git a/src/generated/rules-by-category.ts b/src/generated/rules-by-category.ts index 9a381e9..9cccbb5 100644 --- a/src/generated/rules-by-category.ts +++ b/src/generated/rules-by-category.ts @@ -77,6 +77,7 @@ const pedanticRules = { 'unicorn/prefer-type-error': 'off', 'unicorn/require-number-to-fixed-digits-argument': 'off', '@typescript-eslint/no-array-constructor': 'off', + 'unicorn/no-negated-condition': 'off', '@typescript-eslint/no-redeclare': 'off', 'vitest/no-conditional-in-test': 'off', } as const; diff --git a/src/generated/rules-by-scope.ts b/src/generated/rules-by-scope.ts index 0728a88..f2964d8 100644 --- a/src/generated/rules-by-scope.ts +++ b/src/generated/rules-by-scope.ts @@ -480,6 +480,7 @@ const unicornRules = { 'unicorn/switch-case-braces': 'off', 'unicorn/text-encoding-identifier-case': 'off', 'unicorn/throw-new-error': 'off', + 'unicorn/no-negated-condition': 'off', } as const; const vitestRules = {