diff --git a/.github/workflows/bump_oxlint.yml b/.github/workflows/bump_oxlint.yml index 84fd345f..3d666888 100644 --- a/.github/workflows/bump_oxlint.yml +++ b/.github/workflows/bump_oxlint.yml @@ -5,6 +5,7 @@ on: inputs: version: required: true + description: 'The X.Y.Z version to bump to, no `v` prefix.' type: string env: @@ -22,6 +23,11 @@ jobs: with: persist-credentials: false # should be fine, we give another token for PR creation + - name: Bump Version + env: + OXLINT_VERSION: ${{ inputs.version }} + run: npm version ${OXLINT_VERSION} --no-git-tag-version + - uses: oxc-project/setup-node@8958a8e040102244b619c4a94fccb657a44b1c21 # v1.0.6 - name: Generate version ${{ inputs.version }} @@ -30,17 +36,11 @@ jobs: run: | pnpm install oxlint@${OXLINT_VERSION} pnpm run generate # Generate rules - pnpm run format # run prettier over it - name: Test and update snapshot continue-on-error: true # we check in PR why it fails run: pnpm run test -u # Update test snapshots - - name: Bump oxlint rules - env: - OXLINT_VERSION: ${{ inputs.version }} - run: npm version ${OXLINT_VERSION} --no-git-tag-version - - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 with: # bot account with PAT required for triggering workflow runs diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 809e3dcd..3d7e7bd5 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -32,13 +32,10 @@ jobs: - uses: oxc-project/setup-node@8958a8e040102244b619c4a94fccb657a44b1c21 # v1.0.6 - name: Remove current generated code - run: rm -r ./src/generated/ + run: rm -r ./src/generated/ && rm -r ./scripts/generated/ - name: Generate from source code run: pnpm run generate - - name: Format generated code - run: pnpm run format - - name: Check for git diff run: git diff --exit-code diff --git a/eslint.config.ts b/eslint.config.ts index 1a471a4a..fd633447 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -5,7 +5,7 @@ import tseslint from 'typescript-eslint'; export default [ eslint.configs.recommended, - unicorn.configs['flat/recommended'], + unicorn.configs['recommended'], ...tseslint.configs.recommended, ...oxlint.buildFromOxlintConfigFile('.oxlintrc.json', { typeAware: true, diff --git a/package.json b/package.json index bb8243ce..ae9dab6c 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ }, "scripts": { "prepare": "husky", - "generate": "node --import @oxc-node/core/register ./scripts/generate.ts", + "generate": "node --import @oxc-node/core/register ./scripts/generate-vitest-rules.ts && node --import @oxc-node/core/register ./scripts/generate.ts && pnpm format", "build": "vite build", "lint": "npx oxlint --type-aware --type-check && npx eslint", "format": "npx oxfmt", @@ -79,7 +79,7 @@ "vitest": "^4.0.0" }, "lint-staged": { - "*.{js,cjs,ts}": "eslint", + "*.{js,cjs,ts}": "pnpm run lint", "*": "oxfmt ." }, "volta": { diff --git a/scripts/__snapshots__/rules-generator.test.ts.snap b/scripts/__snapshots__/rules-generator.spec.ts.snap similarity index 100% rename from scripts/__snapshots__/rules-generator.test.ts.snap rename to scripts/__snapshots__/rules-generator.spec.ts.snap diff --git a/scripts/generate-vitest-rules.ts b/scripts/generate-vitest-rules.ts new file mode 100644 index 00000000..381b277f --- /dev/null +++ b/scripts/generate-vitest-rules.ts @@ -0,0 +1,33 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import packageJson from '../package.json' with { type: 'json' }; + +// --- Generate the vitest rules file --- + +const __dirname = new URL('.', import.meta.url).pathname; +// `/scripts/generated/` +const scriptsGenerateFolder = path.resolve(__dirname, `generated`); + +if (!fs.existsSync(scriptsGenerateFolder)) { + fs.mkdirSync(scriptsGenerateFolder); +} + +// Generate the vitest-compatible-jest-rules.json file by pulling it from the oxc repository. +// This keeps the two in sync. +// Use the version of the package to determine which git reference to pull from. +const gitReference = `oxlint_v${packageJson.version}`; + +const githubURL = `https://raw.githubusercontent.com/oxc-project/oxc/${gitReference}/crates/oxc_linter/data/vitest_compatible_jest_rules.json`; +const response = await fetch(githubURL); + +if (!response.ok) { + throw new Error( + `Failed to fetch vitest-compatible-jest-rules.json: ${response.status} ${response.statusText}` + ); +} + +const vitestRules = await response.text(); +const vitestRulesPath = path.resolve(scriptsGenerateFolder, 'vitest-compatible-jest-rules.json'); +fs.writeFileSync(vitestRulesPath, vitestRules, 'utf8'); + +console.log('vitest-compatible-jest-rules.json copied successfully from the oxc repo.'); diff --git a/scripts/generate.ts b/scripts/generate.ts index 4afd85fb..c9947192 100644 --- a/scripts/generate.ts +++ b/scripts/generate.ts @@ -25,3 +25,5 @@ const promises = [rulesGenerator, configGenerator].map(async (generator) => { }); await Promise.all(promises); + +console.log('Rules generated successfully.'); diff --git a/scripts/generated/vitest-compatible-jest-rules.json b/scripts/generated/vitest-compatible-jest-rules.json new file mode 100644 index 00000000..80f61509 --- /dev/null +++ b/scripts/generated/vitest-compatible-jest-rules.json @@ -0,0 +1,43 @@ +[ + "consistent-test-it", + "expect-expect", + "max-expects", + "max-nested-describe", + "no-alias-methods", + "no-commented-out-tests", + "no-conditional-expect", + "no-conditional-in-test", + "no-disabled-tests", + "no-duplicate-hooks", + "no-focused-tests", + "no-hooks", + "no-identical-title", + "no-interpolation-in-snapshots", + "no-large-snapshots", + "no-mocks-import", + "no-restricted-jest-methods", + "no-restricted-matchers", + "no-standalone-expect", + "no-test-prefixes", + "no-test-return-statement", + "prefer-called-with", + "prefer-comparison-matcher", + "prefer-each", + "prefer-equality-matcher", + "prefer-expect-resolves", + "prefer-hooks-in-order", + "prefer-hooks-on-top", + "prefer-lowercase-title", + "prefer-mock-promise-shorthand", + "prefer-spy-on", + "prefer-strict-equal", + "prefer-to-be", + "prefer-to-contain", + "prefer-to-have-length", + "prefer-todo", + "require-hook", + "require-to-throw-message", + "require-top-level-describe", + "valid-describe-callback", + "valid-expect" +] diff --git a/scripts/rules-generator.test.ts b/scripts/rules-generator.spec.ts similarity index 100% rename from scripts/rules-generator.test.ts rename to scripts/rules-generator.spec.ts diff --git a/scripts/traverse-rules.ts b/scripts/traverse-rules.ts index 330b69a0..a8fb290d 100644 --- a/scripts/traverse-rules.ts +++ b/scripts/traverse-rules.ts @@ -5,8 +5,8 @@ import { reactHookRulesInsideReactScope, typescriptRulesExtendEslintRules, unicornRulesExtendEslintRules, - viteTestCompatibleRules, } from '../src/constants.js'; +import vitestCompatibleRules from './generated/vitest-compatible-jest-rules.json' with { type: 'json' }; export type Rule = { value: string; @@ -63,7 +63,7 @@ function getAliasRules(rule: Rule): Rule | undefined { }; } - if (rule.scope === 'jest' && viteTestCompatibleRules.includes(rule.value)) { + if (rule.scope === 'jest' && vitestCompatibleRules.includes(rule.value)) { return { value: `vitest/${rule.value}`, scope: 'vitest', diff --git a/src/build-from-oxlint-config.spec.ts b/src/build-from-oxlint-config.spec.ts index de33d64c..5161eb87 100644 --- a/src/build-from-oxlint-config.spec.ts +++ b/src/build-from-oxlint-config.spec.ts @@ -6,11 +6,8 @@ import { import fs from 'node:fs'; import { execSync } from 'node:child_process'; import type { Linter } from 'eslint'; -import { - typescriptRulesExtendEslintRules, - unicornRulesExtendEslintRules, - viteTestCompatibleRules, -} from './constants.js'; +import { typescriptRulesExtendEslintRules, unicornRulesExtendEslintRules } from './constants.js'; +import vitestCompatibleRules from '../scripts/generated/vitest-compatible-jest-rules.json' with { type: 'json' }; describe('buildFromOxlintConfigFile', () => { it('successfully parse oxlint json config', () => { @@ -163,7 +160,7 @@ describe('integration test with oxlint', () => { // special case for vitest / jest alias rules if (config.plugins?.includes('vitest')) { - expectedCount += viteTestCompatibleRules.filter( + expectedCount += vitestCompatibleRules.filter( (aliasRule) => `vitest/${aliasRule}` in buildConfig.rules! ).length; } diff --git a/src/build-from-oxlint-config/rules.spec.ts b/src/build-from-oxlint-config/rules.spec.ts index 4ff5000c..a921afa6 100644 --- a/src/build-from-oxlint-config/rules.spec.ts +++ b/src/build-from-oxlint-config/rules.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { handleRulesScope } from './rules.js'; -import { unicornRulesExtendEslintRules, viteTestCompatibleRules } from '../constants.js'; +import { unicornRulesExtendEslintRules } from '../constants.js'; +import vitestCompatibleRules from '../../scripts/generated/vitest-compatible-jest-rules.json' with { type: 'json' }; describe('handleRulesScope', () => { for (const ruleSetting of ['error', ['error'], 'warn', ['warn'], 1, [1], 2, [2]]) { @@ -118,7 +119,7 @@ describe('handleRulesScope', () => { expect(rules).toStrictEqual({}); }); - for (const alias of viteTestCompatibleRules) { + for (const alias of vitestCompatibleRules) { it(`disables vitest jest alias rules for ${alias}`, () => { for (const rule of [`jest/${alias}`, `vitest/${alias}`]) { const rules = {}; diff --git a/src/constants.ts b/src/constants.ts index 4f2e1e06..5f3e759a 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -41,53 +41,6 @@ export const typescriptRulesExtendEslintRules = [ 'no-useless-constructor', ]; -// Some vitest rules are re-implemented version of jest rules. -// Since oxlint supports these rules under jest/*, we need to remap them. -// remapping in source-code: -export const viteTestCompatibleRules = [ - 'consistent-test-it', - 'expect-expect', - 'max-expects', - 'max-nested-describe', - 'no-alias-methods', - 'no-commented-out-tests', - 'no-conditional-expect', - 'no-conditional-in-test', - 'no-disabled-tests', - 'no-duplicate-hooks', - 'no-focused-tests', - 'no-hooks', - 'no-identical-title', - 'no-interpolation-in-snapshots', - 'no-large-snapshots', - 'no-mocks-import', - 'no-restricted-jest-methods', - 'no-restricted-matchers', - 'no-standalone-expect', - 'no-test-prefixes', - 'no-test-return-statement', - 'prefer-called-with', - 'prefer-comparison-matcher', - 'prefer-each', - 'prefer-equality-matcher', - 'prefer-expect-resolves', - 'prefer-hooks-in-order', - 'prefer-hooks-on-top', - 'prefer-lowercase-title', - 'prefer-mock-promise-shorthand', - 'prefer-spy-on', - 'prefer-strict-equal', - 'prefer-to-be', - 'prefer-to-contain', - 'prefer-to-have-length', - 'prefer-todo', - 'require-hook', - 'require-to-throw-message', - 'require-top-level-describe', - 'valid-describe-callback', - 'valid-expect', -]; - export const unicornRulesExtendEslintRules = ['no-negated-condition']; // All rules from `eslint-plugin-react-hooks`