From 7fb300e62443431ddeaad32844815427aa1331d3 Mon Sep 17 00:00:00 2001 From: Sysix Date: Sat, 9 Nov 2024 15:04:45 +0100 Subject: [PATCH 1/3] fix: sync vitest compatible rules with jest rules --- scripts/traverse-rules.ts | 13 +++++++++++ src/constants.ts | 20 ++++++++++++++++- src/generated/configs-by-scope.ts | 12 +++++----- src/generated/rules-by-category.ts | 14 ++++++++++++ src/generated/rules-by-scope.ts | 36 +++++++++++++++++++++--------- 5 files changed, 77 insertions(+), 18 deletions(-) diff --git a/scripts/traverse-rules.ts b/scripts/traverse-rules.ts index 9e2f633..f0addee 100644 --- a/scripts/traverse-rules.ts +++ b/scripts/traverse-rules.ts @@ -9,6 +9,7 @@ import { import { reactHookRulesInsideReactScope, typescriptRulesExtendEslintRules, + viteTestCompatibleRules, } from '../src/constants.js'; // Recursive function to read files in a directory, this currently assumes that the directory @@ -136,6 +137,7 @@ async function processFile( category: keywordMatch[1], }); + // special case for eslint and typescript alias rules if (scope === 'eslint') { const ruleName = effectiveRuleName.replace(/^.*\//, ''); @@ -146,6 +148,17 @@ async function processFile( category: keywordMatch[1], }); } + // special case for jest and vitest alias rules + } else if (scope === 'jest') { + const ruleName = effectiveRuleName.replace(/^.*\//, ''); + + if (viteTestCompatibleRules.includes(ruleName)) { + successResultArray.push({ + value: `vitest/${ruleName}`, + scope: 'vitest', + category: keywordMatch[1], + }); + } } } else { failureResultArray.push({ diff --git a/src/constants.ts b/src/constants.ts index d96d059..b11f720 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -15,7 +15,6 @@ export const aliasPluginNames: Record = { }; // Some typescript-eslint rules are re-implemented version of eslint rules. -// e.g. no-array-constructor, max-params, etc... // Since oxlint supports these rules under eslint/* and it also supports TS, // we should override these to make implementation status up-to-date. export const typescriptRulesExtendEslintRules = [ @@ -58,6 +57,25 @@ export const typescriptRulesExtendEslintRules = [ 'space-infix-ops', ]; +// Some vitest rules are re-implemented version of jest rules. +// Since oxlint supports these rules under jest/*, we need to remap them. +export const viteTestCompatibleRules = [ + 'consistent-test-it', + 'expect-expect', + 'no-alias-methods', + 'no-conditional-expect', + 'no-conditional-in-test', + 'no-commented-out-tests', + 'no-disabled-tests', + 'no-focused-tests', + 'no-identical-title', + 'no-restricted-jest-methods', + 'no-test-prefixes', + 'prefer-hooks-in-order', + 'valid-describe-callback', + 'valid-expect', +]; + // 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/configs-by-scope.ts b/src/generated/configs-by-scope.ts index 6d172b0..04b44e1 100644 --- a/src/generated/configs-by-scope.ts +++ b/src/generated/configs-by-scope.ts @@ -22,6 +22,11 @@ const jestConfig = { rules: rules.jestRules, }; +const vitestConfig = { + name: 'oxlint/vitest', + rules: rules.vitestRules, +}; + const jsdocConfig = { name: 'oxlint/jsdoc', rules: rules.jsdocRules, @@ -72,16 +77,12 @@ const unicornConfig = { rules: rules.unicornRules, }; -const vitestConfig = { - name: 'oxlint/vitest', - rules: rules.vitestRules, -}; - const configByScope = { 'flat/eslint': eslintConfig, 'flat/typescript': typescriptConfig, 'flat/import': importConfig, 'flat/jest': jestConfig, + 'flat/vitest': vitestConfig, 'flat/jsdoc': jsdocConfig, 'flat/jsx-a11y': jsxA11yConfig, 'flat/nextjs': nextjsConfig, @@ -92,7 +93,6 @@ const configByScope = { 'flat/react-perf': reactPerfConfig, 'flat/tree-shaking': treeShakingConfig, 'flat/unicorn': unicornConfig, - 'flat/vitest': vitestConfig, }; export default configByScope; diff --git a/src/generated/rules-by-category.ts b/src/generated/rules-by-category.ts index 4fcd29b..7187405 100644 --- a/src/generated/rules-by-category.ts +++ b/src/generated/rules-by-category.ts @@ -24,6 +24,7 @@ const pedanticRules = { 'symbol-description': 'off', 'import/max-dependencies': 'off', 'jest/no-conditional-in-test': 'off', + 'vitest/no-conditional-in-test': 'off', 'jsdoc/require-param': 'off', 'jsdoc/require-param-description': 'off', 'jsdoc/require-param-name': 'off', @@ -175,22 +176,27 @@ const styleRules = { 'sort-keys': 'off', 'import/first': 'off', 'jest/consistent-test-it': 'off', + 'vitest/consistent-test-it': 'off', 'jest/max-expects': 'off', 'jest/max-nested-describe': 'off', 'jest/no-alias-methods': 'off', + 'vitest/no-alias-methods': 'off', 'jest/no-confusing-set-timeout': 'off', 'jest/no-deprecated-functions': 'off', 'jest/no-done-callback': 'off', 'jest/no-duplicate-hooks': 'off', 'jest/no-hooks': 'off', 'jest/no-identical-title': 'off', + 'vitest/no-identical-title': 'off', 'jest/no-interpolation-in-snapshots': 'off', 'jest/no-jasmine-globals': 'off', 'jest/no-large-snapshots': 'off', 'jest/no-mocks-import': 'off', 'jest/no-restricted-jest-methods': 'off', + 'vitest/no-restricted-jest-methods': 'off', 'jest/no-restricted-matchers': 'off', 'jest/no-test-prefixes': 'off', + 'vitest/no-test-prefixes': 'off', 'jest/no-test-return-statement': 'off', 'jest/no-untyped-mock-factory': 'off', 'jest/prefer-called-with': 'off', @@ -198,6 +204,7 @@ const styleRules = { 'jest/prefer-equality-matcher': 'off', 'jest/prefer-expect-resolves': 'off', 'jest/prefer-hooks-in-order': 'off', + 'vitest/prefer-hooks-in-order': 'off', 'jest/prefer-hooks-on-top': 'off', 'jest/prefer-jest-mocked': 'off', 'jest/prefer-lowercase-title': 'off', @@ -317,14 +324,20 @@ const correctnessRules = { 'import/named': 'off', 'import/namespace': 'off', 'jest/expect-expect': 'off', + 'vitest/expect-expect': 'off', 'jest/no-conditional-expect': 'off', + 'vitest/no-conditional-expect': 'off', 'jest/no-disabled-tests': 'off', + 'vitest/no-disabled-tests': 'off', 'jest/no-export': 'off', 'jest/no-focused-tests': 'off', + 'vitest/no-focused-tests': 'off', 'jest/no-standalone-expect': 'off', 'jest/require-to-throw-message': 'off', 'jest/valid-describe-callback': 'off', + 'vitest/valid-describe-callback': 'off', 'jest/valid-expect': 'off', + 'vitest/valid-expect': 'off', 'jest/valid-title': 'off', 'jsdoc/check-property-names': 'off', 'jsdoc/check-tag-names': 'off', @@ -445,6 +458,7 @@ const suspiciousRules = { 'import/no-named-as-default-member': 'off', 'import/no-self-import': 'off', 'jest/no-commented-out-tests': 'off', + 'vitest/no-commented-out-tests': 'off', 'react/iframe-missing-sandbox': 'off', 'react/jsx-no-comment-textnodes': 'off', 'react/react-in-jsx-scope': 'off', diff --git a/src/generated/rules-by-scope.ts b/src/generated/rules-by-scope.ts index c586325..82e57b8 100644 --- a/src/generated/rules-by-scope.ts +++ b/src/generated/rules-by-scope.ts @@ -240,6 +240,30 @@ const jestRules = { 'jest/valid-title': 'off', } as const; +const vitestRules = { + 'vitest/consistent-test-it': 'off', + 'vitest/expect-expect': 'off', + 'vitest/no-alias-methods': 'off', + 'vitest/no-commented-out-tests': 'off', + 'vitest/no-conditional-expect': 'off', + 'vitest/no-conditional-in-test': 'off', + 'vitest/no-disabled-tests': 'off', + 'vitest/no-focused-tests': 'off', + 'vitest/no-identical-title': 'off', + 'vitest/no-restricted-jest-methods': 'off', + 'vitest/no-test-prefixes': 'off', + 'vitest/prefer-hooks-in-order': 'off', + 'vitest/valid-describe-callback': 'off', + 'vitest/valid-expect': 'off', + 'vitest/no-conditional-tests': 'off', + 'vitest/no-import-node-test': 'off', + 'vitest/prefer-each': 'off', + 'vitest/prefer-to-be-falsy': 'off', + 'vitest/prefer-to-be-object': 'off', + 'vitest/prefer-to-be-truthy': 'off', + 'vitest/require-local-test-context-for-concurrent-snapshots': 'off', +} as const; + const jsdocRules = { 'jsdoc/check-access': 'off', 'jsdoc/check-property-names': 'off', @@ -470,21 +494,12 @@ const unicornRules = { 'unicorn/throw-new-error': 'off', } as const; -const vitestRules = { - 'vitest/no-conditional-tests': 'off', - 'vitest/no-import-node-test': 'off', - 'vitest/prefer-each': 'off', - 'vitest/prefer-to-be-falsy': 'off', - 'vitest/prefer-to-be-object': 'off', - 'vitest/prefer-to-be-truthy': 'off', - 'vitest/require-local-test-context-for-concurrent-snapshots': 'off', -} as const; - export { eslintRules, typescriptRules, importRules, jestRules, + vitestRules, jsdocRules, jsxA11yRules, nextjsRules, @@ -495,5 +510,4 @@ export { reactPerfRules, treeShakingRules, unicornRules, - vitestRules, }; From e4eda3c0039074610b1c8ec180e6c6a25335a971 Mon Sep 17 00:00:00 2001 From: Sysix Date: Sat, 9 Nov 2024 15:31:22 +0100 Subject: [PATCH 2/3] fix: sync vitest compatible rules with jest rules --- src/__snapshots__/configs.spec.ts.snap | 42 ++++++++++++++++++++++++++ src/build-from-oxlint-config.spec.ts | 22 +++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/__snapshots__/configs.spec.ts.snap b/src/__snapshots__/configs.spec.ts.snap index a8ab545..aab8c16 100644 --- a/src/__snapshots__/configs.spec.ts.snap +++ b/src/__snapshots__/configs.spec.ts.snap @@ -1286,15 +1286,51 @@ exports[`contains all the oxlint rules 1`] = ` "valid-typeof": [ 0, ], + "vitest/consistent-test-it": [ + 0, + ], + "vitest/expect-expect": [ + 0, + ], + "vitest/no-alias-methods": [ + 0, + ], + "vitest/no-commented-out-tests": [ + 0, + ], + "vitest/no-conditional-expect": [ + 0, + ], + "vitest/no-conditional-in-test": [ + 0, + ], "vitest/no-conditional-tests": [ 0, ], + "vitest/no-disabled-tests": [ + 0, + ], + "vitest/no-focused-tests": [ + 0, + ], + "vitest/no-identical-title": [ + 0, + ], "vitest/no-import-node-test": [ 0, ], + "vitest/no-restricted-jest-methods": [ + 0, + ], + "vitest/no-test-prefixes": [ + 0, + ], "vitest/prefer-each": [ 0, ], + "vitest/prefer-hooks-in-order": [ + 0, + ], "vitest/prefer-to-be-falsy": [ 0, ], @@ -1307,5 +1343,11 @@ exports[`contains all the oxlint rules 1`] = ` "vitest/require-local-test-context-for-concurrent-snapshots": [ 0, ], + "vitest/valid-describe-callback": [ + 0, + ], + "vitest/valid-expect": [ + 0, + ], } `; diff --git a/src/build-from-oxlint-config.spec.ts b/src/build-from-oxlint-config.spec.ts index 4f25855..065d774 100644 --- a/src/build-from-oxlint-config.spec.ts +++ b/src/build-from-oxlint-config.spec.ts @@ -6,7 +6,10 @@ import { import fs from 'node:fs'; import { execSync } from 'node:child_process'; import type { Linter } from 'eslint'; -import { typescriptRulesExtendEslintRules } from './constants.js'; +import { + typescriptRulesExtendEslintRules, + viteTestCompatibleRules, +} from './constants.js'; describe('buildFromOxlintConfig', () => { describe('rule values', () => { @@ -184,6 +187,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 viteTestCompatibleRules) { + it(`disables matching vitest and jest rules for ${alias}`, () => { + for (const rule of [alias, `jest/${alias}`, `vitest/${alias}`]) { + const rules = buildFromOxlintConfig({ + rules: { + [rule]: 'warn', + }, + }); + + expect(rules.length).toBe(1); + expect(rules[0].rules).not.toBeUndefined(); + expect(`vitest/${alias}` in rules[0].rules!).toBe(true); + expect(`jest/${alias}` in rules[0].rules!).toBe(true); + } + }); + } }); const createConfigFileAndBuildFromIt = ( From 33bfa3285c755e9ac3416d6383d4072d963976d1 Mon Sep 17 00:00:00 2001 From: Sysix Date: Fri, 6 Dec 2024 12:46:27 +0100 Subject: [PATCH 3/3] fix: sync vitest compatible rules with jest rules --- src/build-from-oxlint-config.spec.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/build-from-oxlint-config.spec.ts b/src/build-from-oxlint-config.spec.ts index 6c415dc..63d764b 100644 --- a/src/build-from-oxlint-config.spec.ts +++ b/src/build-from-oxlint-config.spec.ts @@ -189,18 +189,17 @@ describe('buildFromOxlintConfig', () => { }); for (const alias of viteTestCompatibleRules) { - it(`disables matching vitest and jest rules for ${alias}`, () => { - for (const rule of [alias, `jest/${alias}`, `vitest/${alias}`]) { - const rules = buildFromOxlintConfig({ + it(`disables vitest jest alias rules for ${alias}`, () => { + for (const rule of [`jest/${alias}`, `vitest/${alias}`]) { + const configs = buildFromOxlintConfig({ rules: { [rule]: 'warn', }, }); - expect(rules.length).toBe(1); - expect(rules[0].rules).not.toBeUndefined(); - expect(`vitest/${alias}` in rules[0].rules!).toBe(true); - expect(`jest/${alias}` in rules[0].rules!).toBe(true); + expect(configs.length).toBe(1); + expect(configs[0].rules).not.toBeUndefined(); + expect(rule in configs[0].rules!).toBe(true); } }); } @@ -426,6 +425,13 @@ describe('integration test with oxlint', () => { ).length; } + // special case for vitest / jest alias rules + if (config.plugins?.includes('vitest')) { + expectedCount += viteTestCompatibleRules.filter( + (aliasRule) => `vitest/${aliasRule}` in configs[0].rules! + ).length; + } + expect(Object.keys(configs[0].rules!).length).toBe(expectedCount); }); }