Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changepacks/changepack_log_YwDonXHvmi8bYbnzCOojh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"note":"Drop eslint-plugin-react (no ESLint 10 support): replace with @eslint-react, @stylistic and eslint-plugin-perfectionist. Rule ids change - react/* -> @eslint-react/*, react/jsx-curly-brace-presence -> @stylistic/jsx-curly-brace-presence, react/jsx-sort-props -> perfectionist/sort-jsx-props. Oxlint plugin drops devup/react/* in favour of devup/perfectionist/sort-jsx-props.","date":"2026-08-21T08:47:59.812656600Z","changes":{"package.json":"Minor"}}
2 changes: 1 addition & 1 deletion .github/workflows/check-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v7
- uses: actions/setup-node@v6
- uses: actions/setup-node@v7
with:
node-version: latest
- uses: oven-sh/setup-bun@v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v7
- uses: actions/setup-node@v6
- uses: actions/setup-node@v7
with:
node-version: latest
registry-url: "https://registry.npmjs.org"
Expand Down
498 changes: 146 additions & 352 deletions bun.lock

Large diffs are not rendered by default.

26 changes: 14 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,34 @@
"license": "ISC",
"dependencies": {
"@devup-ui/eslint-plugin": ">=1.0.16",
"@eslint-react/eslint-plugin": ">=5.18.6",
"@eslint/js": ">=10.0",
"@tanstack/eslint-plugin-query": ">=5.101.2",
"eslint": ">=10.7",
"@stylistic/eslint-plugin": ">=5.10.0",
"@tanstack/eslint-plugin-query": ">=5.101.4",
"eslint": ">=10.8",
"eslint-config-prettier": ">=10",
"eslint-plugin-mdx": ">=3.8.1",
"eslint-plugin-perfectionist": ">=5.10.1",
"eslint-plugin-prettier": ">=5.5.6",
"eslint-plugin-react": ">=7.37.5",
"eslint-plugin-react-hooks": ">=7",
"eslint-plugin-simple-import-sort": ">=13.0.0",
"eslint-plugin-react-hooks": ">=7.1",
"eslint-plugin-simple-import-sort": ">=14.0.0",
"eslint-plugin-unused-imports": ">=4.4.1",
"prettier": ">=3",
"typescript-eslint": ">=8.64"
"typescript-eslint": ">=8.67"
},
"peerDependencies": {
"eslint": "*"
},
"devDependencies": {
"@types/bun": "^1.3",
"@types/bun": "^1.4",
"@types/eslint": "^9.6",
"@typescript-eslint/rule-tester": "^8.64",
"@typescript-eslint/utils": "^8.64",
"eslint-plugin-eslint-plugin": "^7.4",
"@typescript-eslint/rule-tester": "^8.67",
"@typescript-eslint/utils": "^8.67",
"eslint-plugin-eslint-plugin": "^7.6",
"husky": "^9.1",
"oxlint": "^1.73.0",
"oxlint": "^1.79.0",
"typescript": "^6.0",
"vite": "^8.1",
"vite": "^8.2",
"vite-plugin-dts": "^5.0"
}
}
40 changes: 19 additions & 21 deletions src/configs/recommended.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import devupUiEslintPlugin from '@devup-ui/eslint-plugin'
import js from '@eslint/js'
import eslintReact from '@eslint-react/eslint-plugin'
import stylistic from '@stylistic/eslint-plugin'
import pluginQuery from '@tanstack/eslint-plugin-query'
import type { Linter } from 'eslint'
import * as mdx from 'eslint-plugin-mdx'
import perfectionist from 'eslint-plugin-perfectionist'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
// @ts-ignore
import react from 'eslint-plugin-react'
// @ts-ignore
import hooksPlugin from 'eslint-plugin-react-hooks'
import simpleImportSort from 'eslint-plugin-simple-import-sort'
import unusedImports from 'eslint-plugin-unused-imports'
Expand Down Expand Up @@ -35,22 +36,22 @@ export default [
],
},
...devupUiEslintPlugin.configs.recommended,
react.configs.flat!.recommended,
// eslint-plugin-react does not support ESLint 10 - its peer range stops at
// ^9.7.0 and its rules call APIs ESLint 10 removed (`context.getFilename()`,
// `SourceCode#isSpaceBetweenTokens()`). @eslint-react covers the correctness
// rules, @stylistic and perfectionist cover the JSX formatting rules.
eslintReact.configs['recommended-typescript'],
js.configs.recommended,
eslintPluginPrettierRecommended,
...tseslint.configs.recommended,
...pluginQuery.configs['flat/recommended'],
{
settings: {
react: {
version: 'detect',
defaultVersion: '19',
},
},
plugins: {
'react-hooks': hooksPlugin,
'unused-imports': unusedImports,
'simple-import-sort': simpleImportSort,
'@stylistic': stylistic,
perfectionist,
'@devup': {
rules: {
component,
Expand All @@ -60,7 +61,6 @@ export default [
},
},
rules: {
'react/react-in-jsx-scope': 'off',
'require-jsdoc': 'off',
'valid-jsdoc': 'off',
'prettier/prettier': [
Expand All @@ -78,19 +78,20 @@ export default [
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'no-constant-condition': ['error', { checkLoops: false }],
'react/jsx-curly-brace-presence': 'error',
'@stylistic/jsx-curly-brace-presence': 'error',
camelcase: 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'react/jsx-sort-props': [
'perfectionist/sort-jsx-props': [
'error',
{
callbacksLast: false,
shorthandFirst: false,
shorthandLast: false,
type: 'alphabetical',
order: 'asc',
ignoreCase: false,
noSortAlphabetically: false,
reservedFirst: true,
groups: ['reserved', 'unknown'],
customGroups: [
{ groupName: 'reserved', elementNamePattern: '^(key|ref)$' },
],
},
],
'@typescript-eslint/no-unused-vars': [
Expand All @@ -105,11 +106,9 @@ export default [
ignoreRestSiblings: true,
},
],
'react/sort-default-props': 'error',
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': 'off',
'comma-dangle': 'off',
'react/prop-types': 'off',
'no-console': [
'error',
{
Expand Down Expand Up @@ -161,8 +160,7 @@ export default [
files: ['**/*.{md,mdx}/*.{js,jsx,ts,tsx}'],
rules: {
...mdx.flatCodeBlocks.rules,
'react/jsx-no-undef': 'off',
'react/jsx-tag-spacing': ['error', { beforeClosing: 'never' }],
'@stylistic/jsx-tag-spacing': ['error', { beforeClosing: 'never' }],
'no-empty-pattern': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
},
Expand Down
14 changes: 6 additions & 8 deletions src/oxlint-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,17 @@ const prettierOptions = {
}

const jsxSortPropsOptions = {
callbacksLast: false,
shorthandFirst: false,
shorthandLast: false,
type: 'alphabetical',
order: 'asc',
ignoreCase: false,
noSortAlphabetically: false,
reservedFirst: true,
groups: ['reserved', 'unknown'],
customGroups: [{ groupName: 'reserved', elementNamePattern: '^(key|ref)$' }],
}

const devupRuleOverrides: Record<string, RuleConfig> = {
prettier: ['error', prettierOptions],
'unused-imports/no-unused-vars': 'off',
'react/prop-types': 'off',
'react/jsx-sort-props': ['error', jsxSortPropsOptions],
'perfectionist/sort-jsx-props': ['error', jsxSortPropsOptions],
}

const devupRuleGroups = [
Expand All @@ -40,7 +38,7 @@ const devupRuleGroups = [
'simple-import-sort/',
'unused-imports/',
'query/',
'react/',
'perfectionist/',
] as const

function getRuleConfig(ruleName: string): RuleConfig {
Expand Down
17 changes: 8 additions & 9 deletions src/oxlint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import { rules as devupUiRules } from '@devup-ui/eslint-plugin'
import tanstackQueryPlugin from '@tanstack/eslint-plugin-query'
import type { Rule } from 'eslint'
import { rules as mdxRules } from 'eslint-plugin-mdx'
import perfectionistPlugin from 'eslint-plugin-perfectionist'
import eslintPluginPrettier from 'eslint-plugin-prettier'
// @ts-ignore
import reactPlugin from 'eslint-plugin-react'
// @ts-ignore
import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort'
// @ts-ignore
import unusedImportsPlugin from 'eslint-plugin-unused-imports'
Expand Down Expand Up @@ -98,13 +97,13 @@ const plugin = {
// @tanstack/eslint-plugin-query rules (auto-wrapped for oxlint compatibility)
...buildWrappedRules(tanstackQueryPlugin.rules!, 'query'),

// eslint-plugin-react rules not natively supported by oxlint
'react/prop-types': wrapRuleForOxlint(reactPlugin.rules!['prop-types']),
'react/jsx-sort-props': wrapRuleForOxlint(
reactPlugin.rules!['jsx-sort-props'],
),
'react/sort-default-props': wrapRuleForOxlint(
reactPlugin.rules!['sort-default-props'],
// JSX prop sorting is not natively supported by oxlint.
// Sourced from eslint-plugin-perfectionist because eslint-plugin-react
// does not support ESLint 10.
'perfectionist/sort-jsx-props': wrapRuleForOxlint(
perfectionistPlugin.rules![
'sort-jsx-props'
] as unknown as Rule.RuleModule,
),
},
}
Expand Down