@dmitryrechkin/eslint-standard 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/eslint.config.mjs +505 -50
  2. package/package.json +56 -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,8 +48,28 @@ 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
  },
62
+ settings: {
63
+ 'import/resolver': {
64
+ node: {
65
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
66
+ },
67
+ },
68
+ 'import/parsers': {
69
+ '@typescript-eslint/parser': ['.ts', '.tsx'],
70
+ },
71
+ 'import/extensions': ['.js', '.jsx', '.ts', '.tsx'],
72
+ },
44
73
  rules: {
45
74
  // Original @dmitryrechkin/eslint-standard rules
46
75
  '@typescript-eslint/explicit-function-return-type': 'error',
@@ -63,56 +92,7 @@ export default function ({
63
92
  'comma-dangle': 'off', // Disabled in favor of @stylistic/comma-dangle
64
93
  '@stylistic/comma-dangle': ['error', 'never'],
65
94
 
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
- ],
95
+ // Comprehensive naming conventions based on coding standards
116
96
 
117
97
  // Original unused-imports rules
118
98
  'unused-imports/no-unused-imports': 'error',
@@ -202,6 +182,181 @@ export default function ({
202
182
  // Enhanced: Interface brace style
203
183
  'interface-brace/interface-brace-style': 'error',
204
184
 
185
+ // Additional naming conventions based on coding standards
186
+ '@typescript-eslint/naming-convention': [
187
+ 'warn',
188
+ // Existing rules remain the same...
189
+ {
190
+ selector: 'variableLike',
191
+ format: ['camelCase'],
192
+ leadingUnderscore: 'forbid',
193
+ },
194
+ {
195
+ selector: 'variable',
196
+ modifiers: ['const'],
197
+ format: ['camelCase', 'UPPER_CASE'],
198
+ leadingUnderscore: 'forbid',
199
+ },
200
+ {
201
+ selector: 'variable',
202
+ format: ['camelCase'],
203
+ leadingUnderscore: 'forbid',
204
+ custom: {
205
+ 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)$',
206
+ match: false
207
+ }
208
+ },
209
+ {
210
+ selector: 'function',
211
+ format: ['camelCase'],
212
+ leadingUnderscore: 'forbid',
213
+ custom: {
214
+ 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)$',
215
+ match: false
216
+ }
217
+ },
218
+ {
219
+ selector: 'method',
220
+ format: ['camelCase'],
221
+ leadingUnderscore: 'forbid',
222
+ custom: {
223
+ 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)$',
224
+ match: false
225
+ }
226
+ },
227
+ {
228
+ selector: 'method',
229
+ modifiers: ['public'],
230
+ format: ['camelCase'],
231
+ leadingUnderscore: 'forbid'
232
+ // Allow generic names for public methods
233
+ },
234
+ // Services must end with 'Service'
235
+ {
236
+ selector: 'class',
237
+ filter: {
238
+ regex: 'Service$',
239
+ match: true
240
+ },
241
+ format: ['PascalCase'],
242
+ custom: {
243
+ regex: '^[A-Z][a-zA-Z]*Service$',
244
+ match: true
245
+ }
246
+ },
247
+ // Repositories must end with 'Repository'
248
+ {
249
+ selector: 'class',
250
+ filter: {
251
+ regex: 'Repository$',
252
+ match: true
253
+ },
254
+ format: ['PascalCase'],
255
+ custom: {
256
+ regex: '^[A-Z][a-zA-Z]*(Command|Query)?Repository$',
257
+ match: true
258
+ }
259
+ },
260
+ // Helpers must end with 'Helper'
261
+ {
262
+ selector: 'class',
263
+ filter: {
264
+ regex: 'Helper$',
265
+ match: true
266
+ },
267
+ format: ['PascalCase'],
268
+ custom: {
269
+ regex: '^[A-Z][a-zA-Z]*Helper$',
270
+ match: true
271
+ }
272
+ },
273
+ // Factories must end with 'Factory'
274
+ {
275
+ selector: 'class',
276
+ filter: {
277
+ regex: 'Factory$',
278
+ match: true
279
+ },
280
+ format: ['PascalCase'],
281
+ custom: {
282
+ regex: '^[A-Z][a-zA-Z]*Factory$',
283
+ match: true
284
+ }
285
+ },
286
+ // General class naming (excluding specific patterns above)
287
+ {
288
+ selector: 'class',
289
+ format: ['PascalCase'],
290
+ leadingUnderscore: 'forbid',
291
+ custom: {
292
+ 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)$',
293
+ match: false
294
+ }
295
+ },
296
+ {
297
+ selector: 'interface',
298
+ format: ['PascalCase'],
299
+ leadingUnderscore: 'forbid',
300
+ custom: {
301
+ regex: 'Interface$',
302
+ match: true
303
+ }
304
+ },
305
+ {
306
+ selector: 'typeAlias',
307
+ format: ['PascalCase'],
308
+ leadingUnderscore: 'forbid',
309
+ custom: {
310
+ regex: '^Type[A-Z]',
311
+ match: true
312
+ }
313
+ },
314
+ {
315
+ selector: 'parameter',
316
+ format: ['camelCase'],
317
+ leadingUnderscore: 'forbid',
318
+ custom: {
319
+ regex: '^_',
320
+ match: false,
321
+ },
322
+ },
323
+ {
324
+ selector: 'parameter',
325
+ format: null,
326
+ leadingUnderscore: 'require',
327
+ modifiers: ['unused'],
328
+ },
329
+ {
330
+ selector: 'memberLike',
331
+ format: ['camelCase'],
332
+ leadingUnderscore: 'forbid',
333
+ },
334
+ {
335
+ selector: 'property',
336
+ modifiers: ['readonly'],
337
+ format: ['camelCase', 'UPPER_CASE'],
338
+ leadingUnderscore: 'forbid',
339
+ },
340
+ {
341
+ selector: 'enumMember',
342
+ format: ['camelCase', 'UPPER_CASE'],
343
+ leadingUnderscore: 'forbid',
344
+ },
345
+ // Schema table files must end with 'Table'
346
+ {
347
+ selector: 'variable',
348
+ filter: {
349
+ regex: 'Table$',
350
+ match: true
351
+ },
352
+ format: ['camelCase'],
353
+ custom: {
354
+ regex: '[a-z][a-zA-Z]*Table$',
355
+ match: true
356
+ }
357
+ }
358
+ ],
359
+
205
360
  // Code Complexity Rules (industry standards)
