@krivega/eslint-config 1.0.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/jest.js ADDED
@@ -0,0 +1,19 @@
1
+ import pluginJest from 'eslint-plugin-jest';
2
+ import config from './index';
3
+ const jestConfig = [
4
+ ...config,
5
+ {
6
+ files: ['**/*.spec.js', '**/*.test.js', '**/__tests__/**/*.ts', '**/__tests__/**/*.tsx'],
7
+ plugins: { jest: pluginJest },
8
+ languageOptions: {
9
+ globals: pluginJest.environments.globals.globals,
10
+ },
11
+ rules: {
12
+ ...pluginJest.configs['flat/recommended'].rules,
13
+ // Отключаем unbound-method для тестовых файлов, так как в тестах часто нужно
14
+ // проверять, что методы были вызваны без привязки к контексту
15
+ '@typescript-eslint/unbound-method': 'off',
16
+ },
17
+ },
18
+ ];
19
+ export default jestConfig;
package/jest.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { Linter } from 'eslint';
2
+ import pluginJest from 'eslint-plugin-jest';
3
+ import config from './index';
4
+
5
+ const jestConfig: Linter.Config[] = [
6
+ ...config,
7
+ {
8
+ files: ['**/*.spec.js', '**/*.test.js', '**/__tests__/**/*.ts', '**/__tests__/**/*.tsx'],
9
+ plugins: { jest: pluginJest },
10
+ languageOptions: {
11
+ globals: pluginJest.environments.globals.globals,
12
+ },
13
+ rules: {
14
+ ...pluginJest.configs['flat/recommended'].rules,
15
+ // Отключаем unbound-method для тестовых файлов, так как в тестах часто нужно
16
+ // проверять, что методы были вызваны без привязки к контексту
17
+ '@typescript-eslint/unbound-method': 'off',
18
+ },
19
+ },
20
+ ];
21
+
22
+ export default jestConfig;
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@krivega/eslint-config",
3
+ "version": "1.0.0",
4
+ "bugs": {
5
+ "url": "https://github.com/Krivega/eslint-config/issues"
6
+ },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Krivega/eslint-config.git"
10
+ },
11
+ "license": "MIT",
12
+ "author": {
13
+ "name": "Krivega Dmitriy",
14
+ "email": "mr.krivega@gmail.com",
15
+ "url": "https://krivega.com"
16
+ },
17
+ "type": "module",
18
+ "exports": {
19
+ ".": "./index.js",
20
+ "./react": "./react.js",
21
+ "./jest": "./jest.js",
22
+ "./cypress": "./cypress.js",
23
+ "./package.json": "./package.json"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "lint": "yarn lint:src && yarn lint:examples",
28
+ "lint:examples": "yarn --cwd ./example lint && yarn --cwd ./exampleReact lint",
29
+ "lint:src": "yarn lint:ts",
30
+ "lint:ts": "tsc --noEmit --project tsconfig.json",
31
+ "prepublishOnly": "yarn build",
32
+ "release": "standard-version && yarn release:publish",
33
+ "release:major": "standard-version --release-as major && yarn release:publish",
34
+ "release:minor": "standard-version --release-as minor && yarn release:publish",
35
+ "release:pre": "standard-version --prerelease && yarn release:publish",
36
+ "release:publish": "git push --follow-tags origin main && npm publish --access public",
37
+ "run:postinstall": "yarn --cwd ./example install && yarn --cwd ./exampleReact install"
38
+ },
39
+ "dependencies": {
40
+ "@babel/preset-typescript": "^7.27.1",
41
+ "@stylistic/eslint-plugin": "^5.2.3",
42
+ "@types/eslint-plugin-jsx-a11y": "^6.10.0",
43
+ "@typescript-eslint/eslint-plugin": "^8.39.1",
44
+ "@typescript-eslint/parser": "^8.39.1",
45
+ "eslint": "^9.33.0",
46
+ "eslint-import-resolver-typescript": "^4.4.4",
47
+ "eslint-plugin-cypress": "^5.1.0",
48
+ "eslint-plugin-flowtype": "^8.0.3",
49
+ "eslint-plugin-import": "^2.32.0",
50
+ "eslint-plugin-jest": "^29.0.1",
51
+ "eslint-plugin-jsx-a11y": "^6.10.2",
52
+ "eslint-plugin-prettier": "^5.5.4",
53
+ "eslint-plugin-react": "7.37.5",
54
+ "eslint-plugin-react-hooks": "^5.2.0",
55
+ "eslint-plugin-react-refresh": "^0.4.20",
56
+ "eslint-plugin-unicorn": "^60.0.0",
57
+ "globals": "^16.3.0",
58
+ "typescript": "^5.9.2"
59
+ },
60
+ "devDependencies": {
61
+ "@commitlint/cli": "^19.8.1",
62
+ "@commitlint/config-conventional": "^19.8.1",
63
+ "prettier": "^3.6.2",
64
+ "standard-version": "^9.5.0"
65
+ },
66
+ "peerDependencies": {
67
+ "eslint": "^9.33.0",
68
+ "typescript": "^5.9.2"
69
+ },
70
+ "packageManager": "yarn@1.22.22"
71
+ }
package/react.js ADDED
@@ -0,0 +1,505 @@
1
+ import jsxA11y from 'eslint-plugin-jsx-a11y';
2
+ import react from 'eslint-plugin-react';
3
+ import reactHooks from 'eslint-plugin-react-hooks';
4
+ import config from './index';
5
+ const reactConfig = [
6
+ ...config,
7
+ {
8
+ settings: {
9
+ react: {
10
+ version: 'detect',
11
+ },
12
+ },
13
+ plugins: { 'react-hooks': reactHooks, 'jsx-a11y': jsxA11y, react: react },
14
+ rules: {
15
+ '@stylistic/jsx-closing-bracket-location': ['error'],
16
+ '@stylistic/jsx-closing-tag-location': ['error'],
17
+ '@stylistic/jsx-curly-brace-presence': [
18
+ 'error',
19
+ {
20
+ propElementValues: 'always',
21
+ },
22
+ ],
23
+ '@stylistic/jsx-curly-newline': ['error'],
24
+ '@stylistic/jsx-curly-spacing': ['error', 'never'],
25
+ '@stylistic/jsx-equals-spacing': ['error'],
26
+ '@stylistic/jsx-first-prop-new-line': ['error'],
27
+ '@stylistic/jsx-function-call-newline': ['error', 'multiline'],
28
+ '@stylistic/jsx-indent-props': ['error', 2],
29
+ '@stylistic/jsx-max-props-per-line': [
30
+ 'error',
31
+ {
32
+ maximum: 1,
33
+ when: 'multiline',
34
+ },
35
+ ],
36
+ '@stylistic/jsx-quotes': ['error'],
37
+ '@stylistic/jsx-tag-spacing': [
38
+ 'error',
39
+ {
40
+ afterOpening: 'never',
41
+ beforeClosing: 'never',
42
+ beforeSelfClosing: 'always',
43
+ closingSlash: 'never',
44
+ },
45
+ ],
46
+ '@stylistic/jsx-wrap-multilines': [
47
+ 'error',
48
+ {
49
+ arrow: 'parens-new-line',
50
+ assignment: 'parens-new-line',
51
+ condition: 'parens-new-line',
52
+ declaration: 'parens-new-line',
53
+ logical: 'parens-new-line',
54
+ // prop: 'parens-new-line',
55
+ propertyValue: 'parens-new-line',
56
+ return: 'parens-new-line',
57
+ },
58
+ ],
59
+ 'jsx-a11y/alt-text': [
60
+ 'error',
61
+ {
62
+ area: [],
63
+ elements: ['img', 'object', 'area', 'input[type="image"]'],
64
+ img: [],
65
+ 'input[type="image"]': [],
66
+ object: [],
67
+ },
68
+ ],
69
+ 'jsx-a11y/anchor-has-content': [
70
+ 'error',
71
+ {
72
+ components: [],
73
+ },
74
+ ],
75
+ 'jsx-a11y/anchor-is-valid': [
76
+ 'error',
77
+ {
78
+ aspects: ['noHref', 'invalidHref', 'preferButton'],
79
+ components: ['Link'],
80
+ specialLink: ['to'],
81
+ },
82
+ ],
83
+ 'jsx-a11y/aria-activedescendant-has-tabindex': ['error'],
84
+ 'jsx-a11y/aria-props': ['error'],
85
+ 'jsx-a11y/aria-proptypes': ['error'],
86
+ 'jsx-a11y/aria-role': [
87
+ 'error',
88
+ {
89
+ ignoreNonDOM: false,
90
+ },
91
+ ],
92
+ 'jsx-a11y/aria-unsupported-elements': ['error'],
93
+ 'jsx-a11y/click-events-have-key-events': ['error'],
94
+ 'jsx-a11y/control-has-associated-label': [
95
+ 'error',
96
+ {
97
+ controlComponents: [],
98
+ depth: 5,
99
+ ignoreElements: ['audio', 'canvas', 'embed', 'input', 'textarea', 'tr', 'video'],
100
+ ignoreRoles: [
101
+ 'grid',
102
+ 'listbox',
103
+ 'menu',
104
+ 'menubar',
105
+ 'radiogroup',
106
+ 'row',
107
+ 'tablist',
108
+ 'toolbar',
109
+ 'tree',
110
+ 'treegrid',
111
+ ],
112
+ labelAttributes: ['label'],
113
+ },
114
+ ],
115
+ 'jsx-a11y/heading-has-content': [
116
+ 'error',
117
+ {
118
+ components: [''],
119
+ },
120
+ ],
121
+ 'jsx-a11y/html-has-lang': ['error'],
122
+ 'jsx-a11y/iframe-has-title': ['error'],
123
+ 'jsx-a11y/img-redundant-alt': ['error'],
124
+ 'jsx-a11y/interactive-supports-focus': ['error'],
125
+ 'jsx-a11y/label-has-associated-control': [
126
+ 'error',
127
+ {
128
+ assert: 'both',
129
+ controlComponents: [],
130
+ depth: 25,
131
+ labelAttributes: [],
132
+ labelComponents: [],
133
+ },
134
+ ],
135
+ 'jsx-a11y/lang': ['error'],
136
+ 'jsx-a11y/media-has-caption': [
137
+ 'error',
138
+ {
139
+ audio: [],
140
+ track: [],
141
+ video: [],
142
+ },
143
+ ],
144
+ 'jsx-a11y/mouse-events-have-key-events': ['error'],
145
+ 'jsx-a11y/no-access-key': ['error'],
146
+ 'jsx-a11y/no-autofocus': [
147
+ 'error',
148
+ {
149
+ ignoreNonDOM: true,
150
+ },
151
+ ],
152
+ 'jsx-a11y/no-distracting-elements': [
153
+ 'error',
154
+ {
155
+ elements: ['marquee', 'blink'],
156
+ },
157
+ ],
158
+ 'jsx-a11y/no-interactive-element-to-noninteractive-role': [
159
+ 'error',
160
+ {
161
+ tr: ['none', 'presentation'],
162
+ },
163
+ ],
164
+ 'jsx-a11y/no-noninteractive-element-interactions': [
165
+ 'error',
166
+ {
167
+ handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
168
+ },
169
+ ],
170
+ 'jsx-a11y/no-noninteractive-element-to-interactive-role': [
171
+ 'error',
172
+ {
173
+ li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
174
+ ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
175
+ table: ['grid'],
176
+ td: ['gridcell'],
177
+ ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
178
+ },
179
+ ],
180
+ 'jsx-a11y/no-noninteractive-tabindex': [
181
+ 'error',
182
+ {
183
+ roles: ['tabpanel'],
184
+ tags: [],
185
+ },
186
+ ],
187
+ 'jsx-a11y/no-redundant-roles': ['error'],
188
+ 'jsx-a11y/no-static-element-interactions': [
189
+ 'error',
190
+ {
191
+ handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
192
+ },
193
+ ],
194
+ 'jsx-a11y/role-has-required-aria-props': ['error'],
195
+ 'jsx-a11y/role-supports-aria-props': ['error'],
196
+ 'jsx-a11y/scope': ['error'],
197
+ 'jsx-a11y/tabindex-no-positive': ['error'],
198
+ 'jsx-quotes': ['error', 'prefer-double'],
199
+ 'react-hooks/exhaustive-deps': [
200
+ 'error',
201
+ {
202
+ enableDangerousAutofixThisMayCauseInfiniteLoops: false,
203
+ },
204
+ ],
205
+ 'react-hooks/rules-of-hooks': ['error'],
206
+ 'react/button-has-type': [
207
+ 2,
208
+ {
209
+ button: true,
210
+ reset: false,
211
+ submit: true,
212
+ },
213
+ ],
214
+ 'react/checked-requires-onchange-or-readonly': [2],
215
+ 'react/default-props-match-prop-types': [
216
+ 2,
217
+ {
218
+ allowRequiredDefaults: false,
219
+ },
220
+ ],
221
+ 'react/destructuring-assignment': [2, 'always'],
222
+ 'react/display-name': [
223
+ 2,
224
+ {
225
+ ignoreTranspilerName: false,
226
+ },
227
+ ],
228
+ 'react/forbid-component-props': [
229
+ 2,
230
+ {
231
+ forbid: [],
232
+ },
233
+ ],
234
+ 'react/forbid-dom-props': [
235
+ 2,
236
+ {
237
+ forbid: [],
238
+ },
239
+ ],
240
+ 'react/forbid-elements': [
241
+ 2,
242
+ {
243
+ forbid: [],
244
+ },
245
+ ],
246
+ 'react/forbid-foreign-prop-types': [
247
+ 2,
248
+ {
249
+ allowInPropTypes: true,
250
+ },
251
+ ],
252
+ 'react/forward-ref-uses-ref': [2],
253
+ 'react/hook-use-state': [2],
254
+ 'react/iframe-missing-sandbox': [2],
255
+ 'react/jsx-boolean-value': [
256
+ 2,
257
+ 'never',
258
+ {
259
+ always: [],
260
+ },
261
+ ],
262
+ 'react/jsx-closing-bracket-location': [2, 'line-aligned'],
263
+ 'react/jsx-closing-tag-location': [2],
264
+ 'react/jsx-curly-brace-presence': [
265
+ 2,
266
+ {
267
+ children: 'never',
268
+ props: 'never',
269
+ },
270
+ ],
271
+ 'react/jsx-curly-newline': [
272
+ 2,
273
+ {
274
+ multiline: 'consistent',
275
+ singleline: 'consistent',
276
+ },
277
+ ],
278
+ 'react/jsx-curly-spacing': [
279
+ 2,
280
+ 'never',
281
+ {
282
+ allowMultiline: true,
283
+ },
284
+ ],
285
+ 'react/jsx-equals-spacing': [2, 'never'],
286
+ 'react/jsx-filename-extension': [
287
+ 2,
288
+ {
289
+ extensions: ['.jsx', '.tsx'],
290
+ },
291
+ ],
292
+ 'react/jsx-first-prop-new-line': [2, 'multiline-multiprop'],
293
+ 'react/jsx-fragments': [2, 'syntax'],
294
+ 'react/jsx-handler-names': [
295
+ 2,
296
+ {
297
+ eventHandlerPrefix: 'handle',
298
+ eventHandlerPropPrefix: 'on',
299
+ },
300
+ ],
301
+ 'react/jsx-indent': [2, 2],
302
+ 'react/jsx-indent-props': [2, 2],
303
+ 'react/jsx-max-depth': [2],
304
+ 'react/jsx-max-props-per-line': [
305
+ 2,
306
+ {
307
+ maximum: 1,
308
+ when: 'multiline',
309
+ },
310
+ ],
311
+ 'react/jsx-newline': [2],
312
+ 'react/jsx-no-comment-textnodes': [2],
313
+ 'react/jsx-no-duplicate-props': [
314
+ 2,
315
+ {
316
+ ignoreCase: true,
317
+ },
318
+ ],
319
+ 'react/jsx-no-leaked-render': [2],
320
+ 'react/jsx-no-target-blank': [
321
+ 2,
322
+ {
323
+ enforceDynamicLinks: 'always',
324
+ forms: false,
325
+ links: true,
326
+ },
327
+ ],
328
+ 'react/jsx-no-undef': [2],
329
+ 'react/jsx-no-useless-fragment': ['error'],
330
+ 'react/jsx-pascal-case': [
331
+ 2,
332
+ {
333
+ allowAllCaps: true,
334
+ ignore: [],
335
+ },
336
+ ],
337
+ 'react/jsx-props-no-multi-spaces': [2],
338
+ 'react/jsx-props-no-spread-multi': [2],
339
+ 'react/jsx-props-no-spreading': [
340
+ 'error',
341
+ {
342
+ custom: 'enforce',
343
+ exceptions: [],
344
+ explicitSpread: 'ignore',
345
+ html: 'enforce',
346
+ },
347
+ ],
348
+ 'react/jsx-tag-spacing': [
349
+ 2,
350
+ {
351
+ afterOpening: 'never',
352
+ beforeClosing: 'never',
353
+ beforeSelfClosing: 'always',
354
+ closingSlash: 'never',
355
+ },
356
+ ],
357
+ 'react/jsx-uses-vars': [2],
358
+ 'react/no-access-state-in-setstate': [2],
359
+ 'react/no-adjacent-inline-elements': [2],
360
+ 'react/no-array-index-key': [2],
361
+ 'react/no-arrow-function-lifecycle': [2],
362
+ 'react/no-children-prop': [2],
363
+ 'react/no-danger': [2],
364
+ 'react/no-danger-with-children': [2],
365
+ 'react/no-deprecated': [2],
366
+ 'react/no-did-mount-set-state': [2],
367
+ 'react/no-did-update-set-state': [2],
368
+ 'react/no-direct-mutation-state': [2],
369
+ 'react/no-find-dom-node': [2],
370
+ 'react/no-invalid-html-attribute': [2],
371
+ 'react/no-is-mounted': [2],
372
+ 'react/no-multi-comp': [2],
373
+ 'react/no-namespace': [2],
374
+ 'react/no-object-type-as-default-prop': [2],
375
+ 'react/no-redundant-should-component-update': [2],
376
+ 'react/no-render-return-value': [2],
377
+ 'react/no-string-refs': [2],
378
+ 'react/no-this-in-sfc': [2],
379
+ 'react/no-typos': [2],
380
+ 'react/no-unescaped-entities': [2],
381
+ 'react/no-unknown-property': [2],
382
+ 'react/no-unsafe': [2],
383
+ 'react/no-unused-class-component-methods': [2],
384
+ 'react/no-unused-prop-types': [
385
+ 2,
386
+ {
387
+ customValidators: [],
388
+ skipShapeProps: true,
389
+ },
390
+ ],
391
+ 'react/no-unused-state': [2],
392
+ 'react/no-will-update-set-state': [2],
393
+ 'react/prefer-es6-class': [2, 'always'],
394
+ 'react/prefer-exact-props': [2],
395
+ 'react/require-optimization': [
396
+ 2,
397
+ {
398
+ allowDecorators: [],
399
+ },
400
+ ],
401
+ 'react/require-render-return': [2],
402
+ 'react/self-closing-comp': [2],
403
+ 'react/sort-comp': [
404
+ 2,
405
+ {
406
+ groups: {
407
+ lifecycle: [
408
+ 'displayName',
409
+ 'propTypes',
410
+ 'contextTypes',
411
+ 'childContextTypes',
412
+ 'mixins',
413
+ 'statics',
414
+ 'defaultProps',
415
+ 'constructor',
416
+ 'getDefaultProps',
417
+ 'getInitialState',
418
+ 'state',
419
+ 'getChildContext',
420
+ 'getDerivedStateFromProps',
421
+ 'componentWillMount',
422
+ 'UNSAFE_componentWillMount',
423
+ 'componentDidMount',
424
+ 'componentWillReceiveProps',
425
+ 'UNSAFE_componentWillReceiveProps',
426
+ 'shouldComponentUpdate',
427
+ 'componentWillUpdate',
428
+ 'UNSAFE_componentWillUpdate',
429
+ 'getSnapshotBeforeUpdate',
430
+ 'componentDidUpdate',
431
+ 'componentDidCatch',
432
+ 'componentWillUnmount',
433
+ ],
434
+ rendering: ['/^render.+$/', 'render'],
435
+ },
436
+ order: [
437
+ 'static-variables',
438
+ 'static-methods',
439
+ 'instance-variables',
440
+ 'lifecycle',
441
+ '/^handle.+$/',
442
+ '/^on.+$/',
443
+ 'getters',
444
+ 'setters',
445
+ '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
446
+ 'instance-methods',
447
+ 'everything-else',
448
+ 'rendering',
449
+ ],
450
+ },
451
+ ],
452
+ 'react/sort-default-props': [2],
453
+ 'react/sort-prop-types': [
454
+ 2,
455
+ {
456
+ callbacksLast: false,
457
+ ignoreCase: true,
458
+ requiredFirst: false,
459
+ sortShapeProp: true,
460
+ },
461
+ ],
462
+ 'react/static-property-placement': [2, 'property assignment'],
463
+ 'react/style-prop-object': [2],
464
+ 'react/void-dom-elements-no-children': [2],
465
+ 'react/boolean-prop-naming': [
466
+ 'error',
467
+ {
468
+ validateNested: true,
469
+ },
470
+ ],
471
+ 'react/no-unstable-nested-components': 'error',
472
+ 'react/jsx-key': 'error',
473
+ 'react/jsx-no-bind': [
474
+ 'error',
475
+ {
476
+ ignoreRefs: false,
477
+ allowArrowFunctions: true,
478
+ allowFunctions: true,
479
+ allowBind: false,
480
+ ignoreDOMComponents: false,
481
+ },
482
+ ],
483
+ 'react/jsx-sort-props': [
484
+ 'error',
485
+ {
486
+ callbacksLast: true,
487
+ shorthandFirst: true,
488
+ noSortAlphabetically: false,
489
+ reservedFirst: false,
490
+ },
491
+ ],
492
+ 'react/function-component-definition': [
493
+ 'error',
494
+ {
495
+ namedComponents: 'arrow-function',
496
+ unnamedComponents: 'arrow-function',
497
+ },
498
+ ],
499
+ 'react/jsx-no-constructed-context-values': 'error',
500
+ 'react/jsx-no-script-url': 'error',
501
+ 'arrow-body-style': ['error', 'always'],
502
+ },
503
+ },
504
+ ];
505
+ export default reactConfig;