Skip to content

Commit

Permalink
fix: put react-hooks plugin rules into own scope and not under `rea…
Browse files Browse the repository at this point in the history
…ct` (#236)

closes #233
  • Loading branch information
Sysix authored Nov 8, 2024
1 parent 883be80 commit 27960a3
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 11 deletions.
7 changes: 7 additions & 0 deletions scripts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ export const typescriptRulesExtendEslintRules = [
'space-infix-ops',
];

// All rules from `eslint-plugin-react-hooks`
// Since oxlint supports these rules under react/*, we need to remap them.
export const reactHookRulesInsideReactScope = [
'rules-of-hooks',
'exhaustive-deps',
];

export function convertScope(scope: string) {
return Reflect.has(scopeMaps, scope)
? scopeMaps[scope as 'eslint']
Expand Down
21 changes: 18 additions & 3 deletions scripts/traverse-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'node:path';
import {
ignoreScope,
prefixScope,
reactHookRulesInsideReactScope,
SPARSE_CLONE_DIRECTORY,
TARGET_DIRECTORY,
typescriptRulesExtendEslintRules,
Expand Down Expand Up @@ -70,13 +71,27 @@ async function processFile(
let match = blockRegex.exec(content);

// 'ok' way to get the scope, depends on the directory structure
const scope = getFolderNameUnderRules(filePath);
let scope = getFolderNameUnderRules(filePath);
const shouldIgnoreRule = ignoreScope.has(scope);

// when the file is called `mod.rs` we want to use the parent directory name as the rule name
// Note that this is fairly brittle, as relying on the directory structure can be risky
let effectiveRuleName = `${prefixScope(scope)}${getFileNameWithoutExtension(filePath, currentDirectory)}`;
effectiveRuleName = effectiveRuleName.replaceAll('_', '-');
const ruleNameWithoutScope = getFileNameWithoutExtension(
filePath,
currentDirectory
).replaceAll('_', '-');

// All rules from `eslint-plugin-react-hooks`
// Since oxlint supports these rules under react/*, we need to remap them.
if (
scope === 'react' &&
reactHookRulesInsideReactScope.includes(ruleNameWithoutScope)
) {
scope = 'react_hooks';
}

const effectiveRuleName =
`${prefixScope(scope)}${ruleNameWithoutScope}`.replaceAll('_', '-');

// add the rule to the skipped array and continue to see if there's a match regardless
if (shouldIgnoreRule) {
Expand Down
6 changes: 3 additions & 3 deletions src/__snapshots__/configs.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,9 @@ exports[`contains all the oxlint rules 1`] = `
"radix": [
0,
],
"react-hooks/rules-of-hooks": [
0,
],
"react-perf/jsx-no-jsx-as-prop": [
0,
],
Expand Down Expand Up @@ -971,9 +974,6 @@ exports[`contains all the oxlint rules 1`] = `
"react/require-render-return": [
0,
],
"react/rules-of-hooks": [
0,
],
"react/self-closing-comp": [
0,
],
Expand Down
4 changes: 2 additions & 2 deletions src/build-from-oxlint-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ describe('buildFromOxlintConfig', () => {
'react_perf/jsx-no-new-array-as-prop': 'warn',
'nextjs/no-img-element': 'warn',
'jsx_a11y/alt-text': 'warn',
// 'react/rules-of-hooks': 'warn', -- ToDo oxc-project/eslint-plugin-oxlint#233
'react/rules-of-hooks': 'warn',
// 'deepscan/xxx': 'warn',
},
});
Expand All @@ -148,7 +148,7 @@ describe('buildFromOxlintConfig', () => {
);
expect('@next/next/no-img-element' in configs[0].rules!).toBe(true);
expect('jsx-a11y/alt-text' in configs[0].rules!).toBe(true);
// expect('react-hooks/rules-of-hooks' in rules[0].rules!).toBe(true);
expect('react-hooks/rules-of-hooks' in configs[0].rules!).toBe(true);
});

it('detects rules without plugin name', () => {
Expand Down
17 changes: 16 additions & 1 deletion src/build-from-oxlint-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ const aliasPluginNames: Record<string, string> = {
jsx_a11y: 'jsx-a11y',
};

// All rules from `eslint-plugin-react-hooks`
// Since oxlint supports these rules under react/*, we need to remap them.
export const reactHookRulesInsideReactScope = [
'rules-of-hooks',
'exhaustive-deps',
];

const allRulesObjects = Object.values(configByCategory).map(
(config) => config.rules
);
Expand Down Expand Up @@ -139,9 +146,17 @@ const getEsLintRuleName = (rule: string): string | undefined => {
const ruleName = match[2];

// map to the right eslint plugin
const esPluginName =
let esPluginName =
pluginName in aliasPluginNames ? aliasPluginNames[pluginName] : pluginName;

// special case for eslint-plugin-react-hooks
if (
esPluginName === 'react' &&
reactHookRulesInsideReactScope.includes(ruleName)
) {
esPluginName = 'react-hooks';
}

// extra check for eslint
const expectedRule =
esPluginName === '' ? ruleName : `${esPluginName}/${ruleName}`;
Expand Down
6 changes: 6 additions & 0 deletions src/generated/configs-by-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ const reactConfig = {
rules: rules.reactRules,
};

const reactHooksConfig = {
name: 'oxlint/react-hooks',
rules: rules.reactHooksRules,
};

const reactPerfConfig = {
name: 'oxlint/react-perf',
rules: rules.reactPerfRules,
Expand Down Expand Up @@ -83,6 +88,7 @@ const configByScope = {
'flat/node': nodeConfig,
'flat/promise': promiseConfig,
'flat/react': reactConfig,
'flat/react-hooks': reactHooksConfig,
'flat/react-perf': reactPerfConfig,
'flat/tree-shaking': treeShakingConfig,
'flat/unicorn': unicornConfig,
Expand Down
2 changes: 1 addition & 1 deletion src/generated/rules-by-category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const nurseryRules = {
'import/no-unused-modules': 'off',
'promise/no-return-in-finally': 'off',
'react/require-render-return': 'off',
'react/rules-of-hooks': 'off',
'react-hooks/rules-of-hooks': 'off',
'tree-shaking/no-side-effects-in-initialization': 'off',
'@typescript-eslint/consistent-type-imports': 'off',
} as const;
Expand Down
6 changes: 5 additions & 1 deletion src/generated/rules-by-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,15 @@ const reactRules = {
'react/prefer-es6-class': 'off',
'react/react-in-jsx-scope': 'off',
'react/require-render-return': 'off',
'react/rules-of-hooks': 'off',
'react/self-closing-comp': 'off',
'react/style-prop-object': 'off',
'react/void-dom-elements-no-children': 'off',
} as const;

const reactHooksRules = {
'react-hooks/rules-of-hooks': 'off',
} as const;

const reactPerfRules = {
'react-perf/jsx-no-jsx-as-prop': 'off',
'react-perf/jsx-no-new-array-as-prop': 'off',
Expand Down Expand Up @@ -485,6 +488,7 @@ export {
nodeRules,
promiseRules,
reactRules,
reactHooksRules,
reactPerfRules,
treeShakingRules,
unicornRules,
Expand Down

0 comments on commit 27960a3

Please sign in to comment.