eslint-config-agent 1.1.3 → 1.2.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 (49) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/index.js +77 -17
  3. package/package.json +2 -2
  4. package/rules/index.js +3 -0
  5. package/rules/max-file-lines/examples/invalid/long-file.js +113 -0
  6. package/rules/max-file-lines/examples/invalid/medium-file.js +127 -0
  7. package/rules/max-file-lines/examples/invalid/very-long-file.ts +144 -0
  8. package/rules/max-file-lines/examples/valid/short-file.js +66 -0
  9. package/rules/max-file-lines/examples/valid/spec-file.spec.js +44 -0
  10. package/rules/max-file-lines/examples/valid/test-file.test.js +25 -0
  11. package/rules/no-empty-exports/examples/invalid/empty-export.js +2 -0
  12. package/rules/no-empty-exports/examples/invalid/multiple-exports.js +5 -0
  13. package/rules/no-empty-exports/examples/invalid/single-export.js +3 -0
  14. package/rules/no-empty-exports/examples/valid/default-export.js +3 -0
  15. package/rules/no-empty-exports/examples/valid/direct-class.js +6 -0
  16. package/rules/no-empty-exports/examples/valid/direct-const.js +2 -0
  17. package/rules/no-empty-exports/examples/valid/direct-function.js +4 -0
  18. package/rules/no-empty-exports/examples/valid/re-export-from.js +2 -0
  19. package/rules/no-empty-exports/examples/valid/re-export-star.js +2 -0
  20. package/rules/no-empty-exports/index.js +16 -0
  21. package/rules/no-empty-exports/no-empty-exports.spec.js +104 -0
  22. package/rules/plugin/import/group-exports/examples/invalid/mixed-declaration-styles.js +8 -0
  23. package/rules/plugin/import/group-exports/examples/invalid/multiple-export-statements.js +8 -0
  24. package/rules/plugin/import/group-exports/examples/invalid/scattered-exports.js +10 -0
  25. package/rules/plugin/import/group-exports/examples/valid/direct-exports.js +2 -0
  26. package/rules/plugin/import/group-exports/examples/valid/mixed-with-default.js +7 -0
  27. package/rules/plugin/import/group-exports/examples/valid/single-export-statement.js +6 -0
  28. package/rules/plugin/import/group-exports/index.js +3 -0
  29. package/rules/plugin/import/index.js +5 -1
  30. package/rules/plugin/import/no-unused-modules/examples/invalid/dead-code.js +2 -0
  31. package/rules/plugin/import/no-unused-modules/examples/invalid/unused-class.js +6 -0
  32. package/rules/plugin/import/no-unused-modules/examples/invalid/unused-export.js +2 -0
  33. package/rules/plugin/import/no-unused-modules/examples/invalid/unused-function.js +4 -0
  34. package/rules/plugin/import/no-unused-modules/examples/invalid/unused-module.js +4 -0
  35. package/rules/plugin/import/no-unused-modules/examples/valid/consumed-import.js +8 -0
  36. package/rules/plugin/import/no-unused-modules/examples/valid/entry-point.js +5 -0
  37. package/rules/plugin/import/no-unused-modules/examples/valid/used-class.js +6 -0
  38. package/rules/plugin/import/no-unused-modules/examples/valid/used-export.js +2 -0
  39. package/rules/plugin/import/no-unused-modules/examples/valid/used-function.js +4 -0
  40. package/rules/plugin/import/no-unused-modules/index.js +6 -0
  41. package/rules/plugin/typescript-eslint/index.js +3 -1
  42. package/rules/plugin/typescript-eslint/no-explicit-any/examples/invalid/any-array.ts +2 -0
  43. package/rules/plugin/typescript-eslint/no-explicit-any/examples/invalid/any-parameter.ts +4 -0
  44. package/rules/plugin/typescript-eslint/no-explicit-any/examples/invalid/any-return-type.ts +4 -0
  45. package/rules/plugin/typescript-eslint/no-explicit-any/examples/invalid/any-variable.ts +5 -0
  46. package/rules/plugin/typescript-eslint/no-explicit-any/examples/valid/generics.ts +16 -0
  47. package/rules/plugin/typescript-eslint/no-explicit-any/examples/valid/specific-types.ts +9 -0
  48. package/rules/plugin/typescript-eslint/no-explicit-any/examples/valid/unknown-type.ts +8 -0
  49. package/rules/plugin/typescript-eslint/no-explicit-any/index.js +3 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file. See [Conven
4
4
 
5
5
 
6
6
 
7
+ ## [1.2.0](https://github.com/tupe12334/eslint-config/compare/v1.1.4...v1.2.0) (2025-09-11)
8
+
9
+ ### Features
10
+
11
+ * add examples for valid and invalid export patterns and update import rules configuration ([a78e03d](https://github.com/tupe12334/eslint-config/commit/a78e03d201e335b423c1830593c015ddd0346028))
12
+ * add no-explicit-any rule configuration and examples for valid/invalid usage ([2bc0ad8](https://github.com/tupe12334/eslint-config/commit/2bc0ad836ff42199456ebc7ebd0b6948cca1a7b1))
13
+ * add no-unused-modules rule configuration and examples for unused exports ([336db1b](https://github.com/tupe12334/eslint-config/commit/336db1b26bf4ac0d3e9bd56c95817748bfda4799))
14
+ * refine ESLint configuration to include specific index.js files and update CI test command ([5693dbc](https://github.com/tupe12334/eslint-config/commit/5693dbc65dc37cbddb6a41498b4886d360c17684))
15
+ * update ESLint configuration to disable size limits for test/spec files and add examples for valid/invalid file lengths ([ac57e22](https://github.com/tupe12334/eslint-config/commit/ac57e223f7d1cedab32976cee5f305ca197ca0c8))
16
+ * update export statements in test files to use default export syntax ([c4a846b](https://github.com/tupe12334/eslint-config/commit/c4a846bc78105f287fafcb4248c8de334c84b0fb))
17
+
18
+ ## [1.1.4](https://github.com/tupe12334/eslint-config/compare/v1.1.3...v1.1.4) (2025-09-10)
19
+
20
+ ### Features
21
+
22
+ * add no-empty-exports rule to prevent empty export specifiers and include test cases ([7757007](https://github.com/tupe12334/eslint-config/commit/77570076e41bdab64dbed53ca7a40a935eda7e3a))
23
+ * enhance export specifier rules and update test configurations for improved validation ([fe64b9c](https://github.com/tupe12334/eslint-config/commit/fe64b9cb7f1bdf80b16a97db75a5fd04901c2e7f))
24
+ * remove package-specific ignores from ESLint config for cleaner configuration ([03cef75](https://github.com/tupe12334/eslint-config/commit/03cef75a6ad6d682ede5f4c5dc5d5e1a8d0a9aaa))
25
+
7
26
  ## [1.1.3](https://github.com/tupe12334/eslint-config/compare/v1.1.2...v1.1.3) (2025-09-10)
8
27
 
9
28
  ### Features
package/index.js CHANGED
@@ -19,7 +19,6 @@ try {
19
19
  // eslint-plugin-preact is not available
20
20
  }
21
21
 
22
-
23
22
  // Shared rules for both JS and TS files
24
23
  const sharedRules = {
25
24
  ...allRules.pluginRules,
@@ -95,12 +94,14 @@ const sharedRestrictedSyntax = [
95
94
  "Exporting from external libraries is not allowed. Only re-export from relative paths or scoped packages.",
96
95
  },
97
96
  allRules.noProcessEnvPropertiesConfig,
97
+ allRules.noExportSpecifiersConfig,
98
98
  ];
99
99
 
100
100
  // Required export rules (always errors)
101
101
  const requiredExportRules = [
102
102
  {
103
- selector: "ClassDeclaration:not(ExportNamedDeclaration > ClassDeclaration):not(ExportDefaultDeclaration > ClassDeclaration)",
103
+ selector:
104
+ "ClassDeclaration:not(ExportNamedDeclaration > ClassDeclaration):not(ExportDefaultDeclaration > ClassDeclaration)",
104
105
  message:
105
106
  "Classes must be exported. Use 'export class' or 'export default class'.",
106
107
  },
@@ -199,9 +200,6 @@ const config = [
199
200
  },
200
201
  },
201
202
  reactHooks.configs["recommended-latest"],
202
- {
203
- ignores: ["packages/auth-service-sdk/**"],
204
- },
205
203
  js.configs.recommended,
206
204
 
207
205
  // TypeScript and TSX files
@@ -212,10 +210,6 @@ const config = [
212
210
  "**/dist/**",
213
211
  "**/build/**",
214
212
  "pnpm-lock.yaml",
215
- "packages/auth-service-sdk/**",
216
- "packages/auth-service-sdk/src/core/**",
217
- "packages/auth-service-sdk/src/client/**",
218
- "packages/auth-service-sdk/src/*.gen.ts",
219
213
  "**/*.stories.{js,jsx,ts,tsx}",
220
214
  ],
221
215
  languageOptions: {
@@ -425,11 +419,11 @@ const config = [
425
419
  "**/dist/**",
426
420
  "**/build/**",
427
421
  "pnpm-lock.yaml",
428
- "packages/auth-service-sdk/**",
429
422
  "**/*.umd.js",
430
423
  "**/*.cjs",
431
424
  "**/*.mjs",
432
425
  "**/*.stories.{js,jsx,ts,tsx}",
426
+ "**/rules/**/index.js",
433
427
  ],
434
428
  languageOptions: {
435
429
  parserOptions: {
@@ -495,7 +489,6 @@ const config = [
495
489
  "**/dist/**",
496
490
  "**/build/**",
497
491
  "pnpm-lock.yaml",
498
- "packages/auth-service-sdk/**",
499
492
  "**/*.stories.{js,jsx,ts,tsx}",
500
493
  ],
501
494
  languageOptions: {
@@ -615,7 +608,6 @@ const config = [
615
608
  "**/dist/**",
616
609
  "**/build/**",
617
610
  "pnpm-lock.yaml",
618
- "packages/auth-service-sdk/**",
619
611
  "**/*.stories.{js,jsx,ts,tsx}",
620
612
  ],
621
613
  languageOptions: {
@@ -692,7 +684,7 @@ const config = [
692
684
  },
693
685
  },
694
686
 
695
- // Disable function size limits for test and spec files
687
+ // Disable function and file size limits for test and spec files
696
688
  {
697
689
  files: [
698
690
  "**/*.test.{js,jsx,ts,tsx}",
@@ -708,6 +700,7 @@ const config = [
708
700
  ],
709
701
  rules: {
710
702
  "max-lines-per-function": "off",
703
+ "max-lines": "off", // Ignore file length limits in test and spec files
711
704
  // Allow multiple exports in test files for testing import/export patterns
712
705
  "no-restricted-syntax": [
713
706
  "warn",
@@ -716,7 +709,33 @@ const config = [
716
709
  rule.selector !==
717
710
  "ExportNamedDeclaration[specifiers.length>1]:not([source])" &&
718
711
  rule.selector !==
719
- "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))"
712
+ "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))" &&
713
+ rule.selector !==
714
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
715
+ ),
716
+ ...tsOnlyRestrictedSyntax,
717
+ ],
718
+ },
719
+ },
720
+
721
+ // Test files that should have ERROR level rules but exclude export specifier rule
722
+ {
723
+ files: [
724
+ "**/test/type-assertions/**",
725
+ "**/test/test-optional.ts",
726
+ "**/test/test-js-optional.js",
727
+ "**/test/test-record-literals.ts",
728
+ "**/test/no-env-access-test.ts",
729
+ "**/test/import-export-rules.ts",
730
+ ],
731
+ rules: {
732
+ "max-lines-per-function": "off",
733
+ "no-restricted-syntax": [
734
+ "error", // Error level for these test files
735
+ ...sharedRestrictedSyntax.filter(
736
+ (rule) =>
737
+ rule.selector !==
738
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
720
739
  ),
721
740
  ...tsOnlyRestrictedSyntax,
722
741
  ],
@@ -727,6 +746,9 @@ const config = [
727
746
  {
728
747
  files: [
729
748
  "**/test/invalid.tsx", // Special handling for the main test file
749
+ "**/test/single-export-valid.ts", // Allow export specifiers for import/group-exports testing
750
+ "**/test/typescript-rules.ts", // Allow export specifiers for typescript rules testing
751
+ "**/test/type-assertions/indexed-access-valid.ts", // Allow export specifiers for type assertions testing
730
752
  ],
731
753
  rules: {
732
754
  "max-lines-per-function": "off",
@@ -737,7 +759,9 @@ const config = [
737
759
  rule.selector !==
738
760
  "ExportNamedDeclaration[specifiers.length>1]:not([source])" &&
739
761
  rule.selector !==
740
- "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))"
762
+ "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))" &&
763
+ rule.selector !==
764
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
741
765
  ),
742
766
  ...tsOnlyRestrictedSyntax,
743
767
  // For TSX files, also include required export rules as warnings since we can't mix severities
@@ -777,7 +801,13 @@ const config = [
777
801
  // Switch case rules as errors for all TypeScript/JSX files (must come last to override)
778
802
  {
779
803
  files: ["**/*.{ts,tsx,js,jsx}"],
780
- ignores: ["**/*.stories.{js,jsx,ts,tsx}"],
804
+ ignores: [
805
+ "**/*.stories.{js,jsx,ts,tsx}",
806
+ "**/test/**",
807
+ "!**/test/export/**",
808
+ "!**/test/required-exports/**",
809
+ "**/rules/**/index.js",
810
+ ],
781
811
  rules: {
782
812
  "no-restricted-syntax": [
783
813
  "error",
@@ -860,6 +890,7 @@ const config = [
860
890
  },
861
891
  allRules.noTypeAssertionsConfig,
862
892
  allRules.noProcessEnvPropertiesConfig,
893
+ allRules.noExportSpecifiersConfig,
863
894
  // Export restriction rules
864
895
  // Required export rules
865
896
  ...requiredExportRules,
@@ -886,7 +917,14 @@ const config = [
886
917
  // Function and file length rules - strict error thresholds
887
918
  {
888
919
  files: ["**/*.{ts,tsx,js,jsx}"],
889
- ignores: ["**/*.stories.{js,jsx,ts,tsx}"],
920
+ ignores: [
921
+ "**/*.stories.{js,jsx,ts,tsx}",
922
+ "**/*.test.{js,jsx,ts,tsx}",
923
+ "**/*.spec.{js,jsx,ts,tsx}",
924
+ "**/test/**/*.{js,jsx,ts,tsx}",
925
+ "**/tests/**/*.{js,jsx,ts,tsx}",
926
+ "**/__tests__/**/*.{js,jsx,ts,tsx}",
927
+ ],
890
928
  rules: {
891
929
  // Function length: error at 70+ lines
892
930
  "max-lines-per-function": allRules.maxFunctionLinesError,
@@ -946,6 +984,28 @@ const config = [
946
984
  ...storybookPlugin.configs.recommended.rules,
947
985
  },
948
986
  },
987
+
988
+ // Rules directory configuration - allow export specifiers for API definitions (but not examples)
989
+ {
990
+ files: ["**/rules/**/*.{js,ts}"],
991
+ ignores: ["**/rules/**/examples/**"],
992
+ languageOptions: {
993
+ globals: {
994
+ ...globals.node,
995
+ },
996
+ },
997
+ rules: {
998
+ "no-restricted-syntax": [
999
+ "error",
1000
+ // Include all shared rules EXCEPT our export specifier rule
1001
+ ...sharedRestrictedSyntax.filter(
1002
+ (rule) =>
1003
+ rule.selector !==
1004
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
1005
+ ),
1006
+ ],
1007
+ },
1008
+ },
949
1009
  ];
950
1010
 
951
1011
  export default config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-agent",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "ESLint configuration package with TypeScript support",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -28,7 +28,7 @@
28
28
  "test:edge": "eslint test/edge-cases.tsx",
29
29
  "test:performance": "eslint test/performance-test.tsx",
30
30
  "test:comprehensive": "node scripts/test-runner.js",
31
- "test:ci": "eslint . --ignore-pattern 'test/**' --ignore-pattern 'scripts/**' --max-warnings 0",
31
+ "test:ci": "eslint . --ignore-pattern 'test/**' --ignore-pattern 'scripts/**' --ignore-pattern 'rules/**/examples/**' --max-warnings 0",
32
32
  "validate": "node scripts/validate-config.js",
33
33
  "release": "dotenv -e .env -- release-it",
34
34
  "release:patch": "dotenv -e .env -- release-it patch",
package/rules/index.js CHANGED
@@ -13,6 +13,7 @@ import { maxFileLinesWarning, maxFileLinesError } from "./max-file-lines/index.j
13
13
  // Custom restricted syntax rules
14
14
  import { noProcessEnvPropertiesConfig } from "./no-process-env-properties/index.js";
15
15
  import { noTypeAssertionsConfig } from "./no-type-assertions/index.js";
16
+ import { noExportSpecifiersConfig } from "./no-empty-exports/index.js";
16
17
 
17
18
  // Plugin rule configurations
18
19
  import { pluginRules } from "./plugin/index.js";
@@ -30,6 +31,7 @@ const allRules = {
30
31
  // Custom restricted syntax rules
31
32
  noProcessEnvPropertiesConfig,
32
33
  noTypeAssertionsConfig,
34
+ noExportSpecifiersConfig,
33
35
 
34
36
  // Plugin rule configurations
35
37
  pluginRules,
@@ -50,6 +52,7 @@ export {
50
52
  // Custom restricted syntax rules
51
53
  noProcessEnvPropertiesConfig,
52
54
  noTypeAssertionsConfig,
55
+ noExportSpecifiersConfig,
53
56
 
54
57
  // Plugin rule configurations
55
58
  pluginRules,
@@ -0,0 +1,113 @@
1
+ // Invalid: File with more than 100 lines (should trigger max-lines error)
2
+ const line1 = 1;
3
+ const line2 = 2;
4
+ const line3 = 3;
5
+ const line4 = 4;
6
+ const line5 = 5;
7
+ const line6 = 6;
8
+ const line7 = 7;
9
+ const line8 = 8;
10
+ const line9 = 9;
11
+ const line10 = 10;
12
+ const line11 = 11;
13
+ const line12 = 12;
14
+ const line13 = 13;
15
+ const line14 = 14;
16
+ const line15 = 15;
17
+ const line16 = 16;
18
+ const line17 = 17;
19
+ const line18 = 18;
20
+ const line19 = 19;
21
+ const line20 = 20;
22
+ const line21 = 21;
23
+ const line22 = 22;
24
+ const line23 = 23;
25
+ const line24 = 24;
26
+ const line25 = 25;
27
+ const line26 = 26;
28
+ const line27 = 27;
29
+ const line28 = 28;
30
+ const line29 = 29;
31
+ const line30 = 30;
32
+ const line31 = 31;
33
+ const line32 = 32;
34
+ const line33 = 33;
35
+ const line34 = 34;
36
+ const line35 = 35;
37
+ const line36 = 36;
38
+ const line37 = 37;
39
+ const line38 = 38;
40
+ const line39 = 39;
41
+ const line40 = 40;
42
+ const line41 = 41;
43
+ const line42 = 42;
44
+ const line43 = 43;
45
+ const line44 = 44;
46
+ const line45 = 45;
47
+ const line46 = 46;
48
+ const line47 = 47;
49
+ const line48 = 48;
50
+ const line49 = 49;
51
+ const line50 = 50;
52
+ const line51 = 51;
53
+ const line52 = 52;
54
+ const line53 = 53;
55
+ const line54 = 54;
56
+ const line55 = 55;
57
+ const line56 = 56;
58
+ const line57 = 57;
59
+ const line58 = 58;
60
+ const line59 = 59;
61
+ const line60 = 60;
62
+ const line61 = 61;
63
+ const line62 = 62;
64
+ const line63 = 63;
65
+ const line64 = 64;
66
+ const line65 = 65;
67
+ const line66 = 66;
68
+ const line67 = 67;
69
+ const line68 = 68;
70
+ const line69 = 69;
71
+ const line70 = 70;
72
+ const line71 = 71;
73
+ const line72 = 72;
74
+ const line73 = 73;
75
+ const line74 = 74;
76
+ const line75 = 75;
77
+ const line76 = 76;
78
+ const line77 = 77;
79
+ const line78 = 78;
80
+ const line79 = 79;
81
+ const line80 = 80;
82
+ const line81 = 81;
83
+ const line82 = 82;
84
+ const line83 = 83;
85
+ const line84 = 84;
86
+ const line85 = 85;
87
+ const line86 = 86;
88
+ const line87 = 87;
89
+ const line88 = 88;
90
+ const line89 = 89;
91
+ const line90 = 90;
92
+ const line91 = 91;
93
+ const line92 = 92;
94
+ const line93 = 93;
95
+ const line94 = 94;
96
+ const line95 = 95;
97
+ const line96 = 96;
98
+ const line97 = 97;
99
+ const line98 = 98;
100
+ const line99 = 99;
101
+ const line100 = 100;
102
+ const line101 = 101;
103
+ const line102 = 102;
104
+ const line103 = 103;
105
+ const line104 = 104;
106
+ const line105 = 105;
107
+ const line106 = 106;
108
+ const line107 = 107;
109
+ const line108 = 108;
110
+ const line109 = 109;
111
+ const line110 = 110;
112
+
113
+ export default line1;
@@ -0,0 +1,127 @@
1
+ // Invalid: File with 70-100 lines (should trigger max-lines warning)
2
+ // This file demonstrates what happens when a file grows beyond the recommended size
3
+
4
+ class ExtendedNumberUtils {
5
+ constructor() {
6
+ this.cache = new Map();
7
+ }
8
+
9
+ calculateSum(numbers) {
10
+ const key = numbers.join(',');
11
+ if (this.cache.has(key)) {
12
+ return this.cache.get(key);
13
+ }
14
+ const sum = numbers.reduce((acc, num) => acc + num, 0);
15
+ this.cache.set(key, sum);
16
+ return sum;
17
+ }
18
+
19
+ calculateAverage(numbers) {
20
+ if (numbers.length === 0) return 0;
21
+ return this.calculateSum(numbers) / numbers.length;
22
+ }
23
+
24
+ findMaxValue(numbers) {
25
+ if (numbers.length === 0) return null;
26
+ return Math.max(...numbers);
27
+ }
28
+
29
+ findMinValue(numbers) {
30
+ if (numbers.length === 0) return null;
31
+ return Math.min(...numbers);
32
+ }
33
+
34
+ sortNumbers(numbers) {
35
+ return [...numbers].sort((a, b) => a - b);
36
+ }
37
+
38
+ filterEvenNumbers(numbers) {
39
+ return numbers.filter(num => num % 2 === 0);
40
+ }
41
+
42
+ filterOddNumbers(numbers) {
43
+ return numbers.filter(num => num % 2 !== 0);
44
+ }
45
+
46
+ multiplyByTwo(numbers) {
47
+ return numbers.map(num => num * 2);
48
+ }
49
+
50
+ containsNumber(numbers, target) {
51
+ return numbers.includes(target);
52
+ }
53
+
54
+ removeNumber(numbers, target) {
55
+ return numbers.filter(num => num !== target);
56
+ }
57
+
58
+ addNumber(numbers, newNumber) {
59
+ return [...numbers, newNumber];
60
+ }
61
+
62
+ getNumberAtIndex(numbers, index) {
63
+ if (index < 0 || index >= numbers.length) {
64
+ return undefined;
65
+ }
66
+ return numbers[index];
67
+ }
68
+
69
+ getLastNumber(numbers) {
70
+ return numbers.length > 0 ? numbers[numbers.length - 1] : undefined;
71
+ }
72
+
73
+ getFirstNumber(numbers) {
74
+ return numbers.length > 0 ? numbers[0] : undefined;
75
+ }
76
+
77
+ reverseNumbers(numbers) {
78
+ return [...numbers].reverse();
79
+ }
80
+
81
+ shuffleNumbers(numbers) {
82
+ const shuffled = [...numbers];
83
+ for (let i = shuffled.length - 1; i > 0; i--) {
84
+ const j = Math.floor(Math.random() * (i + 1));
85
+ const temp = shuffled[i];
86
+ shuffled[i] = shuffled[j];
87
+ shuffled[j] = temp;
88
+ }
89
+ return shuffled;
90
+ }
91
+
92
+ getUniqueNumbers(numbers) {
93
+ return [...new Set(numbers)];
94
+ }
95
+
96
+ getDuplicateNumbers(numbers) {
97
+ const seen = new Set();
98
+ const duplicates = new Set();
99
+ for (const num of numbers) {
100
+ if (seen.has(num)) {
101
+ duplicates.add(num);
102
+ } else {
103
+ seen.add(num);
104
+ }
105
+ }
106
+ return [...duplicates];
107
+ }
108
+
109
+ countOccurrences(numbers, target) {
110
+ return numbers.filter(num => num === target).length;
111
+ }
112
+
113
+ getNumbersInRange(numbers, min, max) {
114
+ return numbers.filter(num => num >= min && num <= max);
115
+ }
116
+
117
+ clearCache() {
118
+ this.cache.clear();
119
+ }
120
+
121
+ getCacheSize() {
122
+ return this.cache.size;
123
+ }
124
+ }
125
+
126
+ // This file has between 70-100 lines and should trigger a max-lines warning
127
+ export default ExtendedNumberUtils;
@@ -0,0 +1,144 @@
1
+ // Invalid: TypeScript file with way more than 100 lines (should trigger max-lines error)
2
+ interface User { id: number; name: string; email: string; }
3
+ interface Product { id: number; title: string; price: number; }
4
+ interface Order { id: number; userId: number; products: Product[]; }
5
+
6
+ const user1: User = { id: 1, name: 'John', email: 'john@example.com' };
7
+ const user2: User = { id: 2, name: 'Jane', email: 'jane@example.com' };
8
+ const user3: User = { id: 3, name: 'Bob', email: 'bob@example.com' };
9
+ const user4: User = { id: 4, name: 'Alice', email: 'alice@example.com' };
10
+ const user5: User = { id: 5, name: 'Charlie', email: 'charlie@example.com' };
11
+ const user6: User = { id: 6, name: 'Diana', email: 'diana@example.com' };
12
+ const user7: User = { id: 7, name: 'Eve', email: 'eve@example.com' };
13
+ const user8: User = { id: 8, name: 'Frank', email: 'frank@example.com' };
14
+ const user9: User = { id: 9, name: 'Grace', email: 'grace@example.com' };
15
+ const user10: User = { id: 10, name: 'Henry', email: 'henry@example.com' };
16
+
17
+ const product1: Product = { id: 1, title: 'Laptop', price: 999 };
18
+ const product2: Product = { id: 2, title: 'Mouse', price: 25 };
19
+ const product3: Product = { id: 3, title: 'Keyboard', price: 75 };
20
+ const product4: Product = { id: 4, title: 'Monitor', price: 300 };
21
+ const product5: Product = { id: 5, title: 'Headphones', price: 150 };
22
+ const product6: Product = { id: 6, title: 'Webcam', price: 80 };
23
+ const product7: Product = { id: 7, title: 'Speakers', price: 120 };
24
+ const product8: Product = { id: 8, title: 'Microphone', price: 200 };
25
+ const product9: Product = { id: 9, title: 'Tablet', price: 500 };
26
+ const product10: Product = { id: 10, title: 'Phone', price: 700 };
27
+ const product11: Product = { id: 11, title: 'Charger', price: 30 };
28
+ const product12: Product = { id: 12, title: 'Cable', price: 15 };
29
+ const product13: Product = { id: 13, title: 'Case', price: 40 };
30
+ const product14: Product = { id: 14, title: 'Stand', price: 60 };
31
+ const product15: Product = { id: 15, title: 'Bag', price: 90 };
32
+
33
+ const order1: Order = { id: 1, userId: 1, products: [product1, product2] };
34
+ const order2: Order = { id: 2, userId: 2, products: [product3] };
35
+ const order3: Order = { id: 3, userId: 3, products: [product4, product5, product6] };
36
+ const order4: Order = { id: 4, userId: 4, products: [product7, product8] };
37
+ const order5: Order = { id: 5, userId: 5, products: [product9] };
38
+ const order6: Order = { id: 6, userId: 6, products: [product10, product11] };
39
+ const order7: Order = { id: 7, userId: 7, products: [product12, product13, product14] };
40
+ const order8: Order = { id: 8, userId: 8, products: [product15] };
41
+ const order9: Order = { id: 9, userId: 9, products: [product1, product3, product5] };
42
+ const order10: Order = { id: 10, userId: 10, products: [product2, product4] };
43
+
44
+ export class OrderManagementService {
45
+ private users = [user1, user2, user3, user4, user5, user6, user7, user8, user9, user10];
46
+ private products = [product1, product2, product3, product4, product5, product6, product7, product8, product9, product10, product11, product12, product13, product14, product15];
47
+ private orders = [order1, order2, order3, order4, order5, order6, order7, order8, order9, order10];
48
+
49
+ getUserById(id: number): User | undefined {
50
+ return this.users.find(user => user.id === id);
51
+ }
52
+
53
+ getProductById(id: number): Product | undefined {
54
+ return this.products.find(product => product.id === id);
55
+ }
56
+
57
+ getOrderById(id: number): Order | undefined {
58
+ return this.orders.find(order => order.id === id);
59
+ }
60
+
61
+ getUserOrders(userId: number): Order[] {
62
+ return this.orders.filter(order => order.userId === userId);
63
+ }
64
+
65
+ calculateOrderTotal(order: Order): number {
66
+ return order.products.reduce((total, product) => total + product.price, 0);
67
+ }
68
+
69
+ getExpensiveProducts(minPrice: number): Product[] {
70
+ return this.products.filter(product => product.price >= minPrice);
71
+ }
72
+
73
+ getCheapProducts(maxPrice: number): Product[] {
74
+ return this.products.filter(product => product.price <= maxPrice);
75
+ }
76
+
77
+ searchProductsByTitle(query: string): Product[] {
78
+ return this.products.filter(product => product.title.toLowerCase().includes(query.toLowerCase()));
79
+ }
80
+
81
+ getUsersWithOrders(): User[] {
82
+ const userIdsWithOrders = new Set(this.orders.map(order => order.userId));
83
+ return this.users.filter(user => userIdsWithOrders.has(user.id));
84
+ }
85
+
86
+ getMostExpensiveOrder(): Order | undefined {
87
+ let maxOrder: Order | undefined;
88
+ let maxTotal = 0;
89
+
90
+ for (const order of this.orders) {
91
+ const total = this.calculateOrderTotal(order);
92
+ if (total > maxTotal) {
93
+ maxTotal = total;
94
+ maxOrder = order;
95
+ }
96
+ }
97
+
98
+ return maxOrder;
99
+ }
100
+
101
+ getOrdersByPriceRange(minPrice: number, maxPrice: number): Order[] {
102
+ return this.orders.filter(order => {
103
+ const total = this.calculateOrderTotal(order);
104
+ return total >= minPrice && total <= maxPrice;
105
+ });
106
+ }
107
+
108
+ getPopularProducts(): Product[] {
109
+ const productCount = new Map<number, number>();
110
+
111
+ for (const order of this.orders) {
112
+ for (const product of order.products) {
113
+ productCount.set(product.id, (productCount.get(product.id) || 0) + 1);
114
+ }
115
+ }
116
+
117
+ return this.products.filter(product => (productCount.get(product.id) || 0) > 1).sort((a, b) => (productCount.get(b.id) || 0) - (productCount.get(a.id) || 0));
118
+ }
119
+
120
+ getAverageOrderValue(): number {
121
+ const totalValue = this.orders.reduce((sum, order) => sum + this.calculateOrderTotal(order), 0);
122
+ return totalValue / this.orders.length;
123
+ }
124
+
125
+ getUserSpending(userId: number): number {
126
+ const userOrders = this.getUserOrders(userId);
127
+ return userOrders.reduce((total, order) => total + this.calculateOrderTotal(order), 0);
128
+ }
129
+
130
+ getTopSpendingUsers(limit: number = 5): Array<{ user: User; totalSpent: number }> {
131
+ const userSpending = this.users.map(user => ({
132
+ user,
133
+ totalSpent: this.getUserSpending(user.id)
134
+ }));
135
+
136
+ return userSpending.sort((a, b) => b.totalSpent - a.totalSpent).slice(0, limit);
137
+ }
138
+ }
139
+
140
+ const data1 = 'extra'; const data2 = 'data'; const data3 = 'to'; const data4 = 'make'; const data5 = 'file';
141
+ const data6 = 'longer'; const data7 = 'than'; const data8 = '100'; const data9 = 'lines'; const data10 = 'for';
142
+ const data11 = 'testing'; const data12 = 'max'; const data13 = 'lines'; const data14 = 'rule'; const data15 = 'error';
143
+
144
+ // This file has way more than 100 lines and should trigger a max-lines error
@@ -0,0 +1,66 @@
1
+ // Valid: Short file under 70 lines (no warnings or errors)
2
+ // This file demonstrates proper file length management
3
+
4
+ export class NumberUtils {
5
+ static calculateSum(numbers) {
6
+ return numbers.reduce((sum, num) => sum + num, 0);
7
+ }
8
+
9
+ static calculateAverage(numbers) {
10
+ if (numbers.length === 0) return 0;
11
+ return this.calculateSum(numbers) / numbers.length;
12
+ }
13
+
14
+ static findMaxValue(numbers) {
15
+ if (numbers.length === 0) return null;
16
+ return Math.max(...numbers);
17
+ }
18
+
19
+ static findMinValue(numbers) {
20
+ if (numbers.length === 0) return null;
21
+ return Math.min(...numbers);
22
+ }
23
+
24
+ static sortNumbers(numbers) {
25
+ return [...numbers].sort((a, b) => a - b);
26
+ }
27
+
28
+ static filterEvenNumbers(numbers) {
29
+ return numbers.filter((num) => num % 2 === 0);
30
+ }
31
+
32
+ static filterOddNumbers(numbers) {
33
+ return numbers.filter((num) => num % 2 !== 0);
34
+ }
35
+
36
+ static multiplyByTwo(numbers) {
37
+ return numbers.map((num) => num * 2);
38
+ }
39
+
40
+ static containsNumber(numbers, target) {
41
+ return numbers.includes(target);
42
+ }
43
+
44
+ static removeNumber(numbers, target) {
45
+ return numbers.filter((num) => num !== target);
46
+ }
47
+
48
+ static addNumber(numbers, newNumber) {
49
+ return [...numbers, newNumber];
50
+ }
51
+
52
+ static getUniqueNumbers(numbers) {
53
+ return [...new Set(numbers)];
54
+ }
55
+
56
+ static reverseNumbers(numbers) {
57
+ return [...numbers].reverse();
58
+ }
59
+
60
+ static getNumbersInRange(numbers, min, max) {
61
+ return numbers.filter((num) => num >= min && num <= max);
62
+ }
63
+ }
64
+
65
+ // This file has less than 70 lines and should not trigger any max-lines warnings or errors
66
+ export default NumberUtils;
@@ -0,0 +1,44 @@
1
+ // Valid: Spec file that ignores max-lines rule regardless of length
2
+ describe('Long spec file test', () => {
3
+ const testData1 = 'data1'; const testData2 = 'data2'; const testData3 = 'data3';
4
+ const testData4 = 'data4'; const testData5 = 'data5'; const testData6 = 'data6';
5
+ const testData7 = 'data7'; const testData8 = 'data8'; const testData9 = 'data9';
6
+ const testData10 = 'data10'; const testData11 = 'data11'; const testData12 = 'data12';
7
+ const testData13 = 'data13'; const testData14 = 'data14'; const testData15 = 'data15';
8
+ const testData16 = 'data16'; const testData17 = 'data17'; const testData18 = 'data18';
9
+ const testData19 = 'data19'; const testData20 = 'data20'; const testData21 = 'data21';
10
+ const testData22 = 'data22'; const testData23 = 'data23'; const testData24 = 'data24';
11
+ const testData25 = 'data25'; const testData26 = 'data26'; const testData27 = 'data27';
12
+ const testData28 = 'data28'; const testData29 = 'data29'; const testData30 = 'data30';
13
+ const testData31 = 'data31'; const testData32 = 'data32'; const testData33 = 'data33';
14
+ const testData34 = 'data34'; const testData35 = 'data35'; const testData36 = 'data36';
15
+ const testData37 = 'data37'; const testData38 = 'data38'; const testData39 = 'data39';
16
+ const testData40 = 'data40'; const testData41 = 'data41'; const testData42 = 'data42';
17
+ const testData43 = 'data43'; const testData44 = 'data44'; const testData45 = 'data45';
18
+ const testData46 = 'data46'; const testData47 = 'data47'; const testData48 = 'data48';
19
+ const testData49 = 'data49'; const testData50 = 'data50'; const testData51 = 'data51';
20
+ const testData52 = 'data52'; const testData53 = 'data53'; const testData54 = 'data54';
21
+ const testData55 = 'data55'; const testData56 = 'data56'; const testData57 = 'data57';
22
+ const testData58 = 'data58'; const testData59 = 'data59'; const testData60 = 'data60';
23
+ const testData61 = 'data61'; const testData62 = 'data62'; const testData63 = 'data63';
24
+ const testData64 = 'data64'; const testData65 = 'data65'; const testData66 = 'data66';
25
+ const testData67 = 'data67'; const testData68 = 'data68'; const testData69 = 'data69';
26
+ const testData70 = 'data70'; const testData71 = 'data71'; const testData72 = 'data72';
27
+ const testData73 = 'data73'; const testData74 = 'data74'; const testData75 = 'data75';
28
+ const testData76 = 'data76'; const testData77 = 'data77'; const testData78 = 'data78';
29
+ const testData79 = 'data79'; const testData80 = 'data80'; const testData81 = 'data81';
30
+ const testData82 = 'data82'; const testData83 = 'data83'; const testData84 = 'data84';
31
+ const testData85 = 'data85'; const testData86 = 'data86'; const testData87 = 'data87';
32
+ const testData88 = 'data88'; const testData89 = 'data89'; const testData90 = 'data90';
33
+ const testData91 = 'data91'; const testData92 = 'data92'; const testData93 = 'data93';
34
+ const testData94 = 'data94'; const testData95 = 'data95'; const testData96 = 'data96';
35
+ const testData97 = 'data97'; const testData98 = 'data98'; const testData99 = 'data99';
36
+ const testData100 = 'data100'; const testData101 = 'data101'; const testData102 = 'data102';
37
+ const testData103 = 'data103'; const testData104 = 'data104'; const testData105 = 'data105';
38
+ const testData106 = 'data106'; const testData107 = 'data107'; const testData108 = 'data108';
39
+ const testData109 = 'data109'; const testData110 = 'data110'; const testData111 = 'data111';
40
+
41
+ it('should handle long spec files without max-lines errors', () => {
42
+ expect(testData1).toBe('data1');
43
+ });
44
+ });
@@ -0,0 +1,25 @@
1
+ // Valid: Test file that ignores max-lines rule regardless of length
2
+ const line1 = 1; const line2 = 2; const line3 = 3; const line4 = 4; const line5 = 5;
3
+ const line6 = 6; const line7 = 7; const line8 = 8; const line9 = 9; const line10 = 10;
4
+ const line11 = 11; const line12 = 12; const line13 = 13; const line14 = 14; const line15 = 15;
5
+ const line16 = 16; const line17 = 17; const line18 = 18; const line19 = 19; const line20 = 20;
6
+ const line21 = 21; const line22 = 22; const line23 = 23; const line24 = 24; const line25 = 25;
7
+ const line26 = 26; const line27 = 27; const line28 = 28; const line29 = 29; const line30 = 30;
8
+ const line31 = 31; const line32 = 32; const line33 = 33; const line34 = 34; const line35 = 35;
9
+ const line36 = 36; const line37 = 37; const line38 = 38; const line39 = 39; const line40 = 40;
10
+ const line41 = 41; const line42 = 42; const line43 = 43; const line44 = 44; const line45 = 45;
11
+ const line46 = 46; const line47 = 47; const line48 = 48; const line49 = 49; const line50 = 50;
12
+ const line51 = 51; const line52 = 52; const line53 = 53; const line54 = 54; const line55 = 55;
13
+ const line56 = 56; const line57 = 57; const line58 = 58; const line59 = 59; const line60 = 60;
14
+ const line61 = 61; const line62 = 62; const line63 = 63; const line64 = 64; const line65 = 65;
15
+ const line66 = 66; const line67 = 67; const line68 = 68; const line69 = 69; const line70 = 70;
16
+ const line71 = 71; const line72 = 72; const line73 = 73; const line74 = 74; const line75 = 75;
17
+ const line76 = 76; const line77 = 77; const line78 = 78; const line79 = 79; const line80 = 80;
18
+ const line81 = 81; const line82 = 82; const line83 = 83; const line84 = 84; const line85 = 85;
19
+ const line86 = 86; const line87 = 87; const line88 = 88; const line89 = 89; const line90 = 90;
20
+ const line91 = 91; const line92 = 92; const line93 = 93; const line94 = 94; const line95 = 95;
21
+ const line96 = 96; const line97 = 97; const line98 = 98; const line99 = 99; const line100 = 100;
22
+ const line101 = 101; const line102 = 102; const line103 = 103; const line104 = 104; const line105 = 105;
23
+ const line106 = 106; const line107 = 107; const line108 = 108; const line109 = 109; const line110 = 110;
24
+
25
+ export default line1;
@@ -0,0 +1,2 @@
1
+ // Invalid: Empty export specifiers
2
+ export { };
@@ -0,0 +1,5 @@
1
+ // Invalid: Export specifiers with multiple items
2
+ const foo = 1;
3
+ const bar = 2;
4
+ const baz = 3;
5
+ export { foo, bar, baz };
@@ -0,0 +1,3 @@
1
+ // Invalid: Export specifiers with single item
2
+ const bar = 2;
3
+ export { bar };
@@ -0,0 +1,3 @@
1
+ // Valid: Default export
2
+ const something = { value: 42 };
3
+ export default something;
@@ -0,0 +1,6 @@
1
+ // Valid: Direct class export
2
+ export class Baz {
3
+ constructor() {
4
+ this.value = 42;
5
+ }
6
+ }
@@ -0,0 +1,2 @@
1
+ // Valid: Direct const export
2
+ export const foo = 1;
@@ -0,0 +1,4 @@
1
+ // Valid: Direct function export
2
+ export function bar() {
3
+ return 'hello';
4
+ }
@@ -0,0 +1,2 @@
1
+ // Valid: Re-export from other module
2
+ export { something } from './other-file';
@@ -0,0 +1,2 @@
1
+ // Valid: Re-export all from other module
2
+ export * from './other-file';
@@ -0,0 +1,16 @@
1
+ // Rule to prevent export { } statements of any length
2
+
3
+ const selector = 'ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))';
4
+ const message = 'Export specifier syntax "export { ... }" is not allowed. Use direct exports instead.';
5
+
6
+ const rule = {
7
+ selector,
8
+ message,
9
+ };
10
+
11
+ const noExportSpecifiersConfig = {
12
+ selector,
13
+ message,
14
+ };
15
+
16
+ export { rule, selector, message, noExportSpecifiersConfig };
@@ -0,0 +1,104 @@
1
+ import { RuleTester } from "eslint";
2
+ import { selector, message } from "./index.js";
3
+
4
+ const ruleTester = new RuleTester({
5
+ languageOptions: {
6
+ ecmaVersion: 2022,
7
+ sourceType: "module",
8
+ parserOptions: {
9
+ ecmaFeatures: {
10
+ jsx: true,
11
+ },
12
+ },
13
+ },
14
+ });
15
+
16
+ // Create a mock rule for testing
17
+ const mockRule = {
18
+ meta: {
19
+ type: "problem",
20
+ docs: {
21
+ description: "Disallow empty export statements",
22
+ },
23
+ schema: [],
24
+ },
25
+ create(context) {
26
+ return {
27
+ [selector]: (node) => {
28
+ context.report({
29
+ node,
30
+ message,
31
+ });
32
+ },
33
+ };
34
+ },
35
+ };
36
+
37
+ ruleTester.run("no-empty-exports", mockRule, {
38
+ valid: [
39
+ // Named exports with declarations
40
+ 'export const foo = 1;',
41
+ 'export function bar() {}',
42
+ 'export class Baz {}',
43
+
44
+ // Default exports
45
+ 'const foo = 1; export default foo;',
46
+ 'export default function() {}',
47
+ 'export default class {}',
48
+
49
+ // Re-exports from other modules (allowed)
50
+ 'export { } from "./other";',
51
+ 'export { foo } from "./other";',
52
+ 'export * from "./other";',
53
+ 'export * as namespace from "./other";',
54
+
55
+ // Regular exports
56
+ 'const Bar = {}; export { Bar };',
57
+
58
+ // No exports at all
59
+ 'const foo = 1;',
60
+ 'function bar() {}',
61
+ 'class Baz {}',
62
+
63
+ // Named exports with local variables
64
+ 'const foo = 1; const bar = 2; export { foo };',
65
+ 'const foo = 1; const bar = 2; export { foo, bar };',
66
+ 'const foo = 1; export { foo as bar };',
67
+ ],
68
+ invalid: [
69
+ {
70
+ code: 'export { };',
71
+ errors: [{ message }],
72
+ },
73
+ {
74
+ code: 'export {\n};',
75
+ errors: [{ message }],
76
+ },
77
+ {
78
+ code: 'export { };',
79
+ errors: [{ message }],
80
+ },
81
+ {
82
+ code: `export {
83
+ };`,
84
+ errors: [{ message }],
85
+ },
86
+ {
87
+ code: 'export { /* comment */ };',
88
+ errors: [{ message }],
89
+ },
90
+ // Multiple empty exports
91
+ {
92
+ code: `export { };
93
+ export { };`,
94
+ errors: [{ message }, { message }],
95
+ },
96
+ // Mixed with valid exports
97
+ {
98
+ code: `export const foo = 1;
99
+ export { };
100
+ export function bar() {}`,
101
+ errors: [{ message }],
102
+ },
103
+ ],
104
+ });
@@ -0,0 +1,8 @@
1
+ // Invalid: Mix of direct exports and separate export statements
2
+ export const first = 'direct export';
3
+
4
+ const second = 'separate export';
5
+ const third = 'another separate export';
6
+
7
+ export { second };
8
+ export { third };
@@ -0,0 +1,8 @@
1
+ // Invalid: Multiple separate export statements should be consolidated
2
+ const apiUrl = "https://api.example.com";
3
+ const timeout = 5000;
4
+ const retries = 3;
5
+
6
+ export { apiUrl };
7
+ export { timeout };
8
+ export { retries };
@@ -0,0 +1,10 @@
1
+ // Invalid: Named exports scattered across multiple statements
2
+ const config = { api: 'v1' };
3
+ const utils = { format: () => {} };
4
+
5
+ export { config };
6
+
7
+ const helpers = { validate: () => {} };
8
+
9
+ export { utils };
10
+ export { helpers };
@@ -0,0 +1,2 @@
1
+ // Valid: Single direct export at declaration point
2
+ export const apiUrl = "https://api.example.com";
@@ -0,0 +1,7 @@
1
+ // Valid: Default export with grouped named exports
2
+ const mainConfig = { theme: 'dark' };
3
+ const helper1 = () => 'helper';
4
+ const helper2 = () => 'another helper';
5
+
6
+ export default mainConfig;
7
+ export { helper1, helper2 };
@@ -0,0 +1,6 @@
1
+ // Valid: All named exports consolidated into a single export statement
2
+ const apiUrl = "https://api.example.com";
3
+ const timeout = 5000;
4
+ const retries = 3;
5
+
6
+ export { apiUrl, timeout, retries };
@@ -0,0 +1,3 @@
1
+ export const groupExportsConfig = {
2
+ "import/group-exports": "error", // Enforce consolidating exports into single statements
3
+ };
@@ -1,8 +1,12 @@
1
+ import { noUnusedModulesConfig } from "./no-unused-modules/index.js";
2
+ import { groupExportsConfig } from "./group-exports/index.js";
3
+
1
4
  export const importRules = {
2
5
  // Import/export organization and restrictions
3
- "import/group-exports": "error", // Enforce consolidating exports into single statements
6
+ ...groupExportsConfig,
4
7
  "import/no-default-export": "off", // Allow default exports
5
8
  "import/no-namespace": "error",
9
+ ...noUnusedModulesConfig,
6
10
  // Disabled import rules (keep existing behavior)
7
11
  "import/extensions": ["off"],
8
12
  "import/no-extraneous-dependencies": ["off"],
@@ -0,0 +1,2 @@
1
+ // Invalid: This export is never imported (while others in the project might be used)
2
+ export const unusedExport = "This is never imported";
@@ -0,0 +1,6 @@
1
+ // Invalid: This class export is never imported by any other module
2
+ export class UnusedClass {
3
+ method() {
4
+ return "This class is never instantiated";
5
+ }
6
+ }
@@ -0,0 +1,2 @@
1
+ // Invalid: This export is never imported by any other module
2
+ export const unusedConstant = "This value is never used";
@@ -0,0 +1,4 @@
1
+ // Invalid: This function export is never imported by any other module
2
+ export function unusedFunction() {
3
+ return "This function is never called";
4
+ }
@@ -0,0 +1,4 @@
1
+ // Invalid: This entire module is never imported anywhere
2
+ const internalData = [1, 2, 3];
3
+
4
+ export const result = internalData.map(x => x * 2);
@@ -0,0 +1,8 @@
1
+ // Valid: This module consumes exports from other modules
2
+ import { apiUrl } from './used-export.js';
3
+ import { fetchData } from './used-function.js';
4
+ import { DataProcessor } from './used-class.js';
5
+
6
+ const processor = new DataProcessor();
7
+ fetchData().then(data => processor.process(data));
8
+ console.log(`API URL: ${apiUrl}`);
@@ -0,0 +1,5 @@
1
+ // Valid: Entry point that imports and uses modules
2
+ import './consumed-import.js';
3
+
4
+ // Entry points are typically excluded from unused module detection
5
+ console.log('Application started');
@@ -0,0 +1,6 @@
1
+ // Valid: Class export is used by other modules
2
+ export class DataProcessor {
3
+ process(data) {
4
+ return data.map(item => item.value);
5
+ }
6
+ }
@@ -0,0 +1,2 @@
1
+ // Valid: Export is used by other modules
2
+ export const apiUrl = "https://api.example.com";
@@ -0,0 +1,4 @@
1
+ // Valid: Function export is used by other modules
2
+ export function fetchData() {
3
+ return fetch("https://api.example.com");
4
+ }
@@ -0,0 +1,6 @@
1
+ // Note: import/no-unused-modules has compatibility issues with ESLint flat config
2
+ // It requires an .eslintrc file and has complex setup requirements
3
+ // For now, this rule is disabled to avoid configuration conflicts
4
+ export const noUnusedModulesConfig = {
5
+ // "import/no-unused-modules": "off", // Disabled due to flat config compatibility issues
6
+ };
@@ -1,4 +1,6 @@
1
+ import { noExplicitAnyConfig } from "./no-explicit-any/index.js";
2
+
1
3
  export const typescriptEslintRules = {
2
- "@typescript-eslint/no-explicit-any": "error",
4
+ ...noExplicitAnyConfig,
3
5
  "@typescript-eslint/consistent-type-assertions": "off",
4
6
  };
@@ -0,0 +1,2 @@
1
+ // Invalid: Using any in array type
2
+ export const items: any[] = ["hello", 42, true, { name: "test" }];
@@ -0,0 +1,4 @@
1
+ // Invalid: Using any type for function parameter
2
+ export function processData(data: any): number {
3
+ return data.length;
4
+ }
@@ -0,0 +1,4 @@
1
+ // Invalid: Using any as return type
2
+ export function getData(): any {
3
+ return { message: "Hello world" };
4
+ }
@@ -0,0 +1,5 @@
1
+ // Invalid: Using any type for variable declaration
2
+ export const config: any = {
3
+ apiUrl: "https://api.example.com",
4
+ timeout: 5000,
5
+ };
@@ -0,0 +1,16 @@
1
+ // Valid: Using generics instead of any
2
+ export function identity<T>(value: T): T {
3
+ return value;
4
+ }
5
+
6
+ export class Container<T> {
7
+ private value: T;
8
+
9
+ constructor(value: T) {
10
+ this.value = value;
11
+ }
12
+
13
+ getValue(): T {
14
+ return this.value;
15
+ }
16
+ }
@@ -0,0 +1,9 @@
1
+ // Valid: Using specific types instead of any
2
+ export function processData(data: string[]): number {
3
+ return data.length;
4
+ }
5
+
6
+ export const config: { apiUrl: string; timeout: number } = {
7
+ apiUrl: "https://api.example.com",
8
+ timeout: 5000,
9
+ };
@@ -0,0 +1,8 @@
1
+ // Valid: Using unknown instead of any for safer type handling
2
+ export function parseJson(json: string): unknown {
3
+ return JSON.parse(json);
4
+ }
5
+
6
+ export function isString(value: unknown): value is string {
7
+ return typeof value === "string";
8
+ }
@@ -0,0 +1,3 @@
1
+ export const noExplicitAnyConfig = {
2
+ "@typescript-eslint/no-explicit-any": "error", // Disallow usage of the any type
3
+ };