@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 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) - Recommended
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
- sonarjs.configs.recommended,
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: true,
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
- ['value-parent', 'alias'],
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.0-beta.9",
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.28.6",
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",