@alexlit/config-eslint 157.0.0 → 158.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 +110 -21
- package/base.js +68 -0
- package/index.js +17 -2
- package/package.json +4 -2
- package/plugins/de-morgan.js +5 -1
- package/plugins/import-x.js +77 -0
- package/plugins/javascript.js +25 -31
- package/plugins/jsdoc.js +2 -15
- package/plugins/json.js +6 -0
- package/plugins/perfectionist.js +7 -4
- package/plugins/pinia.js +1 -1
- package/plugins/prettier.js +6 -29
- package/plugins/regexp.js +1 -1
- package/plugins/sonar.js +8 -4
- package/plugins/stylistic.js +2 -7
- package/plugins/tailwindcss.js +1 -1
- package/plugins/tanstack-query.js +7 -1
- package/plugins/typescript-type-checked.js +50 -0
- package/plugins/typescript.js +10 -37
- package/plugins/unicorn.js +15 -4
- package/plugins/unocss.js +1 -1
- package/plugins/vitest.js +3 -1
- package/plugins/vue-i18n.js +3 -6
- package/plugins/vue.js +16 -12
- package/plugins/zod.js +1 -1
- package/rules/restricted-syntax.js +28 -0
- package/rules/style.js +15 -0
- package/rules/typescript.js +62 -0
- package/presets/base.js +0 -22
- package/presets/default.js +0 -37
package/README.md
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
> [@alexlit/config-eslint@90](https://www.npmjs.com/package/@alexlit/config-eslint?activeTab=versions)
|
|
6
6
|
> or lower.
|
|
7
7
|
|
|
8
|
+
There are no presets: `base` only provides the shared file scope, ignore
|
|
9
|
+
patterns and globals. Every plugin is enabled explicitly, so you pay only for
|
|
10
|
+
what you use.
|
|
11
|
+
|
|
8
12
|
## Installation
|
|
9
13
|
|
|
10
14
|
```sh
|
|
@@ -13,33 +17,118 @@ npm i @alexlit/config-eslint -D
|
|
|
13
17
|
|
|
14
18
|
## Connection
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
Always start with `base` (it must be first) and finish with `prettierConfig` (it
|
|
21
|
+
must be last, it disables the formatting rules).
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
// eslint.config.js
|
|
25
|
+
import {
|
|
26
|
+
// foundation
|
|
27
|
+
base,
|
|
28
|
+
|
|
29
|
+
// plugins
|
|
30
|
+
deMorgan,
|
|
31
|
+
importX,
|
|
32
|
+
javascript,
|
|
33
|
+
jsdoc,
|
|
34
|
+
json,
|
|
35
|
+
perfectionist,
|
|
36
|
+
prettierConfig,
|
|
37
|
+
regexp,
|
|
38
|
+
sonar,
|
|
39
|
+
stylistic,
|
|
40
|
+
typescript,
|
|
41
|
+
unicorn,
|
|
42
|
+
|
|
43
|
+
// framework plugins
|
|
44
|
+
pinia,
|
|
45
|
+
tailwindcss,
|
|
46
|
+
tanstackQuery,
|
|
47
|
+
unocss,
|
|
48
|
+
vitest,
|
|
49
|
+
vue,
|
|
50
|
+
vueAccessibility,
|
|
51
|
+
vueI18n,
|
|
52
|
+
zod,
|
|
53
|
+
} from '@alexlit/config-eslint';
|
|
54
|
+
|
|
55
|
+
export default [
|
|
56
|
+
...base, // must be first
|
|
57
|
+
|
|
58
|
+
...deMorgan,
|
|
59
|
+
...importX,
|
|
60
|
+
...javascript,
|
|
61
|
+
...jsdoc,
|
|
62
|
+
...json,
|
|
63
|
+
...perfectionist,
|
|
64
|
+
...regexp,
|
|
65
|
+
...sonar,
|
|
66
|
+
...stylistic,
|
|
67
|
+
...typescript,
|
|
68
|
+
...unicorn,
|
|
69
|
+
|
|
70
|
+
...pinia,
|
|
71
|
+
...tanstackQuery,
|
|
72
|
+
...unocss,
|
|
73
|
+
...vitest,
|
|
74
|
+
...vue,
|
|
75
|
+
...vueAccessibility,
|
|
76
|
+
...vueI18n,
|
|
77
|
+
...zod,
|
|
78
|
+
|
|
79
|
+
// `tailwindcss` is the only plugin exported as a factory, because it needs a path to your CSS entrypoint
|
|
80
|
+
...tailwindcss({ cssConfigPath: './src/assets/css/main.css' }),
|
|
81
|
+
|
|
82
|
+
...prettierConfig, // must be last
|
|
17
83
|
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
84
|
+
// Custom rules example
|
|
85
|
+
// { files: ['**/*.js'], rules: { 'no-console': 'off' } },
|
|
86
|
+
];
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Drop what you do not need.
|
|
90
|
+
|
|
91
|
+
## Type-aware rules (optional)
|
|
92
|
+
|
|
93
|
+
Type-aware rules (`no-floating-promises`, `no-misused-promises`,
|
|
94
|
+
`await-thenable`, `no-unsafe-*`, `switch-exhaustiveness-check`,
|
|
95
|
+
`no-unnecessary-condition`, …) require type information, which makes linting
|
|
96
|
+
slower. They are not enabled by default.
|
|
97
|
+
|
|
98
|
+
To enable them, replace `typescript` with `typescriptTypeChecked`:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
import {
|
|
102
|
+
base,
|
|
103
|
+
typescriptTypeChecked,
|
|
104
|
+
prettierConfig,
|
|
105
|
+
} from '@alexlit/config-eslint';
|
|
106
|
+
|
|
107
|
+
export default [
|
|
108
|
+
...base,
|
|
109
|
+
// ...other plugins
|
|
110
|
+
...typescriptTypeChecked, // instead of ...typescript
|
|
111
|
+
...prettierConfig,
|
|
112
|
+
];
|
|
113
|
+
```
|
|
21
114
|
|
|
22
|
-
|
|
23
|
-
|
|
115
|
+
> [!NOTE] `typescriptTypeChecked` needs a `tsconfig.json` in your project root
|
|
116
|
+
> (`projectService` is used, so keep both `tsconfig.json` and
|
|
117
|
+
> `tsconfig.node.json` etc. in a single root if needed). Use it instead of
|
|
118
|
+
> `typescript`, not alongside.
|
|
24
119
|
|
|
25
|
-
|
|
26
|
-
([available plugins](https://github.com/alex-lit/lint-kit/blob/master/packages/config-eslint/index.js))
|
|
120
|
+
## Formatting: `prettier` vs `prettierConfig`
|
|
27
121
|
|
|
28
|
-
|
|
29
|
-
// eslint.config.js
|
|
30
|
-
import { typescript, unicorn, vitest } from '@alexlit/config-eslint';
|
|
122
|
+
Both are included, and they are **not** interchangeable.
|
|
31
123
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
...vitest,
|
|
124
|
+
| Export | From | Effect |
|
|
125
|
+
| ---------------- | ------------------------ | ------------------------------------------------ |
|
|
126
|
+
| `prettierConfig` | `eslint-config-prettier` | only turns off formatting rules that conflict |
|
|
127
|
+
| `prettier` | `eslint-plugin-prettier` | additionally runs Prettier itself as a lint rule |
|
|
37
128
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
];
|
|
42
|
-
```
|
|
129
|
+
Use `prettierConfig` when Prettier runs as a separate step (editor, `prettier`
|
|
130
|
+
CLI, Husky). Use `prettier` if you want ESLint to report and fix formatting in
|
|
131
|
+
one pass — it is slower and duplicates the formatter.
|
|
43
132
|
|
|
44
133
|
## Usefull links
|
|
45
134
|
|
package/base.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { defineConfig } from 'eslint/config';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
|
|
4
|
+
/** All source files covered by the shareable config */
|
|
5
|
+
export const FILES = ['**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts,vue}'];
|
|
6
|
+
|
|
7
|
+
/** TypeScript source files */
|
|
8
|
+
export const TS_FILES = ['**/*.{ts,tsx,mts,cts}'];
|
|
9
|
+
|
|
10
|
+
/** Vue.js single-file components */
|
|
11
|
+
export const VUE_FILES = ['**/*.vue'];
|
|
12
|
+
|
|
13
|
+
/** JSON files */
|
|
14
|
+
export const JSON_FILES = ['**/*.{json,jsonc,json5}'];
|
|
15
|
+
|
|
16
|
+
/** YAML files */
|
|
17
|
+
export const YAML_FILES = ['**/*.{yaml,yml}'];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Files that hold data rather than code.
|
|
21
|
+
*
|
|
22
|
+
* Plugins that ship configs without a `files` key would otherwise apply their
|
|
23
|
+
* rules to these files, so such blocks have to exclude them explicitly.
|
|
24
|
+
*/
|
|
25
|
+
export const DATA_FILES = [...JSON_FILES, ...YAML_FILES];
|
|
26
|
+
|
|
27
|
+
/** Test files */
|
|
28
|
+
export const TEST_FILES = [
|
|
29
|
+
'**/*.{test,spec}.{js,cjs,mjs,jsx,ts,tsx,mts,cts,vue}',
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
/** Type declaration files */
|
|
33
|
+
export const DTS_FILES = ['**/*.d.{ts,mts,cts}'];
|
|
34
|
+
|
|
35
|
+
/** Never linted */
|
|
36
|
+
export const IGNORES = [
|
|
37
|
+
'**/.*',
|
|
38
|
+
'**/.*/**',
|
|
39
|
+
'**/_deprecated/**',
|
|
40
|
+
'**/build/**',
|
|
41
|
+
'**/dist/**',
|
|
42
|
+
'**/docs/**',
|
|
43
|
+
'**/mockServiceWorker.js',
|
|
44
|
+
'**/storybook-*/**',
|
|
45
|
+
'**/sw.js',
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Base config.
|
|
50
|
+
*
|
|
51
|
+
* Provides the file scope, the shared ignore patterns and the global variables.
|
|
52
|
+
* Include it first, then the plugins you actually need.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* import { base, javascript, unicorn } from '@alexlit/config-eslint';
|
|
56
|
+
*
|
|
57
|
+
* export default [...base, ...javascript, ...unicorn];
|
|
58
|
+
*/
|
|
59
|
+
export const base = defineConfig([
|
|
60
|
+
{ files: FILES, languageOptions: { globals: globals.browser } },
|
|
61
|
+
|
|
62
|
+
// Node.js globals for commonjs/esm files
|
|
63
|
+
{ files: ['**/*.{cjs,mjs}'], languageOptions: { globals: globals.node } },
|
|
64
|
+
|
|
65
|
+
{ linterOptions: { reportUnusedDisableDirectives: 'error' } },
|
|
66
|
+
|
|
67
|
+
{ ignores: IGNORES },
|
|
68
|
+
]);
|
package/index.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
+
export {
|
|
2
|
+
base,
|
|
3
|
+
DATA_FILES,
|
|
4
|
+
DTS_FILES,
|
|
5
|
+
FILES,
|
|
6
|
+
IGNORES,
|
|
7
|
+
JSON_FILES,
|
|
8
|
+
TEST_FILES,
|
|
9
|
+
TS_FILES,
|
|
10
|
+
VUE_FILES,
|
|
11
|
+
YAML_FILES,
|
|
12
|
+
} from './base.js';
|
|
13
|
+
|
|
1
14
|
export { deMorgan } from './plugins/de-morgan.js';
|
|
15
|
+
export { importX } from './plugins/import-x.js';
|
|
2
16
|
export { javascript } from './plugins/javascript.js';
|
|
3
17
|
export { jsdoc } from './plugins/jsdoc.js';
|
|
4
18
|
export { json } from './plugins/json.js';
|
|
@@ -10,6 +24,7 @@ export { sonar } from './plugins/sonar.js';
|
|
|
10
24
|
export { stylistic } from './plugins/stylistic.js';
|
|
11
25
|
export { tailwindcss } from './plugins/tailwindcss.js';
|
|
12
26
|
export { tanstackQuery } from './plugins/tanstack-query.js';
|
|
27
|
+
export { typescriptTypeChecked } from './plugins/typescript-type-checked.js';
|
|
13
28
|
export { typescript } from './plugins/typescript.js';
|
|
14
29
|
export { unicorn } from './plugins/unicorn.js';
|
|
15
30
|
export { unocss } from './plugins/unocss.js';
|
|
@@ -18,5 +33,5 @@ export { vueAccessibility } from './plugins/vue-accessibility.js';
|
|
|
18
33
|
export { vueI18n } from './plugins/vue-i18n.js';
|
|
19
34
|
export { vue } from './plugins/vue.js';
|
|
20
35
|
export { zod } from './plugins/zod.js';
|
|
21
|
-
|
|
22
|
-
export {
|
|
36
|
+
export { NO_RESTRICTED_SYNTAX } from './rules/restricted-syntax.js';
|
|
37
|
+
export { TS_RULES } from './rules/typescript.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexlit/config-eslint",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "158.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Sharable ESLint configuration",
|
|
6
6
|
"keywords": [
|
|
@@ -26,8 +26,9 @@
|
|
|
26
26
|
"main": "./index.js",
|
|
27
27
|
"files": [
|
|
28
28
|
"index.js",
|
|
29
|
+
"base.js",
|
|
29
30
|
"plugins/",
|
|
30
|
-
"
|
|
31
|
+
"rules/",
|
|
31
32
|
"README.md"
|
|
32
33
|
],
|
|
33
34
|
"scripts": {
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"eslint": "^10.11.0",
|
|
50
51
|
"eslint-config-prettier": "^10.1.8",
|
|
51
52
|
"eslint-plugin-de-morgan": "^2.2.0",
|
|
53
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
52
54
|
"eslint-plugin-jsdoc": "^65.0.0",
|
|
53
55
|
"eslint-plugin-perfectionist": "^5.12.1",
|
|
54
56
|
"eslint-plugin-pinia": "^0.4.2",
|
package/plugins/de-morgan.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-de-morgan';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
|
+
|
|
4
6
|
/** @see [eslint-plugin-de-morgan](https://github.com/azat-io/eslint-plugin-de-morgan) */
|
|
5
|
-
export const deMorgan = defineConfig([
|
|
7
|
+
export const deMorgan = defineConfig([
|
|
8
|
+
{ files: FILES, ...plugin.configs.recommended },
|
|
9
|
+
]);
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import plugin from 'eslint-plugin-import-x';
|
|
2
|
+
import { createNodeResolver } from 'eslint-plugin-import-x/node-resolver';
|
|
3
|
+
import { defineConfig } from 'eslint/config';
|
|
4
|
+
|
|
5
|
+
import { DATA_FILES, FILES, TEST_FILES, VUE_FILES } from '../base.js';
|
|
6
|
+
|
|
7
|
+
const EXTENSIONS = [
|
|
8
|
+
'.ts',
|
|
9
|
+
'.tsx',
|
|
10
|
+
'.mts',
|
|
11
|
+
'.cts',
|
|
12
|
+
'.js',
|
|
13
|
+
'.jsx',
|
|
14
|
+
'.mjs',
|
|
15
|
+
'.cjs',
|
|
16
|
+
'.vue',
|
|
17
|
+
'.json',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/** @see [eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x) */
|
|
21
|
+
export const importX = defineConfig([
|
|
22
|
+
// `recommended` comes without a `files` key, so it would also land on data
|
|
23
|
+
// files, which are not modules and have nothing to import from.
|
|
24
|
+
{ ...plugin.flatConfigs.recommended, files: FILES, ignores: DATA_FILES },
|
|
25
|
+
|
|
26
|
+
{
|
|
27
|
+
files: FILES,
|
|
28
|
+
languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
|
|
29
|
+
plugins: { 'import-x': plugin },
|
|
30
|
+
rules: {
|
|
31
|
+
'import-x/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
|
32
|
+
'import-x/first': 'error',
|
|
33
|
+
'import-x/newline-after-import': 'warn',
|
|
34
|
+
'import-x/no-absolute-path': 'error',
|
|
35
|
+
'import-x/no-cycle': 'error',
|
|
36
|
+
'import-x/no-extraneous-dependencies': 'error',
|
|
37
|
+
// Both come from `recommended`, but they are wrong for ESLint plugins:
|
|
38
|
+
// the default export is the plugin object, so `plugin.configs` is a
|
|
39
|
+
// property of it, not a named export of the package. Some packages even
|
|
40
|
+
// export `plugin` as a named export, which makes `no-named-as-default`
|
|
41
|
+
// fire on the conventional `import plugin from '…'` line.
|
|
42
|
+
'import-x/no-named-as-default': 'off',
|
|
43
|
+
'import-x/no-named-as-default-member': 'off',
|
|
44
|
+
'import-x/no-nodejs-modules': 'off',
|
|
45
|
+
'import-x/no-self-import': 'error',
|
|
46
|
+
'import-x/no-useless-path-segments': ['error', { noUselessIndex: true }],
|
|
47
|
+
'import-x/unambiguous': 'error',
|
|
48
|
+
},
|
|
49
|
+
settings: {
|
|
50
|
+
'import-x/extensions': EXTENSIONS,
|
|
51
|
+
'import-x/parsers': { '.vue': ['vue-eslint-parser'] },
|
|
52
|
+
// Reads `paths` from the closest `tsconfig.json`, so `~/…`, `@/…` and
|
|
53
|
+
// other aliases are resolved the same way the bundler resolves them.
|
|
54
|
+
'import-x/resolver-next': [
|
|
55
|
+
createNodeResolver({ extensions: EXTENSIONS, tsconfig: 'auto' }),
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
files: TEST_FILES,
|
|
61
|
+
rules: {
|
|
62
|
+
'import-x/no-extraneous-dependencies': [
|
|
63
|
+
'error',
|
|
64
|
+
{ devDependencies: true },
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
{
|
|
70
|
+
files: VUE_FILES,
|
|
71
|
+
rules: {
|
|
72
|
+
// A component without a `<script>` block is a valid component, not an
|
|
73
|
+
// ambiguous module that needs explicit imports.
|
|
74
|
+
'import-x/unambiguous': 'off',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
]);
|
package/plugins/javascript.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import plugin from '@eslint/js';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES, TEST_FILES } from '../base.js';
|
|
5
|
+
import { NO_RESTRICTED_SYNTAX } from '../rules/restricted-syntax.js';
|
|
6
|
+
import { STYLE_RULES } from '../rules/style.js';
|
|
5
7
|
|
|
6
8
|
/** @see [eslint](https://eslint.org) */
|
|
7
9
|
export const javascript = defineConfig([
|
|
@@ -10,11 +12,14 @@ export const javascript = defineConfig([
|
|
|
10
12
|
files: FILES,
|
|
11
13
|
rules: {
|
|
12
14
|
'arrow-body-style': ['error', 'as-needed'],
|
|
13
|
-
|
|
15
|
+
...STYLE_RULES,
|
|
16
|
+
'default-case-last': 'error',
|
|
14
17
|
'dot-notation': ['error'],
|
|
15
|
-
'func-style': ['error', 'expression'],
|
|
16
18
|
'grouped-accessor-pairs': ['error', 'getBeforeSet'],
|
|
19
|
+
'no-alert': 'error',
|
|
20
|
+
'no-console': 'error',
|
|
17
21
|
'no-duplicate-imports': ['error', { includeExports: false }],
|
|
22
|
+
'no-else-return': 'error',
|
|
18
23
|
'no-implicit-coercion': 'error',
|
|
19
24
|
'no-param-reassign': ['error', { props: false }],
|
|
20
25
|
'no-restricted-exports': [
|
|
@@ -24,6 +29,14 @@ export const javascript = defineConfig([
|
|
|
24
29
|
restrictedNamedExportsPattern: '^_',
|
|
25
30
|
},
|
|
26
31
|
],
|
|
32
|
+
'no-restricted-globals': [
|
|
33
|
+
'error',
|
|
34
|
+
// `event`, `top` and `parent` are global browser properties.
|
|
35
|
+
// Reach for `window.event` / `window.top` / `window.parent` instead.
|
|
36
|
+
{ message: 'Use `window.event` instead.', name: 'event' },
|
|
37
|
+
{ message: 'Use `window.parent` instead.', name: 'parent' },
|
|
38
|
+
{ message: 'Use `window.top` instead.', name: 'top' },
|
|
39
|
+
],
|
|
27
40
|
'no-restricted-imports': [
|
|
28
41
|
'error',
|
|
29
42
|
{
|
|
@@ -58,40 +71,21 @@ export const javascript = defineConfig([
|
|
|
58
71
|
],
|
|
59
72
|
},
|
|
60
73
|
],
|
|
61
|
-
'no-restricted-syntax': [
|
|
62
|
-
|
|
63
|
-
{
|
|
64
|
-
message:
|
|
65
|
-
"Не используйте префикс 'handle' для обработчиков событий. Переименуйте метод, заменив 'handle' на 'on' (например, 'onClick' вместо 'handleClick').",
|
|
66
|
-
selector: 'Identifier[name=/^handle[A-Z]/]',
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
message:
|
|
70
|
-
"Используйте методы массивов (.forEach, .map и т.д.) вместо цикла 'for'.",
|
|
71
|
-
selector: 'ForStatement',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
message:
|
|
75
|
-
"Используйте методы объектов (.keys, .values и т.д.) вместо цикла 'for...in'.",
|
|
76
|
-
selector: 'ForInStatement',
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
message:
|
|
80
|
-
"Используйте методы массивов(.forEach, .map и т.д.) вместо цикла 'for...of'.",
|
|
81
|
-
selector: 'ForOfStatement',
|
|
82
|
-
},
|
|
83
|
-
],
|
|
74
|
+
'no-restricted-syntax': ['error', ...NO_RESTRICTED_SYNTAX],
|
|
75
|
+
'no-useless-rename': 'error',
|
|
84
76
|
'prefer-arrow-callback': [
|
|
85
77
|
'error',
|
|
86
78
|
{ allowNamedFunctions: false, allowUnboundThis: false },
|
|
87
79
|
],
|
|
88
80
|
'prefer-const': 'warn',
|
|
89
81
|
'prefer-template': 'warn',
|
|
90
|
-
'
|
|
91
|
-
'error',
|
|
92
|
-
'single',
|
|
93
|
-
{ allowTemplateLiterals: false, avoidEscape: true },
|
|
94
|
-
],
|
|
82
|
+
'require-await': 'error',
|
|
95
83
|
},
|
|
96
84
|
},
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
// Tests are allowed to log and to alert
|
|
88
|
+
files: TEST_FILES,
|
|
89
|
+
rules: { 'no-alert': 'off', 'no-console': 'off' },
|
|
90
|
+
},
|
|
97
91
|
]);
|
package/plugins/jsdoc.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-jsdoc';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) */
|
|
7
7
|
export const jsdoc = defineConfig([
|
|
@@ -11,20 +11,7 @@ export const jsdoc = defineConfig([
|
|
|
11
11
|
rules: {
|
|
12
12
|
'jsdoc/lines-before-block': 'off',
|
|
13
13
|
'jsdoc/no-undefined-types': 'off',
|
|
14
|
-
'jsdoc/require-jsdoc':
|
|
15
|
-
'warn',
|
|
16
|
-
{
|
|
17
|
-
enableFixer: false,
|
|
18
|
-
require: {
|
|
19
|
-
ArrowFunctionExpression: false,
|
|
20
|
-
ClassDeclaration: false,
|
|
21
|
-
ClassExpression: false,
|
|
22
|
-
FunctionDeclaration: false,
|
|
23
|
-
FunctionExpression: false,
|
|
24
|
-
MethodDefinition: false,
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
],
|
|
14
|
+
'jsdoc/require-jsdoc': 'off',
|
|
28
15
|
'jsdoc/require-param-description': 'off',
|
|
29
16
|
'jsdoc/require-param-type': 'off',
|
|
30
17
|
'jsdoc/require-returns': 'off',
|
package/plugins/json.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import plugin from '@eslint/json';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
|
+
import * as yamlParser from 'yaml-eslint-parser';
|
|
4
|
+
|
|
5
|
+
import { YAML_FILES } from '../base.js';
|
|
3
6
|
|
|
4
7
|
/** @see [ESLint/JSON](https://github.com/eslint/json) */
|
|
5
8
|
export const json = defineConfig([
|
|
@@ -15,6 +18,7 @@ export const json = defineConfig([
|
|
|
15
18
|
extends: ['json/recommended'],
|
|
16
19
|
files: ['**/*.jsonc'],
|
|
17
20
|
language: 'json/jsonc',
|
|
21
|
+
languageOptions: { allowTrailingCommas: true },
|
|
18
22
|
plugins: { json: plugin },
|
|
19
23
|
},
|
|
20
24
|
|
|
@@ -24,4 +28,6 @@ export const json = defineConfig([
|
|
|
24
28
|
language: 'json/json5',
|
|
25
29
|
plugins: { json: plugin },
|
|
26
30
|
},
|
|
31
|
+
|
|
32
|
+
{ files: YAML_FILES, languageOptions: { parser: yamlParser } },
|
|
27
33
|
]);
|
package/plugins/perfectionist.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-perfectionist';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [eslint-plugin-perfectionist](https://perfectionist.dev) */
|
|
7
7
|
export const perfectionist = defineConfig([
|
|
@@ -13,7 +13,7 @@ export const perfectionist = defineConfig([
|
|
|
13
13
|
'warn',
|
|
14
14
|
{
|
|
15
15
|
customGroups: [
|
|
16
|
-
// hash
|
|
16
|
+
// hash (nuxt)
|
|
17
17
|
{ elementNamePattern: ['^#'], groupName: 'hash' },
|
|
18
18
|
|
|
19
19
|
// @@/
|
|
@@ -81,8 +81,11 @@ export const perfectionist = defineConfig([
|
|
|
81
81
|
|
|
82
82
|
'type-internal',
|
|
83
83
|
'value-internal',
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
// `parent` and `index` groups are omitted on purpose:
|
|
85
|
+
// `no-restricted-imports` in `javascript.js` forbids `..`, `.`
|
|
86
|
+
// and `**/index` imports, so nothing can ever land in them.
|
|
87
|
+
'type-sibling',
|
|
88
|
+
'value-sibling',
|
|
86
89
|
'ts-equals-import',
|
|
87
90
|
'unknown',
|
|
88
91
|
],
|
package/plugins/pinia.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-pinia';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [eslint-plugin-pinia](https://github.com/lisilinhart/eslint-plugin-pinia) */
|
|
7
7
|
export const pinia = defineConfig([
|
package/plugins/prettier.js
CHANGED
|
@@ -2,7 +2,8 @@ import config from 'eslint-config-prettier';
|
|
|
2
2
|
import plugin from 'eslint-plugin-prettier/recommended';
|
|
3
3
|
import { defineConfig } from 'eslint/config';
|
|
4
4
|
|
|
5
|
-
import { FILES } from '../
|
|
5
|
+
import { FILES, VUE_FILES } from '../base.js';
|
|
6
|
+
import { STYLE_RULES } from '../rules/style.js';
|
|
6
7
|
|
|
7
8
|
const fixes = {
|
|
8
9
|
// fix for prettier
|
|
@@ -18,36 +19,12 @@ const fixes = {
|
|
|
18
19
|
|
|
19
20
|
/** @see [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) */
|
|
20
21
|
export const prettier = defineConfig([
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
...plugin,
|
|
24
|
-
rules: {
|
|
25
|
-
...plugin.rules,
|
|
26
|
-
curly: 'error',
|
|
27
|
-
quotes: [
|
|
28
|
-
'error',
|
|
29
|
-
'single',
|
|
30
|
-
{ allowTemplateLiterals: false, avoidEscape: true },
|
|
31
|
-
],
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
{ files: ['**/*.vue'], rules: { ...fixes } },
|
|
22
|
+
{ files: FILES, ...plugin, rules: { ...plugin.rules, ...STYLE_RULES } },
|
|
23
|
+
{ files: VUE_FILES, rules: { ...fixes } },
|
|
35
24
|
]);
|
|
36
25
|
|
|
37
26
|
/** @see [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) */
|
|
38
27
|
export const prettierConfig = defineConfig([
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
...config,
|
|
42
|
-
rules: {
|
|
43
|
-
...config.rules,
|
|
44
|
-
curly: 'error',
|
|
45
|
-
quotes: [
|
|
46
|
-
'error',
|
|
47
|
-
'single',
|
|
48
|
-
{ allowTemplateLiterals: false, avoidEscape: true },
|
|
49
|
-
],
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
{ files: ['**/*.vue'], rules: { ...fixes } },
|
|
28
|
+
{ files: FILES, ...config, rules: { ...config.rules, ...STYLE_RULES } },
|
|
29
|
+
{ files: VUE_FILES, rules: { ...fixes } },
|
|
53
30
|
]);
|
package/plugins/regexp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-regexp';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [eslint-plugin-regexp](https://github.com/ota-meshi/eslint-plugin-regexp) */
|
|
7
7
|
export const regexp = defineConfig([
|
package/plugins/sonar.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-sonarjs';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [eslint-plugin-sonarjs](https://github.com/SonarSource/SonarJS/blob/master/packages/jsts/src/rules/README.md) */
|
|
7
7
|
export const sonar = defineConfig([
|
|
8
|
-
{ files: FILES, ...plugin.configs.recommended },
|
|
9
8
|
{
|
|
10
9
|
files: FILES,
|
|
11
|
-
|
|
12
|
-
rules: {
|
|
10
|
+
...plugin.configs.recommended,
|
|
11
|
+
rules: {
|
|
12
|
+
...plugin.configs.recommended.rules,
|
|
13
|
+
'sonarjs/no-commented-code': 'warn',
|
|
14
|
+
'sonarjs/todo-tag': 'off',
|
|
15
|
+
'sonarjs/unused-import': 'off', // @typescript-eslint/no-unused-vars
|
|
16
|
+
},
|
|
13
17
|
},
|
|
14
18
|
]);
|
package/plugins/stylistic.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import plugin from '@stylistic/eslint-plugin';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { DATA_FILES, FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [@stylistic/eslint-plugin](https://eslint.style/) */
|
|
7
7
|
export const stylistic = defineConfig([
|
|
8
8
|
{
|
|
9
9
|
...plugin.configs.recommended,
|
|
10
|
-
ignores: [
|
|
11
|
-
...(plugin.configs.recommended.ignores ?? []),
|
|
12
|
-
'**/*.json',
|
|
13
|
-
'**/*.jsonc',
|
|
14
|
-
'**/*.json5',
|
|
15
|
-
],
|
|
10
|
+
ignores: [...(plugin.configs.recommended.ignores ?? []), ...DATA_FILES],
|
|
16
11
|
},
|
|
17
12
|
{
|
|
18
13
|
files: FILES,
|
package/plugins/tailwindcss.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import plugin from '@tanstack/eslint-plugin-query';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
+
import { DATA_FILES } from '../base.js';
|
|
5
|
+
|
|
4
6
|
/** @see [@tanstack/query](https://tanstack.com/query/latest/docs/eslint/eslint-plugin-query) */
|
|
5
7
|
export const tanstackQuery = defineConfig([
|
|
6
|
-
|
|
8
|
+
// The shipped config has no `files` key, so it would also cover data files.
|
|
9
|
+
...plugin.configs['flat/recommended'].map((config) => ({
|
|
10
|
+
...config,
|
|
11
|
+
ignores: [...(config.ignores ?? []), ...DATA_FILES],
|
|
12
|
+
})),
|
|
7
13
|
{ rules: { '@tanstack/query/infinite-query-property-order': 'off' } },
|
|
8
14
|
]);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { defineConfig } from 'eslint/config';
|
|
2
|
+
import plugin from 'typescript-eslint';
|
|
3
|
+
|
|
4
|
+
import { DATA_FILES, FILES, TEST_FILES, TS_FILES } from '../base.js';
|
|
5
|
+
import { TS_RULES } from '../rules/typescript.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Type-aware TypeScript config.
|
|
9
|
+
*
|
|
10
|
+
* Opt-in: requires a `tsconfig.json` in the project and needs type information,
|
|
11
|
+
* which makes linting slower. Use it instead of `typescript`, not alongside
|
|
12
|
+
* it.
|
|
13
|
+
*
|
|
14
|
+
* @see [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint)
|
|
15
|
+
*/
|
|
16
|
+
export const typescriptTypeChecked = defineConfig([
|
|
17
|
+
// The parser is needed for every JS/TS/Vue file, not only for TypeScript ones,
|
|
18
|
+
// otherwise `.js` files fall back to the default parser and modern syntax
|
|
19
|
+
// (`import.meta`, top-level await) breaks.
|
|
20
|
+
{ ...plugin.configs.base, files: FILES },
|
|
21
|
+
|
|
22
|
+
// Non type-aware rules — the same scope as the regular `typescript` plugin,
|
|
23
|
+
// so `.js`/`.vue` files keep the TypeScript versions of the rules.
|
|
24
|
+
// `plugin.configs.strict`/`stylistic` contain blocks without a `files` key,
|
|
25
|
+
// so they would also land on data files that are not JavaScript at all.
|
|
26
|
+
...[...plugin.configs.strict, ...plugin.configs.stylistic].map((config) => ({
|
|
27
|
+
...config,
|
|
28
|
+
ignores: [...(config.ignores ?? []), ...DATA_FILES],
|
|
29
|
+
})),
|
|
30
|
+
|
|
31
|
+
// Type-aware rules only make sense where the type information is available.
|
|
32
|
+
...plugin.configs.strictTypeChecked.map((config) => ({
|
|
33
|
+
...config,
|
|
34
|
+
files: TS_FILES,
|
|
35
|
+
})),
|
|
36
|
+
...plugin.configs.stylisticTypeChecked.map((config) => ({
|
|
37
|
+
...config,
|
|
38
|
+
files: TS_FILES,
|
|
39
|
+
})),
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
files: TS_FILES,
|
|
43
|
+
languageOptions: { parserOptions: { projectService: true } },
|
|
44
|
+
rules: TS_RULES,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
files: TEST_FILES,
|
|
48
|
+
rules: { '@typescript-eslint/no-empty-function': 'off' },
|
|
49
|
+
},
|
|
50
|
+
]);
|
package/plugins/typescript.js
CHANGED
|
@@ -1,48 +1,21 @@
|
|
|
1
|
-
/* eslint-disable unicorn/no-null */
|
|
2
1
|
import { defineConfig } from 'eslint/config';
|
|
3
2
|
import plugin from 'typescript-eslint';
|
|
4
3
|
|
|
5
|
-
import { FILES } from '../
|
|
4
|
+
import { DATA_FILES, FILES, TEST_FILES } from '../base.js';
|
|
5
|
+
import { TS_RULES } from '../rules/typescript.js';
|
|
6
6
|
|
|
7
7
|
/** @see [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint) */
|
|
8
8
|
export const typescript = defineConfig([
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// `plugin.configs.strict`/`stylistic` contain blocks without a `files` key,
|
|
10
|
+
// so they would also land on data files that are not JavaScript at all.
|
|
11
|
+
...[...plugin.configs.strict, ...plugin.configs.stylistic].map((config) => ({
|
|
12
|
+
...config,
|
|
13
|
+
ignores: [...(config.ignores ?? []), ...DATA_FILES],
|
|
14
|
+
})),
|
|
11
15
|
|
|
16
|
+
{ files: FILES, rules: TS_RULES },
|
|
12
17
|
{
|
|
13
|
-
files:
|
|
14
|
-
rules: {
|
|
15
|
-
'@typescript-eslint/naming-convention': [
|
|
16
|
-
'error',
|
|
17
|
-
{
|
|
18
|
-
format: ['strictCamelCase'],
|
|
19
|
-
leadingUnderscore: 'allow',
|
|
20
|
-
selector: 'function',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
format: ['strictCamelCase'],
|
|
24
|
-
leadingUnderscore: 'require',
|
|
25
|
-
modifiers: ['private'],
|
|
26
|
-
selector: 'memberLike',
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
format: ['strictCamelCase'],
|
|
30
|
-
leadingUnderscore: 'allow',
|
|
31
|
-
selector: 'parameter',
|
|
32
|
-
},
|
|
33
|
-
{ format: ['StrictPascalCase'], selector: 'typeLike' },
|
|
34
|
-
{
|
|
35
|
-
format: ['strictCamelCase', 'PascalCase', 'UPPER_CASE'],
|
|
36
|
-
leadingUnderscore: 'allow',
|
|
37
|
-
selector: 'variable',
|
|
38
|
-
},
|
|
39
|
-
{ format: null, modifiers: ['destructured'], selector: 'variable' },
|
|
40
|
-
],
|
|
41
|
-
'@typescript-eslint/no-explicit-any': 'warn',
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
files: ['**/*.{fixtures,test,spec}.{js,ts}'],
|
|
18
|
+
files: TEST_FILES,
|
|
46
19
|
rules: { '@typescript-eslint/no-empty-function': 'off' },
|
|
47
20
|
},
|
|
48
21
|
]);
|
package/plugins/unicorn.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-unicorn';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { DTS_FILES, FILES, VUE_FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) */
|
|
7
7
|
export const unicorn = defineConfig([
|
|
@@ -18,6 +18,10 @@ export const unicorn = defineConfig([
|
|
|
18
18
|
'error',
|
|
19
19
|
{ default: 'arrow-function' },
|
|
20
20
|
],
|
|
21
|
+
// Explicit: the default happens to be kebab case, but the intent is
|
|
22
|
+
// worth pinning down. Applies to `.vue` components too, which is why
|
|
23
|
+
// `vue/match-component-file-name` is kept in sync with it in `vue.js`.
|
|
24
|
+
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
|
21
25
|
'unicorn/iteration-fallback-style': ['error', 'guard'],
|
|
22
26
|
'unicorn/name-replacements': 'off',
|
|
23
27
|
'unicorn/no-array-reduce': ['error', { allowSimpleOperations: true }],
|
|
@@ -42,8 +46,15 @@ export const unicorn = defineConfig([
|
|
|
42
46
|
'unicorn/single-line-block-comment-style': 'off',
|
|
43
47
|
},
|
|
44
48
|
},
|
|
45
|
-
{ files: ['
|
|
46
|
-
{ files:
|
|
49
|
+
{ files: ['**/.*'], rules: { 'unicorn/no-null': 'off' } },
|
|
50
|
+
{ files: DTS_FILES, rules: { 'unicorn/prefer-export-from': 'off' } },
|
|
51
|
+
{
|
|
52
|
+
// `null` is part of the type contract in Vue.js SFC:
|
|
53
|
+
// `ref<Type | null>(null)` is the idiomatic way to declare an initially
|
|
54
|
+
// empty reactive value. Everywhere else `null` remains an error.
|
|
55
|
+
files: VUE_FILES,
|
|
56
|
+
rules: { 'unicorn/no-null': 'off' },
|
|
57
|
+
},
|
|
47
58
|
{
|
|
48
59
|
files: ['**/*.{api,endpoints,fixtures,schemas,service,spec,test}.{js,ts}'],
|
|
49
60
|
rules: {
|
|
@@ -56,6 +67,6 @@ export const unicorn = defineConfig([
|
|
|
56
67
|
},
|
|
57
68
|
{
|
|
58
69
|
files: ['**/temp/**/*.vue'],
|
|
59
|
-
rules: { 'unicorn/
|
|
70
|
+
rules: { 'unicorn/name-replacements': 'off' },
|
|
60
71
|
},
|
|
61
72
|
]);
|
package/plugins/unocss.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import plugin from '@unocss/eslint-config/flat';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [@unocss/eslint-config](https://unocss.dev/integrations/eslint) */
|
|
7
7
|
export const unocss = defineConfig([
|
package/plugins/vitest.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import plugin from '@vitest/eslint-plugin';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
+
import { TEST_FILES } from '../base.js';
|
|
5
|
+
|
|
4
6
|
/** @see [eslint-plugin-vitest](https://github.com/veritem/eslint-plugin-vitest) */
|
|
5
7
|
export const vitest = defineConfig([
|
|
6
8
|
{
|
|
7
|
-
files:
|
|
9
|
+
files: TEST_FILES,
|
|
8
10
|
plugins: { vitest: plugin },
|
|
9
11
|
rules: {
|
|
10
12
|
...plugin.configs.recommended.rules,
|
package/plugins/vue-i18n.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import plugin from '@intlify/eslint-plugin-vue-i18n';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
+
import { DATA_FILES } from '../base.js';
|
|
5
|
+
|
|
4
6
|
/** @see [eslint-plugin-vue-i18n](https://eslint-plugin-vue-i18n.intlify.dev/) */
|
|
5
7
|
export const vueI18n = defineConfig([
|
|
6
8
|
...plugin.configs['flat/recommended'].map((config) => ({
|
|
7
9
|
...config,
|
|
8
|
-
ignores: [
|
|
9
|
-
...(config.ignores ?? []),
|
|
10
|
-
'**/*.json',
|
|
11
|
-
'**/*.jsonc',
|
|
12
|
-
'**/*.json5',
|
|
13
|
-
],
|
|
10
|
+
ignores: [...(config.ignores ?? []), ...DATA_FILES],
|
|
14
11
|
})),
|
|
15
12
|
|
|
16
13
|
{
|
package/plugins/vue.js
CHANGED
|
@@ -2,20 +2,18 @@ import plugin from 'eslint-plugin-vue';
|
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
import typescript from 'typescript-eslint';
|
|
4
4
|
|
|
5
|
+
import { DATA_FILES, TEST_FILES, VUE_FILES } from '../base.js';
|
|
6
|
+
import { NO_RESTRICTED_SYNTAX } from '../rules/restricted-syntax.js';
|
|
7
|
+
|
|
5
8
|
/** @see [eslint-plugin-vue](https://eslint.vuejs.org/rules/) */
|
|
6
9
|
export const vue = defineConfig([
|
|
7
10
|
...plugin.configs['flat/recommended'].map((config) => ({
|
|
8
11
|
...config,
|
|
9
|
-
ignores: [
|
|
10
|
-
...(config.ignores ?? []),
|
|
11
|
-
'**/*.json',
|
|
12
|
-
'**/*.jsonc',
|
|
13
|
-
'**/*.json5',
|
|
14
|
-
],
|
|
12
|
+
ignores: [...(config.ignores ?? []), ...DATA_FILES],
|
|
15
13
|
})),
|
|
16
14
|
|
|
17
15
|
{
|
|
18
|
-
files:
|
|
16
|
+
files: VUE_FILES,
|
|
19
17
|
languageOptions: { parserOptions: { parser: typescript.parser } },
|
|
20
18
|
rules: {
|
|
21
19
|
'@typescript-eslint/no-empty-object-type': [
|
|
@@ -24,6 +22,8 @@ export const vue = defineConfig([
|
|
|
24
22
|
],
|
|
25
23
|
'no-restricted-syntax': [
|
|
26
24
|
'error',
|
|
25
|
+
// Merge the shared list, do not replace it
|
|
26
|
+
...NO_RESTRICTED_SYNTAX,
|
|
27
27
|
{
|
|
28
28
|
message:
|
|
29
29
|
'Запрещено использовать имя "Props". Используйте именованный формат, например: <ИмяКомпонента>Props.',
|
|
@@ -109,7 +109,14 @@ export const vue = defineConfig([
|
|
|
109
109
|
svg: 'always',
|
|
110
110
|
},
|
|
111
111
|
],
|
|
112
|
-
|
|
112
|
+
// Keep in sync with `unicorn/filename-case` in `unicorn.js`:
|
|
113
|
+
// components live in kebab-case files, so the component name is
|
|
114
|
+
// derived from a kebab-case file name instead of being required to be
|
|
115
|
+
// PascalCase in the file name itself.
|
|
116
|
+
'vue/match-component-file-name': [
|
|
117
|
+
'error',
|
|
118
|
+
{ extensions: ['vue'], shouldMatchCase: false },
|
|
119
|
+
],
|
|
113
120
|
'vue/match-component-import-name': ['error'],
|
|
114
121
|
'vue/max-attributes-per-line': ['error', { singleline: 3 }],
|
|
115
122
|
'vue/max-lines-per-block': [
|
|
@@ -244,8 +251,5 @@ export const vue = defineConfig([
|
|
|
244
251
|
rules: { 'vue/multi-word-component-names': 'off' },
|
|
245
252
|
},
|
|
246
253
|
|
|
247
|
-
{
|
|
248
|
-
files: ['**/*.{test,spec}.{js,ts}'],
|
|
249
|
-
rules: { 'vue/one-component-per-file': 'off' },
|
|
250
|
-
},
|
|
254
|
+
{ files: TEST_FILES, rules: { 'vue/one-component-per-file': 'off' } },
|
|
251
255
|
]);
|
package/plugins/zod.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import plugin from 'eslint-plugin-zod';
|
|
2
2
|
import { defineConfig } from 'eslint/config';
|
|
3
3
|
|
|
4
|
-
import { FILES } from '../
|
|
4
|
+
import { FILES } from '../base.js';
|
|
5
5
|
|
|
6
6
|
/** @see [eslint-plugin-zod](https://github.com/marcalexiei/eslint-zod/tree/main/plugins/eslint-plugin-zod) */
|
|
7
7
|
export const zod = defineConfig([
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared restricted syntax rules.
|
|
3
|
+
*
|
|
4
|
+
* Keep it in a standalone module so that plugins which extend the list (e.g.
|
|
5
|
+
* `vue.js`) merge it instead of silently replacing it.
|
|
6
|
+
*/
|
|
7
|
+
export const NO_RESTRICTED_SYNTAX = [
|
|
8
|
+
{
|
|
9
|
+
message:
|
|
10
|
+
"Не используйте префикс 'handle' для обработчиков событий. Переименуйте метод, заменив 'handle' на 'on' (например, 'onClick' вместо 'handleClick').",
|
|
11
|
+
selector: 'Identifier[name=/^handle[A-Z]/]',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
message:
|
|
15
|
+
"Используйте методы массивов (.forEach, .map и т.д.) вместо цикла 'for'.",
|
|
16
|
+
selector: 'ForStatement',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
message:
|
|
20
|
+
"Используйте методы объектов (.keys, .values и т.д.) вместо цикла 'for...in'.",
|
|
21
|
+
selector: 'ForInStatement',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
message:
|
|
25
|
+
"Используйте методы массивов(.forEach, .map и т.д.) вместо цикла 'for...of'.",
|
|
26
|
+
selector: 'ForOfStatement',
|
|
27
|
+
},
|
|
28
|
+
];
|
package/rules/style.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting rules that survive `eslint-config-prettier`.
|
|
3
|
+
*
|
|
4
|
+
* `eslint-config-prettier` turns off every core formatting rule, so these two
|
|
5
|
+
* are declared in a single place and re-applied by `prettier.js` to both
|
|
6
|
+
* `prettier` and `prettierConfig`. Keep them in sync with `prettier.js`.
|
|
7
|
+
*/
|
|
8
|
+
export const STYLE_RULES = {
|
|
9
|
+
curly: 'error',
|
|
10
|
+
quotes: [
|
|
11
|
+
'error',
|
|
12
|
+
'single',
|
|
13
|
+
{ allowTemplateLiterals: false, avoidEscape: true },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* eslint-disable unicorn/no-null */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared TypeScript rules.
|
|
5
|
+
*
|
|
6
|
+
* `format: null` disables the format check for destructured variables — their
|
|
7
|
+
* names may be arbitrary.
|
|
8
|
+
*/
|
|
9
|
+
export const TS_RULES = {
|
|
10
|
+
'@typescript-eslint/consistent-type-imports': [
|
|
11
|
+
'error',
|
|
12
|
+
{ fixStyle: 'separate-type-imports', prefer: 'type-imports' },
|
|
13
|
+
],
|
|
14
|
+
'@typescript-eslint/naming-convention': [
|
|
15
|
+
'error',
|
|
16
|
+
{
|
|
17
|
+
format: ['strictCamelCase'],
|
|
18
|
+
leadingUnderscore: 'allow',
|
|
19
|
+
selector: 'function',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
format: ['strictCamelCase'],
|
|
23
|
+
leadingUnderscore: 'require',
|
|
24
|
+
modifiers: ['private'],
|
|
25
|
+
selector: 'memberLike',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
format: ['strictCamelCase'],
|
|
29
|
+
leadingUnderscore: 'allow',
|
|
30
|
+
selector: 'parameter',
|
|
31
|
+
},
|
|
32
|
+
{ format: ['StrictPascalCase'], selector: 'typeLike' },
|
|
33
|
+
{
|
|
34
|
+
format: ['strictCamelCase', 'PascalCase', 'UPPER_CASE'],
|
|
35
|
+
leadingUnderscore: 'allow',
|
|
36
|
+
selector: 'variable',
|
|
37
|
+
},
|
|
38
|
+
{ format: null, modifiers: ['destructured'], selector: 'variable' },
|
|
39
|
+
{
|
|
40
|
+
format: ['strictCamelCase', 'PascalCase', 'UPPER_CASE'],
|
|
41
|
+
selector: 'enumMember',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
format: ['strictCamelCase', 'UPPER_CASE'],
|
|
45
|
+
leadingUnderscore: 'allow',
|
|
46
|
+
selector: 'classProperty',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
format: ['strictCamelCase', 'PascalCase', 'UPPER_CASE', 'snake_case'],
|
|
50
|
+
leadingUnderscore: 'allow',
|
|
51
|
+
selector: 'typeProperty',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
format: ['strictCamelCase', 'PascalCase', 'UPPER_CASE'],
|
|
55
|
+
leadingUnderscore: 'allow',
|
|
56
|
+
selector: 'import',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
60
|
+
'@typescript-eslint/no-import-type-side-effects': 'error',
|
|
61
|
+
};
|
|
62
|
+
/* eslint-enable unicorn/no-null */
|
package/presets/base.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'eslint/config';
|
|
2
|
-
import globals from 'globals';
|
|
3
|
-
|
|
4
|
-
export const FILES = ['**/*.{js,mjs,cjs,jsx,ts,tsx,vue}'];
|
|
5
|
-
|
|
6
|
-
/** Base config */
|
|
7
|
-
export const base = defineConfig([
|
|
8
|
-
{ files: FILES, languageOptions: { globals: globals.browser } },
|
|
9
|
-
{
|
|
10
|
-
ignores: [
|
|
11
|
-
'**/.*/',
|
|
12
|
-
'**/_deprecated/',
|
|
13
|
-
'**/mockServiceWorker.js',
|
|
14
|
-
'.*/',
|
|
15
|
-
'build',
|
|
16
|
-
'dist',
|
|
17
|
-
'docs',
|
|
18
|
-
'storybook-*',
|
|
19
|
-
'sw.js',
|
|
20
|
-
],
|
|
21
|
-
},
|
|
22
|
-
]);
|
package/presets/default.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'eslint/config';
|
|
2
|
-
|
|
3
|
-
import { deMorgan } from '../plugins/de-morgan.js';
|
|
4
|
-
import { javascript } from '../plugins/javascript.js';
|
|
5
|
-
import { jsdoc } from '../plugins/jsdoc.js';
|
|
6
|
-
import { json } from '../plugins/json.js';
|
|
7
|
-
import { perfectionist } from '../plugins/perfectionist.js';
|
|
8
|
-
import { prettierConfig } from '../plugins/prettier.js';
|
|
9
|
-
import { regexp } from '../plugins/regexp.js';
|
|
10
|
-
import { sonar } from '../plugins/sonar.js';
|
|
11
|
-
import { stylistic } from '../plugins/stylistic.js';
|
|
12
|
-
import { typescript } from '../plugins/typescript.js';
|
|
13
|
-
import { unicorn } from '../plugins/unicorn.js';
|
|
14
|
-
import { vueAccessibility } from '../plugins/vue-accessibility.js';
|
|
15
|
-
import { vueI18n } from '../plugins/vue-i18n.js';
|
|
16
|
-
import { vue } from '../plugins/vue.js';
|
|
17
|
-
import { base } from './base.js';
|
|
18
|
-
|
|
19
|
-
export const defaultPreset = defineConfig([
|
|
20
|
-
...base, // must be first
|
|
21
|
-
|
|
22
|
-
...javascript,
|
|
23
|
-
...deMorgan,
|
|
24
|
-
...jsdoc,
|
|
25
|
-
...json,
|
|
26
|
-
...perfectionist,
|
|
27
|
-
...regexp,
|
|
28
|
-
...sonar,
|
|
29
|
-
...stylistic,
|
|
30
|
-
...typescript,
|
|
31
|
-
...unicorn,
|
|
32
|
-
...vue,
|
|
33
|
-
...vueAccessibility,
|
|
34
|
-
...vueI18n,
|
|
35
|
-
|
|
36
|
-
...prettierConfig, // must be last
|
|
37
|
-
]);
|