lint-suite 1.0.4 → 1.0.6

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/index.js CHANGED
@@ -5,6 +5,8 @@ var angularTemplate = [
5
5
  {
6
6
  files: ["**/*.html"],
7
7
  rules: {
8
+ "@angular-eslint/template/no-any": "error",
9
+ "@angular-eslint/template/no-duplicate-attributes": "error",
8
10
  "@angular-eslint/template/button-has-type": "error",
9
11
  "@angular-eslint/template/no-positive-tabindex": "error",
10
12
  "@angular-eslint/template/valid-aria": "error",
@@ -56,8 +58,8 @@ var angular = [
56
58
 
57
59
  // packages/lint-suite/src/lib/base.ts
58
60
  import nx3 from "@nx/eslint-plugin";
59
- import importPlugin from "eslint-plugin-import";
60
61
  import stylistic from "@stylistic/eslint-plugin";
62
+ import importPluginX from "eslint-plugin-import-x";
61
63
  var base = [
62
64
  ...nx3.configs["flat/base"],
63
65
  {
@@ -71,7 +73,7 @@ var base = [
71
73
  "**/*.cts",
72
74
  "**/*.mts"
73
75
  ],
74
- ...importPlugin.flatConfigs.recommended
76
+ ...importPluginX.flatConfigs.recommended
75
77
  },
76
78
  {
77
79
  files: [
@@ -98,8 +100,60 @@ var base = [
98
100
  "**/*.mts"
99
101
  ],
100
102
  rules: {
101
- "no-console": "warn",
103
+ "no-param-reassign": "error",
104
+ "no-alert": "error",
105
+ "no-console": ["warn", { allow: ["warn", "error"] }],
106
+ "no-debugger": "error",
107
+ eqeqeq: ["error", "always", { null: "ignore" }],
108
+ curly: ["error", "all"],
109
+ "prefer-const": ["error", { destructuring: "all" }],
110
+ "no-var": "error",
111
+ "object-shorthand": "error",
112
+ "prefer-arrow-callback": "error",
113
+ "no-useless-concat": "error",
114
+ "prefer-template": "error",
115
+ "no-nested-ternary": "error",
116
+ "no-return-await": "error",
117
+ "no-else-return": ["error", { allowElseIf: false }],
118
+ // Prefer early returns
119
+ "no-multi-assign": "error",
120
+ // Disallow chaining assignments
121
+ radix: "error",
122
+ // Require radix parameter for parseInt()
123
+ yoda: "error",
124
+ // Disallow yoda conditions (`if ("red" === color)`)
125
+ complexity: ["warn", 10],
126
+ // Warn if function complexity is high
127
+ "max-depth": ["warn", 4],
128
+ // Warn on deeply nested blocks
129
+ "max-lines-per-function": ["warn", 50],
130
+ // Warn on long functions
131
+ "max-params": ["warn", 4],
132
+ // Warn on functions with many parameters
133
+ "no-lonely-if": "error",
134
+ // Disallow if statements as the only statement in an else block
135
+ "grouped-accessor-pairs": ["error", "getBeforeSet"],
136
+ // Enforce consistency for getters/setters
102
137
  "class-methods-use-this": "error",
138
+ "no-underscore-dangle": "error",
139
+ "padding-line-between-statements": [
140
+ "error",
141
+ {
142
+ blankLine: "always",
143
+ prev: "export",
144
+ next: ["export", "const"]
145
+ },
146
+ {
147
+ blankLine: "always",
148
+ prev: "*",
149
+ next: "return"
150
+ },
151
+ {
152
+ blankLine: "always",
153
+ prev: "*",
154
+ next: "if"
155
+ }
156
+ ],
103
157
  "max-len": [
104
158
  "error",
105
159
  {
@@ -177,6 +231,8 @@ var base = [
177
231
  {
178
232
  files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
179
233
  rules: {
234
+ "max-lines-per-function": "off",
235
+ complexity: ["warn", { max: 1 }],
180
236
  "max-lines": [
181
237
  "error",
182
238
  {
@@ -186,35 +242,6 @@ var base = [
186
242
  }
187
243
  ]
188
244
  }
189
- }
190
- ];
191
-
192
- // packages/lint-suite/src/lib/typescript.ts
193
- import nx4 from "@nx/eslint-plugin";
194
- import importPlugin2 from "eslint-plugin-import";
195
- var typescript = [
196
- // NOTE: Checks for 'prettier' and 'eslint-plugin-prettier'
197
- importPlugin2.flatConfigs.typescript,
198
- ...nx4.configs["flat/typescript"],
199
- {
200
- files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
201
- rules: {
202
- "@typescript-eslint/explicit-member-accessibility": "error",
203
- "@typescript-eslint/consistent-type-imports": "error",
204
- "@typescript-eslint/explicit-function-return-type": "warn",
205
- "@typescript-eslint/no-empty-function": "error"
206
- }
207
- },
208
- {
209
- files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
210
- languageOptions: {
211
- parserOptions: {
212
- projectService: true
213
- }
214
- },
215
- rules: {
216
- "@typescript-eslint/prefer-readonly": "error"
217
- }
218
245
  },
219
246
  {
220
247
  files: ["**/*.action.ts"],
@@ -230,15 +257,17 @@ var typescript = [
230
257
  }
231
258
  ];
232
259
 
260
+ // packages/lint-suite/src/lib/javascript.ts
261
+ import nx4 from "@nx/eslint-plugin";
262
+ var javascript = nx4.configs["flat/javascript"];
263
+
233
264
  // packages/lint-suite/src/lib/jest.ts
234
265
  import jestEslint from "eslint-plugin-jest";
235
266
  var jest = [
236
267
  {
237
268
  files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
238
- ...jestEslint.configs["flat/recommended"],
269
+ ...jestEslint.configs["flat/all"],
239
270
  rules: {
240
- ...jestEslint.configs["flat/recommended"].rules,
241
- ...jestEslint.configs["flat/style"].rules,
242
271
  "jest/no-done-callback": "off"
243
272
  }
244
273
  }
@@ -303,6 +332,7 @@ var rxjs = [
303
332
  rules: {
304
333
  "rxjs/prefer-observer": "error",
305
334
  "rxjs/finnish": "warn",
335
+ "rxjs/no-ignored-subscription": "warn",
306
336
  "rxjs/no-ignored-error": "warn",
307
337
  "rxjs/no-unsafe-switchmap": "error",
308
338
  "rxjs/no-unsafe-takeuntil": "error",
@@ -327,13 +357,370 @@ var storybook = [
327
357
  ...storybookEslint.configs["flat/recommended"],
328
358
  {
329
359
  ignores: ["!.storybook"],
330
- files: ["**/*.stories.ts"]
360
+ files: ["**/*.stories.ts"],
361
+ rules: {
362
+ "storybook/no-uninstalled-addons": [
363
+ "error",
364
+ { packageJsonLocation: "package.json" }
365
+ ]
366
+ }
331
367
  }
332
368
  ];
333
369
 
334
- // packages/lint-suite/src/lib/javascript.ts
370
+ // packages/lint-suite/src/lib/typescript.ts
335
371
  import nx5 from "@nx/eslint-plugin";
336
- var javascript = [...nx5.configs["flat/javascript"]];
372
+ import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript";
373
+ import importPluginX2 from "eslint-plugin-import-x";
374
+
375
+ // packages/lint-suite/src/lib/rules/explicit-accessibility.ts
376
+ import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
377
+ var createRule = ESLintUtils.RuleCreator(
378
+ () => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
379
+ );
380
+ var defaultOptions = {
381
+ defaultAccessibility: "private"
382
+ };
383
+ var getNodeName = (node) => {
384
+ if (!node) {
385
+ return "<unknown>";
386
+ }
387
+ if ("key" in node && node.key) {
388
+ if (node.key.type === TSESTree.AST_NODE_TYPES.Identifier) {
389
+ return node.key.name;
390
+ }
391
+ if (node.key.type === TSESTree.AST_NODE_TYPES.PrivateIdentifier) {
392
+ return `#${node.key.name}`;
393
+ }
394
+ return "<computed/complex key>";
395
+ }
396
+ if ("kind" in node && node.kind === "constructor") {
397
+ return "constructor";
398
+ }
399
+ if (node.type === TSESTree.AST_NODE_TYPES.TSParameterProperty) {
400
+ const param = node.parameter;
401
+ if (param.type === TSESTree.AST_NODE_TYPES.Identifier) {
402
+ return param.name;
403
+ }
404
+ if (param.type === TSESTree.AST_NODE_TYPES.AssignmentPattern) {
405
+ if (param.left.type === TSESTree.AST_NODE_TYPES.Identifier) {
406
+ return param.left.name;
407
+ }
408
+ return "<destructured parameter>";
409
+ }
410
+ if (param.type === TSESTree.AST_NODE_TYPES.RestElement && param.argument.type === TSESTree.AST_NODE_TYPES.Identifier) {
411
+ return `...${param.argument.name}`;
412
+ }
413
+ return "<complex parameter>";
414
+ }
415
+ return "<unknown>";
416
+ };
417
+ var explicit_accessibility_default = createRule({
418
+ name: "explicit-accessibility",
419
+ meta: {
420
+ type: "suggestion",
421
+ docs: {
422
+ description: "Require explicit accessibility modifiers on class members"
423
+ },
424
+ fixable: "code",
425
+ schema: [
426
+ {
427
+ type: "object",
428
+ properties: {
429
+ defaultAccessibility: {
430
+ type: "string",
431
+ enum: ["public", "private", "protected"],
432
+ description: "The accessibility modifier to add if one is missing."
433
+ }
434
+ },
435
+ additionalProperties: false
436
+ }
437
+ ],
438
+ messages: {
439
+ missingAccessibility: "Class member '{{ name }}' is missing an explicit accessibility modifier (public/private/protected)."
440
+ }
441
+ },
442
+ defaultOptions: [defaultOptions],
443
+ create(context, [options]) {
444
+ const { defaultAccessibility } = { ...defaultOptions, ...options };
445
+ const sourceCode = context.sourceCode;
446
+ function checkNode(node) {
447
+ if (node.accessibility) {
448
+ return;
449
+ }
450
+ let reportNode = node;
451
+ const name = getNodeName(node);
452
+ if (node.type === TSESTree.AST_NODE_TYPES.MethodDefinition || node.type === TSESTree.AST_NODE_TYPES.PropertyDefinition) {
453
+ reportNode = node.key;
454
+ } else {
455
+ const param = node.parameter;
456
+ if (param.type === TSESTree.AST_NODE_TYPES.Identifier) {
457
+ reportNode = param;
458
+ } else if (param.type === TSESTree.AST_NODE_TYPES.AssignmentPattern && param.left.type === TSESTree.AST_NODE_TYPES.Identifier) {
459
+ reportNode = param.left;
460
+ }
461
+ }
462
+ context.report({
463
+ node: reportNode,
464
+ messageId: "missingAccessibility",
465
+ data: { name },
466
+ fix(fixer) {
467
+ let tokenToInsertBefore = null;
468
+ let insertText = `${defaultAccessibility} `;
469
+ if (node.decorators.length > 0) {
470
+ const lastDecorator = node.decorators[node.decorators.length - 1];
471
+ tokenToInsertBefore = sourceCode.getTokenAfter(lastDecorator);
472
+ } else {
473
+ tokenToInsertBefore = sourceCode.getFirstToken(node);
474
+ }
475
+ if (node.type === TSESTree.AST_NODE_TYPES.TSParameterProperty && node.readonly) {
476
+ const firstToken = sourceCode.getFirstToken(node);
477
+ if (firstToken?.value === "readonly") {
478
+ tokenToInsertBefore = firstToken;
479
+ }
480
+ }
481
+ if (!tokenToInsertBefore)
482
+ return null;
483
+ const tokenAfterInsertion = sourceCode.getTokenAfter(
484
+ tokenToInsertBefore,
485
+ { includeComments: false }
486
+ );
487
+ const textBetween = sourceCode.text.slice(
488
+ tokenToInsertBefore.range[1],
489
+ tokenAfterInsertion?.range[0]
490
+ );
491
+ if (!/^\s/.test(textBetween)) {
492
+ insertText = ` ${insertText}`;
493
+ }
494
+ return fixer.insertTextBefore(tokenToInsertBefore, insertText);
495
+ }
496
+ });
497
+ }
498
+ return {
499
+ MethodDefinition(node) {
500
+ checkNode(node);
501
+ },
502
+ PropertyDefinition(node) {
503
+ checkNode(node);
504
+ },
505
+ TSParameterProperty(node) {
506
+ checkNode(node);
507
+ }
508
+ };
509
+ }
510
+ });
511
+
512
+ // packages/lint-suite/src/lib/typescript.ts
513
+ var localTypescriptRules = {
514
+ rules: {
515
+ "explicit-accessibility": explicit_accessibility_default
516
+ }
517
+ };
518
+ var typescript = [
519
+ // NOTE: Checks for 'prettier' and 'eslint-plugin-prettier'
520
+ importPluginX2.flatConfigs.typescript,
521
+ ...nx5.configs["flat/typescript"],
522
+ {
523
+ files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
524
+ plugins: { local: localTypescriptRules },
525
+ rules: {
526
+ "local/explicit-accessibility": "error",
527
+ "@typescript-eslint/explicit-member-accessibility": "error",
528
+ "@typescript-eslint/explicit-function-return-type": "error",
529
+ "@typescript-eslint/no-empty-function": "error",
530
+ "@typescript-eslint/no-unused-vars": "error",
531
+ "@typescript-eslint/no-use-before-define": "error",
532
+ // A. Eliminating `any` (already covered by strict-type-checked, but explicit for clarity)
533
+ "@typescript-eslint/no-explicit-any": "error",
534
+ "@typescript-eslint/no-unsafe-assignment": "error",
535
+ "@typescript-eslint/no-unsafe-call": "error",
536
+ "@typescript-eslint/no-unsafe-member-access": "error",
537
+ "@typescript-eslint/no-unsafe-return": "error",
538
+ "@typescript-eslint/no-unsafe-argument": "error",
539
+ // B. Explicit Annotations (partially covered, explicit module boundaries is key)
540
+ "@typescript-eslint/explicit-module-boundary-types": "error",
541
+ // Consider enabling if maximum explicitness is desired, even if verbose:
542
+ // C. Null/Undefined Safety (Requires strictNullChecks)
543
+ "@typescript-eslint/no-non-null-assertion": "error",
544
+ // D. Promise Handling (Supplementing plugin:promise/recommended)
545
+ "@typescript-eslint/no-floating-promises": [
546
+ "error",
547
+ { ignoreVoid: true }
548
+ ],
549
+ "@typescript-eslint/no-misused-promises": "warn",
550
+ // Already in recommended-type-checked
551
+ "@typescript-eslint/promise-function-async": "error",
552
+ "@typescript-eslint/await-thenable": "error",
553
+ // Already in recommended-type-checked
554
+ // E. Best Practices & Potential Errors (Some covered by presets, fine-tuning here)
555
+ "@typescript-eslint/no-inferrable-types": "warn",
556
+ // Keep as warn or disable if inference is preferred
557
+ "@typescript-eslint/no-var-requires": "error",
558
+ // Use ES modules
559
+ "@typescript-eslint/require-await": "error",
560
+ "@typescript-eslint/restrict-template-expressions": [
561
+ "error",
562
+ { allowNumber: true, allowBoolean: true }
563
+ ],
564
+ // Allow numbers/booleans in templates
565
+ "@typescript-eslint/restrict-plus-operands": "error",
566
+ // Enforce consistent types for '+'
567
+ "@typescript-eslint/prefer-as-const": "error",
568
+ "@typescript-eslint/no-shadow": "error",
569
+ "@typescript-eslint/switch-exhaustiveness-check": "error",
570
+ // Ensure switch on unions is exhaustive
571
+ "@typescript-eslint/no-unused-expressions": [
572
+ "error",
573
+ { allowShortCircuit: true, allowTernary: true }
574
+ ],
575
+ "@typescript-eslint/no-useless-constructor": "error",
576
+ "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
577
+ // Prefer dot notation where possible
578
+ // F. Consistency & Style (Some covered by stylistic-type-checked)
579
+ "@typescript-eslint/consistent-type-assertions": [
580
+ "error",
581
+ { assertionStyle: "as", objectLiteralTypeAssertions: "never" }
582
+ ],
583
+ "@typescript-eslint/consistent-type-definitions": ["error", "type"],
584
+ "@typescript-eslint/consistent-type-imports": [
585
+ "error",
586
+ { prefer: "type-imports", fixStyle: "separate-type-imports" }
587
+ ],
588
+ "@typescript-eslint/naming-convention": [
589
+ "error",
590
+ {
591
+ selector: "objectLiteralProperty",
592
+ modifiers: ["requiresQuotes"],
593
+ format: null
594
+ },
595
+ {
596
+ selector: "objectLiteralProperty",
597
+ format: ["camelCase", "snake_case", "PascalCase"]
598
+ },
599
+ {
600
+ selector: "parameter",
601
+ format: ["camelCase"],
602
+ leadingUnderscore: "allow"
603
+ },
604
+ { selector: "default", format: ["camelCase"] },
605
+ { selector: "variable", format: ["camelCase", "UPPER_CASE"] },
606
+ { selector: "function", format: ["camelCase"] },
607
+ { selector: "typeLike", format: ["PascalCase"] },
608
+ {
609
+ selector: "property",
610
+ modifiers: ["requiresQuotes"],
611
+ format: null
612
+ },
613
+ {
614
+ selector: "property",
615
+ format: ["camelCase", "PascalCase", "snake_case"]
616
+ }
617
+ ],
618
+ "import-x/order": [
619
+ "error",
620
+ {
621
+ groups: [
622
+ "builtin",
623
+ "external",
624
+ "internal",
625
+ ["parent", "sibling"],
626
+ "index",
627
+ "unknown"
628
+ ],
629
+ pathGroups: [
630
+ {
631
+ pattern: "@angular/**",
632
+ group: "builtin",
633
+ position: "before"
634
+ },
635
+ {
636
+ pattern: "@nestjs/**",
637
+ group: "builtin",
638
+ position: "before"
639
+ },
640
+ {
641
+ pattern: "@*/shared/**",
642
+ group: "internal",
643
+ position: "before"
644
+ },
645
+ {
646
+ pattern: "@*/frontend/**",
647
+ group: "internal",
648
+ position: "after"
649
+ },
650
+ {
651
+ pattern: "@*/backend/**",
652
+ group: "internal",
653
+ position: "after"
654
+ }
655
+ ],
656
+ pathGroupsExcludedImportTypes: ["@angular/**", "@nestjs/**"],
657
+ "newlines-between": "always",
658
+ alphabetize: { order: "asc", caseInsensitive: true }
659
+ }
660
+ ],
661
+ "import-x/no-unresolved": "error",
662
+ "import-x/no-duplicates": "error",
663
+ "import-x/prefer-default-export": "off",
664
+ "import-x/no-useless-path-segments": "error",
665
+ "import-x/newline-after-import": "error",
666
+ "import-x/first": "error",
667
+ "import-x/no-mutable-exports": "error"
668
+ },
669
+ settings: {
670
+ "import-x/resolver-next": [
671
+ createTypeScriptImportResolver({
672
+ alwaysTryTypes: true,
673
+ project: "tsconfig.base.json"
674
+ })
675
+ ]
676
+ }
677
+ },
678
+ {
679
+ files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
680
+ languageOptions: {
681
+ parserOptions: {
682
+ projectService: true
683
+ }
684
+ },
685
+ rules: {
686
+ "@typescript-eslint/prefer-readonly": "error"
687
+ }
688
+ },
689
+ {
690
+ files: ["**/*.action.ts"],
691
+ rules: {
692
+ "@typescript-eslint/no-namespace": "off"
693
+ }
694
+ },
695
+ {
696
+ files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
697
+ rules: {
698
+ "@typescript-eslint/no-empty-function": "off",
699
+ "@typescript-eslint/no-unbound-method": "off",
700
+ "@typescript-eslint/consistent-type-assertions": "off"
701
+ }
702
+ },
703
+ {
704
+ files: ["**/*.stories.ts"],
705
+ rules: {
706
+ "@typescript-eslint/consistent-type-assertions": "off",
707
+ "@typescript-eslint/naming-convention": "off"
708
+ }
709
+ }
710
+ ];
711
+
712
+ // packages/lint-suite/src/index.ts
713
+ var recommended = [
714
+ ...base,
715
+ ...javascript,
716
+ ...typescript,
717
+ ...angular,
718
+ ...angularTemplate,
719
+ ...rxjs,
720
+ ...jest,
721
+ ...json,
722
+ ...storybook
723
+ ];
337
724
  export {
338
725
  angular,
339
726
  angularTemplate,
@@ -341,6 +728,7 @@ export {
341
728
  javascript,
342
729
  jest,
343
730
  json,
731
+ recommended,
344
732
  rxjs,
345
733
  storybook,
346
734
  typescript