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.cjs CHANGED
@@ -36,6 +36,7 @@ __export(src_exports, {
36
36
  javascript: () => javascript,
37
37
  jest: () => jest,
38
38
  json: () => json,
39
+ recommended: () => recommended,
39
40
  rxjs: () => rxjs,
40
41
  storybook: () => storybook,
41
42
  typescript: () => typescript
@@ -49,6 +50,8 @@ var angularTemplate = [
49
50
  {
50
51
  files: ["**/*.html"],
51
52
  rules: {
53
+ "@angular-eslint/template/no-any": "error",
54
+ "@angular-eslint/template/no-duplicate-attributes": "error",
52
55
  "@angular-eslint/template/button-has-type": "error",
53
56
  "@angular-eslint/template/no-positive-tabindex": "error",
54
57
  "@angular-eslint/template/valid-aria": "error",
@@ -100,8 +103,8 @@ var angular = [
100
103
 
101
104
  // packages/lint-suite/src/lib/base.ts
102
105
  var import_eslint_plugin3 = __toESM(require("@nx/eslint-plugin"), 1);
103
- var import_eslint_plugin_import = __toESM(require("eslint-plugin-import"), 1);
104
106
  var import_eslint_plugin4 = __toESM(require("@stylistic/eslint-plugin"), 1);
107
+ var import_eslint_plugin_import_x = __toESM(require("eslint-plugin-import-x"), 1);
105
108
  var base = [
106
109
  ...import_eslint_plugin3.default.configs["flat/base"],
107
110
  {
@@ -115,7 +118,7 @@ var base = [
115
118
  "**/*.cts",
116
119
  "**/*.mts"
117
120
  ],
118
- ...import_eslint_plugin_import.default.flatConfigs.recommended
121
+ ...import_eslint_plugin_import_x.default.flatConfigs.recommended
119
122
  },
120
123
  {
121
124
  files: [
@@ -142,8 +145,60 @@ var base = [
142
145
  "**/*.mts"
143
146
  ],
144
147
  rules: {
145
- "no-console": "warn",
148
+ "no-param-reassign": "error",
149
+ "no-alert": "error",
150
+ "no-console": ["warn", { allow: ["warn", "error"] }],
151
+ "no-debugger": "error",
152
+ eqeqeq: ["error", "always", { null: "ignore" }],
153
+ curly: ["error", "all"],
154
+ "prefer-const": ["error", { destructuring: "all" }],
155
+ "no-var": "error",
156
+ "object-shorthand": "error",
157
+ "prefer-arrow-callback": "error",
158
+ "no-useless-concat": "error",
159
+ "prefer-template": "error",
160
+ "no-nested-ternary": "error",
161
+ "no-return-await": "error",
162
+ "no-else-return": ["error", { allowElseIf: false }],
163
+ // Prefer early returns
164
+ "no-multi-assign": "error",
165
+ // Disallow chaining assignments
166
+ radix: "error",
167
+ // Require radix parameter for parseInt()
168
+ yoda: "error",
169
+ // Disallow yoda conditions (`if ("red" === color)`)
170
+ complexity: ["warn", 10],
171
+ // Warn if function complexity is high
172
+ "max-depth": ["warn", 4],
173
+ // Warn on deeply nested blocks
174
+ "max-lines-per-function": ["warn", 50],
175
+ // Warn on long functions
176
+ "max-params": ["warn", 4],
177
+ // Warn on functions with many parameters
178
+ "no-lonely-if": "error",
179
+ // Disallow if statements as the only statement in an else block
180
+ "grouped-accessor-pairs": ["error", "getBeforeSet"],
181
+ // Enforce consistency for getters/setters
146
182
  "class-methods-use-this": "error",
183
+ "no-underscore-dangle": "error",
184
+ "padding-line-between-statements": [
185
+ "error",
186
+ {
187
+ blankLine: "always",
188
+ prev: "export",
189
+ next: ["export", "const"]
190
+ },
191
+ {
192
+ blankLine: "always",
193
+ prev: "*",
194
+ next: "return"
195
+ },
196
+ {
197
+ blankLine: "always",
198
+ prev: "*",
199
+ next: "if"
200
+ }
201
+ ],
147
202
  "max-len": [
148
203
  "error",
149
204
  {
@@ -221,6 +276,8 @@ var base = [
221
276
  {
222
277
  files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
223
278
  rules: {
279
+ "max-lines-per-function": "off",
280
+ complexity: ["warn", { max: 1 }],
224
281
  "max-lines": [
225
282
  "error",
226
283
  {
@@ -230,35 +287,6 @@ var base = [
230
287
  }
231
288
  ]
232
289
  }
233
- }
234
- ];
235
-
236
- // packages/lint-suite/src/lib/typescript.ts
237
- var import_eslint_plugin5 = __toESM(require("@nx/eslint-plugin"), 1);
238
- var import_eslint_plugin_import2 = __toESM(require("eslint-plugin-import"), 1);
239
- var typescript = [
240
- // NOTE: Checks for 'prettier' and 'eslint-plugin-prettier'
241
- import_eslint_plugin_import2.default.flatConfigs.typescript,
242
- ...import_eslint_plugin5.default.configs["flat/typescript"],
243
- {
244
- files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
245
- rules: {
246
- "@typescript-eslint/explicit-member-accessibility": "error",
247
- "@typescript-eslint/consistent-type-imports": "error",
248
- "@typescript-eslint/explicit-function-return-type": "warn",
249
- "@typescript-eslint/no-empty-function": "error"
250
- }
251
- },
252
- {
253
- files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
254
- languageOptions: {
255
- parserOptions: {
256
- projectService: true
257
- }
258
- },
259
- rules: {
260
- "@typescript-eslint/prefer-readonly": "error"
261
- }
262
290
  },
263
291
  {
264
292
  files: ["**/*.action.ts"],
@@ -274,15 +302,17 @@ var typescript = [
274
302
  }
275
303
  ];
276
304
 
305
+ // packages/lint-suite/src/lib/javascript.ts
306
+ var import_eslint_plugin5 = __toESM(require("@nx/eslint-plugin"), 1);
307
+ var javascript = import_eslint_plugin5.default.configs["flat/javascript"];
308
+
277
309
  // packages/lint-suite/src/lib/jest.ts
278
310
  var import_eslint_plugin_jest = __toESM(require("eslint-plugin-jest"), 1);
279
311
  var jest = [
280
312
  {
281
313
  files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
282
- ...import_eslint_plugin_jest.default.configs["flat/recommended"],
314
+ ...import_eslint_plugin_jest.default.configs["flat/all"],
283
315
  rules: {
284
- ...import_eslint_plugin_jest.default.configs["flat/recommended"].rules,
285
- ...import_eslint_plugin_jest.default.configs["flat/style"].rules,
286
316
  "jest/no-done-callback": "off"
287
317
  }
288
318
  }
@@ -347,6 +377,7 @@ var rxjs = [
347
377
  rules: {
348
378
  "rxjs/prefer-observer": "error",
349
379
  "rxjs/finnish": "warn",
380
+ "rxjs/no-ignored-subscription": "warn",
350
381
  "rxjs/no-ignored-error": "warn",
351
382
  "rxjs/no-unsafe-switchmap": "error",
352
383
  "rxjs/no-unsafe-takeuntil": "error",
@@ -371,13 +402,370 @@ var storybook = [
371
402
  ...import_eslint_plugin_storybook.default.configs["flat/recommended"],
372
403
  {
373
404
  ignores: ["!.storybook"],
374
- files: ["**/*.stories.ts"]
405
+ files: ["**/*.stories.ts"],
406
+ rules: {
407
+ "storybook/no-uninstalled-addons": [
408
+ "error",
409
+ { packageJsonLocation: "package.json" }
410
+ ]
411
+ }
375
412
  }
376
413
  ];
377
414
 
378
- // packages/lint-suite/src/lib/javascript.ts
415
+ // packages/lint-suite/src/lib/typescript.ts
379
416
  var import_eslint_plugin6 = __toESM(require("@nx/eslint-plugin"), 1);
380
- var javascript = [...import_eslint_plugin6.default.configs["flat/javascript"]];
417
+ var import_eslint_import_resolver_typescript = require("eslint-import-resolver-typescript");
418
+ var import_eslint_plugin_import_x2 = __toESM(require("eslint-plugin-import-x"), 1);
419
+
420
+ // packages/lint-suite/src/lib/rules/explicit-accessibility.ts
421
+ var import_utils = require("@typescript-eslint/utils");
422
+ var createRule = import_utils.ESLintUtils.RuleCreator(
423
+ () => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
424
+ );
425
+ var defaultOptions = {
426
+ defaultAccessibility: "private"
427
+ };
428
+ var getNodeName = (node) => {
429
+ if (!node) {
430
+ return "<unknown>";
431
+ }
432
+ if ("key" in node && node.key) {
433
+ if (node.key.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
434
+ return node.key.name;
435
+ }
436
+ if (node.key.type === import_utils.TSESTree.AST_NODE_TYPES.PrivateIdentifier) {
437
+ return `#${node.key.name}`;
438
+ }
439
+ return "<computed/complex key>";
440
+ }
441
+ if ("kind" in node && node.kind === "constructor") {
442
+ return "constructor";
443
+ }
444
+ if (node.type === import_utils.TSESTree.AST_NODE_TYPES.TSParameterProperty) {
445
+ const param = node.parameter;
446
+ if (param.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
447
+ return param.name;
448
+ }
449
+ if (param.type === import_utils.TSESTree.AST_NODE_TYPES.AssignmentPattern) {
450
+ if (param.left.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
451
+ return param.left.name;
452
+ }
453
+ return "<destructured parameter>";
454
+ }
455
+ if (param.type === import_utils.TSESTree.AST_NODE_TYPES.RestElement && param.argument.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
456
+ return `...${param.argument.name}`;
457
+ }
458
+ return "<complex parameter>";
459
+ }
460
+ return "<unknown>";
461
+ };
462
+ var explicit_accessibility_default = createRule({
463
+ name: "explicit-accessibility",
464
+ meta: {
465
+ type: "suggestion",
466
+ docs: {
467
+ description: "Require explicit accessibility modifiers on class members"
468
+ },
469
+ fixable: "code",
470
+ schema: [
471
+ {
472
+ type: "object",
473
+ properties: {
474
+ defaultAccessibility: {
475
+ type: "string",
476
+ enum: ["public", "private", "protected"],
477
+ description: "The accessibility modifier to add if one is missing."
478
+ }
479
+ },
480
+ additionalProperties: false
481
+ }
482
+ ],
483
+ messages: {
484
+ missingAccessibility: "Class member '{{ name }}' is missing an explicit accessibility modifier (public/private/protected)."
485
+ }
486
+ },
487
+ defaultOptions: [defaultOptions],
488
+ create(context, [options]) {
489
+ const { defaultAccessibility } = { ...defaultOptions, ...options };
490
+ const sourceCode = context.sourceCode;
491
+ function checkNode(node) {
492
+ if (node.accessibility) {
493
+ return;
494
+ }
495
+ let reportNode = node;
496
+ const name = getNodeName(node);
497
+ if (node.type === import_utils.TSESTree.AST_NODE_TYPES.MethodDefinition || node.type === import_utils.TSESTree.AST_NODE_TYPES.PropertyDefinition) {
498
+ reportNode = node.key;
499
+ } else {
500
+ const param = node.parameter;
501
+ if (param.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
502
+ reportNode = param;
503
+ } else if (param.type === import_utils.TSESTree.AST_NODE_TYPES.AssignmentPattern && param.left.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
504
+ reportNode = param.left;
505
+ }
506
+ }
507
+ context.report({
508
+ node: reportNode,
509
+ messageId: "missingAccessibility",
510
+ data: { name },
511
+ fix(fixer) {
512
+ let tokenToInsertBefore = null;
513
+ let insertText = `${defaultAccessibility} `;
514
+ if (node.decorators.length > 0) {
515
+ const lastDecorator = node.decorators[node.decorators.length - 1];
516
+ tokenToInsertBefore = sourceCode.getTokenAfter(lastDecorator);
517
+ } else {
518
+ tokenToInsertBefore = sourceCode.getFirstToken(node);
519
+ }
520
+ if (node.type === import_utils.TSESTree.AST_NODE_TYPES.TSParameterProperty && node.readonly) {
521
+ const firstToken = sourceCode.getFirstToken(node);
522
+ if (firstToken?.value === "readonly") {
523
+ tokenToInsertBefore = firstToken;
524
+ }
525
+ }
526
+ if (!tokenToInsertBefore)
527
+ return null;
528
+ const tokenAfterInsertion = sourceCode.getTokenAfter(
529
+ tokenToInsertBefore,
530
+ { includeComments: false }
531
+ );
532
+ const textBetween = sourceCode.text.slice(
533
+ tokenToInsertBefore.range[1],
534
+ tokenAfterInsertion?.range[0]
535
+ );
536
+ if (!/^\s/.test(textBetween)) {
537
+ insertText = ` ${insertText}`;
538
+ }
539
+ return fixer.insertTextBefore(tokenToInsertBefore, insertText);
540
+ }
541
+ });
542
+ }
543
+ return {
544
+ MethodDefinition(node) {
545
+ checkNode(node);
546
+ },
547
+ PropertyDefinition(node) {
548
+ checkNode(node);
549
+ },
550
+ TSParameterProperty(node) {
551
+ checkNode(node);
552
+ }
553
+ };
554
+ }
555
+ });
556
+
557
+ // packages/lint-suite/src/lib/typescript.ts
558
+ var localTypescriptRules = {
559
+ rules: {
560
+ "explicit-accessibility": explicit_accessibility_default
561
+ }
562
+ };
563
+ var typescript = [
564
+ // NOTE: Checks for 'prettier' and 'eslint-plugin-prettier'
565
+ import_eslint_plugin_import_x2.default.flatConfigs.typescript,
566
+ ...import_eslint_plugin6.default.configs["flat/typescript"],
567
+ {
568
+ files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
569
+ plugins: { local: localTypescriptRules },
570
+ rules: {
571
+ "local/explicit-accessibility": "error",
572
+ "@typescript-eslint/explicit-member-accessibility": "error",
573
+ "@typescript-eslint/explicit-function-return-type": "error",
574
+ "@typescript-eslint/no-empty-function": "error",
575
+ "@typescript-eslint/no-unused-vars": "error",
576
+ "@typescript-eslint/no-use-before-define": "error",
577
+ // A. Eliminating `any` (already covered by strict-type-checked, but explicit for clarity)
578
+ "@typescript-eslint/no-explicit-any": "error",
579
+ "@typescript-eslint/no-unsafe-assignment": "error",
580
+ "@typescript-eslint/no-unsafe-call": "error",
581
+ "@typescript-eslint/no-unsafe-member-access": "error",
582
+ "@typescript-eslint/no-unsafe-return": "error",
583
+ "@typescript-eslint/no-unsafe-argument": "error",
584
+ // B. Explicit Annotations (partially covered, explicit module boundaries is key)
585
+ "@typescript-eslint/explicit-module-boundary-types": "error",
586
+ // Consider enabling if maximum explicitness is desired, even if verbose:
587
+ // C. Null/Undefined Safety (Requires strictNullChecks)
588
+ "@typescript-eslint/no-non-null-assertion": "error",
589
+ // D. Promise Handling (Supplementing plugin:promise/recommended)
590
+ "@typescript-eslint/no-floating-promises": [
591
+ "error",
592
+ { ignoreVoid: true }
593
+ ],
594
+ "@typescript-eslint/no-misused-promises": "warn",
595
+ // Already in recommended-type-checked
596
+ "@typescript-eslint/promise-function-async": "error",
597
+ "@typescript-eslint/await-thenable": "error",
598
+ // Already in recommended-type-checked
599
+ // E. Best Practices & Potential Errors (Some covered by presets, fine-tuning here)
600
+ "@typescript-eslint/no-inferrable-types": "warn",
601
+ // Keep as warn or disable if inference is preferred
602
+ "@typescript-eslint/no-var-requires": "error",
603
+ // Use ES modules
604
+ "@typescript-eslint/require-await": "error",
605
+ "@typescript-eslint/restrict-template-expressions": [
606
+ "error",
607
+ { allowNumber: true, allowBoolean: true }
608
+ ],
609
+ // Allow numbers/booleans in templates
610
+ "@typescript-eslint/restrict-plus-operands": "error",
611
+ // Enforce consistent types for '+'
612
+ "@typescript-eslint/prefer-as-const": "error",
613
+ "@typescript-eslint/no-shadow": "error",
614
+ "@typescript-eslint/switch-exhaustiveness-check": "error",
615
+ // Ensure switch on unions is exhaustive
616
+ "@typescript-eslint/no-unused-expressions": [
617
+ "error",
618
+ { allowShortCircuit: true, allowTernary: true }
619
+ ],
620
+ "@typescript-eslint/no-useless-constructor": "error",
621
+ "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
622
+ // Prefer dot notation where possible
623
+ // F. Consistency & Style (Some covered by stylistic-type-checked)
624
+ "@typescript-eslint/consistent-type-assertions": [
625
+ "error",
626
+ { assertionStyle: "as", objectLiteralTypeAssertions: "never" }
627
+ ],
628
+ "@typescript-eslint/consistent-type-definitions": ["error", "type"],
629
+ "@typescript-eslint/consistent-type-imports": [
630
+ "error",
631
+ { prefer: "type-imports", fixStyle: "separate-type-imports" }
632
+ ],
633
+ "@typescript-eslint/naming-convention": [
634
+ "error",
635
+ {
636
+ selector: "objectLiteralProperty",
637
+ modifiers: ["requiresQuotes"],
638
+ format: null
639
+ },
640
+ {
641
+ selector: "objectLiteralProperty",
642
+ format: ["camelCase", "snake_case", "PascalCase"]
643
+ },
644
+ {
645
+ selector: "parameter",
646
+ format: ["camelCase"],
647
+ leadingUnderscore: "allow"
648
+ },
649
+ { selector: "default", format: ["camelCase"] },
650
+ { selector: "variable", format: ["camelCase", "UPPER_CASE"] },
651
+ { selector: "function", format: ["camelCase"] },
652
+ { selector: "typeLike", format: ["PascalCase"] },
653
+ {
654
+ selector: "property",
655
+ modifiers: ["requiresQuotes"],
656
+ format: null
657
+ },
658
+ {
659
+ selector: "property",
660
+ format: ["camelCase", "PascalCase", "snake_case"]
661
+ }
662
+ ],
663
+ "import-x/order": [
664
+ "error",
665
+ {
666
+ groups: [
667
+ "builtin",
668
+ "external",
669
+ "internal",
670
+ ["parent", "sibling"],
671
+ "index",
672
+ "unknown"
673
+ ],
674
+ pathGroups: [
675
+ {
676
+ pattern: "@angular/**",
677
+ group: "builtin",
678
+ position: "before"
679
+ },
680
+ {
681
+ pattern: "@nestjs/**",
682
+ group: "builtin",
683
+ position: "before"
684
+ },
685
+ {
686
+ pattern: "@*/shared/**",
687
+ group: "internal",
688
+ position: "before"
689
+ },
690
+ {
691
+ pattern: "@*/frontend/**",
692
+ group: "internal",
693
+ position: "after"
694
+ },
695
+ {
696
+ pattern: "@*/backend/**",
697
+ group: "internal",
698
+ position: "after"
699
+ }
700
+ ],
701
+ pathGroupsExcludedImportTypes: ["@angular/**", "@nestjs/**"],
702
+ "newlines-between": "always",
703
+ alphabetize: { order: "asc", caseInsensitive: true }
704
+ }
705
+ ],
706
+ "import-x/no-unresolved": "error",
707
+ "import-x/no-duplicates": "error",
708
+ "import-x/prefer-default-export": "off",
709
+ "import-x/no-useless-path-segments": "error",
710
+ "import-x/newline-after-import": "error",
711
+ "import-x/first": "error",
712
+ "import-x/no-mutable-exports": "error"
713
+ },
714
+ settings: {
715
+ "import-x/resolver-next": [
716
+ (0, import_eslint_import_resolver_typescript.createTypeScriptImportResolver)({
717
+ alwaysTryTypes: true,
718
+ project: "tsconfig.base.json"
719
+ })
720
+ ]
721
+ }
722
+ },
723
+ {
724
+ files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
725
+ languageOptions: {
726
+ parserOptions: {
727
+ projectService: true
728
+ }
729
+ },
730
+ rules: {
731
+ "@typescript-eslint/prefer-readonly": "error"
732
+ }
733
+ },
734
+ {
735
+ files: ["**/*.action.ts"],
736
+ rules: {
737
+ "@typescript-eslint/no-namespace": "off"
738
+ }
739
+ },
740
+ {
741
+ files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
742
+ rules: {
743
+ "@typescript-eslint/no-empty-function": "off",
744
+ "@typescript-eslint/no-unbound-method": "off",
745
+ "@typescript-eslint/consistent-type-assertions": "off"
746
+ }
747
+ },
748
+ {
749
+ files: ["**/*.stories.ts"],
750
+ rules: {
751
+ "@typescript-eslint/consistent-type-assertions": "off",
752
+ "@typescript-eslint/naming-convention": "off"
753
+ }
754
+ }
755
+ ];
756
+
757
+ // packages/lint-suite/src/index.ts
758
+ var recommended = [
759
+ ...base,
760
+ ...javascript,
761
+ ...typescript,
762
+ ...angular,
763
+ ...angularTemplate,
764
+ ...rxjs,
765
+ ...jest,
766
+ ...json,
767
+ ...storybook
768
+ ];
381
769
  // Annotate the CommonJS export names for ESM import in node:
382
770
  0 && (module.exports = {
383
771
  angular,
@@ -386,6 +774,7 @@ var javascript = [...import_eslint_plugin6.default.configs["flat/javascript"]];
386
774
  javascript,
387
775
  jest,
388
776
  json,
777
+ recommended,
389
778
  rxjs,
390
779
  storybook,
391
780
  typescript