eslint-config-agent 1.1.2 → 1.1.4

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/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. See [Conven
4
4
 
5
5
 
6
6
 
7
+ ## [1.1.4](https://github.com/tupe12334/eslint-config/compare/v1.1.3...v1.1.4) (2025-09-10)
8
+
9
+ ### Features
10
+
11
+ * add no-empty-exports rule to prevent empty export specifiers and include test cases ([7757007](https://github.com/tupe12334/eslint-config/commit/77570076e41bdab64dbed53ca7a40a935eda7e3a))
12
+ * enhance export specifier rules and update test configurations for improved validation ([fe64b9c](https://github.com/tupe12334/eslint-config/commit/fe64b9cb7f1bdf80b16a97db75a5fd04901c2e7f))
13
+ * remove package-specific ignores from ESLint config for cleaner configuration ([03cef75](https://github.com/tupe12334/eslint-config/commit/03cef75a6ad6d682ede5f4c5dc5d5e1a8d0a9aaa))
14
+
15
+ ## [1.1.3](https://github.com/tupe12334/eslint-config/compare/v1.1.2...v1.1.3) (2025-09-10)
16
+
17
+ ### Features
18
+
19
+ * add no-type-assertions rule to disallow TypeScript type assertions using "as" keyword ([39b708f](https://github.com/tupe12334/eslint-config/commit/39b708f9da6eb0c491b0e53248af78821f4b3598))
20
+ * consolidate ESLint rule imports into a single index file for better organization ([37be460](https://github.com/tupe12334/eslint-config/commit/37be46083350d151a5803b9c230c538caa9eb857))
21
+ * refactor ESLint rule imports to use a consolidated allRules object for improved organization ([47c3eea](https://github.com/tupe12334/eslint-config/commit/47c3eea5f02dd204bf86ab6150d319eed07440da))
22
+
7
23
  ## [1.1.2](https://github.com/tupe12334/eslint-config/compare/v1.1.1...v1.1.2) (2025-09-10)
8
24
 
9
25
  ### Features
package/index.js CHANGED
@@ -9,12 +9,7 @@ import nPlugin from "eslint-plugin-n";
9
9
  import classExportPlugin from "eslint-plugin-class-export";
10
10
  import storybookPlugin from "eslint-plugin-storybook";
11
11
  import globals from "globals";
12
- import noTrailingSpacesConfig from "./rules/no-trailing-spaces/index.js";
13
- import { maxFunctionLinesWarning, maxFunctionLinesError } from "./rules/max-function-lines/index.js";
14
- import { maxFileLinesWarning, maxFileLinesError } from "./rules/max-file-lines/index.js";
15
- import { pluginRules } from "./rules/plugin/index.js";
16
- import { typescriptEslintRules } from "./rules/plugin/typescript-eslint/index.js";
17
- import { noProcessEnvPropertiesConfig } from "./rules/no-process-env-properties/index.js";
12
+ import allRules from "./rules/index.js";
18
13
 
19
14
  // Conditionally import preact plugin if available
20
15
  let preactPlugin = null;
@@ -24,21 +19,20 @@ try {
24
19
  // eslint-plugin-preact is not available
25
20
  }
26
21
 
27
-
28
22
  // Shared rules for both JS and TS files
29
23
  const sharedRules = {
30
- ...pluginRules,
24
+ ...allRules.pluginRules,
31
25
  "object-curly-newline": "off",
32
26
  "no-shadow": "off",
33
27
  "comma-dangle": "off",
34
28
  "function-paren-newline": "off",
35
29
  quotes: "off",
36
30
  "no-unused-vars": "off",
37
- "max-lines-per-function": maxFunctionLinesWarning,
38
- "max-lines": maxFileLinesWarning,
31
+ "max-lines-per-function": allRules.maxFunctionLinesWarning,
32
+ "max-lines": allRules.maxFileLinesWarning,
39
33
  semi: "off",
40
34
  complexity: "off",
41
- "no-trailing-spaces": noTrailingSpacesConfig,
35
+ "no-trailing-spaces": allRules.noTrailingSpacesConfig,
42
36
  "operator-linebreak": "off",
43
37
  "implicit-arrow-linebreak": "off",
44
38
  "arrow-body-style": "off",
@@ -99,13 +93,15 @@ const sharedRestrictedSyntax = [
99
93
  message:
100
94
  "Exporting from external libraries is not allowed. Only re-export from relative paths or scoped packages.",
101
95
  },
102
- noProcessEnvPropertiesConfig,
96
+ allRules.noProcessEnvPropertiesConfig,
97
+ allRules.noExportSpecifiersConfig,
103
98
  ];
104
99
 
105
100
  // Required export rules (always errors)
106
101
  const requiredExportRules = [
107
102
  {
108
- selector: "ClassDeclaration:not(ExportNamedDeclaration > ClassDeclaration):not(ExportDefaultDeclaration > ClassDeclaration)",
103
+ selector:
104
+ "ClassDeclaration:not(ExportNamedDeclaration > ClassDeclaration):not(ExportDefaultDeclaration > ClassDeclaration)",
109
105
  message:
110
106
  "Classes must be exported. Use 'export class' or 'export default class'.",
111
107
  },
@@ -148,11 +144,7 @@ const tsOnlyRestrictedSyntax = [
148
144
  message:
149
145
  "Class properties with literal unions should use a named type declaration.",
150
146
  },
151
- {
152
- selector:
153
- 'TSAsExpression:not(:has(TSTypeReference[typeName.name="const"]))',
154
- message: 'Type assertions with "as" are not allowed except for "as const".',
155
- },
147
+ allRules.noTypeAssertionsConfig,
156
148
  {
157
149
  selector: "TSAsExpression:has(> TSIndexedAccessType > TSTypeQuery)",
158
150
  message:
@@ -208,9 +200,6 @@ const config = [
208
200
  },
209
201
  },
210
202
  reactHooks.configs["recommended-latest"],
211
- {
212
- ignores: ["packages/auth-service-sdk/**"],
213
- },
214
203
  js.configs.recommended,
215
204
 
216
205
  // TypeScript and TSX files
@@ -221,10 +210,6 @@ const config = [
221
210
  "**/dist/**",
222
211
  "**/build/**",
223
212
  "pnpm-lock.yaml",
224
- "packages/auth-service-sdk/**",
225
- "packages/auth-service-sdk/src/core/**",
226
- "packages/auth-service-sdk/src/client/**",
227
- "packages/auth-service-sdk/src/*.gen.ts",
228
213
  "**/*.stories.{js,jsx,ts,tsx}",
229
214
  ],
230
215
  languageOptions: {
@@ -257,7 +242,7 @@ const config = [
257
242
  },
258
243
  rules: {
259
244
  ...sharedRules,
260
- ...typescriptEslintRules,
245
+ ...allRules.typescriptEslintRules,
261
246
  "no-undef": "off", // TypeScript handles this
262
247
  "no-restricted-syntax": [
263
248
  "error",
@@ -434,11 +419,11 @@ const config = [
434
419
  "**/dist/**",
435
420
  "**/build/**",
436
421
  "pnpm-lock.yaml",
437
- "packages/auth-service-sdk/**",
438
422
  "**/*.umd.js",
439
423
  "**/*.cjs",
440
424
  "**/*.mjs",
441
425
  "**/*.stories.{js,jsx,ts,tsx}",
426
+ "**/rules/**",
442
427
  ],
443
428
  languageOptions: {
444
429
  parserOptions: {
@@ -504,7 +489,6 @@ const config = [
504
489
  "**/dist/**",
505
490
  "**/build/**",
506
491
  "pnpm-lock.yaml",
507
- "packages/auth-service-sdk/**",
508
492
  "**/*.stories.{js,jsx,ts,tsx}",
509
493
  ],
510
494
  languageOptions: {
@@ -624,7 +608,6 @@ const config = [
624
608
  "**/dist/**",
625
609
  "**/build/**",
626
610
  "pnpm-lock.yaml",
627
- "packages/auth-service-sdk/**",
628
611
  "**/*.stories.{js,jsx,ts,tsx}",
629
612
  ],
630
613
  languageOptions: {
@@ -725,7 +708,33 @@ const config = [
725
708
  rule.selector !==
726
709
  "ExportNamedDeclaration[specifiers.length>1]:not([source])" &&
727
710
  rule.selector !==
728
- "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))"
711
+ "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))" &&
712
+ rule.selector !==
713
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
714
+ ),
715
+ ...tsOnlyRestrictedSyntax,
716
+ ],
717
+ },
718
+ },
719
+
720
+ // Test files that should have ERROR level rules but exclude export specifier rule
721
+ {
722
+ files: [
723
+ "**/test/type-assertions/**",
724
+ "**/test/test-optional.ts",
725
+ "**/test/test-js-optional.js",
726
+ "**/test/test-record-literals.ts",
727
+ "**/test/no-env-access-test.ts",
728
+ "**/test/import-export-rules.ts",
729
+ ],
730
+ rules: {
731
+ "max-lines-per-function": "off",
732
+ "no-restricted-syntax": [
733
+ "error", // Error level for these test files
734
+ ...sharedRestrictedSyntax.filter(
735
+ (rule) =>
736
+ rule.selector !==
737
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
729
738
  ),
730
739
  ...tsOnlyRestrictedSyntax,
731
740
  ],
@@ -736,6 +745,9 @@ const config = [
736
745
  {
737
746
  files: [
738
747
  "**/test/invalid.tsx", // Special handling for the main test file
748
+ "**/test/single-export-valid.ts", // Allow export specifiers for import/group-exports testing
749
+ "**/test/typescript-rules.ts", // Allow export specifiers for typescript rules testing
750
+ "**/test/type-assertions/indexed-access-valid.ts", // Allow export specifiers for type assertions testing
739
751
  ],
740
752
  rules: {
741
753
  "max-lines-per-function": "off",
@@ -746,7 +758,9 @@ const config = [
746
758
  rule.selector !==
747
759
  "ExportNamedDeclaration[specifiers.length>1]:not([source])" &&
748
760
  rule.selector !==
749
- "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))"
761
+ "Program:has(ExportNamedDeclaration:not([source]) ~ ExportNamedDeclaration:not([source]))" &&
762
+ rule.selector !==
763
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
750
764
  ),
751
765
  ...tsOnlyRestrictedSyntax,
752
766
  // For TSX files, also include required export rules as warnings since we can't mix severities
@@ -786,7 +800,13 @@ const config = [
786
800
  // Switch case rules as errors for all TypeScript/JSX files (must come last to override)
787
801
  {
788
802
  files: ["**/*.{ts,tsx,js,jsx}"],
789
- ignores: ["**/*.stories.{js,jsx,ts,tsx}"],
803
+ ignores: [
804
+ "**/*.stories.{js,jsx,ts,tsx}",
805
+ "**/test/**",
806
+ "!**/test/export/**",
807
+ "!**/test/required-exports/**",
808
+ "**/rules/**",
809
+ ],
790
810
  rules: {
791
811
  "no-restricted-syntax": [
792
812
  "error",
@@ -867,7 +887,9 @@ const config = [
867
887
  message:
868
888
  'Type assertions with indexed access types like "as (typeof X)[number]" are not allowed. Use a named type instead.',
869
889
  },
870
- noProcessEnvPropertiesConfig,
890
+ allRules.noTypeAssertionsConfig,
891
+ allRules.noProcessEnvPropertiesConfig,
892
+ allRules.noExportSpecifiersConfig,
871
893
  // Export restriction rules
872
894
  // Required export rules
873
895
  ...requiredExportRules,
@@ -897,9 +919,9 @@ const config = [
897
919
  ignores: ["**/*.stories.{js,jsx,ts,tsx}"],
898
920
  rules: {
899
921
  // Function length: error at 70+ lines
900
- "max-lines-per-function": maxFunctionLinesError,
922
+ "max-lines-per-function": allRules.maxFunctionLinesError,
901
923
  // File length: error at 100+ lines
902
- "max-lines": maxFileLinesError,
924
+ "max-lines": allRules.maxFileLinesError,
903
925
  },
904
926
  },
905
927
 
@@ -954,6 +976,27 @@ const config = [
954
976
  ...storybookPlugin.configs.recommended.rules,
955
977
  },
956
978
  },
979
+
980
+ // Rules directory configuration - allow export specifiers for API definitions
981
+ {
982
+ files: ["**/rules/**/*.{js,ts}"],
983
+ languageOptions: {
984
+ globals: {
985
+ ...globals.node,
986
+ },
987
+ },
988
+ rules: {
989
+ "no-restricted-syntax": [
990
+ "error",
991
+ // Include all shared rules EXCEPT our export specifier rule
992
+ ...sharedRestrictedSyntax.filter(
993
+ (rule) =>
994
+ rule.selector !==
995
+ "ExportNamedDeclaration:not([source]):not(:has(VariableDeclaration)):not(:has(FunctionDeclaration)):not(:has(ClassDeclaration)):not(:has(TSInterfaceDeclaration)):not(:has(TSTypeAliasDeclaration)):not(:has(TSEnumDeclaration))"
996
+ ),
997
+ ],
998
+ },
999
+ },
957
1000
  ];
958
1001
 
959
1002
  export default config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-agent",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "ESLint configuration package with TypeScript support",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/rules/index.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Aggregated exports for all custom ESLint rules
3
+ *
4
+ * This file centralizes imports from all rule modules in the rules/ directory
5
+ * and re-exports them for easier consumption by the main configuration.
6
+ */
7
+
8
+ // Core rule configurations
9
+ import noTrailingSpacesConfig from "./no-trailing-spaces/index.js";
10
+ import { maxFunctionLinesWarning, maxFunctionLinesError } from "./max-function-lines/index.js";
11
+ import { maxFileLinesWarning, maxFileLinesError } from "./max-file-lines/index.js";
12
+
13
+ // Custom restricted syntax rules
14
+ import { noProcessEnvPropertiesConfig } from "./no-process-env-properties/index.js";
15
+ import { noTypeAssertionsConfig } from "./no-type-assertions/index.js";
16
+ import { noExportSpecifiersConfig } from "./no-empty-exports/index.js";
17
+
18
+ // Plugin rule configurations
19
+ import { pluginRules } from "./plugin/index.js";
20
+ import { typescriptEslintRules } from "./plugin/typescript-eslint/index.js";
21
+
22
+ // Consolidated exports
23
+ const allRules = {
24
+ // Core rule configurations
25
+ noTrailingSpacesConfig,
26
+ maxFunctionLinesWarning,
27
+ maxFunctionLinesError,
28
+ maxFileLinesWarning,
29
+ maxFileLinesError,
30
+
31
+ // Custom restricted syntax rules
32
+ noProcessEnvPropertiesConfig,
33
+ noTypeAssertionsConfig,
34
+ noExportSpecifiersConfig,
35
+
36
+ // Plugin rule configurations
37
+ pluginRules,
38
+ typescriptEslintRules,
39
+ };
40
+
41
+ export default allRules;
42
+
43
+ // Named exports for backward compatibility
44
+ export {
45
+ // Core rule configurations
46
+ noTrailingSpacesConfig,
47
+ maxFunctionLinesWarning,
48
+ maxFunctionLinesError,
49
+ maxFileLinesWarning,
50
+ maxFileLinesError,
51
+
52
+ // Custom restricted syntax rules
53
+ noProcessEnvPropertiesConfig,
54
+ noTypeAssertionsConfig,
55
+ noExportSpecifiersConfig,
56
+
57
+ // Plugin rule configurations
58
+ pluginRules,
59
+ typescriptEslintRules,
60
+ };
@@ -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,38 @@
1
+ /**
2
+ * Rule configuration for no-type-assertions
3
+ *
4
+ * This rule disallows TypeScript type assertions using the "as" keyword,
5
+ * except for "as const" which is allowed for creating readonly literal types.
6
+ *
7
+ * Examples:
8
+ * - ❌ value as string
9
+ * - ❌ value as User
10
+ * - ❌ obj as { name: string }
11
+ * - ✅ { mode: 'prod' } as const
12
+ * - ✅ ['a', 'b'] as const
13
+ *
14
+ * @see https://eslint.org/docs/latest/rules/no-restricted-syntax
15
+ */
16
+
17
+ const rule = "error";
18
+
19
+ const selector =
20
+ 'TSAsExpression:not(:has(TSTypeReference[typeName.name="const"]))';
21
+
22
+ const message =
23
+ 'Type assertions with "as" are not allowed except for "as const".';
24
+
25
+ /**
26
+ * Export the complete rule configuration for no-restricted-syntax
27
+ * Can be used in ESLint config as part of no-restricted-syntax rules:
28
+ * "no-restricted-syntax": ["error", ...otherRules, noTypeAssertionsConfig]
29
+ */
30
+ const noTypeAssertionsConfig = {
31
+ selector,
32
+ message,
33
+ };
34
+
35
+ // Consolidated exports
36
+ export { rule, selector, message, noTypeAssertionsConfig };
37
+
38
+ export default noTypeAssertionsConfig;
@@ -0,0 +1,246 @@
1
+ import { RuleTester } from "eslint";
2
+ import { noTypeAssertionsConfig } from "./index.js";
3
+
4
+ /**
5
+ * Test suite for no-type-assertions rule
6
+ *
7
+ * This tests the no-restricted-syntax configuration that prevents
8
+ * TypeScript type assertions using "as" keyword except for "as const".
9
+ */
10
+
11
+ // Create a custom rule for testing our selector
12
+ const noTypeAssertionsRule = {
13
+ meta: {
14
+ type: "problem",
15
+ docs: {
16
+ description: "Disallow type assertions except 'as const'",
17
+ },
18
+ messages: {
19
+ noTypeAssertions: noTypeAssertionsConfig.message,
20
+ },
21
+ schema: [],
22
+ },
23
+ create(context) {
24
+ return {
25
+ [noTypeAssertionsConfig.selector](node) {
26
+ context.report({
27
+ node,
28
+ messageId: "noTypeAssertions",
29
+ });
30
+ },
31
+ };
32
+ },
33
+ };
34
+
35
+ const ruleTester = new RuleTester({
36
+ languageOptions: {
37
+ ecmaVersion: 2022,
38
+ sourceType: "module",
39
+ parser: (await import("@typescript-eslint/parser")).default,
40
+ parserOptions: {
41
+ ecmaFeatures: {
42
+ jsx: true,
43
+ },
44
+ },
45
+ },
46
+ });
47
+
48
+ ruleTester.run("no-type-assertions", noTypeAssertionsRule, {
49
+ valid: [
50
+ // Valid: "as const" usage
51
+ {
52
+ code: "const config = { mode: 'production' } as const;",
53
+ name: "object as const",
54
+ },
55
+ {
56
+ code: "const colors = ['red', 'green', 'blue'] as const;",
57
+ name: "array as const",
58
+ },
59
+ {
60
+ code: "const status = 'loading' as const;",
61
+ name: "string literal as const",
62
+ },
63
+ {
64
+ code: "const numbers = [1, 2, 3] as const;",
65
+ name: "number array as const",
66
+ },
67
+ {
68
+ code: "const tuple = ['name', 42, true] as const;",
69
+ name: "mixed tuple as const",
70
+ },
71
+ {
72
+ code: "const nested = { items: [{ id: 1 }] as const } as const;",
73
+ name: "nested as const",
74
+ },
75
+
76
+ // Valid: No type assertions at all
77
+ {
78
+ code: "const value: string = 'hello';",
79
+ name: "type annotation instead of assertion",
80
+ },
81
+ {
82
+ code: "function getValue(): string { return 'test'; }",
83
+ name: "function with return type",
84
+ },
85
+ {
86
+ code: "interface User { name: string; } const user: User = { name: 'John' };",
87
+ name: "interface with proper typing",
88
+ },
89
+ {
90
+ code: "const element = document.getElementById('test');",
91
+ name: "no type assertion on DOM access",
92
+ },
93
+ ],
94
+
95
+ invalid: [
96
+ // Invalid: Basic type assertions
97
+ {
98
+ code: "declare const value: unknown; const str = value as string;",
99
+ errors: [{ messageId: "noTypeAssertions" }],
100
+ name: "basic string assertion",
101
+ },
102
+ {
103
+ code: "declare const value: unknown; const num = value as number;",
104
+ errors: [{ messageId: "noTypeAssertions" }],
105
+ name: "basic number assertion",
106
+ },
107
+ {
108
+ code: "declare const value: unknown; const bool = value as boolean;",
109
+ errors: [{ messageId: "noTypeAssertions" }],
110
+ name: "basic boolean assertion",
111
+ },
112
+
113
+ // Invalid: Interface and type assertions
114
+ {
115
+ code: "interface User { name: string; } declare const value: unknown; const user = value as User;",
116
+ errors: [{ messageId: "noTypeAssertions" }],
117
+ name: "interface assertion",
118
+ },
119
+ {
120
+ code: "type Status = 'loading' | 'success'; declare const value: unknown; const status = value as Status;",
121
+ errors: [{ messageId: "noTypeAssertions" }],
122
+ name: "type alias assertion",
123
+ },
124
+
125
+ // Invalid: DOM element assertions
126
+ {
127
+ code: "const element = document.getElementById('test') as HTMLInputElement;",
128
+ errors: [{ messageId: "noTypeAssertions" }],
129
+ name: "DOM element assertion",
130
+ },
131
+ {
132
+ code: "const button = document.querySelector('.btn') as HTMLButtonElement;",
133
+ errors: [{ messageId: "noTypeAssertions" }],
134
+ name: "DOM querySelector assertion",
135
+ },
136
+
137
+ // Invalid: Object and array assertions
138
+ {
139
+ code: "declare const data: unknown; const obj = data as { name: string };",
140
+ errors: [{ messageId: "noTypeAssertions" }],
141
+ name: "object literal type assertion",
142
+ },
143
+ {
144
+ code: "declare const data: unknown; const arr = data as string[];",
145
+ errors: [{ messageId: "noTypeAssertions" }],
146
+ name: "array type assertion",
147
+ },
148
+ {
149
+ code: "declare const data: unknown; const tuple = data as [string, number];",
150
+ errors: [{ messageId: "noTypeAssertions" }],
151
+ name: "tuple type assertion",
152
+ },
153
+
154
+ // Invalid: Function parameter and return assertions
155
+ {
156
+ code: "function test(param: unknown) { return param as string; }",
157
+ errors: [{ messageId: "noTypeAssertions" }],
158
+ name: "return value assertion",
159
+ },
160
+ {
161
+ code: "const fn = (value: unknown) => value as number;",
162
+ errors: [{ messageId: "noTypeAssertions" }],
163
+ name: "arrow function assertion",
164
+ },
165
+
166
+ // Invalid: Complex expressions
167
+ {
168
+ code: "declare const api: any; const result = api.getData() as Promise<User>;",
169
+ errors: [{ messageId: "noTypeAssertions" }],
170
+ name: "method call assertion",
171
+ },
172
+ {
173
+ code: "declare const obj: any; const prop = obj.property as string;",
174
+ errors: [{ messageId: "noTypeAssertions" }],
175
+ name: "property access assertion",
176
+ },
177
+ {
178
+ code: "declare const arr: any[]; const first = arr[0] as string;",
179
+ errors: [{ messageId: "noTypeAssertions" }],
180
+ name: "array access assertion",
181
+ },
182
+
183
+ // Invalid: Generic type assertions
184
+ {
185
+ code: "declare const value: unknown; const generic = value as Array<string>;",
186
+ errors: [{ messageId: "noTypeAssertions" }],
187
+ name: "generic type assertion",
188
+ },
189
+ {
190
+ code: "declare const value: unknown; const promise = value as Promise<number>;",
191
+ errors: [{ messageId: "noTypeAssertions" }],
192
+ name: "Promise generic assertion",
193
+ },
194
+
195
+ // Invalid: Any type assertions
196
+ {
197
+ code: "declare const value: unknown; const anything = value as any;",
198
+ errors: [{ messageId: "noTypeAssertions" }],
199
+ name: "any type assertion",
200
+ },
201
+
202
+ // Invalid: Chained assertions
203
+ {
204
+ code: "declare const value: unknown; const result = (value as any).prop as string;",
205
+ errors: [
206
+ { messageId: "noTypeAssertions" },
207
+ { messageId: "noTypeAssertions" }
208
+ ],
209
+ name: "chained assertions",
210
+ },
211
+
212
+ // Invalid: Template literal expressions
213
+ {
214
+ code: "declare const id: unknown; const message = `User ID: ${id as string}`;",
215
+ errors: [{ messageId: "noTypeAssertions" }],
216
+ name: "assertion in template literal",
217
+ },
218
+
219
+ // Invalid: Conditional expressions
220
+ {
221
+ code: "declare const value: unknown; const result = value ? value as string : 'default';",
222
+ errors: [{ messageId: "noTypeAssertions" }],
223
+ name: "assertion in conditional",
224
+ },
225
+
226
+ // Invalid: Object property values
227
+ {
228
+ code: "declare const name: unknown; const user = { name: name as string, age: 30 };",
229
+ errors: [{ messageId: "noTypeAssertions" }],
230
+ name: "assertion in object property",
231
+ },
232
+
233
+ // Invalid: Array elements
234
+ {
235
+ code: "declare const item: unknown; const items = [item as string, 'other'];",
236
+ errors: [{ messageId: "noTypeAssertions" }],
237
+ name: "assertion in array element",
238
+ },
239
+ ],
240
+ });
241
+
242
+ console.log("✅ All no-type-assertions tests passed!");
243
+ console.log(` Selector: ${noTypeAssertionsConfig.selector}`);
244
+ console.log(` Message: ${noTypeAssertionsConfig.message}`);
245
+
246
+ export { noTypeAssertionsRule };
@@ -1,10 +1,4 @@
1
1
  export const typescriptEslintRules = {
2
2
  "@typescript-eslint/no-explicit-any": "error",
3
- "@typescript-eslint/consistent-type-assertions": [
4
- "error",
5
- {
6
- assertionStyle: "as",
7
- objectLiteralTypeAssertions: "allow-as-parameter",
8
- },
9
- ],
3
+ "@typescript-eslint/consistent-type-assertions": "off",
10
4
  };