@kununu/eslint-config 7.1.5 → 7.3.0
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 +97 -17
- package/eslint.config.mjs +52 -13
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,46 +1,126 @@
|
|
|
1
1
|
# @kununu/eslint-config
|
|
2
2
|
|
|
3
|
-
> kununu config
|
|
3
|
+
> kununu's shared [ESLint](https://eslint.org/) config (ESLint v9 — flat config)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Shared linting rules for consistent JS, JSX, TS, and TSX across kununu's frontend
|
|
6
|
+
apps, BFFs, and shared libraries. It bundles the parsers and plugins it needs, so
|
|
7
|
+
consumers only install this one package.
|
|
6
8
|
|
|
7
|
-
**
|
|
9
|
+
> **Flat config only.** This package targets ESLint v9's flat config
|
|
10
|
+
> (`eslint.config.*`). There is no legacy `.eslintrc` export. (v6.0.0+ is flat
|
|
11
|
+
> config; v4/v5 were the legacy format.)
|
|
8
12
|
|
|
9
13
|
## 📦 Installation
|
|
10
14
|
|
|
11
|
-
Add @kununu/eslint-config npm package as dev dependency to your project:
|
|
12
|
-
|
|
13
15
|
```console
|
|
14
16
|
npm install --save-dev @kununu/eslint-config
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
`typescript` is an optional peer dependency (`>=5.0.0`) — only needed for the
|
|
20
|
+
type-aware TypeScript rules (see below).
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
## 💻 Usage
|
|
20
23
|
|
|
21
|
-
Create an
|
|
24
|
+
Create an **`eslint.config.mjs`** (ESM — the config is published as an ES module):
|
|
22
25
|
|
|
23
26
|
```javascript
|
|
24
27
|
import kununuConfig from '@kununu/eslint-config';
|
|
25
28
|
|
|
26
29
|
export default [
|
|
27
30
|
...kununuConfig,
|
|
28
|
-
//
|
|
31
|
+
// your project-specific overrides here
|
|
29
32
|
];
|
|
30
33
|
```
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
Add a lint script to `package.json`:
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"scripts": {
|
|
40
|
+
"lint": "eslint ."
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
35
44
|
|
|
36
|
-
|
|
45
|
+
See the [ESLint docs](https://eslint.org/docs/latest/use/getting-started) for more
|
|
46
|
+
on configuration and usage.
|
|
37
47
|
|
|
38
|
-
|
|
48
|
+
### TypeScript (type-aware rules)
|
|
39
49
|
|
|
40
|
-
|
|
50
|
+
The TS rules use `@typescript-eslint`'s `projectService`, which auto-discovers
|
|
51
|
+
your `tsconfig.json`. Make sure one exists at the project root, otherwise the
|
|
52
|
+
type-aware rules will error.
|
|
41
53
|
|
|
42
|
-
-
|
|
54
|
+
### Project-specific overrides
|
|
43
55
|
|
|
44
|
-
|
|
56
|
+
Append your own flat-config objects after the spread. Scope them with `files`,
|
|
57
|
+
and remember **last match wins**:
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
import kununuConfig from '@kununu/eslint-config';
|
|
45
61
|
|
|
46
|
-
|
|
62
|
+
export default [
|
|
63
|
+
...kununuConfig,
|
|
64
|
+
{
|
|
65
|
+
rules: {
|
|
66
|
+
'no-console': 'off',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
files: ['**/*.spec.*'],
|
|
71
|
+
rules: {
|
|
72
|
+
// test-only tweaks
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 🎨 What's included
|
|
79
|
+
|
|
80
|
+
Built on `@eslint/js`, `typescript-eslint`, and the React ecosystem, plus kununu
|
|
81
|
+
conventions. Parsers are wired up automatically: **`.ts`/`.tsx`** use
|
|
82
|
+
`@typescript-eslint/parser` (with `projectService`), **`.js`/`.jsx`** use
|
|
83
|
+
`@babel/eslint-parser`.
|
|
84
|
+
|
|
85
|
+
| Area | Plugins |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| Base | `@eslint/js`, `typescript-eslint` |
|
|
88
|
+
| React | `eslint-plugin-react`, `eslint-plugin-react-hooks` (incl. React Compiler rules) |
|
|
89
|
+
| Accessibility | `eslint-plugin-jsx-a11y` |
|
|
90
|
+
| Style / formatting | `@stylistic/eslint-plugin` |
|
|
91
|
+
| Code smells | `eslint-plugin-sonarjs` |
|
|
92
|
+
| Imports / ordering | `eslint-plugin-perfectionist` |
|
|
93
|
+
| Tests (`*.spec.*`) | `eslint-plugin-jest`, `eslint-plugin-jest-dom`, `eslint-plugin-testing-library` |
|
|
94
|
+
| kununu-specific | `eslint-plugin-lodash`, `eslint-plugin-granular-selectors`, `@babel/eslint-plugin` |
|
|
95
|
+
|
|
96
|
+
### Notable conventions
|
|
97
|
+
|
|
98
|
+
- **No default React import** — `import React from 'react'` is disallowed; import
|
|
99
|
+
named hooks/types instead (`import {useState} from 'react'`).
|
|
100
|
+
- **Per-method lodash imports** — `import debounce from 'lodash/debounce'`, not
|
|
101
|
+
`import {debounce} from 'lodash'`.
|
|
102
|
+
- **Import ordering** (`perfectionist/sort-imports`): `react` → types →
|
|
103
|
+
builtins/externals → `@kununu/*` internals → aliases → relatives.
|
|
104
|
+
- **Granular Redux selectors** for `use*Selector*` / `use*Store*` hooks.
|
|
105
|
+
- **Formatting** via `@stylistic` (120-char lines ignoring comments/strings/URLs,
|
|
106
|
+
semicolons, single quotes, …).
|
|
107
|
+
- **React Compiler rules** (`react-hooks/refs`, `set-state-in-effect`, …) are
|
|
108
|
+
**warnings**, not errors.
|
|
109
|
+
- **Test files** (`**/*.spec.*`) automatically get Jest globals plus the jest /
|
|
110
|
+
jest-dom / testing-library rule sets; some source-only rules (e.g.
|
|
111
|
+
`react/prop-types`, `sonarjs/no-hardcoded-passwords`) are relaxed there.
|
|
112
|
+
|
|
113
|
+
## ⚡️ Editor integration
|
|
114
|
+
|
|
115
|
+
Linting runs in CI / pre-commit, but catching errors in your editor is faster. We
|
|
116
|
+
recommend the
|
|
117
|
+
[ESLint VS Code extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint).
|
|
118
|
+
|
|
119
|
+
Recent versions auto-detect flat config. If your editor still defaults to the
|
|
120
|
+
legacy format, enable it in `.vscode/settings.json`:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"eslint.useFlatConfig": true
|
|
125
|
+
}
|
|
126
|
+
```
|
package/eslint.config.mjs
CHANGED
|
@@ -25,8 +25,12 @@ export default defineConfig([
|
|
|
25
25
|
reactPlugin.configs.flat['jsx-runtime'],
|
|
26
26
|
sonarjs.configs.recommended,
|
|
27
27
|
stylistic.configs.recommended,
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// Scope the TypeScript rules to TS files only; .js/.jsx use the Babel parser
|
|
29
|
+
// below and would otherwise run type-aware rules under the wrong parser.
|
|
30
|
+
...tseslint.configs.recommended.map(config => ({
|
|
31
|
+
...config,
|
|
32
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
33
|
+
})),
|
|
30
34
|
|
|
31
35
|
globalIgnores([
|
|
32
36
|
'**/.next/',
|
|
@@ -51,6 +55,18 @@ export default defineConfig([
|
|
|
51
55
|
projectService: true,
|
|
52
56
|
},
|
|
53
57
|
},
|
|
58
|
+
rules: {
|
|
59
|
+
'@typescript-eslint/no-require-imports': 'error',
|
|
60
|
+
// Allow intentionally-unused identifiers prefixed with `_`.
|
|
61
|
+
'@typescript-eslint/no-unused-vars': ['error', {
|
|
62
|
+
argsIgnorePattern: '^_',
|
|
63
|
+
caughtErrorsIgnorePattern: '^_',
|
|
64
|
+
destructuredArrayIgnorePattern: '^_',
|
|
65
|
+
ignoreRestSiblings: true,
|
|
66
|
+
varsIgnorePattern: '^_',
|
|
67
|
+
}],
|
|
68
|
+
'@typescript-eslint/no-use-before-define': 'error',
|
|
69
|
+
},
|
|
54
70
|
},
|
|
55
71
|
|
|
56
72
|
{
|
|
@@ -66,18 +82,33 @@ export default defineConfig([
|
|
|
66
82
|
},
|
|
67
83
|
},
|
|
68
84
|
|
|
85
|
+
// Test-only configs. Spread as separate entries so their plugins/rules
|
|
86
|
+
// aren't clobbered, and scope them to spec files (incl. testing-library,
|
|
87
|
+
// which previously applied to every file).
|
|
88
|
+
{...pluginJest.configs['flat/recommended'], files: ['**/*.spec.*']},
|
|
89
|
+
{...jestDomPlugin.configs['flat/recommended'], files: ['**/*.spec.*']},
|
|
90
|
+
{...testingLibraryPlugin.configs['flat/dom'], files: ['**/*.spec.*']},
|
|
69
91
|
{
|
|
70
|
-
files: [
|
|
71
|
-
['**/*.spec.*'],
|
|
72
|
-
],
|
|
73
|
-
...jestDomPlugin.configs['flat/recommended'],
|
|
74
|
-
languageOptions: {
|
|
75
|
-
globals: pluginJest.environments.globals.globals,
|
|
76
|
-
},
|
|
77
|
-
plugins: {jest: pluginJest},
|
|
92
|
+
files: ['**/*.spec.*'],
|
|
78
93
|
rules: {
|
|
79
94
|
'@typescript-eslint/no-explicit-any': 'off',
|
|
95
|
+
// Tests legitimately require() dynamic mocks / json fixtures.
|
|
96
|
+
'@typescript-eslint/no-require-imports': 'off',
|
|
97
|
+
// Recognise assertions made through `assert*` helper functions, not just
|
|
98
|
+
// direct expect() calls.
|
|
99
|
+
'jest/expect-expect': ['warn', {assertFunctionNames: ['expect', 'assert*']}],
|
|
100
|
+
// kununu stores shared test fixtures under __mocks__ and imports them
|
|
101
|
+
// directly; this rule targets jest auto-mocks, not that convention.
|
|
102
|
+
'jest/no-mocks-import': 'off',
|
|
80
103
|
'react/display-name': 'off',
|
|
104
|
+
// Prop-types are redundant in a TypeScript codebase.
|
|
105
|
+
'react/prop-types': 'off',
|
|
106
|
+
// Test fixtures often contain password-like strings (mock query strings,
|
|
107
|
+
// tokens) that aren't real credentials; keep the rule for source code.
|
|
108
|
+
'sonarjs/no-hardcoded-passwords': 'off',
|
|
109
|
+
// Direct DOM access is common and acceptable in tests.
|
|
110
|
+
'testing-library/no-node-access': 'off',
|
|
111
|
+
'testing-library/render-result-naming-convention': 'off',
|
|
81
112
|
},
|
|
82
113
|
},
|
|
83
114
|
|
|
@@ -146,7 +177,8 @@ export default defineConfig([
|
|
|
146
177
|
{blankLine: 'any', next: 'import', prev: 'import'},
|
|
147
178
|
// Always require blank line after imports when followed by non-imports
|
|
148
179
|
{blankLine: 'always', next: '*', prev: 'import'},
|
|
149
|
-
//
|
|
180
|
+
// Re-allow consecutive imports with no blank line. Must stay AFTER the
|
|
181
|
+
// rule above (last match wins) or every adjacent import is forced apart.
|
|
150
182
|
{blankLine: 'any', next: 'import', prev: 'import'},
|
|
151
183
|
// Allow any spacing between variable declarations (before and between)
|
|
152
184
|
{blankLine: 'any', next: ['const', 'let', 'var'], prev: '*'},
|
|
@@ -163,8 +195,6 @@ export default defineConfig([
|
|
|
163
195
|
'@stylistic/quote-props': ['error', 'as-needed'],
|
|
164
196
|
'@stylistic/semi': ['error', 'always'],
|
|
165
197
|
'@stylistic/switch-colon-spacing': 'error',
|
|
166
|
-
'@typescript-eslint/no-use-before-define': 'error',
|
|
167
|
-
'@typescript-eslint/no-var-requires': 'error',
|
|
168
198
|
'granular-selectors/granular-selectors': ['error', {
|
|
169
199
|
include: ['use.*Selector.*', 'use.*Store.*'],
|
|
170
200
|
}],
|
|
@@ -254,7 +284,14 @@ export default defineConfig([
|
|
|
254
284
|
}],
|
|
255
285
|
'prefer-template': 'error',
|
|
256
286
|
'react-hooks/exhaustive-deps': 'warn',
|
|
287
|
+
// React Compiler rules: advisory for now. They flag patterns the compiler
|
|
288
|
+
// can't optimise, but the current codebases use them widely; keep as
|
|
289
|
+
// warnings rather than blocking errors.
|
|
290
|
+
'react-hooks/immutability': 'warn',
|
|
291
|
+
'react-hooks/refs': 'warn',
|
|
257
292
|
'react-hooks/rules-of-hooks': 'error',
|
|
293
|
+
'react-hooks/set-state-in-effect': 'warn',
|
|
294
|
+
'react-hooks/use-memo': 'warn',
|
|
258
295
|
'react/jsx-closing-bracket-location': ['error', 'tag-aligned'],
|
|
259
296
|
// More restrictive JSX rules that are auto-fixable
|
|
260
297
|
'react/jsx-curly-spacing': ['error', 'never'],
|
|
@@ -271,6 +308,8 @@ export default defineConfig([
|
|
|
271
308
|
closingSlash: 'never',
|
|
272
309
|
}],
|
|
273
310
|
'sonarjs/deprecation': ['warn'],
|
|
311
|
+
// TypeScript already infers/checks return types; this duplicates it.
|
|
312
|
+
'sonarjs/function-return-type': 'off',
|
|
274
313
|
'sonarjs/todo-tag': ['warn'],
|
|
275
314
|
},
|
|
276
315
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kununu/eslint-config",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"description": "kununu's ESLint config",
|
|
5
5
|
"main": "eslint.config.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -30,24 +30,24 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/kununu/eslint-config#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@babel/core": "
|
|
34
|
-
"@babel/eslint-parser": "
|
|
35
|
-
"@babel/eslint-plugin": "
|
|
33
|
+
"@babel/core": "8.0.1",
|
|
34
|
+
"@babel/eslint-parser": "8.0.1",
|
|
35
|
+
"@babel/eslint-plugin": "8.0.1",
|
|
36
36
|
"@eslint/js": "9.39.4",
|
|
37
37
|
"@stylistic/eslint-plugin": "5.10.0",
|
|
38
|
-
"@typescript-eslint/parser": "8.
|
|
38
|
+
"@typescript-eslint/parser": "8.62.0",
|
|
39
39
|
"eslint": "9.39.2",
|
|
40
40
|
"eslint-plugin-granular-selectors": "1.5.0",
|
|
41
|
-
"eslint-plugin-jest": "29.15.
|
|
41
|
+
"eslint-plugin-jest": "29.15.3",
|
|
42
42
|
"eslint-plugin-jest-dom": "5.5.0",
|
|
43
43
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
|
44
44
|
"eslint-plugin-lodash": "8.0.0",
|
|
45
|
-
"eslint-plugin-perfectionist": "5.9.
|
|
45
|
+
"eslint-plugin-perfectionist": "5.9.1",
|
|
46
46
|
"eslint-plugin-react": "7.37.5",
|
|
47
47
|
"eslint-plugin-react-hooks": "7.1.1",
|
|
48
|
-
"eslint-plugin-sonarjs": "4.0
|
|
48
|
+
"eslint-plugin-sonarjs": "4.1.0",
|
|
49
49
|
"eslint-plugin-testing-library": "7.16.2",
|
|
50
|
-
"typescript-eslint": "8.
|
|
50
|
+
"typescript-eslint": "8.62.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"typescript": ">=5.0.0"
|