@kununu/eslint-config 6.0.0-beta.8 → 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,19 +14,11 @@ 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
- Create an `eslint.config.js` file:
21
+ Create an `eslint.config.cjs` file:
30
22
 
31
23
  ```javascript
32
24
  import kununuConfig from '@kununu/eslint-config';
@@ -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
@@ -1,371 +1,270 @@
1
1
  import babelParser from '@babel/eslint-parser';
2
2
  import babelPlugin from '@babel/eslint-plugin';
3
3
  import js from '@eslint/js';
4
+ import stylistic from '@stylistic/eslint-plugin';
4
5
  import typescriptParser from '@typescript-eslint/parser';
5
6
  import eslintConfigPrettier from 'eslint-config-prettier/flat';
6
7
  import granularSelectorsPlugin from 'eslint-plugin-granular-selectors';
7
- import importPlugin from 'eslint-plugin-import';
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';
11
- import perfectionist from 'eslint-plugin-perfectionist';
12
+ import perfectionistPlugin from 'eslint-plugin-perfectionist';
12
13
  import reactPlugin from 'eslint-plugin-react';
13
14
  import reactHooksPlugin from 'eslint-plugin-react-hooks';
14
- import sortDestructureKeysPlugin from 'eslint-plugin-sort-destructure-keys';
15
+ import sonarjs from 'eslint-plugin-sonarjs';
15
16
  import testingLibraryPlugin from 'eslint-plugin-testing-library';
16
- import typescriptEslint from 'typescript-eslint';
17
+ import {defineConfig, globalIgnores} from 'eslint/config';
18
+ import tseslint from 'typescript-eslint';
17
19
 
18
- // Base rules shared between JS and TS configurations
19
- const baseRules = {
20
- '@babel/object-curly-spacing': 'error',
21
- 'arrow-parens': ['error', 'as-needed'],
22
- 'eol-last': ['error', 'always'],
23
- 'granular-selectors/granular-selectors': ['error', {
24
- include: ['use.*Selector.*', 'use.*Store.*']
25
- }],
26
- 'import/extensions': ['error', 'ignorePackages', {
27
- 'js': 'never',
28
- 'json': 'always',
29
- 'jsx': 'never',
30
- 'scss': 'ignorePackages',
31
- 'ts': 'never',
32
- 'tsx': 'never'
33
- }],
34
- 'import/no-extraneous-dependencies': ['error', {
35
- devDependencies: [
36
- '**/*.spec.js',
37
- '**/*.spec.jsx',
38
- '**/*.test.js',
39
- '**/*.test.jsx',
40
- '**/stories.jsx',
41
- '*/test-*/*.js',
42
- '*/test-*/*.jsx',
43
- 'config/**/*.js',
44
- 'jest.setup.js',
45
- 'jestsetup.js',
46
- 'mockBff/*',
47
- 'next.config.js',
48
- ],
49
- }],
50
- 'import/no-useless-path-segments': ['error', {
51
- 'noUselessIndex': true,
52
- }],
53
- 'import/order': [
54
- 'error',
55
- {
56
- 'alphabetize': {
57
- 'caseInsensitive': true,
58
- 'order': 'asc'
59
- },
60
- 'groups': [
61
- 'builtin',
62
- 'external',
63
- 'internal',
64
- 'parent',
65
- 'sibling',
66
- 'index'
67
- ],
68
- 'newlines-between': 'always',
69
- 'pathGroups': [
70
- {
71
- 'group': 'builtin',
72
- 'pattern': 'react',
73
- 'position': 'before'
74
- },
75
- {
76
- 'group': 'external',
77
- 'pattern': '@kununu/**',
78
- 'position': 'after'
79
- }
80
- ],
81
- 'pathGroupsExcludedImportTypes': ['react']
82
- }
83
- ],
84
- 'indent': 'off',
85
- 'jsx-a11y/anchor-is-valid': ['error', {
86
- components: ['Link'],
87
- specialLink: ['to'],
88
- }],
89
- 'jsx-a11y/label-has-for': ['error', {
90
- 'required': 'id',
91
- }],
92
- 'lodash/import-scope': [2, 'method'],
93
- 'max-len': 'off',
94
- 'no-confusing-arrow': 'off',
95
- 'no-multiple-empty-lines': ['error', {'max': 1, 'maxEOF': 1}],
96
- 'no-param-reassign': ['error', {props: false}],
97
- 'no-prototype-builtins': 'off',
98
- 'no-restricted-exports': 'off',
99
- 'no-restricted-syntax': ['error',
100
- {
101
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.',
102
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > JSXElement'
103
- },
104
- {
105
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.',
106
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > JSXFragment'
107
- },
108
- {
109
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.',
110
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > CallExpression'
111
- },
112
- {
113
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.',
114
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > ObjectExpression'
115
- },
116
- {
117
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.',
118
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > ArrayExpression'
119
- },
120
- {
121
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.',
122
- selector: 'ReturnStatement > SequenceExpression LogicalExpression[operator="&&"]'
123
- },
124
- {
125
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.',
126
- selector: 'ReturnStatement > ParenthesizedExpression > SequenceExpression LogicalExpression[operator="&&"]'
127
- }
128
- ],
129
- 'no-underscore-dangle': ['error', {'allow': ['__NEXT_DATA__', '__NEXT_REDUX_STORE__']}],
130
- 'no-use-before-define': 'off',
131
- 'object-curly-spacing': 'off',
132
- 'padding-line-between-statements': ['error', {
133
- 'blankLine': 'always', 'next': '*', 'prev': ['const', 'let', 'var'],
134
- }, {
135
- 'blankLine': 'any', 'next': ['const', 'let', 'var'], 'prev': ['const', 'let', 'var'],
136
- }],
137
- 'prefer-promise-reject-errors': 'off',
138
- 'react-hooks/exhaustive-deps': 'warn',
139
- 'react-hooks/rules-of-hooks': 'error',
140
- 'react/function-component-definition': 'off',
141
- 'react/jsx-props-no-spreading': ['error', {
142
- 'custom': 'ignore',
143
- 'html': 'enforce',
144
- }],
145
- 'react/jsx-sort-props': ['error', {
146
- 'ignoreCase': true
147
- }],
148
- 'react/no-direct-mutation-state': 'error',
149
- 'react/react-in-jsx-scope': 'off',
150
- 'react/require-default-props': 0,
151
- 'react/sort-default-props': ['error', {
152
- 'ignoreCase': true
153
- }],
154
- 'react/sort-prop-types': ['error', {
155
- 'ignoreCase': true
156
- }],
157
- 'react/state-in-constructor': 'off',
158
- 'react/static-property-placement': ['error', 'property assignment'],
159
- 'sort-destructure-keys/sort-destructure-keys': [2, {'caseSensitive': false}],
160
- 'sort-keys': ['error', 'asc', {'caseSensitive': false, 'natural': false}],
161
- 'testing-library/prefer-screen-queries': 'off',
162
- 'testing-library/render-result-naming-convention': 'off'
163
- };
20
+ export default defineConfig([
21
+ eslintConfigPrettier,
22
+ js.configs.recommended,
23
+ jsxA11yPlugin.flatConfigs.recommended,
24
+ perfectionistPlugin.configs['recommended-natural'],
25
+ reactHooksPlugin.configs.flat.recommended,
26
+ reactPlugin.configs.flat.recommended,
27
+ reactPlugin.configs.flat['jsx-runtime'],
28
+ sonarjs.configs.recommended,
29
+ stylistic.configs.recommended,
30
+ testingLibraryPlugin.configs['flat/dom'],
31
+ tseslint.configs.recommended,
32
+
33
+ globalIgnores([
34
+ '**/.next/',
35
+ '**/__mocks__/',
36
+ '**/__snapshots__/',
37
+ '**/build/',
38
+ '**/coverage/',
39
+ '**/dist/',
40
+ '**/node_modules/',
41
+ '**/out/',
42
+ '.git/',
43
+ 'jest.config.js',
44
+ 'newrelic.js',
45
+ 'next.config.js',
46
+ ]),
164
47
 
165
- export default [
166
- // Global ignores
167
48
  {
168
- ignores: [
169
- '**/node_modules/**',
170
- '**/dist/**',
171
- '**/build/**',
172
- '**/.next/**',
173
- '**/coverage/**',
174
- ]
49
+ files: ['**/*.ts', '**/*.tsx'],
50
+ languageOptions: {
51
+ parser: typescriptParser,
52
+ parserOptions: {
53
+ projectService: true,
54
+ },
55
+ },
175
56
  },
176
57
 
177
- // Base JavaScript/JSX configuration
178
58
  {
179
59
  files: ['**/*.js', '**/*.jsx'],
180
60
  languageOptions: {
181
- globals: {
182
- __dirname: 'readonly',
183
- __filename: 'readonly',
184
- afterAll: 'readonly',
185
- afterEach: 'readonly',
186
- beforeAll: 'readonly',
187
- beforeEach: 'readonly',
188
- Buffer: 'readonly',
189
- console: 'readonly',
190
- describe: 'readonly',
191
- document: 'readonly',
192
- expect: 'readonly',
193
- exports: 'readonly',
194
- fetch: 'readonly',
195
- it: 'readonly',
196
- jest: 'readonly',
197
- localStorage: 'readonly',
198
- module: 'readonly',
199
- navigator: 'readonly',
200
- process: 'readonly',
201
- require: 'readonly',
202
- sessionStorage: 'readonly',
203
- test: 'readonly',
204
- window: 'readonly',
205
- },
206
61
  parser: babelParser,
207
62
  parserOptions: {
208
- babelOptions: {
209
- presets: ['@babel/preset-react'],
210
- },
211
- ecmaFeatures: {
212
- jsx: true,
213
- },
214
- ecmaVersion: 'latest',
215
63
  requireConfigFile: false,
216
- sourceType: 'module',
217
64
  },
218
65
  },
219
66
  plugins: {
220
- '@babel': babelPlugin,
221
- 'granular-selectors': granularSelectorsPlugin,
222
- 'import': importPlugin,
223
- 'jest-dom': jestDomPlugin,
224
- 'jsx-a11y': jsxA11yPlugin,
225
- 'lodash': lodashPlugin,
226
- 'react': reactPlugin,
227
- 'react-hooks': reactHooksPlugin,
228
- 'sort-destructure-keys': sortDestructureKeysPlugin,
67
+ babel: babelPlugin,
229
68
  },
230
- rules: {
231
- ...js.configs.recommended.rules,
232
- ...baseRules,
69
+ },
70
+
71
+ {
72
+ files: [
73
+ ['**/*.spec.*'],
74
+ ],
75
+ ...jestDomPlugin.configs['flat/recommended'],
76
+ languageOptions: {
77
+ globals: pluginJest.environments.globals.globals,
233
78
  },
234
- settings: {
235
- 'import/resolver': {
236
- node: {
237
- extensions: ['.js', '.jsx', '.json'],
238
- },
239
- },
240
- react: {
241
- version: 'detect',
242
- },
79
+ plugins: {jest: pluginJest},
80
+ rules: {
81
+ '@typescript-eslint/no-explicit-any': 'off',
82
+ 'react/display-name': 'off',
243
83
  },
244
84
  },
245
85
 
246
- // TypeScript configuration
247
86
  {
248
- files: ['**/*.ts', '**/*.tsx'],
249
87
  languageOptions: {
250
- globals: {
251
- __dirname: 'readonly',
252
- __filename: 'readonly',
253
- afterAll: 'readonly',
254
- afterEach: 'readonly',
255
- beforeAll: 'readonly',
256
- beforeEach: 'readonly',
257
- Buffer: 'readonly',
258
- console: 'readonly',
259
- describe: 'readonly',
260
- document: 'readonly',
261
- expect: 'readonly',
262
- exports: 'readonly',
263
- fetch: 'readonly',
264
- it: 'readonly',
265
- jest: 'readonly',
266
- localStorage: 'readonly',
267
- module: 'readonly',
268
- navigator: 'readonly',
269
- process: 'readonly',
270
- require: 'readonly',
271
- sessionStorage: 'readonly',
272
- test: 'readonly',
273
- window: 'readonly',
274
- },
275
- parser: typescriptParser,
276
88
  parserOptions: {
277
89
  ecmaFeatures: {
278
90
  jsx: true,
279
91
  },
280
- ecmaVersion: 'latest',
281
- sourceType: 'module',
282
92
  },
283
93
  },
94
+ linterOptions: {
95
+ reportUnusedDisableDirectives: 'error',
96
+ },
284
97
  plugins: {
285
- '@babel': babelPlugin,
286
- '@typescript-eslint': typescriptEslint.plugin,
287
98
  'granular-selectors': granularSelectorsPlugin,
288
- 'import': importPlugin,
289
- 'jest-dom': jestDomPlugin,
290
- 'jsx-a11y': jsxA11yPlugin,
291
- 'lodash': lodashPlugin,
292
- 'react': reactPlugin,
293
- 'react-hooks': reactHooksPlugin,
294
- 'sort-destructure-keys': sortDestructureKeysPlugin,
99
+ lodash: lodashPlugin,
295
100
  },
296
101
  rules: {
297
- ...js.configs.recommended.rules,
298
- ...typescriptEslint.configs.recommended.rules,
299
- ...typescriptEslint.configs.stylistic.rules,
300
- ...baseRules,
301
- '@typescript-eslint/indent': 'off',
302
- '@typescript-eslint/no-use-before-define': ['error'],
303
- '@typescript-eslint/no-var-requires': 'off',
304
- 'import/no-extraneous-dependencies': ['error', {
305
- devDependencies: [
306
- '**/*.spec.ts',
307
- '**/*.spec.tsx',
308
- '**/stories.tsx',
309
- ],
102
+ // Prevent empty lines in arrays
103
+ '@stylistic/array-bracket-newline': ['error', 'consistent'],
104
+ '@stylistic/array-bracket-spacing': ['error', 'never'],
105
+ '@stylistic/arrow-parens': ['error', 'as-needed'],
106
+ '@stylistic/brace-style': ['error', '1tbs'],
107
+ '@stylistic/member-delimiter-style': ['error', {
108
+ multiline: {
109
+ delimiter: 'semi',
110
+ requireLast: true,
111
+ },
112
+ overrides: {
113
+ interface: {
114
+ multiline: {
115
+ delimiter: 'semi',
116
+ requireLast: true,
117
+ },
118
+ },
119
+ },
120
+ singleline: {
121
+ delimiter: 'semi',
122
+ requireLast: false,
123
+ },
310
124
  }],
311
- 'react/prop-types': 'off',
312
- },
313
- settings: {
314
- 'import/resolver': {
315
- node: {
316
- extensions: ['.ts', '.tsx', '.json'],
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
134
+ '@stylistic/object-curly-spacing': ['error', 'never'],
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'}],
156
+ '@stylistic/quote-props': ['error', 'as-needed'],
157
+ '@stylistic/semi': ['error', 'always'],
158
+ '@stylistic/switch-colon-spacing': 'error',
159
+ '@typescript-eslint/no-use-before-define': 'error',
160
+ '@typescript-eslint/no-var-requires': 'error',
161
+ 'granular-selectors/granular-selectors': ['error', {
162
+ include: ['use.*Selector.*', 'use.*Store.*'],
163
+ }],
164
+ 'lodash/import-scope': [2, 'method'],
165
+ 'no-console': 'warn',
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
+ ],
317
177
  },
318
- typescript: true,
319
- },
320
- react: {
321
- version: 'detect',
322
- },
323
- },
324
- },
325
-
326
- // TypeScript stories and spec files
327
- {
328
- files: ['**/stories.tsx', '**/*.spec.ts', '**/*.spec.tsx'],
329
- rules: {
330
- '@typescript-eslint/no-explicit-any': 'off',
331
- },
332
- },
333
-
334
- // Test files configuration
335
- {
336
- files: [
337
- '**/__tests__/**/*.[jt]s?(x)',
338
- '**/?(*.)+(spec|test).[jt]s?(x)'
339
- ],
340
- plugins: {
341
- 'testing-library': testingLibraryPlugin,
342
- },
343
- rules: {
344
- 'global-require': 'off',
345
- 'jsx-a11y/anchor-is-valid': 'off',
346
- },
347
- },
348
-
349
- // Spec files only
350
- {
351
- files: ['*.spec.js', '*.spec.jsx', '*.spec.ts', '*.spec.tsx'],
352
- rules: {
353
- 'global-require': 'off',
354
- 'jsx-a11y/anchor-is-valid': 'off',
178
+ ],
179
+ 'no-use-before-define': 'off',
180
+ 'perfectionist/sort-imports': [
181
+ 'error',
182
+ {
183
+ customGroups: [
184
+ {
185
+ elementNamePattern: ['^react$'],
186
+ groupName: 'react',
187
+ },
188
+ {
189
+ elementNamePattern: [
190
+ '^actions/.+',
191
+ '^client/.+',
192
+ '^components/.+',
193
+ '^contexts/.+',
194
+ '^genericTypes/.+',
195
+ '^hooks/.+',
196
+ '^images/.+',
197
+ '^mocks/.+',
198
+ '^pages/.+',
199
+ '^server/.+',
200
+ '^slices/.+',
201
+ '^src/.+',
202
+ '^state/.+',
203
+ '^tracking/.+',
204
+ '^types/.+',
205
+ '^utils/.+',
206
+ ],
207
+ groupName: 'alias',
208
+ },
209
+ ],
210
+ groups: [
211
+ 'react',
212
+ 'type-import',
213
+ ['type-builtin', 'type-external'],
214
+ 'type-internal',
215
+ 'type-parent',
216
+ 'type-sibling',
217
+ 'type-index',
218
+ ['value-builtin', 'value-external'],
219
+ 'value-internal',
220
+ 'alias',
221
+ 'value-parent',
222
+ 'value-sibling',
223
+ 'value-index',
224
+ 'ts-equals-import',
225
+ 'unknown',
226
+ ],
227
+ internalPattern: ['^~/.+', '^@kununu/.+'],
228
+ type: 'natural',
229
+ },
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',
249
+ 'react-hooks/exhaustive-deps': 'warn',
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'],
267
+ 'sonarjs/todo-tag': ['warn'],
355
268
  },
356
269
  },
357
-
358
- // Reducer files
359
- {
360
- files: [
361
- '**/reducers/**/*.js',
362
- '**/reducers/**/*.ts'
363
- ],
364
- rules: {
365
- 'default-param-last': 'off'
366
- }
367
- },
368
-
369
- perfectionist.configs['recommended-natural'],
370
- eslintConfigPrettier,
371
- ];
270
+ ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kununu/eslint-config",
3
- "version": "6.0.0-beta.8",
3
+ "version": "6.0.1",
4
4
  "description": "kununu's ESLint config",
5
5
  "main": "eslint.config.mjs",
6
6
  "type": "module",
@@ -30,27 +30,24 @@
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
- "@eslint/compat": "2.0.1",
37
36
  "@eslint/js": "9.39.2",
38
- "@typescript-eslint/eslint-plugin": "8.54.0",
37
+ "@stylistic/eslint-plugin": "5.7.1",
39
38
  "@typescript-eslint/parser": "8.54.0",
40
39
  "eslint": "9.39.2",
41
40
  "eslint-config-prettier": "10.1.8",
42
- "eslint-import-resolver-alias": "1.1.2",
43
41
  "eslint-plugin-granular-selectors": "1.4.0",
44
- "eslint-plugin-import": "2.32.0",
42
+ "eslint-plugin-jest": "29.12.2",
45
43
  "eslint-plugin-jest-dom": "5.5.0",
46
44
  "eslint-plugin-jsx-a11y": "6.10.2",
47
45
  "eslint-plugin-lodash": "8.0.0",
48
- "eslint-plugin-prettier": "5.5.5",
46
+ "eslint-plugin-perfectionist": "5.4.0",
49
47
  "eslint-plugin-react": "7.37.5",
50
48
  "eslint-plugin-react-hooks": "7.0.1",
51
- "eslint-plugin-sort-destructure-keys": "2.0.0",
49
+ "eslint-plugin-sonarjs": "3.0.6",
52
50
  "eslint-plugin-testing-library": "7.15.4",
53
- "eslint-plugin-perfectionist": "5.4.0",
54
51
  "prettier": "3.8.1",
55
52
  "typescript-eslint": "8.54.0"
56
53
  },
@@ -1,181 +0,0 @@
1
- # ESLint Config v6.0.0 Migration Notes
2
-
3
- This document outlines the breaking changes and migration steps from v5.x to v6.0.0.
4
-
5
- ## Major Version Updates
6
-
7
- ### 1. ESLint v9 (9.17.0 → 9.39.2)
8
-
9
- - **Change**: Minor version update within ESLint 9
10
- - **Impact**: No breaking changes, improvements and bug fixes
11
- - **Action**: None required
12
-
13
- ### 2. @eslint/js (9.17.0 → 9.39.2)
14
-
15
- - **Change**: Minor version update
16
- - **Impact**: Updated recommended rules
17
- - **Action**: None required
18
-
19
- ### 3. @eslint/compat (1.2.4 → 2.0.1) āš ļø MAJOR
20
-
21
- - **Change**: API improvements for flat config compatibility
22
- - **Impact**: Better compatibility layer for legacy plugins
23
- - **Action**: None required - internal API improvements
24
-
25
- ### 4. TypeScript ESLint v8 (7.18.0 → 8.54.0) āš ļø MAJOR
26
-
27
- **Breaking Changes:**
28
-
29
- - New unified package structure via `typescript-eslint`
30
- - Plugin and parser now accessed through unified exports
31
- - Some rule names and behaviors changed
32
-
33
- **Migration Actions Taken:**
34
-
35
- - Added `typescript-eslint` package (v8.54.0)
36
- - Updated imports from `@typescript-eslint/eslint-plugin` to `typescript-eslint`
37
- - Changed `typescriptPlugin` to `typescriptEslint.plugin`
38
- - Updated config access from `typescriptPlugin.configs.*` to `typescriptEslint.configs.*`
39
- - Kept separate `@typescript-eslint/parser` and `@typescript-eslint/eslint-plugin` for compatibility
40
-
41
- **Key Changes:**
42
-
43
- ```javascript
44
- // Old (v7)
45
- const typescriptPlugin = require('@typescript-eslint/eslint-plugin');
46
- plugins: { '@typescript-eslint': typescriptPlugin }
47
- rules: { ...typescriptPlugin.configs.recommended.rules }
48
-
49
- // New (v8)
50
- const typescriptEslint = require('typescript-eslint');
51
- plugins: { '@typescript-eslint': typescriptEslint.plugin }
52
- rules: { ...typescriptEslint.configs.recommended.rules }
53
- ```
54
-
55
- ### 5. eslint-plugin-lodash (7.4.0 → 8.0.0) āš ļø MAJOR
56
-
57
- - **Change**: ESLint 9 compatibility updates
58
- - **Impact**: Improved flat config support
59
- - **Action**: None required - API compatible
60
-
61
- ### 6. eslint-plugin-react-hooks (4.6.2 → 7.0.1) āš ļø MAJOR
62
-
63
- **Breaking Changes:**
64
-
65
- - Requires ESLint 9+ (already met)
66
- - Stricter exhaustive-deps checking
67
- - Better support for React 19
68
-
69
- **Migration Actions:**
70
-
71
- - No code changes required
72
- - Existing rules remain compatible
73
- - May surface additional dependency warnings (intended behavior)
74
-
75
- **Current Rules:**
76
-
77
- ```javascript
78
- 'react-hooks/rules-of-hooks': 'error',
79
- 'react-hooks/exhaustive-deps': 'warn',
80
- ```
81
-
82
- ## Package.json Updates
83
-
84
- All dependencies updated to latest versions:
85
-
86
- ```json
87
- {
88
- "@eslint/compat": "2.0.1", // 1.2.4 → 2.0.1
89
- "@eslint/js": "9.39.2", // 9.17.0 → 9.39.2
90
- "@typescript-eslint/eslint-plugin": "8.54.0", // 7.18.0 → 8.54.0
91
- "@typescript-eslint/parser": "8.54.0", // 7.18.0 → 8.54.0
92
- "eslint": "9.39.2", // 9.17.0 → 9.39.2
93
- "eslint-plugin-lodash": "8.0.0", // 7.4.0 → 8.0.0
94
- "eslint-plugin-react-hooks": "7.0.1", // 4.6.2 → 7.0.1
95
- "eslint-plugin-perfectionist": "5.4.0", // REPLACES eslint-plugin-typescript-sort-keys
96
- "typescript-eslint": "8.54.0" // NEW PACKAGE
97
- }
98
- ```
99
-
100
- **Removed Dependencies**
101
-
102
- **Airbnb Configs Removed:**
103
-
104
- - `eslint-config-airbnb` - Not compatible with ESLint 9
105
- - `eslint-config-airbnb-typescript` - Not compatible with ESLint 9
106
-
107
- **Reason**: These packages haven't been updated to support ESLint 9's flat config format.
108
- The rules they provided are already covered by our custom rule set and the recommended
109
- configs from individual plugins (React, JSX A11y, Import, etc.). The flat config format
110
- doesn't use `extends` in the traditional way, so we've incorporated the rules directly.
111
-
112
- **Replaced Dependencies**
113
-
114
- **eslint-plugin-typescript-sort-keys → eslint-plugin-perfectionist:**
115
-
116
- - `eslint-plugin-typescript-sort-keys` - Doesn't support ESLint 9
117
- - Replaced with `eslint-plugin-perfectionist` v5.4.0 (ESLint 9 compatible)
118
- - Perfectionist provides the same interface/enum sorting functionality plus additional sorting capabilities
119
- - Rules migrated:
120
- - `typescript-sort-keys/interface` → `perfectionist/sort-interfaces`
121
- - `typescript-sort-keys/string-enum` → `perfectionist/sort-enums`
122
-
123
- ## Configuration Format
124
-
125
- The configuration now uses ESLint v9 flat config format (`eslint.config.mjs`):
126
-
127
- - **ESM format** (import/export) instead of CommonJS (require/module.exports)
128
- - Array-based configuration instead of object
129
- - `languageOptions` instead of `env`, `parser`, `parserOptions`
130
- - Explicit `globals` definitions
131
- - Direct plugin imports as objects
132
- - File-based configuration overrides using `files` property
133
-
134
- **Note**: The configuration file is now `eslint.config.mjs` (ESM) because some plugins
135
- (like `eslint-plugin-perfectionist`) are ESM-only. Your consuming projects should use
136
- ESM format for their ESLint configs as well.
137
-
138
- ## Testing & Validation
139
-
140
- After updating, ensure:
141
-
142
- 1. **Install dependencies:**
143
-
144
- ```bash
145
- npm install --legacy-peer-deps
146
- ```
147
-
148
- **Note**: The `--legacy-peer-deps` flag is required because some plugins
149
- (`eslint-plugin-typescript-sort-keys`) haven't updated their peer dependencies
150
- to support ESLint 9 yet, even though they work correctly with it.
151
-
152
- 2. **Test in consuming projects:**
153
- - Update import: `extends: ['@kununu/eslint-config']` (if using old format)
154
- - Or import config: `const kununuConfig = require('@kununu/eslint-config')`
155
- - You may also need `--legacy-peer-deps` in consuming projects
156
-
157
- 3. **Check for new warnings:**
158
- - TypeScript rules may be stricter
159
- - React Hooks exhaustive-deps may surface more warnings
160
- - Review and address any new lint errors
161
-
162
- 4. **Verify compatibility:**
163
- - Test with JavaScript files
164
- - Test with TypeScript files
165
- - Test with React components
166
- - Test with test files (*.spec.*, *.test.*)
167
-
168
- ## Rollback Plan
169
-
170
- If issues occur, you can rollback to v5.x:
171
-
172
- ```bash
173
- npm install @kununu/eslint-config@5.11.7
174
- ```
175
-
176
- And revert to using `index.js` configuration format.
177
-
178
- ## Support
179
-
180
- For issues or questions, please file an issue at:
181
- <https://github.com/kununu/eslint-config/issues>
package/index.js DELETED
@@ -1,345 +0,0 @@
1
- // we need to have the baseRules to have the same on the typescript override
2
- // because it has extends the eslint does not take into consideration the ones from the base
3
- const baseRules = {
4
- 'import/no-extraneous-dependencies': ['error', {
5
- devDependencies: [
6
- '**/*.spec.js',
7
- '**/*.spec.jsx',
8
- '**/*.test.js',
9
- '**/*.test.jsx',
10
- '**/stories.jsx',
11
- '*/test-*/*.js',
12
- '*/test-*/*.jsx',
13
- 'config/**/*.js',
14
- 'jest.setup.js',
15
- 'jestsetup.js',
16
- 'mockBff/*',
17
- 'next.config.js',
18
- ],
19
- }],
20
- 'max-len': 'off', // Sometimes longer lines are more readable (Airbnb rule change)
21
- 'no-param-reassign': ['error', {props: false}],
22
- 'no-prototype-builtins': 'off', // Objects aren't created that don't extend from Object.prototype (Airbnb rule change)
23
- 'object-curly-spacing': 'off', // Disabled in favor of @babel/object-curly-spacing in order to avoid false positives with ECMAScript modules (Airbnb rule change)
24
- 'no-use-before-define': 'off',
25
- 'sort-destructure-keys/sort-destructure-keys': [2, {'caseSensitive': false}],
26
-
27
- // https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules
28
- 'react/no-direct-mutation-state': 'error', // Use .setState() always (Airbnb rule change)
29
-
30
- // https://github.com/babel/babel/tree/main/eslint/babel-eslint-plugin#rules
31
- '@babel/object-curly-spacing': 'error', // No spaces in single-line objects to make nested objects like {a: {b: 'c'}} look more sane (Airbnb rule change)
32
-
33
- // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/
34
- 'import/order': ['error', { // Make import sort order an error (Airbnb rule change)
35
- 'newlines-between': 'always',
36
- groups: [
37
- 'builtin', // import fs from 'fs';
38
- 'external', // import chalk from 'chalk';
39
- 'internal', // import foo from 'src/foo';
40
- 'parent', // import qux from '../qux';
41
- 'sibling', // import bar from './bar';
42
- 'index', // import main from './';
43
- ],
44
- }],
45
-
46
- 'import/no-useless-path-segments': ['error', {
47
- 'noUselessIndex': true,
48
- }],
49
-
50
- // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md#rule-details
51
- // allow `Link` to have `to` and not the mandatory `href`
52
- 'jsx-a11y/anchor-is-valid': ['error', {
53
- components: ['Link'],
54
- specialLink: ['to'],
55
- }],
56
-
57
- // https://eslint.org/docs/rules/no-confusing-arrow
58
- // turn off to prevent conflict with
59
- // https://eslint.org/docs/rules/arrow-body-style
60
- 'no-confusing-arrow': 'off',
61
-
62
- // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md
63
- // 'label' tags need 'htmlFor' prop, but nesting is not required
64
- 'jsx-a11y/label-has-for': ['error', {
65
- 'required': 'id',
66
- }],
67
-
68
- // https://eslint.org/docs/rules/padding-line-between-statements
69
- // enforce empty lines after variable declarations
70
- 'padding-line-between-statements': ['error', {
71
- 'blankLine': 'always', 'prev': ['const', 'let', 'var'], 'next': '*',
72
- }, {
73
- 'blankLine': 'any', 'prev': ['const', 'let', 'var'], 'next': ['const', 'let', 'var'],
74
- }],
75
-
76
- // https://www.npmjs.com/package/eslint-plugin-react-hooks
77
- // enforces the rules of react-hooks (call at top level and only from functional components; checks dependencies)
78
- 'react-hooks/rules-of-hooks': 'error',
79
- 'react-hooks/exhaustive-deps': 'warn',
80
-
81
- // https://eslint.org/docs/rules/no-underscore-dangle
82
- // no underscores at either the beginning or end of an identifier
83
- 'no-underscore-dangle': ['error', {'allow': ['__NEXT_DATA__', '__NEXT_REDUX_STORE__']}],
84
-
85
- 'no-multiple-empty-lines': ['error', {'max': 1, 'maxEOF': 1}],
86
-
87
- // https://eslint.org/docs/rules/eol-last
88
- // require newline at the end of files
89
- 'eol-last': ['error', 'always'],
90
-
91
- // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/sort-default-props.md
92
- // enforce defaultProps declarations alphabetical sorting
93
- 'react/sort-default-props': ['error', {
94
- 'ignoreCase': true
95
- }],
96
-
97
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md
98
- // enforce props alphabetical sorting
99
- 'react/jsx-sort-props': ['error', {
100
- 'ignoreCase': true
101
- }],
102
-
103
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md
104
- // enforce propTypes declarations alphabetical sorting
105
- 'react/sort-prop-types': ['error', {
106
- 'ignoreCase': true
107
- }],
108
-
109
- // https://eslint.org/docs/rules/sort-keys
110
- // require object keys to be sorted
111
- 'sort-keys': ['error', 'asc', {'caseSensitive': false, 'natural': false}],
112
-
113
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/static-property-placement.md
114
- // enforces where React component static properties should be positioned
115
- 'react/static-property-placement': ['error', 'property assignment'],
116
-
117
- // https://eslint.org/docs/rules/indent
118
- // enforces a consistent 2 spaces indentation style
119
- 'indent': ['error', 2, {
120
- 'SwitchCase': 1
121
- }],
122
-
123
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/state-in-constructor.md
124
- // enforces the state initialization style to be either in a constructor or with a class property
125
- 'react/state-in-constructor': 'off',
126
-
127
- // https://eslint.org/docs/rules/arrow-parens
128
- // enforces no braces where they can be omitted
129
- 'arrow-parens': ['error', 'as-needed'],
130
-
131
- // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md
132
- 'import/extensions': ['error', 'ignorePackages', {
133
- 'js': 'never',
134
- 'jsx': 'never',
135
- 'ts': 'never',
136
- 'tsx': 'never',
137
- 'scss': 'ignorePackages',
138
- 'json': 'always'
139
- }],
140
-
141
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-props-no-spreading.md
142
- // disallow spread on html tags directly but allows it on React components
143
- 'react/jsx-props-no-spreading': ['error', {
144
- 'html': 'enforce',
145
- 'custom': 'ignore',
146
- }],
147
-
148
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md
149
- 'react/function-component-definition': 'off',
150
- 'react/react-in-jsx-scope': 'off',
151
- 'prefer-promise-reject-errors': 'off',
152
- 'no-restricted-exports': 'off',
153
-
154
- 'testing-library/prefer-screen-queries': 'off',
155
- 'testing-library/render-result-naming-convention': 'off',
156
-
157
- 'indent': 'off',
158
-
159
- 'prettier/prettier': [
160
- 'error',
161
- {
162
- 'arrowParens': 'avoid',
163
- 'bracketSpacing': false,
164
- 'semi': true,
165
- 'singleQuote': true,
166
- 'trailingComma': 'all',
167
- },
168
- ],
169
-
170
- 'import/order': [
171
- 'error',
172
- {
173
- 'groups': [
174
- 'builtin',
175
- 'external',
176
- 'internal',
177
- 'parent',
178
- 'sibling',
179
- 'index'
180
- ],
181
- 'newlines-between': 'always',
182
- 'alphabetize': {
183
- 'order': 'asc',
184
- 'caseInsensitive': true
185
- },
186
- 'pathGroups': [
187
- {
188
- 'pattern': 'react',
189
- 'group': 'builtin',
190
- 'position': 'before'
191
- },
192
- {
193
- 'pattern': '@kununu/**',
194
- 'group': 'external',
195
- 'position': 'after'
196
- }
197
- ],
198
- 'pathGroupsExcludedImportTypes': ['react']
199
- }
200
- ],
201
-
202
- 'lodash/import-scope': [2, 'method'],
203
-
204
- // https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-proptypes-and-defaultprops
205
- 'react/require-default-props': 0,
206
-
207
- 'no-restricted-syntax': ['error',
208
- // Target JSX elements specifically
209
- {
210
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > JSXElement',
211
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.'
212
- },
213
- // Target JSX fragments
214
- {
215
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > JSXFragment',
216
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.'
217
- },
218
- // Target function calls (which could be component invocations)
219
- {
220
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > CallExpression',
221
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.'
222
- },
223
- // Target object expressions (which could be props)
224
- {
225
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > ObjectExpression',
226
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.'
227
- },
228
- // Target array expressions
229
- {
230
- selector: 'ReturnStatement > LogicalExpression[operator="&&"] > ArrayExpression',
231
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.'
232
- },
233
- // Keep the sequence expression rules
234
- {
235
- selector: 'ReturnStatement > SequenceExpression LogicalExpression[operator="&&"]',
236
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.'
237
- },
238
- {
239
- selector: 'ReturnStatement > ParenthesizedExpression > SequenceExpression LogicalExpression[operator="&&"]',
240
- message: 'Prefer early returns over logical expressions in return statements. Use if (condition) return value; instead.'
241
- }
242
- ],
243
-
244
- 'granular-selectors/granular-selectors': ['error', {
245
- // Array of patterns to include for selector function detection
246
- include: ['use.*Selector.*', 'use.*Store.*']
247
- }]
248
- };
249
-
250
- module.exports = {
251
- extends: [
252
- 'airbnb', // Many strict rules for ECMAScript and React
253
- 'airbnb/hooks',
254
- 'plugin:import/errors',
255
- 'plugin:jest-dom/recommended',
256
- 'plugin:prettier/recommended',
257
- 'plugin:react-hooks/recommended',
258
- ],
259
-
260
- parser: '@babel/eslint-parser',
261
-
262
- plugins: [
263
- '@babel',
264
- 'lodash',
265
- 'sort-destructure-keys',
266
- 'granular-selectors'
267
- ],
268
-
269
- env: {
270
- browser: true,
271
- jest: true,
272
- node: true,
273
- es6: true,
274
- },
275
-
276
- rules: baseRules,
277
-
278
- overrides: [{
279
- files: [
280
- '**/__tests__/**/*.[jt]s?(x)',
281
- '**/?(*.)+(spec|test).[jt]s?(x)'
282
- ],
283
- extends: [
284
- 'plugin:testing-library/react'
285
- ],
286
- }, {
287
- files: [
288
- '**/*.ts',
289
- '**/*.tsx',
290
- ],
291
- extends: [
292
- 'airbnb', // Many strict rules for ECMAScript and React
293
- 'airbnb-typescript',
294
- 'airbnb/hooks',
295
- 'plugin:@typescript-eslint/recommended',
296
- 'plugin:@typescript-eslint/stylistic',
297
- 'plugin:import/errors',
298
- 'plugin:jest-dom/recommended',
299
- 'plugin:prettier/recommended',
300
- 'plugin:react-hooks/recommended',
301
- ],
302
- parser: '@typescript-eslint/parser',
303
- plugins: [
304
- 'typescript-sort-keys'
305
- ],
306
- rules: {
307
- ...baseRules,
308
- '@typescript-eslint/indent': 'off',
309
- '@typescript-eslint/no-use-before-define': ['error'],
310
- '@typescript-eslint/no-var-requires': 'off',
311
- 'react/prop-types': 'off',
312
- 'typescript-sort-keys/interface': ['error', 'asc', {'caseSensitive': false, 'natural': false, requiredFirst: true}],
313
- 'typescript-sort-keys/string-enum': ['error', 'asc', {'caseSensitive': false, 'natural': false}],
314
- 'import/no-extraneous-dependencies': ['error', {
315
- devDependencies: [
316
- '**/*.spec.ts',
317
- '**/*.spec.tsx',
318
- '**/stories.tsx',
319
- ],
320
- }],
321
- },
322
- overrides: [
323
- {
324
- files: ['**/stories.tsx', '*.spec.ts', '*.spec.tsx'],
325
- rules: {
326
- '@typescript-eslint/no-explicit-any': 'off',
327
- },
328
- }
329
- ],
330
- }, {
331
- files: ['*.spec.js', '*.spec.jsx', '*.spec.ts', '*.spec.tsx'],
332
- rules: {
333
- 'global-require': 'off',
334
- 'jsx-a11y/anchor-is-valid': 'off',
335
- },
336
- }, {
337
- files: [
338
- '**/reducers/**/*.js',
339
- '**/reducers/**/*.ts'
340
- ],
341
- rules: {
342
- 'default-param-last': 'off'
343
- }
344
- }],
345
- };
package/test.mjs DELETED
@@ -1,57 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Simple test to verify the ESLint config loads and exports correctly
5
- */
6
-
7
- import config from './eslint.config.mjs';
8
-
9
- console.log('Testing @kununu/eslint-config...\n');
10
-
11
- // Test 1: Config is an array
12
- if (!Array.isArray(config)) {
13
- console.error('āœ— Config should be an array');
14
- process.exit(1);
15
- }
16
- console.log('āœ“ Config is an array');
17
-
18
- // Test 2: Has expected number of config objects
19
- if (config.length < 5) {
20
- console.error('āœ— Config should have at least 5 config objects');
21
- process.exit(1);
22
- }
23
- console.log(`āœ“ Config has ${config.length} config objects`);
24
-
25
- // Test 3: Has ignores
26
- const hasIgnores = config.some(c => c.ignores);
27
- if (!hasIgnores) {
28
- console.error('āœ— Config should have ignores');
29
- process.exit(1);
30
- }
31
- console.log('āœ“ Config has ignores');
32
-
33
- // Test 4: Has TypeScript config
34
- const hasTsConfig = config.some(c => c.files && c.files.some(f => f.includes('*.ts')));
35
- if (!hasTsConfig) {
36
- console.error('āœ— Config should have TypeScript config');
37
- process.exit(1);
38
- }
39
- console.log('āœ“ Config has TypeScript support');
40
-
41
- // Test 5: Has perfectionist plugin
42
- const hasPerfectionist = config.some(c => c.plugins && c.plugins.perfectionist);
43
- if (!hasPerfectionist) {
44
- console.error('āœ— Config should have perfectionist plugin');
45
- process.exit(1);
46
- }
47
- console.log('āœ“ Config has perfectionist plugin');
48
-
49
- // Test 6: Has React plugin
50
- const hasReact = config.some(c => c.plugins && c.plugins.react);
51
- if (!hasReact) {
52
- console.error('āœ— Config should have React plugin');
53
- process.exit(1);
54
- }
55
- console.log('āœ“ Config has React plugin');
56
-
57
- console.log('\nāœ“ All tests passed!');