Skip to content

Commit

Permalink
feat: update react options
Browse files Browse the repository at this point in the history
  • Loading branch information
coderwyd committed Dec 16, 2024
1 parent 6cc70d3 commit cebad8a
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 33 deletions.
84 changes: 51 additions & 33 deletions src/configs/react.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
import { isPackageExists } from 'local-pkg'
import { GLOB_SRC } from '../constants/glob'
import { isUsingNext, isUsingRemix } from '../env'
import { ensurePackages, interopDefault, toArray } from '../shared'
import {
GLOB_ASTRO_TS,
GLOB_MARKDOWN,
GLOB_SRC,
GLOB_TS,
GLOB_TSX,
} from '../constants/glob'
import { isAllowConstantExport, isUsingNext, isUsingRemix } from '../env'

import { ensurePackages, interopDefault } from '../shared'
import type {
OptionsFiles,
OptionsOverrides,
OptionsTypeScriptParserOptions,
OptionsTypeScriptWithTypes,
TypedFlatConfigItem,
} from '../types'

// react refresh
const ReactRefreshAllowConstantExportPackages = ['vite']

export async function react(
options: OptionsTypeScriptWithTypes & OptionsOverrides & OptionsFiles = {},
options: OptionsTypeScriptParserOptions &
OptionsTypeScriptWithTypes &
OptionsOverrides &
OptionsFiles = {},
): Promise<TypedFlatConfigItem[]> {
const { files = [GLOB_SRC], overrides = {} } = options
const {
files = [GLOB_SRC],
filesTypeAware = [GLOB_TS, GLOB_TSX],
ignoresTypeAware = [`${GLOB_MARKDOWN}/**`, GLOB_ASTRO_TS],
overrides = {},
tsconfigPath,
} = options

await ensurePackages([
'@eslint-react/eslint-plugin',
'eslint-plugin-react-hooks',
'eslint-plugin-react-refresh',
])

const tsconfigPath = options?.tsconfigPath
? toArray(options.tsconfigPath)
: undefined
const isTypeAware = !!tsconfigPath

const [pluginReact, pluginReactHooks, pluginReactRefresh, parserTs] =
await Promise.all([
const typeAwareRules: TypedFlatConfigItem['rules'] = {
'react/no-leaked-conditional-rendering': 'warn',
}

const [pluginReact, pluginReactHooks, pluginReactRefresh] = await Promise.all(
[
interopDefault(import('@eslint-react/eslint-plugin')),
interopDefault(import('eslint-plugin-react-hooks')),
interopDefault(import('eslint-plugin-react-refresh')),
interopDefault(import('@typescript-eslint/parser')),
] as const)

const isAllowConstantExport = ReactRefreshAllowConstantExportPackages.some(
(i) => isPackageExists(i),
] as const,
)

const plugins = pluginReact.configs.all.plugins
Expand All @@ -57,12 +67,10 @@ export async function react(
{
files,
languageOptions: {
parser: parserTs,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
...(isTypeAware ? { project: tsconfigPath } : {}),
},
sourceType: 'module',
},
Expand Down Expand Up @@ -117,25 +125,30 @@ export async function react(

// recommended rules from @eslint-react
'react/ensure-forward-ref-using-ref': 'warn',
'react/jsx-no-duplicate-props': 'warn',
'react/jsx-uses-vars': 'warn',
'react/no-access-state-in-setstate': 'error',
'react/no-array-index-key': 'warn',
'react/no-children-count': 'warn',
'react/no-children-for-each': 'warn',
'react/no-children-map': 'warn',
'react/no-children-only': 'warn',
'react/no-children-prop': 'warn',
'react/no-children-to-array': 'warn',
'react/no-clone-element': 'warn',
'react/no-comment-textnodes': 'warn',
'react/no-component-will-mount': 'error',
'react/no-component-will-receive-props': 'error',
'react/no-component-will-update': 'error',
'react/no-context-provider': 'warn',
'react/no-create-ref': 'error',
'react/no-default-props': 'error',
'react/no-direct-mutation-state': 'error',
'react/no-duplicate-key': 'error',
'react/no-implicit-key': 'error',
'react/no-forward-ref': 'warn',
'react/no-implicit-key': 'warn',
'react/no-missing-key': 'error',
'react/no-nested-components': 'warn',
'react/no-nested-components': 'error',
'react/no-prop-types': 'error',
'react/no-redundant-should-component-update': 'error',
'react/no-set-state-in-component-did-mount': 'warn',
'react/no-set-state-in-component-did-update': 'warn',
Expand All @@ -144,24 +157,29 @@ export async function react(
'react/no-unsafe-component-will-mount': 'warn',
'react/no-unsafe-component-will-receive-props': 'warn',
'react/no-unsafe-component-will-update': 'warn',
'react/no-unstable-context-value': 'error',
'react/no-unstable-default-props': 'error',
'react/no-unstable-context-value': 'warn',
'react/no-unstable-default-props': 'warn',
'react/no-unused-class-component-members': 'warn',
'react/no-unused-state': 'warn',
'react/no-useless-fragment': 'warn',
'react/prefer-destructuring-assignment': 'warn',
'react/prefer-shorthand-boolean': 'warn',
'react/prefer-shorthand-fragment': 'warn',

...(isTypeAware
? {
'react/no-leaked-conditional-rendering': 'warn',
}
: {}),

// overrides
...overrides,
},
},
...(isTypeAware
? [
{
files: filesTypeAware,
ignores: ignoresTypeAware,
name: 'coderwyd/react/type-aware-rules',
rules: {
...typeAwareRules,
},
},
]
: []),
]
}
6 changes: 6 additions & 0 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ const RemixPackages = [

const NextJsPackages = ['next']

// react refresh
const ReactRefreshAllowConstantExportPackages = ['vite']

// export const hasReact = hasPackages(['react', ...RemixPackages, ...NextJsPackages])
export const isUsingRemix = hasPackages(RemixPackages)
export const isUsingNext = hasPackages(NextJsPackages)
export const isAllowConstantExport = hasPackages(
ReactRefreshAllowConstantExportPackages,
)

function hasPackages(packages: string[]) {
return packages.some((name) => isPackageExists(name))
Expand Down

0 comments on commit cebad8a

Please sign in to comment.