@infra-x/create-eslint-config 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +8 -10
- package/dist/template/.turbo/turbo-build.log +13 -0
- package/dist/template/CHANGELOG.md +7 -0
- package/dist/template/README.md +95 -1
- package/dist/template/eslint.config.mts +1 -2
- package/dist/template/package.json +25 -13
- package/dist/template/src/configs/a11y.ts +2 -2
- package/dist/template/src/configs/better-tailwindcss.ts +3 -3
- package/dist/template/src/configs/boundaries.ts +1 -1
- package/dist/template/src/configs/depend.ts +3 -4
- package/dist/template/src/configs/global-ignores.ts +70 -0
- package/dist/template/src/configs/imports.ts +23 -22
- package/dist/template/src/configs/javascript.ts +1 -1
- package/dist/template/src/configs/jsdoc.ts +1 -1
- package/dist/template/src/configs/nextjs.ts +2 -2
- package/dist/template/src/configs/oxlint.ts +16 -0
- package/dist/template/src/configs/package-json.ts +1 -1
- package/dist/template/src/configs/react.ts +16 -7
- package/dist/template/src/configs/storybook.ts +1 -1
- package/dist/template/src/configs/stylistic.ts +1 -1
- package/dist/template/src/configs/typescript.ts +3 -11
- package/dist/template/src/configs/unicorn.ts +1 -1
- package/dist/template/src/configs/vitest.ts +3 -4
- package/dist/template/src/index.ts +59 -73
- package/dist/template/src/types.ts +44 -37
- package/dist/template/src/utils.ts +17 -17
- package/dist/template/tsconfig.json +1 -1
- package/package.json +16 -17
- package/README.md +0 -14
- package/dist/template/src/configs/ignores.ts +0 -78
- package/dist/template/src/configs/prettier.ts +0 -25
package/dist/index.mjs
CHANGED
|
@@ -3,24 +3,23 @@ import { access, cp, readdir } from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { confirm, intro, log, outro } from "@clack/prompts";
|
|
6
|
-
|
|
7
6
|
//#region src/index.ts
|
|
8
|
-
async function getConflicts(templateDir
|
|
9
|
-
const entries = await readdir(templateDir
|
|
7
|
+
async function getConflicts(templateDir, destDir) {
|
|
8
|
+
const entries = await readdir(templateDir, {
|
|
10
9
|
recursive: true,
|
|
11
10
|
withFileTypes: true
|
|
12
11
|
});
|
|
13
|
-
const conflicts
|
|
12
|
+
const conflicts = [];
|
|
14
13
|
for (const entry of entries) {
|
|
15
14
|
if (!entry.isFile()) continue;
|
|
16
|
-
const rel = path.join(entry.parentPath, entry.name).slice(templateDir
|
|
17
|
-
const destPath = path.join(destDir
|
|
15
|
+
const rel = path.join(entry.parentPath, entry.name).slice(templateDir.length + 1);
|
|
16
|
+
const destPath = path.join(destDir, rel);
|
|
18
17
|
try {
|
|
19
18
|
await access(destPath);
|
|
20
|
-
conflicts
|
|
19
|
+
conflicts.push(rel);
|
|
21
20
|
} catch {}
|
|
22
21
|
}
|
|
23
|
-
return conflicts
|
|
22
|
+
return conflicts;
|
|
24
23
|
}
|
|
25
24
|
intro("@infra-x/create-eslint-config");
|
|
26
25
|
const templateDir = path.join(fileURLToPath(new URL(".", import.meta.url)), "template");
|
|
@@ -35,6 +34,5 @@ if (conflicts.length > 0) {
|
|
|
35
34
|
}
|
|
36
35
|
await cp(templateDir, destDir, { recursive: true });
|
|
37
36
|
outro("复制完成!");
|
|
38
|
-
|
|
39
37
|
//#endregion
|
|
40
|
-
export {
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
> @infra-x/eslint-config@0.1.6 build /home/runner/work/infra-code/infra-code/packages/eslint-config
|
|
3
|
+
> tsdown
|
|
4
|
+
|
|
5
|
+
[34mℹ[39m tsdown [2mv0.21.4[22m powered by rolldown [2mv1.0.0-rc.9[22m
|
|
6
|
+
[34mℹ[39m config file: [4m/home/runner/work/infra-code/infra-code/packages/eslint-config/tsdown.config.ts[24m
|
|
7
|
+
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
8
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
|
+
[34mℹ[39m Build start
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m16.72 kB[22m [2m│ gzip: 4.79 kB[22m
|
|
11
|
+
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 7.11 kB[22m [2m│ gzip: 2.31 kB[22m
|
|
12
|
+
[34mℹ[39m 2 files, total: 23.83 kB
|
|
13
|
+
[32m✔[39m Build complete in [32m1801ms[39m
|
package/dist/template/README.md
CHANGED
|
@@ -1,3 +1,97 @@
|
|
|
1
1
|
# @infra-x/eslint-config
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Composable ESLint flat config factory for infra-x projects.
|
|
4
|
+
|
|
5
|
+
## Release
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm release
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
交互式选择版本号,自动 bump `package.json`、提交、打 tag。
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add -D @infra-x/eslint-config eslint globals
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// eslint.config.mts
|
|
23
|
+
import { composeConfig } from '@infra-x/eslint-config'
|
|
24
|
+
|
|
25
|
+
export default composeConfig({
|
|
26
|
+
typescript: { tsconfigRootDir: import.meta.dirname },
|
|
27
|
+
react: true,
|
|
28
|
+
tailwind: true,
|
|
29
|
+
imports: true,
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For multiple config segments (e.g. separate test rules):
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// eslint.config.mts
|
|
37
|
+
import { GLOB_TESTS, composeConfig } from '@infra-x/eslint-config'
|
|
38
|
+
import { defineConfig } from 'eslint/config'
|
|
39
|
+
|
|
40
|
+
const appConfig = defineConfig({
|
|
41
|
+
extends: composeConfig({
|
|
42
|
+
typescript: { tsconfigRootDir: import.meta.dirname },
|
|
43
|
+
imports: true,
|
|
44
|
+
react: true,
|
|
45
|
+
nextjs: true,
|
|
46
|
+
}),
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const vitestConfig = defineConfig({
|
|
50
|
+
files: GLOB_TESTS,
|
|
51
|
+
extends: composeConfig({
|
|
52
|
+
typescript: { tsconfigRootDir: import.meta.dirname },
|
|
53
|
+
vitest: true,
|
|
54
|
+
unicorn: false,
|
|
55
|
+
stylistic: false,
|
|
56
|
+
depend: false,
|
|
57
|
+
}),
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
export default [...appConfig, ...vitestConfig]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Each option accepts `true` (defaults), an options object, or `false` (disable).
|
|
64
|
+
|
|
65
|
+
## Options
|
|
66
|
+
|
|
67
|
+
Default-on: `globalIgnores` · `javascript` · `typescript` · `stylistic` · `unicorn` · `depend`
|
|
68
|
+
|
|
69
|
+
Opt-in:
|
|
70
|
+
|
|
71
|
+
| Option | Description |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `react` | React + react-hooks rules; set `vite: true` for react-refresh |
|
|
74
|
+
| `nextjs` | Next.js rules |
|
|
75
|
+
| `tailwind` | Tailwind CSS class ordering (`entryPoint` defaults to `src/global.css`) |
|
|
76
|
+
| `imports` | Import ordering and resolution |
|
|
77
|
+
| `a11y` | Accessibility rules |
|
|
78
|
+
| `jsdoc` | JSDoc rules |
|
|
79
|
+
| `boundaries` | Module boundary enforcement |
|
|
80
|
+
| `packageJson` | `package.json` rules |
|
|
81
|
+
| `vitest` | Vitest testing rules |
|
|
82
|
+
| `storybook` | Storybook rules |
|
|
83
|
+
| `oxlint` | Disable ESLint rules already covered by oxlint (requires oxlint to run separately) |
|
|
84
|
+
|
|
85
|
+
All options support an `overrides` field for custom rule overrides, and most accept a `files` glob array.
|
|
86
|
+
|
|
87
|
+
## Oxlint Integration
|
|
88
|
+
|
|
89
|
+
When running oxlint alongside ESLint, enable the `oxlint` option to disable duplicate rules:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// uses flat/recommended preset
|
|
93
|
+
composeConfig({ oxlint: true })
|
|
94
|
+
|
|
95
|
+
// generate disabled rules from your oxlint config file
|
|
96
|
+
composeConfig({ oxlint: { configFile: './.oxlintrc.json' } })
|
|
97
|
+
```
|
|
@@ -5,9 +5,8 @@ import type { Linter } from 'eslint'
|
|
|
5
5
|
const config: Linter.Config[] = composeConfig({
|
|
6
6
|
typescript: { tsconfigRootDir: import.meta.dirname },
|
|
7
7
|
imports: {
|
|
8
|
-
typescript: true,
|
|
9
8
|
overrides: {
|
|
10
|
-
//
|
|
9
|
+
// This package uses relative imports internally since no path aliases are configured
|
|
11
10
|
'no-restricted-imports': 'off',
|
|
12
11
|
},
|
|
13
12
|
},
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"typecheck": "tsc --noEmit"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
+
"@infra-x/typescript-config": "0.1.6",
|
|
22
23
|
"@types/eslint-plugin-jsx-a11y": "^6.10.1",
|
|
23
24
|
"@types/node": "^25.0.3",
|
|
24
25
|
"eslint": "^9.39.2",
|
|
@@ -30,32 +31,43 @@
|
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
33
|
"@eslint-react/eslint-plugin": "^2.13.0",
|
|
33
|
-
"@eslint/compat": "
|
|
34
|
+
"@eslint/compat": "2.0.3",
|
|
34
35
|
"@eslint/core": "0.17.0",
|
|
35
|
-
"@eslint/js": "^
|
|
36
|
+
"@eslint/js": "^10.0.1",
|
|
36
37
|
"@next/eslint-plugin-next": "^16.1.6",
|
|
37
38
|
"@stylistic/eslint-plugin": "^5.9.0",
|
|
38
39
|
"@vitest/eslint-plugin": "^1.6.9",
|
|
39
40
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
40
41
|
"eslint-plugin-better-tailwindcss": "^4.3.1",
|
|
41
42
|
"eslint-plugin-boundaries": "^5.4.0",
|
|
42
|
-
"eslint-plugin-depend": "^1.
|
|
43
|
-
"eslint-plugin-import-x": "4.16.
|
|
44
|
-
"eslint-plugin-jsdoc": "^
|
|
43
|
+
"eslint-plugin-depend": "^1.5.0",
|
|
44
|
+
"eslint-plugin-import-x": "4.16.2",
|
|
45
|
+
"eslint-plugin-jsdoc": "^62.7.1",
|
|
45
46
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
46
|
-
"eslint-plugin-package-json": "^0.
|
|
47
|
-
"eslint-plugin-prettier": "^5.5.5",
|
|
47
|
+
"eslint-plugin-package-json": "^0.91.0",
|
|
48
48
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
49
|
-
"eslint-plugin-react-refresh": "^0.
|
|
50
|
-
"eslint-plugin-
|
|
51
|
-
"eslint-plugin-
|
|
49
|
+
"eslint-plugin-react-refresh": "^0.5.2",
|
|
50
|
+
"eslint-plugin-oxlint": "^0.16.0",
|
|
51
|
+
"eslint-plugin-storybook": "^10.2.14",
|
|
52
|
+
"eslint-plugin-unicorn": "^63.0.0",
|
|
52
53
|
"typescript-eslint": "^8.56.1"
|
|
53
54
|
},
|
|
54
55
|
"peerDependencies": {
|
|
55
|
-
"eslint": "^9.39.2",
|
|
56
|
-
"globals": "
|
|
56
|
+
"eslint": "^9.39.2 || ^10.0.0",
|
|
57
|
+
"globals": "17.4.0",
|
|
57
58
|
"jiti": "2.6.1",
|
|
58
|
-
"
|
|
59
|
+
"storybook": ">=10.0.0",
|
|
59
60
|
"typescript": "^5.9.3"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"jiti": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"storybook": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"typescript": {
|
|
70
|
+
"optional": true
|
|
71
|
+
}
|
|
60
72
|
}
|
|
61
73
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* eslint-plugin-jsx-a11y
|
|
2
|
+
* eslint-plugin-jsx-a11y configuration for detecting accessibility issues in JSX (WCAG standard)
|
|
3
3
|
*/
|
|
4
4
|
import { defineConfig } from 'eslint/config'
|
|
5
5
|
import jsxA11y from 'eslint-plugin-jsx-a11y'
|
|
@@ -10,7 +10,7 @@ import type { A11yOptions } from '../types'
|
|
|
10
10
|
import type { Linter } from 'eslint'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Accessibility rule configuration
|
|
14
14
|
*/
|
|
15
15
|
export function a11y(options: A11yOptions = {}): Linter.Config[] {
|
|
16
16
|
const { files = [GLOB_JSX], overrides = {} } = options
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tailwind CSS ESLint
|
|
2
|
+
* Tailwind CSS ESLint configuration using the official recommended ruleset
|
|
3
3
|
*/
|
|
4
4
|
import { defineConfig } from 'eslint/config'
|
|
5
5
|
import eslintPluginBetterTailwindcss from 'eslint-plugin-better-tailwindcss'
|
|
@@ -10,10 +10,10 @@ import type { TailwindOptions } from '../types'
|
|
|
10
10
|
import type { Linter } from 'eslint'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Tailwind CSS
|
|
13
|
+
* Tailwind CSS rule configuration
|
|
14
14
|
*/
|
|
15
15
|
export function tailwind(options: TailwindOptions = {}): Linter.Config[] {
|
|
16
|
-
const { files = [GLOB_JSX], overrides = {}, entryPoint = 'src/global.css' } = options
|
|
16
|
+
const { files = [GLOB_JSX], overrides = {}, entryPoint = 'src/styles/global.css' } = options
|
|
17
17
|
|
|
18
18
|
return defineConfig({
|
|
19
19
|
name: 'tailwind/rules',
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Dependency optimization rule configuration for detecting packages replaceable with native APIs or micro-utilities
|
|
3
3
|
*/
|
|
4
|
-
import { fixupPluginRules } from '@eslint/compat'
|
|
5
4
|
import dependPlugin from 'eslint-plugin-depend'
|
|
6
5
|
|
|
7
6
|
import { GLOB_SRC } from '../utils'
|
|
8
7
|
|
|
9
8
|
import type { DependOptions } from '../types'
|
|
10
|
-
import type {
|
|
9
|
+
import type { Linter } from 'eslint'
|
|
11
10
|
|
|
12
11
|
const DEFAULT_PRESETS: DependOptions['presets'] = ['native', 'microutilities', 'preferred']
|
|
13
12
|
|
|
@@ -19,7 +18,7 @@ export function depend(options: DependOptions = {}): Linter.Config[] {
|
|
|
19
18
|
name: 'depend/rules',
|
|
20
19
|
files: [GLOB_SRC],
|
|
21
20
|
plugins: {
|
|
22
|
-
depend:
|
|
21
|
+
depend: dependPlugin,
|
|
23
22
|
},
|
|
24
23
|
rules: {
|
|
25
24
|
'depend/ban-dependencies': [
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint ignore configuration with built-in default ignore patterns and .gitignore integration
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
|
|
7
|
+
import { convertIgnorePatternToMinimatch } from '@eslint/compat'
|
|
8
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
9
|
+
|
|
10
|
+
import type { IgnoresOptions } from '../types'
|
|
11
|
+
import type { Linter } from 'eslint'
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_IGNORES: string[] = [
|
|
14
|
+
// Dependency directories
|
|
15
|
+
'**/node_modules/**',
|
|
16
|
+
'**/.pnp.*',
|
|
17
|
+
|
|
18
|
+
// Build artifacts
|
|
19
|
+
'**/dist/**',
|
|
20
|
+
'**/build/**',
|
|
21
|
+
'**/out/**',
|
|
22
|
+
'**/.next/**',
|
|
23
|
+
|
|
24
|
+
// Cache directories
|
|
25
|
+
'**/.cache/**',
|
|
26
|
+
'**/.turbo/**',
|
|
27
|
+
'**/.eslintcache',
|
|
28
|
+
|
|
29
|
+
// Version control
|
|
30
|
+
'**/.git/**',
|
|
31
|
+
'**/.svn/**',
|
|
32
|
+
'**/.hg/**',
|
|
33
|
+
'**/public/**',
|
|
34
|
+
|
|
35
|
+
// Type declaration files
|
|
36
|
+
'**/*.d.ts',
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
export function ignores(options: IgnoresOptions = {}): Linter.Config[] {
|
|
40
|
+
const { ignores: userIgnores, gitignore = true } = options
|
|
41
|
+
|
|
42
|
+
if (userIgnores === false) {
|
|
43
|
+
return []
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const gitignorePatterns: string[] = []
|
|
47
|
+
if (gitignore) {
|
|
48
|
+
const gitignoreFile = path.resolve(process.cwd(), '.gitignore')
|
|
49
|
+
if (existsSync(gitignoreFile)) {
|
|
50
|
+
const lines = readFileSync(gitignoreFile, 'utf8').split(/\r?\n/u)
|
|
51
|
+
gitignorePatterns.push(
|
|
52
|
+
...lines
|
|
53
|
+
.map((line) => line.trim())
|
|
54
|
+
.filter((line) => line && !line.startsWith('#'))
|
|
55
|
+
.map((line) => convertIgnorePatternToMinimatch(line)),
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const userPatterns = userIgnores
|
|
61
|
+
? (Array.isArray(userIgnores) ? userIgnores : [userIgnores])
|
|
62
|
+
: []
|
|
63
|
+
|
|
64
|
+
return defineConfig([
|
|
65
|
+
globalIgnores(
|
|
66
|
+
[...DEFAULT_IGNORES, ...gitignorePatterns, ...userPatterns],
|
|
67
|
+
'ignores/globals/defaults',
|
|
68
|
+
),
|
|
69
|
+
])
|
|
70
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Import
|
|
2
|
+
* Import rule configuration providing import ordering, circular dependency detection, and TypeScript support
|
|
3
3
|
*/
|
|
4
4
|
import { defineConfig } from 'eslint/config'
|
|
5
5
|
import { importX } from 'eslint-plugin-import-x'
|
|
@@ -10,14 +10,19 @@ import type { ImportsOptions } from '../types'
|
|
|
10
10
|
import type { ESLint, Linter } from 'eslint'
|
|
11
11
|
|
|
12
12
|
export function imports(options: ImportsOptions = {}): Linter.Config[] {
|
|
13
|
-
const { overrides = {},
|
|
13
|
+
const { overrides = {}, typescript = false, noRelativeParentImports = false, tsconfigRootDir } = options
|
|
14
14
|
|
|
15
15
|
const files = [GLOB_SRC]
|
|
16
16
|
|
|
17
17
|
const settingsForTypescript = typescript
|
|
18
18
|
? {
|
|
19
19
|
...importX.configs['flat/recommended'].settings,
|
|
20
|
-
'import-x/resolver': {
|
|
20
|
+
'import-x/resolver': {
|
|
21
|
+
typescript: {
|
|
22
|
+
alwaysTryTypes: true,
|
|
23
|
+
...(tsconfigRootDir && { project: tsconfigRootDir }),
|
|
24
|
+
},
|
|
25
|
+
},
|
|
21
26
|
}
|
|
22
27
|
: {}
|
|
23
28
|
|
|
@@ -32,8 +37,17 @@ export function imports(options: ImportsOptions = {}): Linter.Config[] {
|
|
|
32
37
|
}
|
|
33
38
|
: {}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
return defineConfig([
|
|
41
|
+
{
|
|
42
|
+
name: 'imports/rules',
|
|
43
|
+
files,
|
|
44
|
+
plugins: {
|
|
45
|
+
'import-x': importX as unknown as ESLint.Plugin,
|
|
46
|
+
},
|
|
47
|
+
settings: settingsForTypescript,
|
|
48
|
+
rules: {
|
|
49
|
+
...importX.configs['flat/recommended'].rules,
|
|
50
|
+
...rulesForTypescript,
|
|
37
51
|
'import-x/newline-after-import': ['error', { count: 1 }],
|
|
38
52
|
'import-x/order': [
|
|
39
53
|
'error',
|
|
@@ -62,25 +76,12 @@ export function imports(options: ImportsOptions = {}): Linter.Config[] {
|
|
|
62
76
|
'distinctGroup': true,
|
|
63
77
|
},
|
|
64
78
|
],
|
|
65
|
-
}
|
|
66
|
-
: {}
|
|
67
|
-
|
|
68
|
-
return defineConfig([
|
|
69
|
-
{
|
|
70
|
-
name: 'imports/rules',
|
|
71
|
-
files,
|
|
72
|
-
plugins: {
|
|
73
|
-
'import-x': importX as unknown as ESLint.Plugin,
|
|
74
|
-
},
|
|
75
|
-
settings: settingsForTypescript,
|
|
76
|
-
rules: {
|
|
77
|
-
...importX.configs['flat/recommended'].rules,
|
|
78
|
-
...rulesForTypescript,
|
|
79
|
-
...rulesForStylistic,
|
|
80
79
|
'import-x/consistent-type-specifier-style': 'error',
|
|
81
80
|
'import-x/no-named-as-default': 'warn',
|
|
82
|
-
|
|
83
|
-
'import-x/no-
|
|
81
|
+
// maxDepth 避免全图遍历导致性能问题
|
|
82
|
+
'import-x/no-cycle': ['error', { maxDepth: 5 }],
|
|
83
|
+
// ignoreExports 防止入口文件的导出被误报为未使用
|
|
84
|
+
'import-x/no-unused-modules': ['error', { unusedExports: true, ignoreExports: ['**/index.ts', '**/index.tsx'] }],
|
|
84
85
|
'import-x/no-deprecated': 'warn',
|
|
85
86
|
'import-x/no-extraneous-dependencies': 'error',
|
|
86
87
|
'import-x/no-relative-parent-imports': noRelativeParentImports ? 'error' : 'off',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Next.js ESLint
|
|
2
|
+
* Next.js ESLint configuration using the official plugin for best practices and Core Web Vitals enforcement
|
|
3
3
|
*/
|
|
4
4
|
import nextjsPlugin from '@next/eslint-plugin-next'
|
|
5
5
|
import { defineConfig } from 'eslint/config'
|
|
@@ -11,7 +11,7 @@ const recommended = nextjsPlugin.configs.recommended as unknown as Linter.Config
|
|
|
11
11
|
const coreWebVitals = nextjsPlugin.configs['core-web-vitals'] as unknown as Linter.Config
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Next.js
|
|
14
|
+
* Next.js rule configuration
|
|
15
15
|
*/
|
|
16
16
|
export function nextjs(options: NextjsOptions = {}): Linter.Config[] {
|
|
17
17
|
const { overrides = {} } = options
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Oxlint integration — disables ESLint rules already covered by oxlint
|
|
3
|
+
* to avoid duplicate checking when running both linters in parallel.
|
|
4
|
+
*/
|
|
5
|
+
import oxlint from 'eslint-plugin-oxlint'
|
|
6
|
+
|
|
7
|
+
import type { OxlintOptions } from '../types'
|
|
8
|
+
import type { Linter } from 'eslint'
|
|
9
|
+
|
|
10
|
+
export function oxlintConfig(options: OxlintOptions = {}): Linter.Config[] {
|
|
11
|
+
const { configFile } = options
|
|
12
|
+
|
|
13
|
+
return configFile
|
|
14
|
+
? oxlint.buildFromOxlintConfigFile(configFile)
|
|
15
|
+
: [...oxlint.configs['flat/recommended']]
|
|
16
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* React ESLint
|
|
2
|
+
* React ESLint configuration integrating @eslint-react, react-hooks, and react-refresh plugins
|
|
3
3
|
*/
|
|
4
4
|
import reactPlugin from '@eslint-react/eslint-plugin'
|
|
5
5
|
import { defineConfig } from 'eslint/config'
|
|
6
|
-
import reactHooksPlugin from 'eslint-plugin-react-hooks'
|
|
6
|
+
// import reactHooksPlugin from 'eslint-plugin-react-hooks'// reactPlugin 新版本已经包含了 reactHooksPlugin
|
|
7
7
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
8
8
|
|
|
9
9
|
import { GLOB_JSX } from '../utils'
|
|
@@ -12,20 +12,29 @@ import type { ReactOptions } from '../types'
|
|
|
12
12
|
import type { Linter } from 'eslint'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* React
|
|
15
|
+
* React rule configuration
|
|
16
16
|
*/
|
|
17
17
|
export function react(options: ReactOptions = {}): Linter.Config[] {
|
|
18
|
-
const { files = [GLOB_JSX], overrides = {} } = options
|
|
18
|
+
const { files = [GLOB_JSX], overrides = {}, vite = false } = options
|
|
19
19
|
|
|
20
20
|
return defineConfig({
|
|
21
21
|
name: 'react/rules',
|
|
22
22
|
files,
|
|
23
23
|
extends: [
|
|
24
|
-
reactPlugin.configs['recommended-
|
|
25
|
-
reactHooksPlugin.configs.flat['recommended-latest'],
|
|
26
|
-
reactRefresh.configs.recommended,
|
|
24
|
+
reactPlugin.configs['recommended-type-checked'],
|
|
25
|
+
// reactHooksPlugin.configs.flat['recommended-latest'],
|
|
26
|
+
...(vite ? [reactRefresh.configs.recommended] : []),
|
|
27
27
|
],
|
|
28
28
|
rules: {
|
|
29
|
+
// attributes: false 允许在 JSX 事件属性(如 onClick)上传入 async 函数,此场景仅在 React 中存在
|
|
30
|
+
'@typescript-eslint/no-misused-promises': [
|
|
31
|
+
'error',
|
|
32
|
+
{
|
|
33
|
+
checksVoidReturn: {
|
|
34
|
+
attributes: false,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
],
|
|
29
38
|
...overrides,
|
|
30
39
|
},
|
|
31
40
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TypeScript ESLint
|
|
2
|
+
* TypeScript ESLint configuration with type-aware linting (recommended rules + stylistic rules)
|
|
3
3
|
*/
|
|
4
4
|
import { defineConfig } from 'eslint/config'
|
|
5
5
|
import { configs, parser, plugin } from 'typescript-eslint'
|
|
@@ -10,7 +10,7 @@ import type { TypeScriptOptions } from '../types'
|
|
|
10
10
|
import type { Linter } from 'eslint'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* TypeScript
|
|
13
|
+
* TypeScript rule configuration
|
|
14
14
|
*/
|
|
15
15
|
export function typescript(options: TypeScriptOptions = {}): Linter.Config[] {
|
|
16
16
|
const { files = [GLOB_TS], tsconfigRootDir, overrides = {} } = options
|
|
@@ -34,16 +34,8 @@ export function typescript(options: TypeScriptOptions = {}): Linter.Config[] {
|
|
|
34
34
|
'@typescript-eslint/consistent-type-imports': 'error',
|
|
35
35
|
'@typescript-eslint/no-unused-vars': 'off',
|
|
36
36
|
'@typescript-eslint/no-deprecated': 'warn',
|
|
37
|
-
'@typescript-eslint/no-inferrable-types': 'off',
|
|
37
|
+
// '@typescript-eslint/no-inferrable-types': 'off', 会导致冗余的类型注解
|
|
38
38
|
'@typescript-eslint/unbound-method': 'warn',
|
|
39
|
-
'@typescript-eslint/no-misused-promises': [
|
|
40
|
-
'error',
|
|
41
|
-
{
|
|
42
|
-
checksVoidReturn: {
|
|
43
|
-
attributes: false,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
39
|
|
|
48
40
|
...overrides,
|
|
49
41
|
},
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vitest
|
|
2
|
+
* Vitest test rule configuration with testing best practices and quality assurance rules
|
|
3
3
|
*/
|
|
4
|
-
import { fixupPluginRules } from '@eslint/compat'
|
|
5
4
|
import vitestPlugin from '@vitest/eslint-plugin'
|
|
6
5
|
import { defineConfig } from 'eslint/config'
|
|
7
6
|
|
|
8
7
|
import { GLOB_TESTS, isInEditorEnv } from '../utils'
|
|
9
8
|
|
|
10
9
|
import type { VitestOptions } from '../types'
|
|
11
|
-
import type {
|
|
10
|
+
import type { Linter } from 'eslint'
|
|
12
11
|
|
|
13
12
|
export function vitest(options: VitestOptions = {}): Linter.Config[] {
|
|
14
13
|
const {
|
|
@@ -22,7 +21,7 @@ export function vitest(options: VitestOptions = {}): Linter.Config[] {
|
|
|
22
21
|
name: 'vitest/rules',
|
|
23
22
|
files,
|
|
24
23
|
plugins: {
|
|
25
|
-
vitest:
|
|
24
|
+
vitest: vitestPlugin,
|
|
26
25
|
},
|
|
27
26
|
rules: {
|
|
28
27
|
...vitestPlugin.configs.recommended.rules,
|