@kununu/eslint-config 6.0.0-beta.9 → 6.0.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/README.md +1 -62
- package/eslint.config.mjs +102 -7
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -14,17 +14,9 @@ Add @kununu/eslint-config npm package as dev dependency to your project:
|
|
|
14
14
|
npm install --save-dev @kununu/eslint-config
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
### TypeScript Projects
|
|
18
|
-
|
|
19
|
-
If you're linting TypeScript files, you'll also need to install TypeScript:
|
|
20
|
-
|
|
21
|
-
```console
|
|
22
|
-
npm install --save-dev typescript
|
|
23
|
-
```
|
|
24
|
-
|
|
25
17
|
## 💻 Usage
|
|
26
18
|
|
|
27
|
-
### ESLint v9 (Flat Config)
|
|
19
|
+
### ESLint v9 (Flat Config)
|
|
28
20
|
|
|
29
21
|
Create an `eslint.config.cjs` file:
|
|
30
22
|
|
|
@@ -37,59 +29,6 @@ export default [
|
|
|
37
29
|
];
|
|
38
30
|
```
|
|
39
31
|
|
|
40
|
-
### ESLint v8 (Legacy Format)
|
|
41
|
-
|
|
42
|
-
If you're still using ESLint v8, use version 5.x of this package:
|
|
43
|
-
|
|
44
|
-
```console
|
|
45
|
-
npm install --save-dev @kununu/eslint-config@5
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Then create a `.eslintrc.js` file:
|
|
49
|
-
|
|
50
|
-
```javascript
|
|
51
|
-
module.exports = {
|
|
52
|
-
extends: '@kununu/eslint-config'
|
|
53
|
-
};
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## 🔧 Configuration Details
|
|
57
|
-
|
|
58
|
-
This config includes rules for:
|
|
59
|
-
|
|
60
|
-
- **JavaScript/JSX**: Babel parser with React support
|
|
61
|
-
- **TypeScript/TSX**: TypeScript ESLint v8 with strict typing
|
|
62
|
-
- **React**: React 18+ with hooks support
|
|
63
|
-
- **Testing**: Jest, Jest DOM, and Testing Library
|
|
64
|
-
- **Code Quality**: Import ordering, Lodash optimization, granular selectors
|
|
65
|
-
- **Formatting**: Prettier integration with consistent style
|
|
66
|
-
|
|
67
|
-
### Included Plugins
|
|
68
|
-
|
|
69
|
-
- `@babel/eslint-plugin` - Babel-specific rules
|
|
70
|
-
- `eslint-plugin-react` - React-specific linting rules
|
|
71
|
-
- `eslint-plugin-react-hooks` - Rules for React Hooks
|
|
72
|
-
- `eslint-plugin-jsx-a11y` - Accessibility rules for JSX
|
|
73
|
-
- `eslint-plugin-import` - Import/export syntax validation
|
|
74
|
-
- `eslint-plugin-lodash` - Lodash optimization
|
|
75
|
-
- `eslint-plugin-prettier` - Prettier integration
|
|
76
|
-
- `@typescript-eslint` - TypeScript support
|
|
77
|
-
- `eslint-plugin-testing-library` - Testing Library best practices
|
|
78
|
-
- `eslint-plugin-jest-dom` - Jest DOM matchers
|
|
79
|
-
- `eslint-plugin-sort-destructure-keys` - Destructuring key sorting
|
|
80
|
-
- `eslint-plugin-granular-selectors` - Zustand/Redux selector validation
|
|
81
|
-
- `eslint-plugin-perfectionist` - Universal sorting (interfaces, enums, objects, imports, etc.)
|
|
82
|
-
|
|
83
|
-
## 📝 Key Rules
|
|
84
|
-
|
|
85
|
-
- Prefer early returns over logical expressions in return statements
|
|
86
|
-
- Alphabetically sorted imports with newlines between groups
|
|
87
|
-
- React components with sorted props and defaultProps
|
|
88
|
-
- TypeScript interfaces with sorted keys
|
|
89
|
-
- 2-space indentation
|
|
90
|
-
- Single quotes, trailing commas
|
|
91
|
-
- No semicolons (via Prettier)
|
|
92
|
-
|
|
93
32
|
See [docs](https://eslint.org/docs/user-guide/getting-started) to find more detailed information on ESLint configuration and usage.
|
|
94
33
|
|
|
95
34
|
## ⚡️ Plugins
|
package/eslint.config.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import stylistic from '@stylistic/eslint-plugin';
|
|
|
5
5
|
import typescriptParser from '@typescript-eslint/parser';
|
|
6
6
|
import eslintConfigPrettier from 'eslint-config-prettier/flat';
|
|
7
7
|
import granularSelectorsPlugin from 'eslint-plugin-granular-selectors';
|
|
8
|
+
import pluginJest from 'eslint-plugin-jest';
|
|
8
9
|
import jestDomPlugin from 'eslint-plugin-jest-dom';
|
|
9
10
|
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
|
|
10
11
|
import lodashPlugin from 'eslint-plugin-lodash';
|
|
@@ -17,17 +18,17 @@ import {defineConfig, globalIgnores} from 'eslint/config';
|
|
|
17
18
|
import tseslint from 'typescript-eslint';
|
|
18
19
|
|
|
19
20
|
export default defineConfig([
|
|
20
|
-
js.configs.recommended,
|
|
21
|
-
tseslint.configs.recommended,
|
|
22
21
|
eslintConfigPrettier,
|
|
22
|
+
js.configs.recommended,
|
|
23
|
+
jsxA11yPlugin.flatConfigs.recommended,
|
|
23
24
|
perfectionistPlugin.configs['recommended-natural'],
|
|
24
25
|
reactHooksPlugin.configs.flat.recommended,
|
|
25
26
|
reactPlugin.configs.flat.recommended,
|
|
26
27
|
reactPlugin.configs.flat['jsx-runtime'],
|
|
28
|
+
sonarjs.configs.recommended,
|
|
27
29
|
stylistic.configs.recommended,
|
|
28
|
-
jsxA11yPlugin.flatConfigs.recommended,
|
|
29
30
|
testingLibraryPlugin.configs['flat/dom'],
|
|
30
|
-
|
|
31
|
+
tseslint.configs.recommended,
|
|
31
32
|
|
|
32
33
|
globalIgnores([
|
|
33
34
|
'**/.next/',
|
|
@@ -48,6 +49,9 @@ export default defineConfig([
|
|
|
48
49
|
files: ['**/*.ts', '**/*.tsx'],
|
|
49
50
|
languageOptions: {
|
|
50
51
|
parser: typescriptParser,
|
|
52
|
+
parserOptions: {
|
|
53
|
+
projectService: true,
|
|
54
|
+
},
|
|
51
55
|
},
|
|
52
56
|
},
|
|
53
57
|
|
|
@@ -69,6 +73,10 @@ export default defineConfig([
|
|
|
69
73
|
['**/*.spec.*'],
|
|
70
74
|
],
|
|
71
75
|
...jestDomPlugin.configs['flat/recommended'],
|
|
76
|
+
languageOptions: {
|
|
77
|
+
globals: pluginJest.environments.globals.globals,
|
|
78
|
+
},
|
|
79
|
+
plugins: {jest: pluginJest},
|
|
72
80
|
rules: {
|
|
73
81
|
'@typescript-eslint/no-explicit-any': 'off',
|
|
74
82
|
'react/display-name': 'off',
|
|
@@ -83,12 +91,19 @@ export default defineConfig([
|
|
|
83
91
|
},
|
|
84
92
|
},
|
|
85
93
|
},
|
|
94
|
+
linterOptions: {
|
|
95
|
+
reportUnusedDisableDirectives: 'error',
|
|
96
|
+
},
|
|
86
97
|
plugins: {
|
|
87
98
|
'granular-selectors': granularSelectorsPlugin,
|
|
88
99
|
lodash: lodashPlugin,
|
|
89
100
|
},
|
|
90
101
|
rules: {
|
|
102
|
+
// Prevent empty lines in arrays
|
|
103
|
+
'@stylistic/array-bracket-newline': ['error', 'consistent'],
|
|
104
|
+
'@stylistic/array-bracket-spacing': ['error', 'never'],
|
|
91
105
|
'@stylistic/arrow-parens': ['error', 'as-needed'],
|
|
106
|
+
'@stylistic/brace-style': ['error', '1tbs'],
|
|
92
107
|
'@stylistic/member-delimiter-style': ['error', {
|
|
93
108
|
multiline: {
|
|
94
109
|
delimiter: 'semi',
|
|
@@ -104,20 +119,63 @@ export default defineConfig([
|
|
|
104
119
|
},
|
|
105
120
|
singleline: {
|
|
106
121
|
delimiter: 'semi',
|
|
107
|
-
requireLast:
|
|
122
|
+
requireLast: false,
|
|
108
123
|
},
|
|
109
124
|
}],
|
|
125
|
+
// Prevent multiple consecutive empty lines but allow single ones
|
|
126
|
+
'@stylistic/no-multiple-empty-lines': ['error', {
|
|
127
|
+
max: 1,
|
|
128
|
+
maxBOF: 0,
|
|
129
|
+
maxEOF: 0,
|
|
130
|
+
}],
|
|
131
|
+
// For object destructuring patterns
|
|
132
|
+
'@stylistic/object-curly-newline': ['error', {consistent: true}],
|
|
133
|
+
// Prevent empty lines inside object literals and destructuring
|
|
110
134
|
'@stylistic/object-curly-spacing': ['error', 'never'],
|
|
111
|
-
'@stylistic/operator-linebreak': ['error', 'after'],
|
|
135
|
+
'@stylistic/operator-linebreak': ['error', 'after', {overrides: {'|': 'before'}}],
|
|
136
|
+
'@stylistic/padded-blocks': ['error', 'never'],
|
|
137
|
+
'@stylistic/padding-line-between-statements': ['error',
|
|
138
|
+
// Allow any spacing between imports (to allow grouping and other import rules)
|
|
139
|
+
{blankLine: 'any', next: 'import', prev: 'import'},
|
|
140
|
+
// Always require blank line after imports when followed by non-imports
|
|
141
|
+
{blankLine: 'always', next: '*', prev: 'import'},
|
|
142
|
+
// But allow imports to be followed by imports without forcing blank line
|
|
143
|
+
{blankLine: 'any', next: 'import', prev: 'import'},
|
|
144
|
+
// Allow any spacing between variable declarations (before and between)
|
|
145
|
+
{blankLine: 'any', next: ['const', 'let', 'var'], prev: '*'},
|
|
146
|
+
// Always require blank line after variable declarations when followed by non-variables
|
|
147
|
+
{blankLine: 'always', next: '*', prev: ['const', 'let', 'var']},
|
|
148
|
+
// But allow variables to be followed by variables without forcing blank line (override above)
|
|
149
|
+
{blankLine: 'any', next: ['const', 'let', 'var'], prev: ['const', 'let', 'var']},
|
|
150
|
+
// Always require blank line before return statements
|
|
151
|
+
{blankLine: 'always', next: 'return', prev: '*'},
|
|
152
|
+
// Always require blank line before case and default statements
|
|
153
|
+
{blankLine: 'always', next: '*', prev: ['case', 'default']},
|
|
154
|
+
// Allow blank lines between JSX elements (expression statements)
|
|
155
|
+
{blankLine: 'any', next: 'expression', prev: 'expression'}],
|
|
112
156
|
'@stylistic/quote-props': ['error', 'as-needed'],
|
|
113
157
|
'@stylistic/semi': ['error', 'always'],
|
|
158
|
+
'@stylistic/switch-colon-spacing': 'error',
|
|
114
159
|
'@typescript-eslint/no-use-before-define': 'error',
|
|
115
160
|
'@typescript-eslint/no-var-requires': 'error',
|
|
116
161
|
'granular-selectors/granular-selectors': ['error', {
|
|
117
162
|
include: ['use.*Selector.*', 'use.*Store.*'],
|
|
118
163
|
}],
|
|
119
164
|
'lodash/import-scope': [2, 'method'],
|
|
165
|
+
'no-console': 'warn',
|
|
120
166
|
'no-param-reassign': ['error', {props: false}],
|
|
167
|
+
'no-restricted-imports': [
|
|
168
|
+
'error',
|
|
169
|
+
{
|
|
170
|
+
paths: [
|
|
171
|
+
{
|
|
172
|
+
importNames: ['default'],
|
|
173
|
+
message: '\n We want to avoid importing react directly. Please import individual hooks and types from the react module instead.',
|
|
174
|
+
name: 'react',
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
],
|
|
121
179
|
'no-use-before-define': 'off',
|
|
122
180
|
'perfectionist/sort-imports': [
|
|
123
181
|
'error',
|
|
@@ -132,6 +190,7 @@ export default defineConfig([
|
|
|
132
190
|
'^actions/.+',
|
|
133
191
|
'^client/.+',
|
|
134
192
|
'^components/.+',
|
|
193
|
+
'^contexts/.+',
|
|
135
194
|
'^genericTypes/.+',
|
|
136
195
|
'^hooks/.+',
|
|
137
196
|
'^images/.+',
|
|
@@ -139,6 +198,7 @@ export default defineConfig([
|
|
|
139
198
|
'^pages/.+',
|
|
140
199
|
'^server/.+',
|
|
141
200
|
'^slices/.+',
|
|
201
|
+
'^src/.+',
|
|
142
202
|
'^state/.+',
|
|
143
203
|
'^tracking/.+',
|
|
144
204
|
'^types/.+',
|
|
@@ -157,7 +217,8 @@ export default defineConfig([
|
|
|
157
217
|
'type-index',
|
|
158
218
|
['value-builtin', 'value-external'],
|
|
159
219
|
'value-internal',
|
|
160
|
-
|
|
220
|
+
'alias',
|
|
221
|
+
'value-parent',
|
|
161
222
|
'value-sibling',
|
|
162
223
|
'value-index',
|
|
163
224
|
'ts-equals-import',
|
|
@@ -167,8 +228,42 @@ export default defineConfig([
|
|
|
167
228
|
type: 'natural',
|
|
168
229
|
},
|
|
169
230
|
],
|
|
231
|
+
'perfectionist/sort-modules': ['error', {type: 'usage'}],
|
|
232
|
+
'perfectionist/sort-union-types': ['error', {
|
|
233
|
+
groups: [
|
|
234
|
+
'conditional',
|
|
235
|
+
'function',
|
|
236
|
+
'import',
|
|
237
|
+
'intersection',
|
|
238
|
+
'keyword',
|
|
239
|
+
'literal',
|
|
240
|
+
'named',
|
|
241
|
+
'object',
|
|
242
|
+
'operator',
|
|
243
|
+
'tuple',
|
|
244
|
+
'union',
|
|
245
|
+
'nullish',
|
|
246
|
+
],
|
|
247
|
+
}],
|
|
248
|
+
'prefer-template': 'error',
|
|
170
249
|
'react-hooks/exhaustive-deps': 'warn',
|
|
171
250
|
'react-hooks/rules-of-hooks': 'error',
|
|
251
|
+
'react/jsx-closing-bracket-location': ['error', 'tag-aligned'],
|
|
252
|
+
// More restrictive JSX rules that are auto-fixable
|
|
253
|
+
'react/jsx-curly-spacing': ['error', 'never'],
|
|
254
|
+
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
|
|
255
|
+
// Control JSX prop formatting more precisely
|
|
256
|
+
'react/jsx-max-props-per-line': ['error', {maximum: 1, when: 'multiline'}],
|
|
257
|
+
// Keep the non-auto-fixable rule to detect the issue
|
|
258
|
+
'react/jsx-props-no-multi-spaces': 'error',
|
|
259
|
+
// Use jsx-tag-spacing for what it can auto-fix
|
|
260
|
+
'react/jsx-tag-spacing': ['error', {
|
|
261
|
+
afterOpening: 'never',
|
|
262
|
+
beforeClosing: 'never',
|
|
263
|
+
beforeSelfClosing: 'always',
|
|
264
|
+
closingSlash: 'never',
|
|
265
|
+
}],
|
|
266
|
+
'sonarjs/deprecation': ['warn'],
|
|
172
267
|
'sonarjs/todo-tag': ['warn'],
|
|
173
268
|
},
|
|
174
269
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kununu/eslint-config",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "kununu's ESLint config",
|
|
5
5
|
"main": "eslint.config.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/kununu/eslint-config#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@babel/core": "7.
|
|
33
|
+
"@babel/core": "7.29.0",
|
|
34
34
|
"@babel/eslint-parser": "7.28.6",
|
|
35
35
|
"@babel/eslint-plugin": "7.27.1",
|
|
36
36
|
"@eslint/js": "9.39.2",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"eslint": "9.39.2",
|
|
40
40
|
"eslint-config-prettier": "10.1.8",
|
|
41
41
|
"eslint-plugin-granular-selectors": "1.4.0",
|
|
42
|
+
"eslint-plugin-jest": "29.12.2",
|
|
42
43
|
"eslint-plugin-jest-dom": "5.5.0",
|
|
43
44
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
|
44
45
|
"eslint-plugin-lodash": "8.0.0",
|