lint-suite 1.0.3 → 1.0.5

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