206
361
  'complexity': ['error', 10], // Cyclomatic complexity - max 10 paths through a function
207
362
  'max-lines-per-function': ['error', {
@@ -321,6 +476,306 @@ export default function ({
321
476
  ignoreClassFieldInitialValues: true
322
477
  }], // Named constants for magic numbers
323
478
 
479
+ // Identifier length rules
480
+ 'id-length': ['warn', {
481
+ min: 3,
482
+ exceptions: ['i', 'j', 'k', 'x', 'y', 'z', 'id', 'db', 'fs', 'os', 'io', 'ui', 'vm', '_', 'idx'],
483
+ properties: 'never' // Don't apply to object properties
484
+ }],
485
+
486
+ // Security plugin rules
487
+ 'security/detect-eval-with-expression': 'error',
488
+ 'security/detect-non-literal-fs-filename': 'warn',
489
+ 'security/detect-non-literal-regexp': 'warn',
490
+ 'security/detect-unsafe-regex': 'error',
491
+ 'security/detect-buffer-noassert': 'error',
492
+ 'security/detect-child-process': 'warn',
493
+ 'security/detect-disable-mustache-escape': 'error',
494
+ 'security/detect-no-csrf-before-method-override': 'error',
495
+ 'security/detect-object-injection': 'warn',
496
+ 'security/detect-possible-timing-attacks': 'warn',
497
+ 'security/detect-pseudoRandomBytes': 'error',
498
+
499
+ // Promise plugin rules
500
+ 'promise/always-return': 'error',
501
+ 'promise/no-return-wrap': 'error',
502
+ 'promise/param-names': 'error',
503
+ 'promise/catch-or-return': 'error',
504
+ 'promise/no-native': 'off',
505
+ 'promise/no-nesting': 'warn',
506
+ 'promise/no-promise-in-callback': 'warn',
507
+ 'promise/no-callback-in-promise': 'warn',
508
+ 'promise/avoid-new': 'off',
509
+ 'promise/no-new-statics': 'error',
510
+ 'promise/no-return-in-finally': 'error',
511
+ 'promise/valid-params': 'error',
512
+ 'promise/prefer-await-to-then': 'warn',
513
+ 'promise/prefer-await-to-callbacks': 'warn',
514
+
515
+ // Import plugin rules
516
+ 'import/no-unresolved': ['error', {
517
+ ignore: ['\\.ts$', '\\.tsx$'],
518
+ caseSensitive: false
519
+ }],
520
+ 'import/named': 'error',
521
+ 'import/default': 'error',
522
+ 'import/namespace': 'error',
523
+ 'import/no-restricted-paths': 'off',
524
+ 'import/no-absolute-path': 'error',
525
+ 'import/no-dynamic-require': 'error',
526
+ 'import/no-internal-modules': 'off',
527
+ 'import/no-webpack-loader-syntax': 'error',
528
+ 'import/no-self-import': 'error',
529
+ 'import/no-cycle': ['error', { maxDepth: 3 }],
530
+ 'import/no-useless-path-segments': 'error',
531
+ 'import/no-relative-parent-imports': 'off',
532
+ 'import/export': 'error',
533
+ 'import/no-named-as-default': 'error',
534
+ 'import/no-named-as-default-member': 'error',
535
+ 'import/no-deprecated': 'warn',
536
+ 'import/no-extraneous-dependencies': ['error', {
537
+ devDependencies: ['**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}', '**/test/**', '**/tests/**', '**/__tests__/**']
538
+ }],
539
+ 'import/no-mutable-exports': 'error',
540
+ 'import/no-unused-modules': 'off', // Disabled due to .eslintrc requirement in flat config
541
+ 'import/unambiguous': 'off',
542
+ 'import/no-commonjs': 'off',
543
+ 'import/no-amd': 'error',
544
+ 'import/no-nodejs-modules': 'off',
545
+ 'import/first': 'error',
546
+ 'import/exports-last': 'off',
547
+ 'import/no-duplicates': 'error',
548
+ 'import/no-namespace': 'off',
549
+ 'import/extensions': ['error', 'ignorePackages', {
550
+ js: 'never',
551
+ jsx: 'never',
552
+ ts: 'never',
553
+ tsx: 'never'
554
+ }],
555
+ 'import/newline-after-import': 'error',
556
+ 'import/prefer-default-export': 'off',
557
+ 'import/max-dependencies': ['warn', { max: 20 }],
558
+ 'import/no-unassigned-import': 'off',
559
+ 'import/no-named-default': 'error',
560
+ 'import/no-default-export': 'off',
561
+ 'import/no-named-export': 'off',
562
+ 'import/no-anonymous-default-export': 'warn',
563
+ 'import/group-exports': 'off',
564
+ 'import/dynamic-import-chunkname': 'off',
565
+
566
+ // JSX A11y plugin rules (only active for React/JSX files)
567
+ 'jsx-a11y/alt-text': 'error',
568
+ 'jsx-a11y/anchor-has-content': 'error',
569
+ 'jsx-a11y/anchor-is-valid': 'error',
570
+ 'jsx-a11y/aria-props': 'error',
571
+ 'jsx-a11y/aria-role': 'error',
572
+ 'jsx-a11y/aria-unsupported-elements': 'error',
573
+ 'jsx-a11y/click-events-have-key-events': 'warn',
574
+ 'jsx-a11y/heading-has-content': 'error',
575
+ 'jsx-a11y/html-has-lang': 'error',
576
+ 'jsx-a11y/iframe-has-title': 'error',
577
+ 'jsx-a11y/img-redundant-alt': 'error',
578
+ 'jsx-a11y/interactive-supports-focus': 'error',
579
+ 'jsx-a11y/label-has-associated-control': 'error',
580
+ 'jsx-a11y/media-has-caption': 'warn',
581
+ 'jsx-a11y/mouse-events-have-key-events': 'warn',
582
+ 'jsx-a11y/no-access-key': 'error',
583
+ 'jsx-a11y/no-autofocus': 'warn',
584
+ 'jsx-a11y/no-distracting-elements': 'error',
585
+ 'jsx-a11y/no-interactive-element-to-noninteractive-role': 'error',
586
+ 'jsx-a11y/no-noninteractive-element-interactions': 'warn',
587
+ 'jsx-a11y/no-noninteractive-element-to-interactive-role': 'error',
588
+ 'jsx-a11y/no-redundant-roles': 'error',
589
+ 'jsx-a11y/no-static-element-interactions': 'warn',
590
+ 'jsx-a11y/role-has-required-aria-props': 'error',
591
+ 'jsx-a11y/role-supports-aria-props': 'error',
592
+ 'jsx-a11y/scope': 'error',
593
+ 'jsx-a11y/tabindex-no-positive': 'error',
594
+
595
+ // SonarJS plugin rules - Code smells and cognitive complexity
596
+ 'sonarjs/cognitive-complexity': ['error', 15], // More sophisticated than cyclomatic
597
+ 'sonarjs/no-identical-expressions': 'error',
598
+ 'sonarjs/no-identical-functions': 'error',
599
+ 'sonarjs/no-duplicate-string': ['error', { threshold: 3 }],
600
+ 'sonarjs/prefer-immediate-return': 'error',
601
+ 'sonarjs/prefer-object-literal': 'error',
602
+ 'sonarjs/prefer-single-boolean-return': 'error',
603
+ 'sonarjs/no-redundant-boolean': 'error',
604
+ 'sonarjs/no-unused-collection': 'error',
605
+ 'sonarjs/no-useless-catch': 'error',
606
+ 'sonarjs/prefer-while': 'error',
607
+ 'sonarjs/max-switch-cases': ['error', 30],
608
+ 'sonarjs/no-nested-switch': 'error',
609
+ 'sonarjs/no-nested-template-literals': 'error',
610
+ 'sonarjs/no-redundant-jump': 'error',
611
+ 'sonarjs/no-same-line-conditional': 'error',
612
+ 'sonarjs/non-existent-operator': 'error',
613
+
614
+ // Unicorn plugin rules - Modern JavaScript best practices
615
+ 'unicorn/better-regex': 'error',
616
+ 'unicorn/catch-error-name': 'error',
617
+ 'unicorn/consistent-destructuring': 'error',
618
+ 'unicorn/consistent-function-scoping': 'error',
619
+ 'unicorn/custom-error-definition': 'error',
620
+ 'unicorn/error-message': 'error',
621
+ 'unicorn/escape-case': 'error',
622
+ 'unicorn/expiring-todo-comments': 'error',
623
+ 'unicorn/explicit-length-check': 'error',
624
+ 'unicorn/filename-case': ['warn', {
625
+ cases: {
626
+ camelCase: true, // For folders: userAuth, licenseActivation
627
+ pascalCase: true, // For class files: UserService.ts
628
+ }
629
+ }],
630
+ 'unicorn/import-style': 'error',
631
+ 'unicorn/new-for-builtins': 'error',
632
+ 'unicorn/no-abusive-eslint-disable': 'error',
633
+ 'unicorn/no-array-callback-reference': 'error',
634
+ 'unicorn/no-array-for-each': 'error',
635
+ 'unicorn/no-array-method-this-argument': 'error',
636
+ 'unicorn/no-array-push-push': 'error',
637
+ 'unicorn/no-array-reduce': 'warn',
638
+ 'unicorn/no-await-expression-member': 'error',
639
+ 'unicorn/no-console-spaces': 'error',
640
+ 'unicorn/no-document-cookie': 'error',
641
+ 'unicorn/no-empty-file': 'error',
642
+ 'unicorn/no-for-loop': 'error',
643
+ 'unicorn/no-hex-escape': 'error',
644
+ 'unicorn/no-instanceof-array': 'error',
645
+ 'unicorn/no-invalid-remove-event-listener': 'error',
646
+ 'unicorn/no-keyword-prefix': 'off',
647
+ 'unicorn/no-lonely-if': 'error',
648
+ 'unicorn/no-nested-ternary': 'error',
649
+ 'unicorn/no-new-array': 'error',
650
+ 'unicorn/no-new-buffer': 'error',
651
+ 'unicorn/no-null': 'error', // Use undefined instead of null per coding standards
652
+ 'unicorn/no-object-as-default-parameter': 'error',
653
+ 'unicorn/no-process-exit': 'error',
654
+ 'unicorn/no-static-only-class': 'error',
655
+ 'unicorn/no-thenable': 'error',
656
+ 'unicorn/no-this-assignment': 'error',
657
+ 'unicorn/no-typeof-undefined': 'error',
658
+ 'unicorn/no-unnecessary-await': 'error',
659
+ 'unicorn/no-unreadable-array-destructuring': 'error',
660
+ 'unicorn/no-unreadable-iife': 'error',
661
+ 'unicorn/no-unsafe-regex': 'error',
662
+ 'unicorn/no-unused-properties': 'off',
663
+ 'unicorn/no-useless-fallback-in-spread': 'error',
664
+ 'unicorn/no-useless-length-check': 'error',
665
+ 'unicorn/no-useless-promise-resolve-reject': 'error',
666
+ 'unicorn/no-useless-spread': 'error',
667
+ 'unicorn/no-useless-switch-case': 'error',
668
+ 'unicorn/no-zero-fractions': 'error',
669
+ 'unicorn/number-literal-case': 'error',
670
+ 'unicorn/numeric-separators-style': 'error',
671
+ 'unicorn/prefer-add-event-listener': 'error',
672
+ 'unicorn/prefer-array-find': 'error',
673
+ 'unicorn/prefer-array-flat': 'error',
674
+ 'unicorn/prefer-array-flat-map': 'error',
675
+ 'unicorn/prefer-array-index-of': 'error',
676
+ 'unicorn/prefer-array-some': 'error',
677
+ 'unicorn/prefer-at': 'error',
678
+ 'unicorn/prefer-code-point': 'error',
679
+ 'unicorn/prefer-date-now': 'error',
680
+ 'unicorn/prefer-default-parameters': 'error',
681
+ 'unicorn/prefer-dom-node-append': 'error',
682
+ 'unicorn/prefer-dom-node-dataset': 'error',
683
+ 'unicorn/prefer-dom-node-remove': 'error',
684
+ 'unicorn/prefer-dom-node-text-content': 'error',
685
+ 'unicorn/prefer-includes': 'error',
686
+ 'unicorn/prefer-json-parse-buffer': 'off',
687
+ 'unicorn/prefer-keyboard-event-key': 'error',
688
+ 'unicorn/prefer-logical-operator-over-ternary': 'error',
689
+ 'unicorn/prefer-math-trunc': 'error',
690
+ 'unicorn/prefer-modern-dom-apis': 'error',
691
+ 'unicorn/prefer-modern-math-apis': 'error',
692
+ 'unicorn/prefer-module': 'error',
693
+ 'unicorn/prefer-native-coercion-functions': 'error',
694
+ 'unicorn/prefer-negative-index': 'error',
695
+ 'unicorn/prefer-node-protocol': 'error',
696
+ 'unicorn/prefer-number-properties': 'error',
697
+ 'unicorn/prefer-object-from-entries': 'error',
698
+ 'unicorn/prefer-optional-catch-binding': 'error',
699
+ 'unicorn/prefer-prototype-methods': 'error',
700
+ 'unicorn/prefer-query-selector': 'error',
701
+ 'unicorn/prefer-reflect-apply': 'error',
702
+ 'unicorn/prefer-regexp-test': 'error',
703
+ 'unicorn/prefer-set-has': 'error',
704
+ 'unicorn/prefer-set-size': 'error',
705
+ 'unicorn/prefer-spread': 'error',
706
+ 'unicorn/prefer-string-replace-all': 'error',
707
+ 'unicorn/prefer-string-slice': 'error',
708
+ 'unicorn/prefer-string-starts-ends-with': 'error',
709
+ 'unicorn/prefer-string-trim-start-end': 'error',
710
+ 'unicorn/prefer-switch': 'error',
711
+ 'unicorn/prefer-ternary': 'error',
712
+ 'unicorn/prefer-top-level-await': 'error',
713
+ 'unicorn/prefer-type-error': 'error',
714
+ 'unicorn/prevent-abbreviations': 'off', // Too aggressive for existing code
715
+ 'unicorn/relative-url-style': 'error',
716
+ 'unicorn/require-array-join-separator': 'error',
717
+ 'unicorn/require-number-to-fixed-digits-argument': 'error',
718
+ 'unicorn/require-post-message-target-origin': 'error',
719
+ 'unicorn/string-content': 'off',
720
+ 'unicorn/switch-case-braces': 'error',
721
+ 'unicorn/template-indent': 'warn',
722
+ 'unicorn/text-encoding-identifier-case': 'error',
723
+ 'unicorn/throw-new-error': 'error',
724
+
725
+ // No Secrets plugin rules - Prevent secrets in code
726
+ 'no-secrets/no-secrets': ['error', {
727
+ tolerance: 4.2,
728
+ ignoreContent: '^CHANGE ME$',
729
+ ignoreModules: true,
730
+ ignoreIdentifiers: ['BASE64_CHARS', 'HEX_CHARS'],
731
+ additionalRegexes: {
732
+ 'AWS Access Key': 'AKIA[0-9A-Z]{16}',
733
+ 'GitHub Token': 'ghp_[a-zA-Z0-9]{36}',
734
+ 'JWT Token': 'eyJ[a-zA-Z0-9_-]*\\.[a-zA-Z0-9_-]*\\.[a-zA-Z0-9_-]*'
735
+ }
736
+ }],
737
+
738
+ // RegExp plugin rules - Essential RegExp safety (conservative set for v2.9.0)
739
+ 'regexp/no-control-character': 'error',
740
+ 'regexp/no-empty-character-class': 'error',
741
+ 'regexp/no-empty-group': 'error',
742
+ 'regexp/no-invalid-regexp': 'error',
743
+ 'regexp/no-misleading-capturing-group': 'error',
744
+ 'regexp/no-misleading-unicode-character': 'error',
745
+ 'regexp/no-super-linear-backtracking': 'error', // Prevents ReDoS
746
+ 'regexp/no-unused-capturing-group': 'error',
747
+ 'regexp/no-useless-character-class': 'error',
748
+ 'regexp/no-useless-escape': 'error',
749
+ 'regexp/no-useless-flag': 'error',
750
+ 'regexp/no-useless-quantifier': 'error',
751
+ 'regexp/no-useless-range': 'error',
752
+ 'regexp/prefer-character-class': 'error',
753
+ 'regexp/prefer-d': 'error',
754
+ 'regexp/prefer-plus-quantifier': 'error',
755
+ 'regexp/prefer-star-quantifier': 'error',
756
+ 'regexp/prefer-w': 'error',
757
+
758
+ // Functional plugin rules - Immutability and functional programming
759
+ 'functional/no-let': 'warn', // Encourage const
760
+ 'functional/prefer-readonly-type': 'warn', // Readonly arrays/objects
761
+ 'functional/no-method-signature': 'off', // Allow method signatures in interfaces
762
+ 'functional/no-expression-statements': 'off', // Too restrictive for most code
763
+ 'functional/functional-parameters': 'off', // Too restrictive
764
+ 'functional/no-return-void': 'off', // Allow void returns
765
+ 'functional/no-conditional-statements': 'off', // Too restrictive
766
+ 'functional/no-loop-statements': 'warn', // Encourage functional alternatives
767
+ 'functional/immutable-data': ['warn', {
768
+ ignoreImmediateMutation: true,
769
+ ignoreAccessorPattern: ['**.current', '**.ref']
770
+ }],
771
+ 'functional/no-throw-statements': 'off', // Allow throwing errors
772
+ 'functional/no-try-statements': 'off', // Allow try-catch
773
+ 'functional/no-promise-reject': 'off', // Allow promise rejection
774
+
775
+ // Custom rules for coding standards compliance
776
+ 'unicorn/prefer-query-selector': 'off', // Allow different DOM query methods
777
+ 'unicorn/prevent-abbreviations': 'off', // Allow abbreviations for domain-specific terms
778
+
324
779
  // Allow custom rules to be added
325
780
  ...rules,
326
781
  },
package/package.json CHANGED
@@ -1,50 +1,73 @@
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.1",
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-import-resolver-typescript": "^3.0.0",
41
+ "eslint-plugin-jsdoc": "^50.0.0",
42
+ "eslint-plugin-jsx-a11y": "^6.0.0",
43
+ "eslint-plugin-no-secrets": "^1.0.0",
44
+ "eslint-plugin-perfectionist": "^4.0.0",
45
+ "eslint-plugin-promise": "^7.0.0",
46
+ "eslint-plugin-regexp": "^2.0.0",
47
+ "eslint-plugin-security": "^3.0.0",
48
+ "eslint-plugin-simple-import-sort": "^12.0.0",
49
+ "eslint-plugin-sonarjs": "^3.0.0",
50
+ "eslint-plugin-unicorn": "^56.0.0",
51
+ "eslint-plugin-unused-imports": "^4.0.0"
39
52
  },
40
53
  "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"
54
+ "@stylistic/eslint-plugin": "^5.2.2",
55
+ "@typescript-eslint/eslint-plugin": "^8.38.0",
56
+ "@typescript-eslint/parser": "^8.38.0",
57
+ "eslint": "^9.32.0",
58
+ "eslint-plugin-functional": "^7.3.0",
59
+ "eslint-plugin-import": "^2.32.0",
60
+ "eslint-import-resolver-typescript": "^3.6.3",
61
+ "eslint-plugin-jsdoc": "^50.8.0",
62
+ "eslint-plugin-jsx-a11y": "^6.10.2",
63
+ "eslint-plugin-no-secrets": "^1.1.2",
64
+ "eslint-plugin-perfectionist": "^4.15.0",
65
+ "eslint-plugin-promise": "^7.2.1",
66
+ "eslint-plugin-regexp": "^2.9.0",
67
+ "eslint-plugin-security": "^3.0.1",
68
+ "eslint-plugin-simple-import-sort": "^12.1.1",
69
+ "eslint-plugin-sonarjs": "^3.0.4",
70
+ "eslint-plugin-unicorn": "^56.0.1",
71
+ "eslint-plugin-unused-imports": "^4.1.4"
49
72
  }
50
- }
73
+ }