@dmitryrechkin/eslint-standard 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/eslint.config.mjs +491 -50
  2. package/package.json +54 -33
package/eslint.config.mjs CHANGED
@@ -8,6 +8,15 @@ import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
8
8
  import perfectionistPlugin from 'eslint-plugin-perfectionist';
9
9
  import jsdocIndentPlugin from './src/plugins/jsdoc-indent.mjs';
10
10
  import interfaceBracePlugin from './src/plugins/interface-brace.mjs';
11
+ import securityPlugin from 'eslint-plugin-security';
12
+ import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
13
+ import promisePlugin from 'eslint-plugin-promise';
14
+ import importPlugin from 'eslint-plugin-import';
15
+ import sonarjsPlugin from 'eslint-plugin-sonarjs';
16
+ import unicornPlugin from 'eslint-plugin-unicorn';
17
+ import noSecretsPlugin from 'eslint-plugin-no-secrets';
18
+ import regexpPlugin from 'eslint-plugin-regexp';
19
+ import functionalPlugin from 'eslint-plugin-functional';
11
20
 
12
21
  export default function ({
13
22
  tsconfigPath = './tsconfig.json',
@@ -39,6 +48,15 @@ export default function ({
39
48
  'perfectionist': perfectionistPlugin,
40
49
  'jsdoc-indent': jsdocIndentPlugin,
41
50
  'interface-brace': interfaceBracePlugin,
51
+ 'security': securityPlugin,
52
+ 'jsx-a11y': jsxA11yPlugin,
53
+ 'promise': promisePlugin,
54
+ 'import': importPlugin,
55
+ 'sonarjs': sonarjsPlugin,
56
+ 'unicorn': unicornPlugin,
57
+ 'no-secrets': noSecretsPlugin,
58
+ 'regexp': regexpPlugin,
59
+ 'functional': functionalPlugin,
42
60
  ...plugins,
43
61
  },
44
62
  rules: {
@@ -63,56 +81,7 @@ export default function ({
63
81
  'comma-dangle': 'off', // Disabled in favor of @stylistic/comma-dangle
64
82
  '@stylistic/comma-dangle': ['error', 'never'],
65
83
 
66
- // Original naming conventions
67
- '@typescript-eslint/naming-convention': [
68
- 'error',
69
- {
70
- selector: 'variableLike',
71
- format: ['camelCase'],
72
- leadingUnderscore: 'forbid',
73
- },
74
- {
75
- selector: 'function',
76
- format: ['camelCase'],
77
- leadingUnderscore: 'forbid',
78
- },
79
- {
80
- selector: 'class',
81
- format: ['PascalCase'],
82
- leadingUnderscore: 'forbid',
83
- },
84
- {
85
- selector: 'parameter',
86
- format: ['camelCase'],
87
- leadingUnderscore: 'forbid',
88
- custom: {
89
- regex: '^_',
90
- match: false,
91
- },
92
- },
93
- {
94
- selector: 'parameter',
95
- format: null,
96
- leadingUnderscore: 'require',
97
- modifiers: ['unused'],
98
- },
99
- {
100
- selector: 'memberLike',
101
- format: ['camelCase'],
102
- leadingUnderscore: 'forbid',
103
- },
104
- {
105
- selector: 'property',
106
- modifiers: ['readonly'],
107
- format: ['camelCase', 'UPPER_CASE'],
108
- leadingUnderscore: 'forbid',
109
- },
110
- {
111
- selector: 'enumMember',
112
- format: ['UPPER_CASE'],
113
- leadingUnderscore: 'forbid',
114
- },
115
- ],
84
+ // Comprehensive naming conventions based on coding standards
116
85
 
117
86
  // Original unused-imports rules
118
87
  'unused-imports/no-unused-imports': 'error',
@@ -202,6 +171,181 @@ export default function ({
202
171
  // Enhanced: Interface brace style
203
172
  'interface-brace/interface-brace-style': 'error',
204
173
 
174
+ // Additional naming conventions based on coding standards
175
+ '@typescript-eslint/naming-convention': [
176
+ 'warn',
177
+ // Existing rules remain the same...
178
+ {
179
+ selector: 'variableLike',
180
+ format: ['camelCase'],
181
+ leadingUnderscore: 'forbid',
182
+ },
183
+ {
184
+ selector: 'variable',
185
+ modifiers: ['const'],
186
+ format: ['camelCase', 'UPPER_CASE'],
187
+ leadingUnderscore: 'forbid',
188
+ },
189
+ {
190
+ selector: 'variable',
191
+ format: ['camelCase'],
192
+ leadingUnderscore: 'forbid',
193
+ custom: {
194
+ regex: '^(data|info|item|obj|object|val|value|temp|tmp|res|result|ret|param|params|arg|args|opt|options|config|cfg|ctx|context|e|err|error|cb|callback|fn|func|handler|util|utils|helper|helpers|mgr|manager|svc|service|ctrl|controller|comp|component|elem|element|str|string|num|number|bool|boolean|arr|array|list|items|dict|map|hash|i|j|k|n|x|y|z)$',
195
+ match: false
196
+ }
197
+ },
198
+ {
199
+ selector: 'function',
200
+ format: ['camelCase'],
201
+ leadingUnderscore: 'forbid',
202
+ custom: {
203
+ regex: '^(create|make|get|set|update|delete|remove|add|init|load|save|fetch|find|search|check|validate|handle|process|execute|run|start|stop|open|close|read|write|parse|format|convert|transform|build|render|draw|calculate|compute|generate|send|receive|submit|cancel|reset|clear|test|log|debug|trace|info|warn|error|show|hide|enable|disable|toggle|select|click|focus|blur|scroll|resize|move|copy|paste|cut|undo|redo|forward|back|up|down|left|right|first|last|next|prev|push|pop|shift|unshift|splice|slice|concat|join|split|replace|trim|pad|truncate|wrap|unwrap|escape|unescape|encode|decode|encrypt|decrypt|compress|decompress|serialize|deserialize|clone|merge|extend|assign|bind|unbind|on|off|once|emit|trigger|listen|unlisten|subscribe|unsubscribe|publish|unpublish|attach|detach|append|prepend|insert|inject|extract|filter|map|reduce|forEach|some|every|find|findIndex|indexOf|lastIndexOf|includes|contains|has|is|equals|compare|match|test|verify|assert|ensure|require|expect|should|must|can|may|might|will|shall|would|could)$',
204
+ match: false
205
+ }
206
+ },
207
+ {
208
+ selector: 'method',
209
+ format: ['camelCase'],
210
+ leadingUnderscore: 'forbid',
211
+ custom: {
212
+ regex: '^(create|make|get|set|update|delete|remove|add|init|load|save|fetch|find|search|check|validate|handle|process|execute|run|start|stop|open|close|read|write|parse|format|convert|transform|build|render|draw|calculate|compute|generate|send|receive|submit|cancel|reset|clear|test|log|debug|trace|info|warn|error|show|hide|enable|disable|toggle|select|click|focus|blur|scroll|resize|move|copy|paste|cut|undo|redo|forward|back|up|down|left|right|first|last|next|prev|push|pop|shift|unshift|splice|slice|concat|join|split|replace|trim|pad|truncate|wrap|unwrap|escape|unescape|encode|decode|encrypt|decrypt|compress|decompress|serialize|deserialize|clone|merge|extend|assign|bind|unbind|on|off|once|emit|trigger|listen|unlisten|subscribe|unsubscribe|publish|unpublish|attach|detach|append|prepend|insert|inject|extract|filter|map|reduce|forEach|some|every|find|findIndex|indexOf|lastIndexOf|includes|contains|has|is|equals|compare|match|test|verify|assert|ensure|require|expect|should|must|can|may|might|will|shall|would|could)$',
213
+ match: false
214
+ }
215
+ },
216
+ {
217
+ selector: 'method',
218
+ modifiers: ['public'],
219
+ format: ['camelCase'],
220
+ leadingUnderscore: 'forbid'
221
+ // Allow generic names for public methods
222
+ },
223
+ // Services must end with 'Service'
224
+ {
225
+ selector: 'class',
226
+ filter: {
227
+ regex: 'Service$',
228
+ match: true
229
+ },
230
+ format: ['PascalCase'],
231
+ custom: {
232
+ regex: '^[A-Z][a-zA-Z]*Service$',
233
+ match: true
234
+ }
235
+ },
236
+ // Repositories must end with 'Repository'
237
+ {
238
+ selector: 'class',
239
+ filter: {
240
+ regex: 'Repository$',
241
+ match: true
242
+ },
243
+ format: ['PascalCase'],
244
+ custom: {
245
+ regex: '^[A-Z][a-zA-Z]*(Command|Query)?Repository$',
246
+ match: true
247
+ }
248
+ },
249
+ // Helpers must end with 'Helper'
250
+ {
251
+ selector: 'class',
252
+ filter: {
253
+ regex: 'Helper$',
254
+ match: true
255
+ },
256
+ format: ['PascalCase'],
257
+ custom: {
258
+ regex: '^[A-Z][a-zA-Z]*Helper$',
259
+ match: true
260
+ }
261
+ },
262
+ // Factories must end with 'Factory'
263
+ {
264
+ selector: 'class',
265
+ filter: {
266
+ regex: 'Factory$',
267
+ match: true
268
+ },
269
+ format: ['PascalCase'],
270
+ custom: {
271
+ regex: '^[A-Z][a-zA-Z]*Factory$',
272
+ match: true
273
+ }
274
+ },
275
+ // General class naming (excluding specific patterns above)
276
+ {
277
+ selector: 'class',
278
+ format: ['PascalCase'],
279
+ leadingUnderscore: 'forbid',
280
+ custom: {
281
+ regex: '^(Base|Abstract|Main|App|Application|Component|Element|Item|Object|Entity|Model|View|Controller|Service|Manager|Handler|Helper|Util|Utils|Factory|Builder|Provider|Container|Wrapper|Adapter|Proxy|Decorator|Observer|Listener|Event|Action|Command|Request|Response|Result|Error|Exception|Interface|Type|Class|Struct|Enum|Module|Package|Library|Framework|System|Core|Common|Shared|Global|Default|Generic|Simple|Basic|Standard|Custom|Internal|External|Public|Private|Static|Dynamic|Singleton|Instance|Collection|List|Array|Map|Set|Dictionary|Queue|Stack|Tree|Graph|Node|Edge|Link|Data|Info|Config|Settings|Options|Parameters|Arguments|Properties|Attributes|State|Status|Context|Environment|Session|Transaction|Process|Thread|Task|Job|Worker|Pool|Cache|Buffer|Stream|Channel|Connection|Client|Server|Database|Repository|Store|Resource|Asset|File|Folder|Directory|Path|Route|Endpoint|Api|Rest|Http|Https|Tcp|Udp|Socket|Port|Host|Domain|Url|Uri|Query|Param|Header|Body|Content|Message|Packet|Frame|Byte|Bit|Flag|Token|Key|Value|Pair|Entry|Record|Row|Column|Field|Cell|Table|Index|Page|Form|Input|Output|Button|Label|Text|Image|Icon|Media|Audio|Video|Document|Template|Layout|Style|Theme|Color|Font|Size|Position|Location|Coordinate|Point|Vector|Matrix|Shape|Line|Circle|Rectangle|Polygon|Curve|Surface|Volume|Space|Time|Date|Duration|Period|Interval|Range|Sequence|Series|Pattern|Format|Encoder|Decoder|Parser|Formatter|Validator|Converter|Transformer|Filter|Mapper|Reducer|Sorter|Comparator|Iterator|Generator|Consumer|Producer|Publisher|Subscriber|Emitter|Receiver|Sender|Dispatcher|Router|Gateway|Bridge|Tunnel|Pipeline|Chain|Link|Hook|Plugin|Extension|Addon|Feature|Capability|Function|Method|Procedure|Routine|Algorithm|Strategy|Policy|Rule|Constraint|Condition|Requirement|Specification|Definition|Declaration|Implementation|Execution|Operation|Instruction|Statement|Expression|Variable|Constant|Parameter|Argument|Return|Result|Output|Input|IO|UI|GUI|CLI|API|SDK|IDE|OS|VM|CPU|GPU|RAM|ROM|HDD|SSD|DB|SQL|NoSQL|ORM|ODM|DTO|DAO|POJO|POCO|VO|BO|DO|PO|TO|SO|MO|NO)$',
282
+ match: false
283
+ }
284
+ },
285
+ {
286
+ selector: 'interface',
287
+ format: ['PascalCase'],
288
+ leadingUnderscore: 'forbid',
289
+ custom: {
290
+ regex: 'Interface$',
291
+ match: true
292
+ }
293
+ },
294
+ {
295
+ selector: 'typeAlias',
296
+ format: ['PascalCase'],
297
+ leadingUnderscore: 'forbid',
298
+ custom: {
299
+ regex: '^Type[A-Z]',
300
+ match: true
301
+ }
302
+ },
303
+ {
304
+ selector: 'parameter',
305
+ format: ['camelCase'],
306
+ leadingUnderscore: 'forbid',
307
+ custom: {
308
+ regex: '^_',
309
+ match: false,
310
+ },
311
+ },
312
+ {
313
+ selector: 'parameter',
314
+ format: null,
315
+ leadingUnderscore: 'require',
316
+ modifiers: ['unused'],
317
+ },
318
+ {
319
+ selector: 'memberLike',
320
+ format: ['camelCase'],
321
+ leadingUnderscore: 'forbid',
322
+ },
323
+ {
324
+ selector: 'property',
325
+ modifiers: ['readonly'],
326
+ format: ['camelCase', 'UPPER_CASE'],
327
+ leadingUnderscore: 'forbid',
328
+ },
329
+ {
330
+ selector: 'enumMember',
331
+ format: ['camelCase', 'UPPER_CASE'],
332
+ leadingUnderscore: 'forbid',
333
+ },
334
+ // Schema table files must end with 'Table'
335
+ {
336
+ selector: 'variable',
337
+ filter: {
338
+ regex: 'Table$',
339
+ match: true
340
+ },
341
+ format: ['camelCase'],
342
+ custom: {
343
+ regex: '[a-z][a-zA-Z]*Table$',
344
+ match: true
345
+ }
346
+ }
347
+ ],
348
+
205
349
  // Code Complexity Rules (industry standards)
206
350
  'complexity': ['error', 10], // Cyclomatic complexity - max 10 paths through a function
207
351
  'max-lines-per-function': ['error', {
@@ -321,6 +465,303 @@ export default function ({
321
465
  ignoreClassFieldInitialValues: true
322
466
  }], // Named constants for magic numbers
323
467
 
468
+ // Identifier length rules
469
+ 'id-length': ['warn', {
470
+ min: 3,
471
+ exceptions: ['i', 'j', 'k', 'x', 'y', 'z', 'id', 'db', 'fs', 'os', 'io', 'ui', 'vm', '_', 'idx'],
472
+ properties: 'never' // Don't apply to object properties
473
+ }],
474
+
475
+ // Security plugin rules
476
+ 'security/detect-eval-with-expression': 'error',
477
+ 'security/detect-non-literal-fs-filename': 'warn',
478
+ 'security/detect-non-literal-regexp': 'warn',
479
+ 'security/detect-unsafe-regex': 'error',
480
+ 'security/detect-buffer-noassert': 'error',
481
+ 'security/detect-child-process': 'warn',
482
+ 'security/detect-disable-mustache-escape': 'error',
483
+ 'security/detect-no-csrf-before-method-override': 'error',
484
+ 'security/detect-object-injection': 'warn',
485
+ 'security/detect-possible-timing-attacks': 'warn',
486
+ 'security/detect-pseudoRandomBytes': 'error',
487
+
488
+ // Promise plugin rules
489
+ 'promise/always-return': 'error',
490
+ 'promise/no-return-wrap': 'error',
491
+ 'promise/param-names': 'error',
492
+ 'promise/catch-or-return': 'error',
493
+ 'promise/no-native': 'off',
494
+ 'promise/no-nesting': 'warn',
495
+ 'promise/no-promise-in-callback': 'warn',
496
+ 'promise/no-callback-in-promise': 'warn',
497
+ 'promise/avoid-new': 'off',
498
+ 'promise/no-new-statics': 'error',
499
+ 'promise/no-return-in-finally': 'error',
500
+ 'promise/valid-params': 'error',
501
+ 'promise/prefer-await-to-then': 'warn',
502
+ 'promise/prefer-await-to-callbacks': 'warn',
503
+
504
+ // Import plugin rules
505
+ 'import/no-unresolved': 'error',
506
+ 'import/named': 'error',
507
+ 'import/default': 'error',
508
+ 'import/namespace': 'error',
509
+ 'import/no-restricted-paths': 'off',
510
+ 'import/no-absolute-path': 'error',
511
+ 'import/no-dynamic-require': 'error',
512
+ 'import/no-internal-modules': 'off',
513
+ 'import/no-webpack-loader-syntax': 'error',
514
+ 'import/no-self-import': 'error',
515
+ 'import/no-cycle': ['error', { maxDepth: 3 }],
516
+ 'import/no-useless-path-segments': 'error',
517
+ 'import/no-relative-parent-imports': 'off',
518
+ 'import/export': 'error',
519
+ 'import/no-named-as-default': 'error',
520
+ 'import/no-named-as-default-member': 'error',
521
+ 'import/no-deprecated': 'warn',
522
+ 'import/no-extraneous-dependencies': ['error', {
523
+ devDependencies: ['**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}', '**/test/**', '**/tests/**', '**/__tests__/**']
524
+ }],
525
+ 'import/no-mutable-exports': 'error',
526
+ 'import/no-unused-modules': 'off', // Disabled due to .eslintrc requirement in flat config
527
+ 'import/unambiguous': 'off',
528
+ 'import/no-commonjs': 'off',
529
+ 'import/no-amd': 'error',
530
+ 'import/no-nodejs-modules': 'off',
531
+ 'import/first': 'error',
532
+ 'import/exports-last': 'off',
533
+ 'import/no-duplicates': 'error',
534
+ 'import/no-namespace': 'off',
535
+ 'import/extensions': ['error', 'ignorePackages', {
536
+ js: 'never',
537
+ jsx: 'never',
538
+ ts: 'never',
539
+ tsx: 'never'
540
+ }],
541
+ 'import/newline-after-import': 'error',
542
+ 'import/prefer-default-export': 'off',
543
+ 'import/max-dependencies': ['warn', { max: 20 }],
544
+ 'import/no-unassigned-import': 'off',
545
+ 'import/no-named-default': 'error',
546
+ 'import/no-default-export': 'off',
547
+ 'import/no-named-export': 'off',
548
+ 'import/no-anonymous-default-export': 'warn',
549
+ 'import/group-exports': 'off',
550
+ 'import/dynamic-import-chunkname': 'off',
551
+
552
+ // JSX A11y plugin rules (only active for React/JSX files)
553
+ 'jsx-a11y/alt-text': 'error',
554
+ 'jsx-a11y/anchor-has-content': 'error',
555
+ 'jsx-a11y/anchor-is-valid': 'error',
556
+ 'jsx-a11y/aria-props': 'error',
557
+ 'jsx-a11y/aria-role': 'error',
558
+ 'jsx-a11y/aria-unsupported-elements': 'error',
559
+ 'jsx-a11y/click-events-have-key-events': 'warn',
560
+ 'jsx-a11y/heading-has-content': 'error',
561
+ 'jsx-a11y/html-has-lang': 'error',
562
+ 'jsx-a11y/iframe-has-title': 'error',
563
+ 'jsx-a11y/img-redundant-alt': 'error',
564
+ 'jsx-a11y/interactive-supports-focus': 'error',
565
+ 'jsx-a11y/label-has-associated-control': 'error',
566
+ 'jsx-a11y/media-has-caption': 'warn',
567
+ 'jsx-a11y/mouse-events-have-key-events': 'warn',
568
+ 'jsx-a11y/no-access-key': 'error',
569
+ 'jsx-a11y/no-autofocus': 'warn',
570
+ 'jsx-a11y/no-distracting-elements': 'error',
571
+ 'jsx-a11y/no-interactive-element-to-noninteractive-role': 'error',
572
+ 'jsx-a11y/no-noninteractive-element-interactions': 'warn',
573
+ 'jsx-a11y/no-noninteractive-element-to-interactive-role': 'error',
574
+ 'jsx-a11y/no-redundant-roles': 'error',
575
+ 'jsx-a11y/no-static-element-interactions': 'warn',
576
+ 'jsx-a11y/role-has-required-aria-props': 'error',
577
+ 'jsx-a11y/role-supports-aria-props': 'error',
578
+ 'jsx-a11y/scope': 'error',
579
+ 'jsx-a11y/tabindex-no-positive': 'error',
580
+
581
+ // SonarJS plugin rules - Code smells and cognitive complexity
582
+ 'sonarjs/cognitive-complexity': ['error', 15], // More sophisticated than cyclomatic
583
+ 'sonarjs/no-identical-expressions': 'error',
584
+ 'sonarjs/no-identical-functions': 'error',
585
+ 'sonarjs/no-duplicate-string': ['error', { threshold: 3 }],
586
+ 'sonarjs/prefer-immediate-return': 'error',
587
+ 'sonarjs/prefer-object-literal': 'error',
588
+ 'sonarjs/prefer-single-boolean-return': 'error',
589
+ 'sonarjs/no-redundant-boolean': 'error',
590
+ 'sonarjs/no-unused-collection': 'error',
591
+ 'sonarjs/no-useless-catch': 'error',
592
+ 'sonarjs/prefer-while': 'error',
593
+ 'sonarjs/max-switch-cases': ['error', 30],
594
+ 'sonarjs/no-nested-switch': 'error',
595
+ 'sonarjs/no-nested-template-literals': 'error',
596
+ 'sonarjs/no-redundant-jump': 'error',
597
+ 'sonarjs/no-same-line-conditional': 'error',
598
+ 'sonarjs/non-existent-operator': 'error',
599
+
600
+ // Unicorn plugin rules - Modern JavaScript best practices
601
+ 'unicorn/better-regex': 'error',
602
+ 'unicorn/catch-error-name': 'error',
603
+ 'unicorn/consistent-destructuring': 'error',
604
+ 'unicorn/consistent-function-scoping': 'error',
605
+ 'unicorn/custom-error-definition': 'error',
606
+ 'unicorn/error-message': 'error',
607
+ 'unicorn/escape-case': 'error',
608
+ 'unicorn/expiring-todo-comments': 'error',
609
+ 'unicorn/explicit-length-check': 'error',
610
+ 'unicorn/filename-case': ['warn', {
611
+ cases: {
612
+ camelCase: true, // For folders: userAuth, licenseActivation
613
+ pascalCase: true, // For class files: UserService.ts
614
+ }
615
+ }],
616
+ 'unicorn/import-style': 'error',
617
+ 'unicorn/new-for-builtins': 'error',
618
+ 'unicorn/no-abusive-eslint-disable': 'error',
619
+ 'unicorn/no-array-callback-reference': 'error',
620
+ 'unicorn/no-array-for-each': 'error',
621
+ 'unicorn/no-array-method-this-argument': 'error',
622
+ 'unicorn/no-array-push-push': 'error',
623
+ 'unicorn/no-array-reduce': 'warn',
624
+ 'unicorn/no-await-expression-member': 'error',
625
+ 'unicorn/no-console-spaces': 'error',
626
+ 'unicorn/no-document-cookie': 'error',
627
+ 'unicorn/no-empty-file': 'error',
628
+ 'unicorn/no-for-loop': 'error',
629
+ 'unicorn/no-hex-escape': 'error',
630
+ 'unicorn/no-instanceof-array': 'error',
631
+ 'unicorn/no-invalid-remove-event-listener': 'error',
632
+ 'unicorn/no-keyword-prefix': 'off',
633
+ 'unicorn/no-lonely-if': 'error',
634
+ 'unicorn/no-nested-ternary': 'error',
635
+ 'unicorn/no-new-array': 'error',
636
+ 'unicorn/no-new-buffer': 'error',
637
+ 'unicorn/no-null': 'error', // Use undefined instead of null per coding standards
638
+ 'unicorn/no-object-as-default-parameter': 'error',
639
+ 'unicorn/no-process-exit': 'error',
640
+ 'unicorn/no-static-only-class': 'error',
641
+ 'unicorn/no-thenable': 'error',
642
+ 'unicorn/no-this-assignment': 'error',
643
+ 'unicorn/no-typeof-undefined': 'error',
644
+ 'unicorn/no-unnecessary-await': 'error',
645
+ 'unicorn/no-unreadable-array-destructuring': 'error',
646
+ 'unicorn/no-unreadable-iife': 'error',
647
+ 'unicorn/no-unsafe-regex': 'error',
648
+ 'unicorn/no-unused-properties': 'off',
649
+ 'unicorn/no-useless-fallback-in-spread': 'error',
650
+ 'unicorn/no-useless-length-check': 'error',
651
+ 'unicorn/no-useless-promise-resolve-reject': 'error',
652
+ 'unicorn/no-useless-spread': 'error',
653
+ 'unicorn/no-useless-switch-case': 'error',
654
+ 'unicorn/no-zero-fractions': 'error',
655
+ 'unicorn/number-literal-case': 'error',
656
+ 'unicorn/numeric-separators-style': 'error',
657
+ 'unicorn/prefer-add-event-listener': 'error',
658
+ 'unicorn/prefer-array-find': 'error',
659
+ 'unicorn/prefer-array-flat': 'error',
660
+ 'unicorn/prefer-array-flat-map': 'error',
661
+ 'unicorn/prefer-array-index-of': 'error',
662
+ 'unicorn/prefer-array-some': 'error',
663
+ 'unicorn/prefer-at': 'error',
664
+ 'unicorn/prefer-code-point': 'error',
665
+ 'unicorn/prefer-date-now': 'error',
666
+ 'unicorn/prefer-default-parameters': 'error',
667
+ 'unicorn/prefer-dom-node-append': 'error',
668
+ 'unicorn/prefer-dom-node-dataset': 'error',
669
+ 'unicorn/prefer-dom-node-remove': 'error',
670
+ 'unicorn/prefer-dom-node-text-content': 'error',
671
+ 'unicorn/prefer-includes': 'error',
672
+ 'unicorn/prefer-json-parse-buffer': 'off',
673
+ 'unicorn/prefer-keyboard-event-key': 'error',
674
+ 'unicorn/prefer-logical-operator-over-ternary': 'error',
675
+ 'unicorn/prefer-math-trunc': 'error',
676
+ 'unicorn/prefer-modern-dom-apis': 'error',
677
+ 'unicorn/prefer-modern-math-apis': 'error',
678
+ 'unicorn/prefer-module': 'error',
679
+ 'unicorn/prefer-native-coercion-functions': 'error',
680
+ 'unicorn/prefer-negative-index': 'error',
681
+ 'unicorn/prefer-node-protocol': 'error',
682
+ 'unicorn/prefer-number-properties': 'error',
683
+ 'unicorn/prefer-object-from-entries': 'error',
684
+ 'unicorn/prefer-optional-catch-binding': 'error',
685
+ 'unicorn/prefer-prototype-methods': 'error',
686
+ 'unicorn/prefer-query-selector': 'error',
687
+ 'unicorn/prefer-reflect-apply': 'error',
688
+ 'unicorn/prefer-regexp-test': 'error',
689
+ 'unicorn/prefer-set-has': 'error',
690
+ 'unicorn/prefer-set-size': 'error',
691
+ 'unicorn/prefer-spread': 'error',
692
+ 'unicorn/prefer-string-replace-all': 'error',
693
+ 'unicorn/prefer-string-slice': 'error',
694
+ 'unicorn/prefer-string-starts-ends-with': 'error',
695
+ 'unicorn/prefer-string-trim-start-end': 'error',
696
+ 'unicorn/prefer-switch': 'error',
697
+ 'unicorn/prefer-ternary': 'error',
698
+ 'unicorn/prefer-top-level-await': 'error',
699
+ 'unicorn/prefer-type-error': 'error',
700
+ 'unicorn/prevent-abbreviations': 'off', // Too aggressive for existing code
701
+ 'unicorn/relative-url-style': 'error',
702
+ 'unicorn/require-array-join-separator': 'error',
703
+ 'unicorn/require-number-to-fixed-digits-argument': 'error',
704
+ 'unicorn/require-post-message-target-origin': 'error',
705
+ 'unicorn/string-content': 'off',
706
+ 'unicorn/switch-case-braces': 'error',
707
+ 'unicorn/template-indent': 'warn',
708
+ 'unicorn/text-encoding-identifier-case': 'error',
709
+ 'unicorn/throw-new-error': 'error',
710
+
711
+ // No Secrets plugin rules - Prevent secrets in code
712
+ 'no-secrets/no-secrets': ['error', {
713
+ tolerance: 4.2,
714
+ ignoreContent: '^CHANGE ME$',
715
+ ignoreModules: true,
716
+ ignoreIdentifiers: ['BASE64_CHARS', 'HEX_CHARS'],
717
+ additionalRegexes: {
718
+ 'AWS Access Key': 'AKIA[0-9A-Z]{16}',
719
+ 'GitHub Token': 'ghp_[a-zA-Z0-9]{36}',
720
+ 'JWT Token': 'eyJ[a-zA-Z0-9_-]*\\.[a-zA-Z0-9_-]*\\.[a-zA-Z0-9_-]*'
721
+ }
722
+ }],
723
+
724
+ // RegExp plugin rules - Essential RegExp safety (conservative set for v2.9.0)
725
+ 'regexp/no-control-character': 'error',
726
+ 'regexp/no-empty-character-class': 'error',
727
+ 'regexp/no-empty-group': 'error',
728
+ 'regexp/no-invalid-regexp': 'error',
729
+ 'regexp/no-misleading-capturing-group': 'error',
730
+ 'regexp/no-misleading-unicode-character': 'error',
731
+ 'regexp/no-super-linear-backtracking': 'error', // Prevents ReDoS
732
+ 'regexp/no-unused-capturing-group': 'error',
733
+ 'regexp/no-useless-character-class': 'error',
734
+ 'regexp/no-useless-escape': 'error',
735
+ 'regexp/no-useless-flag': 'error',
736
+ 'regexp/no-useless-quantifier': 'error',
737
+ 'regexp/no-useless-range': 'error',
738
+ 'regexp/prefer-character-class': 'error',
739
+ 'regexp/prefer-d': 'error',
740
+ 'regexp/prefer-plus-quantifier': 'error',
741
+ 'regexp/prefer-star-quantifier': 'error',
742
+ 'regexp/prefer-w': 'error',
743
+
744
+ // Functional plugin rules - Immutability and functional programming
745
+ 'functional/no-let': 'warn', // Encourage const
746
+ 'functional/prefer-readonly-type': 'warn', // Readonly arrays/objects
747
+ 'functional/no-method-signature': 'off', // Allow method signatures in interfaces
748
+ 'functional/no-expression-statements': 'off', // Too restrictive for most code
749
+ 'functional/functional-parameters': 'off', // Too restrictive
750
+ 'functional/no-return-void': 'off', // Allow void returns
751
+ 'functional/no-conditional-statements': 'off', // Too restrictive
752
+ 'functional/no-loop-statements': 'warn', // Encourage functional alternatives
753
+ 'functional/immutable-data': ['warn', {
754
+ ignoreImmediateMutation: true,
755
+ ignoreAccessorPattern: ['**.current', '**.ref']
756
+ }],
757
+ 'functional/no-throw-statements': 'off', // Allow throwing errors
758
+ 'functional/no-try-statements': 'off', // Allow try-catch
759
+ 'functional/no-promise-reject': 'off', // Allow promise rejection
760
+
761
+ // Custom rules for coding standards compliance
762
+ 'unicorn/prefer-query-selector': 'off', // Allow different DOM query methods
763
+ 'unicorn/prevent-abbreviations': 'off', // Allow abbreviations for domain-specific terms
764
+
324
765
  // Allow custom rules to be added
325
766
  ...rules,
326
767
  },
package/package.json CHANGED
@@ -1,50 +1,71 @@
1
1
  {
2
2
  "name": "@dmitryrechkin/eslint-standard",
3
3
  "description": "This package provides a shared ESLint configuration which includes TypeScript support and a set of specific linting rules designed to ensure high-quality and consistent code style across projects.",
4
- "version": "1.2.0",
4
+ "version": "1.3.0",
5
5
  "main": "eslint.config.mjs",
6
6
  "bin": {
7
- "eslint-standard": "./src/cli/index.mjs"
7
+ "eslint-standard": "./src/cli/index.mjs"
8
8
  },
9
9
  "files": [
10
- "eslint.config.mjs",
11
- "src/",
12
- "docs/",
13
- "README.md",
14
- "LICENSE"
10
+ "eslint.config.mjs",
11
+ "src/",
12
+ "docs/",
13
+ "README.md",
14
+ "LICENSE"
15
15
  ],
16
16
  "scripts": {
17
- "postinstall": "node src/cli/postinstall.mjs",
18
- "package:publish": "npm publish --access public",
19
- "test": "node tests/test-all-rules.js",
20
- "test:all": "node tests/test-all-rules.js",
21
- "test:formatting": "node tests/test-runner.js",
22
- "test:complexity": "node tests/test-complexity-rules.js",
23
- "test:safety": "node tests/test-safety-rules.js",
24
- "test:cli": "node tests/test-cli.js",
25
- "test:install": "node tests/test-install-simulation.js"
17
+ "postinstall": "node src/cli/postinstall.mjs",
18
+ "package:publish": "npm publish --access public",
19
+ "test": "node tests/test-all-rules.js",
20
+ "test:all": "node tests/test-all-rules.js",
21
+ "test:formatting": "node tests/test-runner.js",
22
+ "test:complexity": "node tests/test-complexity-rules.js",
23
+ "test:safety": "node tests/test-safety-rules.js",
24
+ "test:security": "node tests/test-security-rules.js",
25
+ "test:sonarjs": "node tests/test-sonarjs-rules.js",
26
+ "test:unicorn": "node tests/test-unicorn-rules.js",
27
+ "test:cli": "node tests/test-cli.js",
28
+ "test:install": "node tests/test-install-simulation.js"
26
29
  },
27
30
  "keywords": [],
28
31
  "author": "",
29
32
  "license": "MIT",
30
33
  "peerDependencies": {
31
- "@typescript-eslint/eslint-plugin": "^8.0.0",
32
- "@typescript-eslint/parser": "^8.0.0",
33
- "eslint": "^9.0.0",
34
- "eslint-plugin-unused-imports": "^4.0.0",
35
- "@stylistic/eslint-plugin": "^5.0.0",
36
- "eslint-plugin-jsdoc": "^50.0.0",
37
- "eslint-plugin-simple-import-sort": "^12.0.0",
38
- "eslint-plugin-perfectionist": "^4.0.0"
34
+ "@stylistic/eslint-plugin": "^5.0.0",
35
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
36
+ "@typescript-eslint/parser": "^8.0.0",
37
+ "eslint": "^9.0.0",
38
+ "eslint-plugin-functional": "^7.0.0",
39
+ "eslint-plugin-import": "^2.0.0",
40
+ "eslint-plugin-jsdoc": "^50.0.0",
41
+ "eslint-plugin-jsx-a11y": "^6.0.0",
42
+ "eslint-plugin-no-secrets": "^1.0.0",
43
+ "eslint-plugin-perfectionist": "^4.0.0",
44
+ "eslint-plugin-promise": "^7.0.0",
45
+ "eslint-plugin-regexp": "^2.0.0",
46
+ "eslint-plugin-security": "^3.0.0",
47
+ "eslint-plugin-simple-import-sort": "^12.0.0",
48
+ "eslint-plugin-sonarjs": "^3.0.0",
49
+ "eslint-plugin-unicorn": "^56.0.0",
50
+ "eslint-plugin-unused-imports": "^4.0.0"
39
51
  },
40
52
  "devDependencies": {
41
- "@typescript-eslint/eslint-plugin": "^8.36.0",
42
- "@typescript-eslint/parser": "^8.36.0",
43
- "eslint": "^9.31.0",
44
- "eslint-plugin-unused-imports": "^4.1.4",
45
- "@stylistic/eslint-plugin": "^5.1.0",
46
- "eslint-plugin-jsdoc": "^50.6.0",
47
- "eslint-plugin-simple-import-sort": "^12.1.1",
48
- "eslint-plugin-perfectionist": "^4.15.0"
53
+ "@stylistic/eslint-plugin": "^5.2.2",
54
+ "@typescript-eslint/eslint-plugin": "^8.38.0",
55
+ "@typescript-eslint/parser": "^8.38.0",
56
+ "eslint": "^9.32.0",
57
+ "eslint-plugin-functional": "^7.3.0",
58
+ "eslint-plugin-import": "^2.32.0",
59
+ "eslint-plugin-jsdoc": "^50.8.0",
60
+ "eslint-plugin-jsx-a11y": "^6.10.2",
61
+ "eslint-plugin-no-secrets": "^1.1.2",
62
+ "eslint-plugin-perfectionist": "^4.15.0",
63
+ "eslint-plugin-promise": "^7.2.1",
64
+ "eslint-plugin-regexp": "^2.9.0",
65
+ "eslint-plugin-security": "^3.0.1",
66
+ "eslint-plugin-simple-import-sort": "^12.1.1",
67
+ "eslint-plugin-sonarjs": "^3.0.4",
68
+ "eslint-plugin-unicorn": "^56.0.1",
69
+ "eslint-plugin-unused-imports": "^4.1.4"
49
70
  }
50
- }
71
+ }