arui-presets-lint 10.1.0 → 10.2.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/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 10.2.0
2
+
3
+ ### Minor Changes
4
+
5
+ - [#136](https://github.com/core-ds/arui-presets-lint/pull/136) [`3612e03`](https://github.com/core-ds/arui-presets-lint/commit/3612e0386142053b43a800d8e7f9cf7e7b41205e) Thanks [@kiskv](https://github.com/kiskv)! - ## New Features
6
+
7
+ - Подключены плагины [`@eslint/json`](https://github.com/eslint/json) и [`@eslint/markdown`](https://github.com/eslint/markdown).
8
+ - `.json` файлы проверяются как строгий JSON, `.jsonc` и `tsconfig*.json` - как JSONC, `.json5` — как JSON5. Правила: `json/no-duplicate-keys`, `json/no-empty-keys`, `json/no-unnormalized-keys`, `json/no-unsafe-values` (как error).
9
+ - `.md` файлы проверяются по CommonMark (как warning). Подключены все рекомендованные правила `@eslint/markdown` (контроль уровней заголовков, отсутствие пустых ссылок/изображений, alt-текст и т.д.). `**/CHANGELOG.md` игнорируется по умолчанию.
10
+ - Добавлены константы для удобного прописывания области видимости правил на уровне проекта
11
+
12
+ ## Bug fixes
13
+
14
+ - Исправлены скоупы files, все плагины определены глобально, для того чтобы корректно срабатывало переопределение.
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies []:
19
+ - @alfalab/stylelint-core-vars@3.0.0
20
+
1
21
  ## 10.1.0
2
22
 
3
23
  ### Minor Changes
@@ -1,4 +1,6 @@
1
- # Гид по миграции на arui-presets-lint@9
1
+ # Гид по миграции на arui-presets-lint@9/10 с 8
2
+
3
+ [Обновляетесь с 7 и более ранних на 8?](https://github.com/core-ds/arui-presets-lint/blob/v8.8.1/V8_MIGRATION_GUIDE.md)
2
4
 
3
5
  ## Введение
4
6
 
@@ -13,8 +15,7 @@ yarn add arui-presets-lint@latest
13
15
  1. Удалить свойство `eslintConfig` из package.json, и создать в корне проекта файл `eslint.config.mts` со следующим содержимым:
14
16
 
15
17
  ```typescript
16
- import { defineConfig } from 'arui-presets-lint/eslint/config';
17
- import { eslintConfig } from 'arui-presets-lint/eslint';
18
+ import { defineConfig, eslintConfig, CYPRESS_SCRIPTS_SCOPE } from 'arui-presets-lint/eslint';
18
19
 
19
20
  export default defineConfig(eslintConfig);
20
21
  ```
@@ -23,23 +24,40 @@ export default defineConfig(eslintConfig);
23
24
 
24
25
  ```typescript
25
26
  import pluginCypress from 'eslint-plugin-cypress';
26
- import { defineConfig } from 'arui-presets-lint/eslint/config';
27
- import { eslintConfig } from 'arui-presets-lint/eslint';
27
+ import { defineConfig, eslintConfig } from 'arui-presets-lint/eslint';
28
28
 
29
29
  export default defineConfig(eslintConfig, [
30
30
  pluginCypress.configs.recommended,
31
31
  {
32
+ // Константы появились в arui-presets-lint@10.2.0, если у вас более ранняя - укажите текстом:
33
+ // files: ['cypress/**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}']
34
+ files: [CYPRESS_SCOPE],
32
35
  rules: {
33
- 'cypress/no-unnecessary-waiting': 'off',
36
+ 'cypress/no-unnecessary-waiting': 'warn',
34
37
  },
35
38
  },
36
- // Тут лежат glob-паттерны файлов, которые нужно игнорировать в проекте. Возможно он вам не понадобится, так как глобальный игнор на основные файлы и папки уже настроен на уровне arui-presets-lint
37
- ignores: []
38
39
  ]);
39
40
  ```
40
41
 
41
42
  ^^ Тут мы добавляем eslint-plugin-cypress, и определяем кастомные правила на уровне проекта. Про новый формат конфига - подробности [тут](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-objects)
42
43
 
44
+ Не забывайте про директиву files, её нужно указывать, если правило переопределяется (не выключается). Константы можно импортировать из arui-presets-lint, например:
45
+
46
+ ```typescript
47
+ import { defineConfig, eslintConfig, TYPESCRIPT_SCRIPTS_SCOPE } from 'arui-presets-lint/eslint'
48
+
49
+ export default defineConfig(eslintConfig, [
50
+ {
51
+ rules: {
52
+ '@typescript-eslint/consistent-type-assertions': 'warning',
53
+ }
54
+ // Константы появились в arui-presets-lint@10.2.0, если у вас более ранняя - укажите текстом:
55
+ // files: '**/*.{ts,tsx,mts,cts,mtsx,ctsx}',
56
+ files: [TYPESCRIPT_SCRIPTS_SCOPE],
57
+ },
58
+ ]);
59
+ ```
60
+
43
61
  > если нужно использовать плагины и правила, которые не поддерживают eslint 9, можно использовать для их подключения утилиты из пакета [@eslint/compat](https://www.npmjs.com/package/@eslint/compat)
44
62
 
45
63
  1. `tsconfig.eslint.json` и правила игнорирования
@@ -47,8 +65,7 @@ export default defineConfig(eslintConfig, [
47
65
  Ранее мы использовали кастомный tsconfig.eslint.json, например для того чтобы включить eslint для файлов в корневой директории - с переходом на [typescript-eslint projectService](https://typescript-eslint.io/blog/project-service/#introducing-the-project-service) он больше не нужен. Используйте основной tsconfig.json, а те файлы которые туда нельзя добавить, добавьте с помощью опции languageOptions.parserOptions.projectService.allowDefaultProject. Учтите что папки добавлять нельзя, так как это аффектит на производительность. Пример такого конфига:
48
66
 
49
67
  ```typescript
50
- import { eslintConfig } from 'arui-presets-lint/eslint';
51
- import { defineConfig } from 'arui-presets-lint/eslint/config';
68
+ import { defineConfig, eslintConfig, TYPESCRIPT_SCRIPTS_SCOPE } from 'arui-presets-lint/eslint';
52
69
 
53
70
  export default defineConfig(eslintConfig, [
54
71
  {
@@ -63,7 +80,7 @@ export default defineConfig(eslintConfig, [
63
80
  },
64
81
  },
65
82
  },
66
- files: ['**/*.{ts,tsx,mts,cts,mtsx,ctsx}'],
83
+ files: [TYPESCRIPT_SCRIPTS_SCOPE],
67
84
  },
68
85
  ]);
69
86
  ```
@@ -84,6 +101,8 @@ export default defineConfig(eslintConfig, [
84
101
  Если необходима проверка без ограничения глубины или другое значение, то переопределите правило в своём `eslint.config.mts`:
85
102
 
86
103
  ```typescript
104
+ import { GLOBAL_SCRIPTS_SCOPE } from 'arui-presets-lint/eslint'
105
+
87
106
  {
88
107
  rules: {
89
108
  'import-x/no-cycle': ['error', { ignoreExternal: true, maxDepth: 50 }],
@@ -92,6 +111,8 @@ export default defineConfig(eslintConfig, [
92
111
  // или отключить правило:
93
112
  // 'import-x/no-cycle': 'off',
94
113
  },
114
+ // files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}']
115
+ files: [GLOBAL_SCRIPTS_SCOPE]
95
116
  },
96
117
  ```
97
118
 
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  [Как я могу внести изменения?](./CONTRIBUTING.md)
16
16
 
17
- 🚀 [Миграция на версию 9](./V9_MIGRATION_GUIDE.md)
17
+ 🚀 [Миграция на версию 9/10 c 8](./MIGRATION_GUIDE.md)
18
18
 
19
19
  ## Установка и обновление
20
20
 
@@ -41,8 +41,7 @@
41
41
  Для настройки eslint нужно создать в корне проекта файл `eslint.config.mts` со следующим содержанием:
42
42
 
43
43
  ```typescript
44
- import { defineConfig } from 'arui-presets-lint/eslint/config';
45
- import { eslintConfig } from 'arui-presets-lint/eslint';
44
+ import { defineConfig, eslintConfig } from 'arui-presets-lint/eslint';
46
45
 
47
46
  export default defineConfig(eslintConfig);
48
47
  ```
@@ -51,8 +50,7 @@ export default defineConfig(eslintConfig);
51
50
 
52
51
  ```typescript
53
52
  import pluginCypress from 'eslint-plugin-cypress';
54
- import { defineConfig } from 'arui-presets-lint/eslint/config';
55
- import { eslintConfig } from 'arui-presets-lint/eslint';
53
+ import { defineConfig, eslintConfig, CYPRESS_SCOPE } from 'arui-presets-lint/eslint';
56
54
 
57
55
  export default defineConfig(eslintConfig, [
58
56
  {
@@ -63,20 +61,35 @@ export default defineConfig(eslintConfig, [
63
61
  },
64
62
  pluginCypress.configs.recommended,
65
63
  {
64
+ files: [CYPRESS_SCOPE],
66
65
  rules: {
67
- 'cypress/no-unnecessary-waiting': 'off',
66
+ 'cypress/no-unnecessary-waiting': 'warn',
68
67
  },
69
68
  },
70
69
  ]);
71
70
  ```
72
71
 
72
+ Не забывайте про директиву files, её нужно указывать, если правило переопределяется (не выключается). Константы можно импортировать из arui-presets-lint, например:
73
+
74
+ ```typescript
75
+ import { defineConfig, eslintConfig, TYPESCRIPT_SCRIPTS_SCOPE } from 'arui-presets-lint/eslint'
76
+
77
+ export default defineConfig(eslintConfig, [
78
+ {
79
+ rules: {
80
+ '@typescript-eslint/consistent-type-assertions': 'warning',
81
+ }
82
+ files: [TYPESCRIPT_SCRIPTS_SCOPE],
83
+ },
84
+ ]);
85
+ ```
86
+
73
87
  Если в проекте есть файлы typescript, которые не добавлены в `tsconfig.json`, или исключены из него принудительно, то eslint выдаст ошибку `<filename> was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject`. Есть несколько способов решения этой проблемы:
74
88
 
75
89
  - (Рекомендуется) Добавить нужные файлы через опцию allowDefaultProject:
76
90
 
77
91
  ```typescript
78
- import { eslintConfig } from 'arui-presets-lint/eslint';
79
- import { defineConfig } from 'arui-presets-lint/eslint/config';
92
+ import { defineConfig, eslintConfig, TYPESCRIPT_SCRIPTS_SCOPE } from 'arui-presets-lint/eslint';
80
93
 
81
94
  export default defineConfig(eslintConfig, [
82
95
  {
@@ -91,7 +104,7 @@ export default defineConfig(eslintConfig, [
91
104
  },
92
105
  },
93
106
  },
94
- files: ['**/*.{ts,tsx,mts,cts,mtsx,ctsx}'],
107
+ files: [TYPESCRIPT_SCRIPTS_SCOPE],
95
108
  },
96
109
  ]);
97
110
  ```
@@ -99,8 +112,7 @@ export default defineConfig(eslintConfig, [
99
112
  - (НЕ рекомендуется) Добавить файлы в globalIgnores. В этом случае eslint не будет его проверять:
100
113
 
101
114
  ```typescript
102
- import { eslintConfig } from 'arui-presets-lint/eslint';
103
- import { defineConfig, globalIgnores } from 'arui-presets-lint/eslint/config';
115
+ import { defineConfig, globalIgnores, eslintConfig } from 'arui-presets-lint/eslint';
104
116
 
105
117
  export default defineConfig(eslintConfig, [
106
118
  {
@@ -129,7 +141,7 @@ export default defineConfig(eslintConfig, [
129
141
  > Вместо файла .eslintignore рекомендуется использовать globalIgnores в конфиге eslint ([подробнее](https://eslint.org/docs/latest/use/configure/ignore)). Импортируем функцию globalIgnores из `arui-presets-lint` вот так:
130
142
 
131
143
  ```typescript
132
- import { defineConfig, globalIgnores } from 'arui-presets-lint/eslint/config';
144
+ import { defineConfig, globalIgnores } from 'arui-presets-lint/eslint';
133
145
  ...
134
146
  ```
135
147
 
@@ -0,0 +1,10 @@
1
+ export declare const GLOBAL_SCRIPTS_SCOPE = "**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}";
2
+ export declare const NODEJS_SCRIPTS_SCOPE = "**/server/**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}";
3
+ export declare const TYPESCRIPT_SCRIPTS_SCOPE = "**/*.{ts,tsx,mts,cts,mtsx,ctsx}";
4
+ export declare const REACT_SCRIPTS_SCOPE = "**/*.{jsx,mjsx,tsx,mtsx,ctsx}";
5
+ export declare const TESTS_SCRIPTS_SCOPE = "**/*.{test,tests,spec}.{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}";
6
+ export declare const CYPRESS_SCOPE = "cypress/**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}";
7
+ export declare const PLAYWRIGHT_SCOPE = "playwright/**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}";
8
+ export declare const MARKDOWN_SCOPE = "**/*.md";
9
+ export declare const JSON_SCOPE = "**/*.{json,json5,jsonc}";
10
+ export declare const ANOTHER_FILES_SCOPE = "**/*.{yaml,yml,css,jpeg,jpg,png,webp,gif,avif,heic,svg,ico,wasm,html,woff,woff2,ttf,otf,eot,graphql,gql}";
@@ -0,0 +1,12 @@
1
+ const scriptsExtentionsPattern = '{js,mjs,cjs,jsx,mjsx,ts,tsx,mts,cts,mtsx,ctsx}';
2
+ export const GLOBAL_SCRIPTS_SCOPE = `**/*.${scriptsExtentionsPattern}`;
3
+ export const NODEJS_SCRIPTS_SCOPE = `**/server/**/*.${scriptsExtentionsPattern}`;
4
+ export const TYPESCRIPT_SCRIPTS_SCOPE = '**/*.{ts,tsx,mts,cts,mtsx,ctsx}';
5
+ export const REACT_SCRIPTS_SCOPE = '**/*.{jsx,mjsx,tsx,mtsx,ctsx}';
6
+ export const TESTS_SCRIPTS_SCOPE = `**/*.{test,tests,spec}.${scriptsExtentionsPattern}`;
7
+ export const CYPRESS_SCOPE = `cypress/**/*.${scriptsExtentionsPattern}`;
8
+ export const PLAYWRIGHT_SCOPE = `playwright/**/*.${scriptsExtentionsPattern}`;
9
+ export const MARKDOWN_SCOPE = '**/*.md';
10
+ export const JSON_SCOPE = '**/*.{json,json5,jsonc}';
11
+ // Не должен пересекаться с остальными
12
+ export const ANOTHER_FILES_SCOPE = '**/*.{yaml,yml,css,jpeg,jpg,png,webp,gif,avif,heic,svg,ico,wasm,html,woff,woff2,ttf,otf,eot,graphql,gql}';
package/eslint/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type Linter } from 'eslint';
2
2
  export declare const eslintConfig: Linter.Config;
3
3
  export { defineConfig, globalIgnores, globals } from './config.js';
4
+ export * from './constants.js';
4
5
  export { type Linter } from 'eslint';
5
6
  export { type TSESLint } from '@typescript-eslint/utils';
package/eslint/index.js CHANGED
@@ -1,10 +1,23 @@
1
1
  import eslintJS from '@eslint/js';
2
+ import jsonPlugin from '@eslint/json';
3
+ import markdownPlugin from '@eslint/markdown';
2
4
  import {} from 'eslint';
3
5
  import gitignore from 'eslint-config-flat-gitignore';
6
+ import checkFilePlugin from 'eslint-plugin-check-file';
7
+ import deMorgan from 'eslint-plugin-de-morgan';
8
+ import { importX } from 'eslint-plugin-import-x';
9
+ import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
10
+ import nodePlugin from 'eslint-plugin-n';
11
+ import reactPlugin from 'eslint-plugin-react';
12
+ import reactHooksPlugin from 'eslint-plugin-react-hooks';
13
+ import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
14
+ import unicornPlugin from 'eslint-plugin-unicorn';
4
15
  import globals from 'globals';
5
- import { disableCommentsConfig } from './plugins/index.js';
16
+ import tseslint from 'typescript-eslint';
17
+ import { disableCommentsConfig, disableCommentsPlugin } from './plugins/index.js';
6
18
  import { globalIgnores } from './config.js';
7
- import { bestPracticesConfig, importsConfig, nodeRulesConfig, reactA11yConfig, reactConfig, testsConfig, typescriptConfig, variablesConfig, } from './rules.js';
19
+ import { GLOBAL_SCRIPTS_SCOPE } from './constants.js';
20
+ import { bestPracticesConfig, checkFileConfig, importsConfig, jsonConfig, markdownConfig, nodeRulesConfig, reactA11yConfig, reactConfig, testsConfig, typescriptConfig, variablesConfig, } from './rules.js';
8
21
  export const eslintConfig = [
9
22
  gitignore({
10
23
  files: ['.gitignore', '.eslintignore'],
@@ -25,21 +38,42 @@ export const eslintConfig = [
25
38
  ]),
26
39
  {
27
40
  languageOptions: {
28
- ecmaVersion: 2022,
41
+ ecmaVersion: 'latest',
29
42
  sourceType: 'module',
30
43
  parserOptions: {
31
44
  ecmaFeatures: { jsx: true },
32
45
  },
33
46
  globals: {
34
- ...globals.es2023,
47
+ ...globals.es2026,
35
48
  ...globals.browser,
36
- ...globals.node,
37
49
  },
38
50
  },
39
- files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
51
+ files: [GLOBAL_SCRIPTS_SCOPE],
52
+ rules: {
53
+ // https://github.com/eslint/eslint/blob/main/packages/js/src/configs/eslint-recommended.js
54
+ ...eslintJS.configs.recommended.rules,
55
+ },
56
+ },
57
+ // ВСЕ плагины должны регистрироваться глобально
58
+ // Иначе будут проблемы с переопределением
59
+ {
60
+ name: 'arui-presets-lint/plugins',
61
+ plugins: {
62
+ 'import-x': importX,
63
+ 'simple-import-sort': simpleImportSortPlugin,
64
+ 'check-file': checkFilePlugin,
65
+ react: reactPlugin,
66
+ 'react-hooks': reactHooksPlugin,
67
+ 'jsx-a11y': jsxA11yPlugin,
68
+ unicorn: unicornPlugin,
69
+ 'disable-comments': disableCommentsPlugin,
70
+ '@typescript-eslint': tseslint.plugin,
71
+ 'de-morgan': deMorgan,
72
+ n: nodePlugin,
73
+ json: jsonPlugin,
74
+ markdown: markdownPlugin,
75
+ },
40
76
  },
41
- // https://github.com/eslint/eslint/blob/main/packages/js/src/configs/eslint-recommended.js
42
- eslintJS.configs.recommended,
43
77
  /*
44
78
  ☭ Наши наборы правил ☭
45
79
  */
@@ -52,16 +86,14 @@ export const eslintConfig = [
52
86
  typescriptConfig,
53
87
  importsConfig,
54
88
  disableCommentsConfig,
89
+ jsonConfig,
90
+ markdownConfig,
91
+ checkFileConfig,
55
92
  /*
56
93
  ☭.
57
94
  */
58
- {
59
- // Включаем проверку других расширений файлов в eslint-plugin-check-file
60
- // ⚠️ НЕ ДОЛЖНО ПЕРЕСЕКАТЬСЯ С ПАТТЕРНОМ, УКАЗАННЫМ ВЫШЕ
61
- files: ['**/*.{yaml,yml,json,css}'],
62
- processor: 'check-file/eslint-processor-check-file',
63
- },
64
95
  ];
65
96
  export { defineConfig, globalIgnores, globals } from './config.js';
97
+ export * from './constants.js';
66
98
  export {} from 'eslint';
67
99
  export {} from '@typescript-eslint/utils';
@@ -109,7 +109,7 @@ export default [
109
109
  | `missingDescription` | Директива ESLint без описания. Добавьте описание после -- или комментарий над директивой. |
110
110
  | `invalidDescription` | Описание слишком общее или неинформативное. Укажите конкретную причину. |
111
111
  | `suggestDebug` | Добавить комментарий — "Используется временно для отладки" |
112
- | `suggestAboveComment` | Добавить задачу — "TODO: [ссылка на задачу] Описание" |
112
+ | `suggestAboveComment` | Добавить задачу — "TODO: \[ссылка на задачу\] Описание" |
113
113
 
114
114
  #### Автоматические исправления
115
115
  - `createSuggestionFix` – добавляет описание после разделителя --.
@@ -1,4 +1,5 @@
1
1
  import {} from '@typescript-eslint/utils';
2
+ import { GLOBAL_SCRIPTS_SCOPE } from '../../../constants.js';
2
3
  import { disableCommentsPlugin } from './plugin.js';
3
4
  /**
4
5
  * Config, который подключает плагин
@@ -6,6 +7,7 @@ import { disableCommentsPlugin } from './plugin.js';
6
7
  */
7
8
  export const disableCommentsConfig = {
8
9
  name: 'arui-presets-lint/disable-comments',
10
+ files: [GLOBAL_SCRIPTS_SCOPE],
9
11
  plugins: {
10
12
  'disable-comments': disableCommentsPlugin,
11
13
  },
@@ -1,9 +1,11 @@
1
1
  import {} from 'eslint';
2
2
  import deMorgan from 'eslint-plugin-de-morgan';
3
3
  import unicornPlugin from 'eslint-plugin-unicorn';
4
+ import { GLOBAL_SCRIPTS_SCOPE } from '../constants.js';
4
5
  export const bestPracticesConfig = {
5
6
  ...unicornPlugin.configs.unopinionated,
6
7
  name: 'arui-presets-lint/best-practices',
8
+ files: [GLOBAL_SCRIPTS_SCOPE],
7
9
  plugins: {
8
10
  unicorn: unicornPlugin,
9
11
  'de-morgan': deMorgan,
@@ -0,0 +1,2 @@
1
+ import { type Linter } from 'eslint';
2
+ export declare const checkFileConfig: Linter.Config[];
@@ -0,0 +1,47 @@
1
+ import {} from 'eslint';
2
+ import checkFilePlugin from 'eslint-plugin-check-file';
3
+ import { ANOTHER_FILES_SCOPE, GLOBAL_SCRIPTS_SCOPE, JSON_SCOPE } from '../constants.js';
4
+ export const checkFileConfig = [
5
+ {
6
+ name: 'arui-presets-lint/check-file',
7
+ plugins: {
8
+ 'check-file': checkFilePlugin,
9
+ },
10
+ rules: {
11
+ // Все названия папок должны быть в kebab-case
12
+ // https://github.com/dukeluo/eslint-plugin-check-file/blob/main/docs/rules/filename-naming-convention.md
13
+ 'check-file/folder-naming-convention': [
14
+ 'error',
15
+ { '**/*.*': 'KEBAB_CASE' },
16
+ { ignoreMiddleExtensions: true },
17
+ ],
18
+ // Все названия файлов должны быть в kebab-case
19
+ // https://github.com/dukeluo/eslint-plugin-check-file/blob/main/docs/rules/folder-naming-convention.md
20
+ 'check-file/filename-naming-convention': [
21
+ 'error',
22
+ {
23
+ [GLOBAL_SCRIPTS_SCOPE]: 'KEBAB_CASE',
24
+ [ANOTHER_FILES_SCOPE]: 'KEBAB_CASE',
25
+ [JSON_SCOPE]: 'KEBAB_CASE',
26
+ },
27
+ { ignoreMiddleExtensions: true },
28
+ ],
29
+ // Список запрещенных названий файлов
30
+ // https://github.com/dukeluo/eslint-plugin-check-file/blob/main/docs/rules/filename-blocklist.md
31
+ 'check-file/filename-blocklist': [
32
+ 'error',
33
+ { '**/tsconfig.eslint.json': '*tsconfig.json' },
34
+ {
35
+ errorMessage: 'Вместо tsconfig.eslint.json используйте languageOptions.parserOptions.projectService.allowDefaultProject в конфиге eslint',
36
+ },
37
+ ],
38
+ },
39
+ },
40
+ {
41
+ // Включаем проверку других расширений файлов в eslint-plugin-check-file (которые процессор eslint не поддерживает).
42
+ // Для JSON и Markdown полноценный парсинг подключён через @eslint/json и @eslint/markdown, поэтому здесь они не нужны.
43
+ // Не должен пересекаться с остальными расширениями, см. constants.ts
44
+ files: [ANOTHER_FILES_SCOPE],
45
+ processor: 'check-file/eslint-processor-check-file',
46
+ },
47
+ ];
@@ -1,15 +1,15 @@
1
1
  import {} from 'eslint';
2
- import checkFilePlugin from 'eslint-plugin-check-file';
3
2
  import { importX } from 'eslint-plugin-import-x';
4
3
  import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
4
+ import { GLOBAL_SCRIPTS_SCOPE } from '../constants.js';
5
5
  export const importsConfig = {
6
6
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/src/config/flat/typescript.ts
7
7
  ...importX.flatConfigs.typescript,
8
8
  name: 'arui-presets-lint/imports',
9
+ files: [GLOBAL_SCRIPTS_SCOPE],
9
10
  plugins: {
10
11
  'import-x': importX,
11
12
  'simple-import-sort': simpleImportSortPlugin,
12
- 'check-file': checkFilePlugin,
13
13
  },
14
14
  settings: {
15
15
  ...importX.flatConfigs.typescript.settings,
@@ -246,28 +246,5 @@ export const importsConfig = {
246
246
  // Сортировка импортов
247
247
  // https://eslint.org/docs/rules/sort-imports
248
248
  'sort-imports': 'off',
249
- // Все названия файлов должны быть в kebab-case
250
- // https://github.com/dukeluo/eslint-plugin-check-file/blob/main/docs/rules/filename-naming-convention.md
251
- 'check-file/folder-naming-convention': [
252
- 'error',
253
- { '**/*.*': 'KEBAB_CASE' },
254
- { ignoreMiddleExtensions: true },
255
- ],
256
- // Все названия папок должны быть в kebab-case
257
- // https://github.com/dukeluo/eslint-plugin-check-file/blob/main/docs/rules/folder-naming-convention.md
258
- 'check-file/filename-naming-convention': [
259
- 'error',
260
- { '**/*.*': 'KEBAB_CASE' },
261
- { ignoreMiddleExtensions: true },
262
- ],
263
- // Список запрещенных названий файлов
264
- // https://github.com/dukeluo/eslint-plugin-check-file/blob/main/docs/rules/filename-blocklist.md
265
- 'check-file/filename-blocklist': [
266
- 'error',
267
- { '**/tsconfig.eslint.json': '*tsconfig.json' },
268
- {
269
- errorMessage: 'Вместо tsconfig.eslint.json используйте languageOptions.parserOptions.projectService.allowDefaultProject в конфиге eslint',
270
- },
271
- ],
272
249
  },
273
250
  };
@@ -1,8 +1,11 @@
1
1
  export { bestPracticesConfig } from './best-practices.js';
2
2
  export { importsConfig } from './imports.js';
3
+ export { jsonConfig } from './json.js';
4
+ export { markdownConfig } from './markdown.js';
3
5
  export { nodeRulesConfig } from './node.js';
4
6
  export { reactA11yConfig } from './react-a11y.js';
5
7
  export { reactConfig } from './react.js';
6
8
  export { testsConfig } from './tests.js';
7
9
  export { typescriptConfig } from './typescript.js';
8
10
  export { variablesConfig } from './variables.js';
11
+ export { checkFileConfig } from './check-file.js';
@@ -1,8 +1,11 @@
1
1
  export { bestPracticesConfig } from './best-practices.js';
2
2
  export { importsConfig } from './imports.js';
3
+ export { jsonConfig } from './json.js';
4
+ export { markdownConfig } from './markdown.js';
3
5
  export { nodeRulesConfig } from './node.js';
4
6
  export { reactA11yConfig } from './react-a11y.js';
5
7
  export { reactConfig } from './react.js';
6
8
  export { testsConfig } from './tests.js';
7
9
  export { typescriptConfig } from './typescript.js';
8
10
  export { variablesConfig } from './variables.js';
11
+ export { checkFileConfig } from './check-file.js';
@@ -0,0 +1,2 @@
1
+ import { type Linter } from 'eslint';
2
+ export declare const jsonConfig: Linter.Config[];
@@ -0,0 +1,46 @@
1
+ import jsonPlugin from '@eslint/json';
2
+ import {} from 'eslint';
3
+ const jsonRules = {
4
+ // Запрещает дублирование ключей в JSON-объектах
5
+ // https://github.com/eslint/json/blob/main/docs/rules/no-duplicate-keys.md
6
+ 'json/no-duplicate-keys': 'error',
7
+ // Запрещает пустые ключи в JSON-объектах
8
+ // https://github.com/eslint/json/blob/main/docs/rules/no-empty-keys.md
9
+ 'json/no-empty-keys': 'error',
10
+ // Запрещает ключи, не приведённые к нормальной юникод-форме (NFC)
11
+ // https://github.com/eslint/json/blob/main/docs/rules/no-unnormalized-keys.md
12
+ 'json/no-unnormalized-keys': 'error',
13
+ // Запрещает числа выходящие за пределы безопасного диапазона Number
14
+ // https://github.com/eslint/json/blob/main/docs/rules/no-unsafe-values.md
15
+ 'json/no-unsafe-values': 'error',
16
+ };
17
+ const plugins = { json: jsonPlugin };
18
+ export const jsonConfig = [
19
+ {
20
+ name: 'arui-presets-lint/json',
21
+ files: ['**/*.json'],
22
+ // Файлы с трейлинг-комментариями или огромным размером, которые JSON-парсер не сможет обработать
23
+ ignores: ['**/package-lock.json', '**/tsconfig*.json'],
24
+ plugins,
25
+ language: 'json/json',
26
+ rules: jsonRules,
27
+ },
28
+ {
29
+ name: 'arui-presets-lint/jsonc',
30
+ // tsconfig*.json по соглашению поддерживает комментарии и трейлинг-запятые
31
+ files: ['**/*.jsonc', '**/tsconfig*.json'],
32
+ plugins,
33
+ language: 'json/jsonc',
34
+ languageOptions: {
35
+ allowTrailingCommas: true,
36
+ },
37
+ rules: jsonRules,
38
+ },
39
+ {
40
+ name: 'arui-presets-lint/json5',
41
+ files: ['**/*.json5'],
42
+ plugins,
43
+ language: 'json/json5',
44
+ rules: jsonRules,
45
+ },
46
+ ];
@@ -0,0 +1,2 @@
1
+ import { type Linter } from 'eslint';
2
+ export declare const markdownConfig: Linter.Config;
@@ -0,0 +1,67 @@
1
+ import markdownPlugin from '@eslint/markdown';
2
+ import {} from 'eslint';
3
+ import { MARKDOWN_SCOPE } from '../constants.js';
4
+ export const markdownConfig = {
5
+ name: 'arui-presets-lint/markdown',
6
+ files: [MARKDOWN_SCOPE],
7
+ // CHANGELOG.md обычно генерируется автоматически (например, changesets/lerna)
8
+ // и не соответствует строгим правилам CommonMark
9
+ ignores: ['**/CHANGELOG.md'],
10
+ plugins: {
11
+ markdown: markdownPlugin,
12
+ },
13
+ language: 'markdown/commonmark',
14
+ rules: {
15
+ // Требует указывать язык для блоков кода с тройными бэктиками
16
+ // https://github.com/eslint/markdown/blob/main/docs/rules/fenced-code-language.md
17
+ 'markdown/fenced-code-language': 'warn',
18
+ // Уровни заголовков должны увеличиваться строго на единицу
19
+ // https://github.com/eslint/markdown/blob/main/docs/rules/heading-increment.md
20
+ 'markdown/heading-increment': 'warn',
21
+ // Запрещает дублирование definitions для ссылок и изображений
22
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-duplicate-definitions.md
23
+ 'markdown/no-duplicate-definitions': 'warn',
24
+ // Запрещает definitions без URL
25
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-empty-definitions.md
26
+ 'markdown/no-empty-definitions': 'warn',
27
+ // Запрещает изображения с пустым src
28
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-empty-images.md
29
+ 'markdown/no-empty-images': 'warn',
30
+ // Запрещает ссылки с пустым URL
31
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-empty-links.md
32
+ 'markdown/no-empty-links': 'warn',
33
+ // Запрещает невалидный синтаксис меток-ссылок
34
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-invalid-label-refs.md
35
+ 'markdown/no-invalid-label-refs': 'warn',
36
+ // Требует пробел после решёток в ATX-заголовках (# Заголовок, а не #Заголовок)
37
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-missing-atx-heading-space.md
38
+ 'markdown/no-missing-atx-heading-space': 'warn',
39
+ // Запрещает ссылаться на несуществующие метки
40
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-missing-label-refs.md
41
+ 'markdown/no-missing-label-refs': 'warn',
42
+ // Запрещает ссылки на несуществующие якоря/заголовки в текущем документе
43
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-missing-link-fragments.md
44
+ 'markdown/no-missing-link-fragments': 'warn',
45
+ // Запрещает несколько H1 в одном документе
46
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-multiple-h1.md
47
+ 'markdown/no-multiple-h1': 'warn',
48
+ // Запрещает URL, по форме совпадающие с reference-метками
49
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-reference-like-urls.md
50
+ 'markdown/no-reference-like-urls': 'warn',
51
+ // Запрещает перевёрнутый синтаксис ссылок/изображений ((text)[url] вместо [text](url))
52
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-reversed-media-syntax.md
53
+ 'markdown/no-reversed-media-syntax': 'warn',
54
+ // Запрещает пробелы вокруг маркеров выделения (* _)
55
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-space-in-emphasis.md
56
+ 'markdown/no-space-in-emphasis': 'warn',
57
+ // Запрещает неиспользуемые definitions
58
+ // https://github.com/eslint/markdown/blob/main/docs/rules/no-unused-definitions.md
59
+ 'markdown/no-unused-definitions': 'warn',
60
+ // Требует alt-текст для изображений
61
+ // https://github.com/eslint/markdown/blob/main/docs/rules/require-alt-text.md
62
+ 'markdown/require-alt-text': 'warn',
63
+ // Количество ячеек в строке таблицы должно совпадать с количеством колонок в заголовке
64
+ // https://github.com/eslint/markdown/blob/main/docs/rules/table-column-count.md
65
+ 'markdown/table-column-count': 'warn',
66
+ },
67
+ };
@@ -1,6 +1,7 @@
1
1
  import {} from 'eslint';
2
2
  import nodePlugin from 'eslint-plugin-n';
3
3
  import globals from 'globals';
4
+ import { NODEJS_SCRIPTS_SCOPE } from '../constants.js';
4
5
  export const nodeRulesConfig = {
5
6
  ...nodePlugin.configs['flat/recommended'],
6
7
  name: 'arui-presets-lint/node',
@@ -12,7 +13,7 @@ export const nodeRulesConfig = {
12
13
  plugins: {
13
14
  n: nodePlugin,
14
15
  },
15
- files: ['**/server/**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
16
+ files: [NODEJS_SCRIPTS_SCOPE],
16
17
  rules: {
17
18
  // https://github.com/eslint-community/eslint-plugin-n?tab=readme-ov-file#-rules
18
19
  ...nodePlugin.configs['flat/recommended'].rules,
@@ -1,8 +1,10 @@
1
1
  import {} from 'eslint';
2
2
  import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
3
+ import { REACT_SCRIPTS_SCOPE } from '../constants.js';
3
4
  export const reactA11yConfig = {
4
5
  ...jsxA11yPlugin.flatConfigs.recommended,
5
6
  name: 'arui-presets-lint/react-a11y',
7
+ files: [REACT_SCRIPTS_SCOPE],
6
8
  plugins: {
7
9
  'jsx-a11y': jsxA11yPlugin,
8
10
  },
@@ -1,10 +1,12 @@
1
1
  import {} from 'eslint';
2
2
  import reactPlugin from 'eslint-plugin-react';
3
3
  import reactHooksPlugin from 'eslint-plugin-react-hooks';
4
+ import { REACT_SCRIPTS_SCOPE } from '../constants.js';
4
5
  export const reactConfig = {
5
6
  ...reactPlugin.configs.flat.recommended,
6
7
  ...reactHooksPlugin.configs['recommended-latest'],
7
8
  name: 'arui-presets-lint/react',
9
+ files: [REACT_SCRIPTS_SCOPE],
8
10
  plugins: {
9
11
  react: reactPlugin,
10
12
  'react-hooks': reactHooksPlugin,
@@ -1,11 +1,13 @@
1
1
  import {} from 'eslint';
2
2
  import globals from 'globals';
3
+ import { TESTS_SCRIPTS_SCOPE } from '../constants.js';
3
4
  export const testsConfig = {
4
5
  name: 'arui-presets-lint/tests',
5
- files: ['**/*.{test,tests,spec}.{js,jsx,ts,tsx,cjs,cts,mjs,mts}'],
6
+ files: [TESTS_SCRIPTS_SCOPE],
6
7
  languageOptions: {
7
8
  globals: {
8
9
  ...globals.jest,
10
+ ...globals.vitest,
9
11
  },
10
12
  },
11
13
  rules: {
@@ -2,6 +2,7 @@ import {} from '@typescript-eslint/utils';
2
2
  import {} from 'eslint';
3
3
  import globals from 'globals';
4
4
  import tseslint from 'typescript-eslint';
5
+ import { TYPESCRIPT_SCRIPTS_SCOPE } from '../constants.js';
5
6
  import { bestPracticesConfig } from './best-practices.js';
6
7
  import { importsConfig } from './imports.js';
7
8
  import { variablesConfig } from './variables.js';
@@ -10,17 +11,17 @@ const importsRules = importsConfig.rules;
10
11
  const variablesRules = variablesConfig.rules;
11
12
  export const typescriptConfig = {
12
13
  name: 'arui-presets-lint/typescript',
13
- files: ['**/*.{ts,tsx,mts,cts,mtsx,ctsx}'],
14
+ files: [TYPESCRIPT_SCRIPTS_SCOPE],
14
15
  languageOptions: {
15
16
  parser: tseslint.parser,
16
- ecmaVersion: 2022,
17
+ ecmaVersion: 'latest',
17
18
  sourceType: 'module',
18
19
  parserOptions: {
19
20
  projectService: true,
20
21
  ecmaFeatures: { jsx: true },
21
22
  },
22
23
  globals: {
23
- ...globals.es2023,
24
+ ...globals.es2026,
24
25
  ...globals.browser,
25
26
  ...globals.node,
26
27
  },
@@ -1,6 +1,8 @@
1
1
  import {} from 'eslint';
2
+ import { GLOBAL_SCRIPTS_SCOPE } from '../constants.js';
2
3
  export const variablesConfig = {
3
4
  name: 'arui-presets-lint/variables',
5
+ files: [GLOBAL_SCRIPTS_SCOPE],
4
6
  rules: {
5
7
  // Требует/запрещает инициализацию переменных при объявлении
6
8
  // https://eslint.org/docs/rules/init-declarations
package/eslint/rules.d.ts CHANGED
@@ -1 +1 @@
1
- export { bestPracticesConfig, importsConfig, nodeRulesConfig, reactA11yConfig, reactConfig, testsConfig, typescriptConfig, variablesConfig, } from './rules/index.js';
1
+ export { bestPracticesConfig, importsConfig, jsonConfig, markdownConfig, nodeRulesConfig, reactA11yConfig, reactConfig, testsConfig, typescriptConfig, variablesConfig, checkFileConfig, } from './rules/index.js';
package/eslint/rules.js CHANGED
@@ -1 +1 @@
1
- export { bestPracticesConfig, importsConfig, nodeRulesConfig, reactA11yConfig, reactConfig, testsConfig, typescriptConfig, variablesConfig, } from './rules/index.js';
1
+ export { bestPracticesConfig, importsConfig, jsonConfig, markdownConfig, nodeRulesConfig, reactA11yConfig, reactConfig, testsConfig, typescriptConfig, variablesConfig, checkFileConfig, } from './rules/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arui-presets-lint",
3
- "version": "10.1.0",
3
+ "version": "10.2.0",
4
4
  "description": "Config files for arui-apps",
5
5
  "author": "core-ds contributors",
6
6
  "license": "MIT",
@@ -15,8 +15,10 @@
15
15
  "@commitlint/cli": "20.5.3",
16
16
  "@commitlint/config-conventional": "20.5.3",
17
17
  "@eslint/js": "9.39.4",
18
+ "@eslint/json": "1.2.0",
19
+ "@eslint/markdown": "8.0.2",
18
20
  "@types/eslint-plugin-jsx-a11y": "6.10.1",
19
- "@typescript-eslint/utils": "8.59.2",
21
+ "@typescript-eslint/utils": "8.59.4",
20
22
  "eslint": "9.39.4",
21
23
  "eslint-config-flat-gitignore": "2.3.0",
22
24
  "eslint-import-resolver-typescript": "4.4.4",
@@ -32,19 +34,19 @@
32
34
  "execa": "^9.6.1",
33
35
  "globals": "^17.0.0",
34
36
  "jiti": "^2.6.1",
35
- "lefthook": "2.1.6",
37
+ "lefthook": "2.1.8",
36
38
  "prettier": "3.8.3",
37
- "stylelint": "17.11.0",
39
+ "stylelint": "17.12.0",
38
40
  "stylelint-order": "8.1.1",
39
- "typescript-eslint": "8.59.2"
41
+ "typescript-eslint": "8.59.4"
40
42
  },
41
43
  "engines": {
42
44
  "node": ">=20.19.0"
43
45
  },
44
46
  "devDependencies": {},
45
47
  "scripts": {
46
- "build": "rimraf dist && tsc -p tsconfig.build.json && copyfiles 'lefthook/*.yml' '**/*.md' dist && tsx cli/build-dist-package.ts",
47
- "test": "tsc --noEmit && eslint-config-prettier ./eslint/index.ts && tsx ./cli/duplicates-checker.ts && yarn lint && yarn test:unit",
48
+ "build": "rimraf dist && tsc -p tsconfig.build.json && copyfiles 'lefthook/*.yml' '**/*.md' dist && tsx _internal/build-dist-package.ts",
49
+ "test": "tsc --noEmit && eslint-config-prettier ./eslint/index.ts && tsx _internal/duplicates-checker.ts && yarn lint && yarn test:unit",
48
50
  "test:unit": "vitest --run --coverage",
49
51
  "lint": "yarn lint:styles && yarn lint:scripts && yarn format:check",
50
52
  "lint:fix": "yarn lint:styles --fix && yarn lint:scripts --fix && yarn format",
@@ -0,0 +1,19 @@
1
+ # Заголовок верхнего уровня
2
+
3
+ Корректный markdown-файл для проверки правил CommonMark.
4
+
5
+ ## Подзаголовок
6
+
7
+ Текст с *выделением* и **сильным выделением**.
8
+
9
+ ```ts
10
+ const value = 42;
11
+
12
+ ```
13
+
14
+ - Пункт списка один
15
+ - Пункт списка два
16
+
17
+ [Ссылка на ESLint](https://eslint.org)
18
+
19
+ ![Альт-текст изображения](https://example.com/image.png)