Skip to content
Closed
29 changes: 29 additions & 0 deletions src/build-from-oxlint-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ import fs from 'node:fs';
import { execSync } from 'node:child_process';
import type { Linter } from 'eslint';
import { typescriptRulesExtendEslintRules } from './constants.js';
import configByCategory from './generated/configs-by-category.js';

const allRulesObjects = Object.values(configByCategory).map(
(config) => config.rules
);
const allRules: string[] = allRulesObjects.flatMap((rulesObject) =>
Object.keys(rulesObject)
);

const supportedTypescriptRulesExtendEslintRules = allRules.filter((rule) =>
typescriptRulesExtendEslintRules.includes(rule)
);

describe('buildFromOxlintConfig', () => {
describe('rule values', () => {
Expand Down Expand Up @@ -184,6 +196,23 @@ describe('buildFromOxlintConfig', () => {
expect('unknown' in configs[0].rules!).toBe(false);
expect('@next/next/no-img-element' in configs[0].rules!).toBe(false);
});

for (const alias of supportedTypescriptRulesExtendEslintRules) {
it(`disables matching typescript and eslint rules for ${alias}`, () => {
for (const rule of [alias, `@typescript-eslint/${alias}`]) {
const rules = buildFromOxlintConfig({
rules: {
[rule]: 'warn',
},
});

expect(rules.length).toBe(1);
expect(rules[0].rules).not.toBeUndefined();
expect(alias in rules[0].rules!).toBe(true);
expect(`@typescript-eslint/${alias}` in rules[0].rules!).toBe(true);
}
});
}
});

const createConfigFileAndBuildFromIt = (
Expand Down
46 changes: 34 additions & 12 deletions src/build-from-oxlint-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,18 @@ const handleCategoriesScope = (
}
};

const getEsLintRuleName = (rule: string): string | undefined => {
/**
* returns all eslint rules names for a oxlint rule.
* oxlint rules are deactivating one or more eslint rules.
*
* Oxlint rules do not need a plugin-scope.
* When no eslint rules are found, an empty array is returned.
*
*/
const getEsLintRuleNames = (rule: string): string[] => {
// there is no plugin prefix, it can be all plugin
if (!rule.includes('/')) {
return allRules.find(
return allRules.filter(
(search) => search.endsWith(`/${rule}`) || search === rule
);
}
Expand All @@ -121,7 +129,7 @@ const getEsLintRuleName = (rule: string): string | undefined => {
const match = rule.match(/(^.*)\/(.*)/);

if (match === null) {
return undefined;
return [];
}

const pluginName = match[1];
Expand All @@ -143,7 +151,19 @@ const getEsLintRuleName = (rule: string): string | undefined => {
const expectedRule =
esPluginName === '' ? ruleName : `${esPluginName}/${ruleName}`;

return allRules.find((rule) => rule == expectedRule);
// Some typescript-eslint rules are re-implemented version of eslint rules.
if (esPluginName === '@typescript-eslint' || esPluginName === '') {
return allRules.filter(
(rule) =>
rule === expectedRule ||
(esPluginName === '@typescript-eslint' && rule === ruleName) ||
(esPluginName === '' && rule === `@typescript-eslint/${ruleName}`)
);
}

const found = allRules.find((rule) => rule === expectedRule);

return found === undefined ? [] : [found];
};

/**
Expand All @@ -154,21 +174,23 @@ const handleRulesScope = (
rules: Record<string, 'off'>
): void => {
for (const rule in oxlintRules) {
const eslintName = getEsLintRuleName(rule);
const eslintNames = getEsLintRuleNames(rule);

if (eslintName === undefined) {
if (eslintNames.length === 0) {
console.warn(
`eslint-plugin-oxlint: could not find matching eslint rule for "${rule}"`
);
continue;
}

// is this rules not turned off
if (isActiveValue(oxlintRules[rule])) {
rules[eslintName] = 'off';
} else if (rule in rules && isDeactivateValue(oxlintRules[rule])) {
// rules extended by categories or plugins can be disabled manually
delete rules[eslintName];
for (const eslintName of eslintNames) {
// is this rules not turned off
if (isActiveValue(oxlintRules[rule])) {
rules[eslintName] = 'off';
} else if (rule in rules && isDeactivateValue(oxlintRules[rule])) {
// rules extended by categories or plugins can be disabled manually
delete rules[eslintName];
}
}
}
};
Expand Down