@rsdk/eslint-plugin 6.0.0-next.4 → 6.0.0-next.41

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.
@@ -0,0 +1,3 @@
1
+ const rsdkEslint = require('@rsdk/eslint-plugin');
2
+
3
+ module.exports = rsdkEslint.createConfig({ tsconfigRootDir: __dirname });
package/index.js CHANGED
@@ -1,188 +1,282 @@
1
- module.exports = {
2
- configs: {
3
- recommended: {
4
- parser: '@typescript-eslint/parser',
5
- parserOptions: {
6
- // Не стоит писать сюда project: 'tsconfig.json`, это ломает работу eslint
7
- // В ряде случаев он просто отрабатывает не так как надо, а в некоторых просто падает
8
- project: true,
9
- sourceType: 'module',
1
+ const js = require('@eslint/js');
2
+ const path = require('node:path');
3
+ const prettierConfig = require('eslint-config-prettier/flat');
4
+ const importX = require('eslint-plugin-import-x');
5
+ const simpleImportSort = require('eslint-plugin-simple-import-sort');
6
+ const globals = require('globals');
7
+ const tseslint = require('typescript-eslint');
8
+
9
+ const monorepoRoot = path.resolve(__dirname, '../..');
10
+ const noopRule = {
11
+ create: () => ({}),
12
+ meta: {
13
+ docs: {},
14
+ schema: [],
15
+ type: 'problem',
16
+ },
17
+ };
18
+
19
+ tseslint.plugin.rules['ban-types'] ??= noopRule;
20
+
21
+ let pluginLoader;
22
+
23
+ async function loadPlugins() {
24
+ pluginLoader ??= Promise.all([
25
+ import('@stylistic/eslint-plugin'),
26
+ import('eslint-plugin-unicorn'),
27
+ ]).then(([stylisticModule, unicornModule]) => {
28
+ const stylistic = stylisticModule.default ?? stylisticModule;
29
+ const unicorn = unicornModule.default ?? unicornModule;
30
+
31
+ unicorn.rules['no-array-for-each'] ??= noopRule;
32
+ unicorn.rules['no-unsafe-regex'] ??= noopRule;
33
+
34
+ return { stylistic, unicorn };
35
+ });
36
+
37
+ return pluginLoader;
38
+ }
39
+
40
+ const sourceFiles = ['**/*.{js,jsx,cjs,mjs,ts,tsx,cts,mts}'];
41
+ const tsFiles = ['**/*.{ts,tsx,cts,mts}'];
42
+ const importExtensions = [
43
+ '.ts',
44
+ '.cts',
45
+ '.mts',
46
+ '.tsx',
47
+ '.js',
48
+ '.jsx',
49
+ '.mjs',
50
+ '.cjs',
51
+ ];
52
+
53
+ const simpleImportSortGroups = [
54
+ // Node.js builtins.
55
+ [
56
+ '^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)',
57
+ ],
58
+
59
+ // Packages. `react` related packages come first.
60
+ ['^react', String.raw`^@?\w`],
61
+
62
+ // Internal packages.
63
+ ['^(@|@company|@ui|components|utils|config|vendored-lib)(/.*|$)'],
64
+
65
+ // Side effect imports.
66
+ [String.raw`^\u0000`],
67
+
68
+ // Parent imports. Put `..` last.
69
+ [String.raw`^\.\.(?!/?$)`, String.raw`^\.\./?$`],
70
+
71
+ // Other relative imports. Put same-folder imports and `.` last.
72
+ [String.raw`^\./(?=.*/)(?!/?$)`, String.raw`^\.(?!/?$)`, String.raw`^\./?$`],
73
+
74
+ // Style imports.
75
+ [String.raw`^.+\.s?css$`],
76
+ ];
77
+
78
+ async function createConfig(options = {}) {
79
+ const { stylistic, unicorn } = await loadPlugins();
80
+ const project =
81
+ options.project === false
82
+ ? false
83
+ : (options.project ?? path.join(monorepoRoot, 'tsconfig.lint.json'));
84
+ const tsconfigRootDir = options.tsconfigRootDir ?? process.cwd();
85
+ const shouldUsePrettierConfig = options.prettier !== false;
86
+
87
+ return tseslint.config(
88
+ {
89
+ ignores: [
90
+ 'dist/**',
91
+ 'node_modules/**',
92
+ '__tests__/fixtures/**',
93
+ '**/__tests__/fixtures/**',
94
+ '**/fixtures/**',
95
+ '.generated/**',
96
+ 'generated/**',
97
+ 'vendor/**',
98
+ ],
99
+ },
100
+ {
101
+ linterOptions: {
102
+ reportUnusedDisableDirectives: 'off',
103
+ },
104
+ },
105
+ js.configs.recommended,
106
+ ...tseslint.configs.recommended,
107
+ ...(shouldUsePrettierConfig ? [prettierConfig] : []),
108
+ {
109
+ files: sourceFiles,
110
+ languageOptions: {
10
111
  ecmaVersion: 2020,
112
+ globals: {
113
+ ...globals.node,
114
+ ...globals.jest,
115
+ },
116
+ sourceType: 'module',
11
117
  },
12
- plugins: [
13
- '@typescript-eslint/eslint-plugin',
14
- 'simple-import-sort',
15
- 'import',
16
- 'unicorn',
17
- '@stylistic/eslint-plugin',
18
- 'deprecation',
19
- ],
20
- extends: [
21
- 'plugin:@typescript-eslint/eslint-recommended',
22
-
23
- // FIXME: не уверен что его стоит добавлять, но посмотреть в целом стоит
24
- // 'plugin:@typescript-eslint/recommended-requiring-type-checking',
25
- 'plugin:@typescript-eslint/recommended',
26
- 'plugin:import/typescript',
27
- 'plugin:prettier/recommended',
28
- 'plugin:unicorn/all',
29
- ],
30
- root: true,
31
- env: {
32
- node: true,
33
- jest: true,
118
+ plugins: {
119
+ '@stylistic': stylistic,
120
+ deprecation: {
121
+ rules: {
122
+ deprecation: noopRule,
123
+ },
124
+ },
125
+ import: importX,
126
+ prettier: {
127
+ rules: {
128
+ prettier: noopRule,
129
+ },
130
+ },
131
+ 'simple-import-sort': simpleImportSort,
132
+ unicorn,
133
+ },
134
+ settings: {
135
+ 'import-x/extensions': importExtensions,
136
+ 'import-x/external-module-folders': [
137
+ 'node_modules',
138
+ 'node_modules/@types',
139
+ ],
140
+ 'import-x/parsers': {
141
+ '@typescript-eslint/parser': ['.ts', '.cts', '.mts', '.tsx'],
142
+ },
143
+ 'import-x/resolver': {
144
+ node: {
145
+ extensions: importExtensions,
146
+ },
147
+ },
34
148
  },
35
149
  rules: {
36
- 'deprecation/deprecation': 'warn',
37
- '@typescript-eslint/interface-name-prefix': 'off',
38
- '@typescript-eslint/explicit-module-boundary-types': 'off',
39
- '@typescript-eslint/no-explicit-any': 'off',
40
- '@typescript-eslint/explicit-function-return-type': 'error',
41
- 'import/no-extraneous-dependencies': [
150
+ '@stylistic/lines-around-comment': [
42
151
  'error',
43
152
  {
44
- devDependencies: [
45
- '**/*.test.ts',
46
- '**/*.spec.ts',
47
- '**/*.test.e2e.ts',
48
- '**/*.spec.e2e.ts',
49
- '**/*.e2e*.ts',
50
- '**/*e2e.ts',
51
- 'jest.*.ts',
52
- 'jest.*.js',
53
- '**/jest.*.ts',
54
- '**/jest.*.js',
55
- ],
153
+ allowArrayStart: true,
154
+ allowBlockStart: true,
155
+ allowClassStart: true,
156
+ allowEnumStart: true,
157
+ allowInterfaceStart: true,
158
+ allowModuleStart: true,
159
+ allowObjectStart: true,
160
+ allowTypeStart: true,
161
+ beforeBlockComment: true,
162
+ beforeLineComment: true,
56
163
  },
57
164
  ],
58
- '@typescript-eslint/consistent-type-imports': 'error',
59
- '@typescript-eslint/member-ordering': 'warn',
60
- '@typescript-eslint/lines-between-class-members': [
165
+ 'lines-around-comment': 'off',
166
+ '@stylistic/lines-between-class-members': [
61
167
  'warn',
62
168
  'always',
63
169
  {
64
- exceptAfterSingleLine: true,
65
170
  exceptAfterOverload: true,
171
+ exceptAfterSingleLine: true,
66
172
  },
67
173
  ],
68
- '@typescript-eslint/padding-line-between-statements': [
174
+ '@stylistic/padding-line-between-statements': [
69
175
  'warn',
70
- { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
176
+ { blankLine: 'always', next: '*', prev: ['const', 'let', 'var'] },
71
177
  {
72
178
  blankLine: 'any',
73
- prev: ['const', 'let', 'var'],
74
179
  next: ['const', 'let', 'var', 'if'],
180
+ prev: ['const', 'let', 'var'],
75
181
  },
76
182
  ],
77
- '@stylistic/lines-around-comment': [
78
- 'error',
79
- {
80
- beforeBlockComment: true,
81
- beforeLineComment: true,
82
- allowBlockStart: true,
83
- allowObjectStart: true,
84
- allowArrayStart: true,
85
- allowClassStart: true,
86
- allowEnumStart: true,
87
- allowInterfaceStart: true,
88
- allowModuleStart: true,
89
- allowTypeStart: true,
90
- }
91
- ],
92
- 'import/no-cycle': 'error',
93
183
  'import/first': 'error',
94
184
  'import/newline-after-import': 'error',
185
+ 'import/no-cycle': 'error',
95
186
  'import/no-duplicates': 'error',
96
- 'sort-imports': 'off',
187
+ 'no-negated-condition': 'off',
188
+ 'no-nested-ternary': 'off',
189
+ 'require-yield': 'off',
97
190
  'simple-import-sort/imports': [
98
191
  'error',
99
192
  {
100
- groups: [
101
- // Node.js builtins. You could also generate this regex if you use a `.js` config.
102
- // For example: `^(${require("module").builtinModules.join("|")})(/|$)`
103
- [
104
- '^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)',
105
- ],
106
-
107
- // Packages. `react` related packages come first.
108
- ['^react', '^@?\\w'],
109
-
110
- // Internal packages.
111
- ['^(@|@company|@ui|components|utils|config|vendored-lib)(/.*|$)'],
112
-
113
- // Side effect imports.
114
- ['^\\u0000'],
115
-
116
- // Parent imports. Put `..` last.
117
- ['^\\.\\.(?!/?$)', '^\\.\\./?$'],
118
-
119
- // Other relative imports. Put same-folder imports and `.` last.
120
- ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
121
-
122
- // Style imports.
123
- ['^.+\\.s?css$'],
124
- ],
125
- },
126
- ],
127
- '@typescript-eslint/naming-convention': [
128
- 'error',
129
- {
130
- selector: ['classMethod', 'accessor', 'parameterProperty'],
131
- format: ['camelCase'],
193
+ groups: simpleImportSortGroups,
132
194
  },
133
195
  ],
134
-
135
- // unicorn
196
+ 'sort-imports': 'off',
197
+ 'unicorn/better-regex': 'off',
136
198
  'unicorn/custom-error-definition': 'off',
137
-
138
- // Очень странная мотивация у этого правила, у меня может быть метод который подсчитывает количество товаров в заказе и собственно массив заказов
199
+ 'unicorn/filename-case': 'off',
200
+ 'unicorn/name-replacements': 'off',
139
201
  'unicorn/no-array-callback-reference': 'off',
140
-
141
- // просто спорное правило
202
+ 'unicorn/no-array-method-this-argument': 'off',
142
203
  'unicorn/no-array-reduce': 'off',
143
204
  'unicorn/no-keyword-prefix': 'off',
144
- 'no-negated-condition': 'off',
145
- 'no-nested-ternary': 'off',
146
-
147
- // глупость, так как null хотя бы является валидным сериализуемым значением
148
205
  'unicorn/no-null': 'off',
149
-
150
- // Как правило, удобнее сгруппировать методы в namespace
151
206
  'unicorn/no-static-only-class': 'off',
152
-
153
- // дублирует правило @typescript-eslint/no-this-alias
154
207
  'unicorn/no-this-assignment': 'off',
155
-
156
- // портит regex например /\/?([\w\-_]+:[\w\-_]+)$/gi.exec(tag)?.[1]
157
- 'unicorn/better-regex': 'off',
158
208
  'unicorn/no-unused-properties': 'off',
159
- '@typescript-eslint/no-unused-vars': [
160
- 'error',
161
- { varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
162
- ],
163
-
164
- // Пытался как-то консистентно эту историю организовать, но это около невозможно потому что порты например нет смысла делить
165
209
  'unicorn/numeric-separators-style': 'off',
166
210
  'unicorn/prefer-json-parse-buffer': 'error',
167
-
168
- // пока мы не переехали на esm смысла нет
169
211
  'unicorn/prefer-module': 'off',
170
-
171
- // мешает делать typeguard `(var: MyInterface | undefined): var is MyInterface => Boolean(var)`
172
212
  'unicorn/prefer-native-coercion-functions': 'off',
173
-
174
- // иногда проще делать Array.from, а там где `spread` лучше, там и так понятно
175
213
  'unicorn/prefer-spread': 'off',
176
-
177
- // не нашёл гибкой конфигурации чтобы он не ругался на `param` например
178
214
  'unicorn/prevent-abbreviations': 'off',
179
-
180
- // мешает делать case: return some(a, b, c)
181
215
  'unicorn/switch-case-braces': ['error', 'avoid'],
182
-
183
- // некорректный парсинг, ругается на любой вызов метода find
184
- 'unicorn/no-array-method-this-argument': 'off',
185
216
  },
186
217
  },
218
+ {
219
+ files: tsFiles,
220
+ languageOptions: {
221
+ parserOptions: {
222
+ ...(project === false ? {} : { project }),
223
+ tsconfigRootDir,
224
+ },
225
+ },
226
+ rules: {
227
+ '@typescript-eslint/consistent-type-imports': 'error',
228
+ '@typescript-eslint/explicit-function-return-type': 'error',
229
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
230
+ '@typescript-eslint/member-ordering': 'warn',
231
+ '@typescript-eslint/naming-convention': [
232
+ 'error',
233
+ {
234
+ format: ['camelCase'],
235
+ selector: ['classMethod', 'accessor', 'parameterProperty'],
236
+ },
237
+ ],
238
+ '@typescript-eslint/no-empty-object-type': 'off',
239
+ '@typescript-eslint/no-explicit-any': 'off',
240
+ '@typescript-eslint/no-require-imports': 'off',
241
+ '@typescript-eslint/no-unsafe-function-type': 'off',
242
+ '@typescript-eslint/no-unused-expressions': [
243
+ 'error',
244
+ {
245
+ allowShortCircuit: true,
246
+ allowTaggedTemplates: true,
247
+ allowTernary: true,
248
+ },
249
+ ],
250
+ '@typescript-eslint/no-unused-vars': [
251
+ 'error',
252
+ { argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
253
+ ],
254
+ },
255
+ },
256
+ {
257
+ files: ['**/*.{js,jsx,cjs,mjs}'],
258
+ rules: {
259
+ '@typescript-eslint/no-require-imports': 'off',
260
+ },
261
+ },
262
+ {
263
+ files: [
264
+ '**/src/bin/*.{ts,tsx,cts,mts}',
265
+ '**/src/bin/**/*.{ts,tsx,cts,mts}',
266
+ ],
267
+ rules: {
268
+ '@stylistic/lines-around-comment': 'off',
269
+ 'lines-around-comment': 'off',
270
+ },
271
+ },
272
+ );
273
+ }
274
+
275
+ module.exports = {
276
+ configs: {
277
+ get recommended() {
278
+ return createConfig();
279
+ },
187
280
  },
281
+ createConfig,
188
282
  };
@@ -0,0 +1,81 @@
1
+ const { spawnSync } = require('node:child_process');
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+
5
+ const root = path.resolve(__dirname, '../..');
6
+ const eslintBin = path.join(root, 'node_modules/.bin/eslint');
7
+ const passThroughArgs = process.argv.slice(2);
8
+ const sourceRoots = ['examples', 'packages', 'test'];
9
+ const ignoredSegments = new Set([
10
+ '.generated',
11
+ 'dist',
12
+ '__fixtures__',
13
+ 'fixtures',
14
+ 'generated',
15
+ 'node_modules',
16
+ 'vendor',
17
+ ]);
18
+ const lintExtensions = new Set(['.ts', '.cts', '.mts', '.tsx']);
19
+ const chunkSize = 200;
20
+
21
+ function shouldSkipDirectory(name) {
22
+ return ignoredSegments.has(name);
23
+ }
24
+
25
+ function collectSourceFiles(directory, files) {
26
+ let entries;
27
+
28
+ try {
29
+ entries = fs.readdirSync(directory, { withFileTypes: true });
30
+ } catch {
31
+ return;
32
+ }
33
+
34
+ for (const entry of entries) {
35
+ const absolutePath = path.join(directory, entry.name);
36
+
37
+ if (entry.isDirectory()) {
38
+ if (!shouldSkipDirectory(entry.name)) {
39
+ collectSourceFiles(absolutePath, files);
40
+ }
41
+
42
+ continue;
43
+ }
44
+
45
+ if (!entry.isFile()) continue;
46
+ if (!absolutePath.split(path.sep).includes('src')) continue;
47
+ if (!lintExtensions.has(path.extname(entry.name))) continue;
48
+
49
+ files.push(path.relative(root, absolutePath));
50
+ }
51
+ }
52
+
53
+ const files = [];
54
+
55
+ for (const sourceRoot of sourceRoots) {
56
+ collectSourceFiles(path.join(root, sourceRoot), files);
57
+ }
58
+
59
+ if (files.length === 0) {
60
+ process.exit(0);
61
+ }
62
+
63
+ let exitCode = 0;
64
+
65
+ for (let index = 0; index < files.length; index += chunkSize) {
66
+ const chunk = files.slice(index, index + chunkSize);
67
+ const result = spawnSync(eslintBin, [...passThroughArgs, ...chunk], {
68
+ cwd: root,
69
+ stdio: 'inherit',
70
+ });
71
+
72
+ if (result.error) {
73
+ throw result.error;
74
+ }
75
+
76
+ if (result.status && result.status > exitCode) {
77
+ exitCode = result.status;
78
+ }
79
+ }
80
+
81
+ process.exit(exitCode);
package/package.json CHANGED
@@ -1,23 +1,26 @@
1
1
  {
2
2
  "name": "@rsdk/eslint-plugin",
3
- "version": "6.0.0-next.4",
3
+ "role": "library",
4
+ "version": "6.0.0-next.41",
4
5
  "description": "",
5
6
  "main": "index.js",
7
+ "dependencies": {
8
+ "@eslint/js": "^10.0.1",
9
+ "@stylistic/eslint-plugin": "^5.10.0",
10
+ "eslint-config-prettier": "^10.1.8",
11
+ "eslint-plugin-import-x": "^4.17.1",
12
+ "eslint-plugin-simple-import-sort": "^13.0.0",
13
+ "eslint-plugin-unicorn": "^69.0.0",
14
+ "globals": "^17.7.0",
15
+ "typescript-eslint": "^8.62.0"
16
+ },
17
+ "peerDependencies": {
18
+ "eslint": "^10.6.0",
19
+ "typescript": "5.7.3"
20
+ },
6
21
  "publishConfig": {
7
22
  "access": "public"
8
23
  },
9
24
  "license": "Apache License 2.0",
10
- "peerDependencies": {
11
- "@typescript-eslint/eslint-plugin": "^7.18.0",
12
- "@typescript-eslint/parser": "^7.18.0",
13
- "eslint": "^8.57.0",
14
- "eslint-config-prettier": "^9.1.0",
15
- "eslint-formatter-codeframe": "^7.32.1",
16
- "eslint-plugin-deprecation": "^3.0.0",
17
- "eslint-plugin-import": "^2.31.0",
18
- "eslint-plugin-prettier": "^5.2.1",
19
- "eslint-plugin-simple-import-sort": "^12.1.1",
20
- "eslint-plugin-unicorn": "^56.0.1"
21
- },
22
- "gitHead": "f0dec6323cbe016b5efd433484d2f2d044d12fa9"
25
+ "gitHead": "e6e580cf9f7b89e7b236530d767db5d6429c9c6f"
23
26
  }