@ttsc/lint 0.13.0 → 0.14.0-dev.20250530.1

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 (498) hide show
  1. package/README.md +955 -85
  2. package/lib/defaultFormat.d.ts +15 -8
  3. package/lib/defaultFormat.js +15 -8
  4. package/lib/defaultFormat.js.map +1 -1
  5. package/lib/index.d.ts +46 -0
  6. package/lib/index.js +60 -37
  7. package/lib/index.js.map +1 -1
  8. package/lib/structures/ITtscLintConfig.d.ts +12 -6
  9. package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
  10. package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
  11. package/lib/structures/TtscLintRuleSetting.js.map +1 -0
  12. package/lib/structures/format/ITtscLintFormat.d.ts +128 -0
  13. package/lib/structures/{TtscLintRuleMap.js → format/ITtscLintFormat.js} +1 -1
  14. package/lib/structures/format/ITtscLintFormat.js.map +1 -0
  15. package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +17 -0
  16. package/lib/structures/{ITtscLintFormatConfig.js → format/ITtscLintFormatJsDoc.js} +1 -1
  17. package/lib/structures/format/ITtscLintFormatJsDoc.js.map +1 -0
  18. package/lib/structures/format/ITtscLintFormatSortImports.d.ts +54 -0
  19. package/lib/structures/format/ITtscLintFormatSortImports.js +3 -0
  20. package/lib/structures/format/ITtscLintFormatSortImports.js.map +1 -0
  21. package/lib/structures/format/index.d.ts +3 -0
  22. package/lib/structures/format/index.js +20 -0
  23. package/lib/structures/format/index.js.map +1 -0
  24. package/lib/structures/index.d.ts +3 -4
  25. package/lib/structures/index.js +3 -4
  26. package/lib/structures/index.js.map +1 -1
  27. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +95 -0
  28. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +13 -0
  29. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
  30. package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +75 -0
  31. package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
  32. package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
  33. package/lib/structures/rules/ITtscLintContributorRules.d.ts +16 -0
  34. package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
  35. package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
  36. package/lib/structures/rules/ITtscLintCoreRules.d.ts +1229 -0
  37. package/lib/structures/rules/ITtscLintCoreRules.js +3 -0
  38. package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
  39. package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
  40. package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
  41. package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
  42. package/lib/structures/rules/ITtscLintCypressRules.d.ts +125 -0
  43. package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
  44. package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
  45. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +154 -0
  46. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
  47. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
  48. package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +162 -0
  49. package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
  50. package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
  51. package/lib/structures/rules/ITtscLintJestRules.d.ts +190 -0
  52. package/lib/structures/rules/ITtscLintJestRules.js +3 -0
  53. package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
  54. package/lib/structures/rules/ITtscLintJsdocRules.d.ts +133 -0
  55. package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
  56. package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
  57. package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +294 -0
  58. package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
  59. package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
  60. package/lib/structures/rules/ITtscLintNextjsRules.d.ts +180 -0
  61. package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
  62. package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
  63. package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +312 -0
  64. package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
  65. package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
  66. package/lib/structures/rules/ITtscLintPromiseRules.d.ts +179 -0
  67. package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
  68. package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
  69. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
  70. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
  71. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
  72. package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +49 -0
  73. package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
  74. package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
  75. package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +37 -0
  76. package/lib/structures/rules/ITtscLintReactRuleOptions.js +11 -0
  77. package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
  78. package/lib/structures/rules/ITtscLintReactRules.d.ts +276 -0
  79. package/lib/structures/rules/ITtscLintReactRules.js +3 -0
  80. package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
  81. package/lib/structures/rules/ITtscLintRegexpRules.d.ts +182 -0
  82. package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
  83. package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
  84. package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +65 -0
  85. package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
  86. package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
  87. package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
  88. package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
  89. package/lib/structures/rules/ITtscLintRules.js.map +1 -0
  90. package/lib/structures/rules/ITtscLintSecurityRules.d.ts +141 -0
  91. package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
  92. package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
  93. package/lib/structures/rules/ITtscLintSolidRules.d.ts +178 -0
  94. package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
  95. package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
  96. package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +20 -0
  97. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
  98. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
  99. package/lib/structures/rules/ITtscLintStorybookRules.d.ts +165 -0
  100. package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
  101. package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
  102. package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +88 -0
  103. package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
  104. package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
  105. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +21 -0
  106. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
  107. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
  108. package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +293 -0
  109. package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
  110. package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
  111. package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1074 -0
  112. package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
  113. package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
  114. package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
  115. package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
  116. package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
  117. package/lib/structures/rules/ITtscLintVitestRules.d.ts +133 -0
  118. package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
  119. package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
  120. package/lib/structures/rules/index.d.ts +31 -0
  121. package/lib/structures/rules/index.js +48 -0
  122. package/lib/structures/rules/index.js.map +1 -0
  123. package/linthost/ast_helpers.go +30 -5
  124. package/linthost/compile.go +33 -2
  125. package/linthost/config.go +118 -71
  126. package/linthost/config_format.go +270 -104
  127. package/linthost/directives.go +67 -25
  128. package/linthost/dispatch.go +14 -3
  129. package/linthost/engine.go +160 -40
  130. package/linthost/fix.go +10 -3
  131. package/linthost/flags_gen.go +17 -15
  132. package/linthost/format.go +222 -25
  133. package/linthost/format_editor_settings.go +262 -0
  134. package/linthost/host.go +40 -3
  135. package/linthost/lsp.go +898 -0
  136. package/linthost/print_dispatch.go +5 -2
  137. package/linthost/print_engine.go +5 -5
  138. package/linthost/print_nodes_call.go +149 -67
  139. package/linthost/print_nodes_function.go +27 -2
  140. package/linthost/print_nodes_list.go +40 -5
  141. package/linthost/print_nodes_object.go +1 -1
  142. package/linthost/print_nodes_ternary.go +86 -0
  143. package/linthost/rule_names.go +14 -0
  144. package/linthost/rules_arrays.go +2 -2
  145. package/linthost/rules_boundaries.go +532 -0
  146. package/linthost/rules_camelcase.go +133 -0
  147. package/linthost/rules_complexity.go +95 -0
  148. package/linthost/rules_consistent_return.go +130 -0
  149. package/linthost/rules_console.go +1 -1
  150. package/linthost/rules_core_extra.go +739 -0
  151. package/linthost/rules_curly.go +70 -0
  152. package/linthost/rules_cypress.go +608 -0
  153. package/linthost/rules_debugger.go +2 -2
  154. package/linthost/rules_default_case.go +39 -0
  155. package/linthost/rules_default_case_last.go +46 -0
  156. package/linthost/rules_dupes.go +3 -3
  157. package/linthost/rules_empty.go +3 -3
  158. package/linthost/rules_escape.go +44 -24
  159. package/linthost/rules_eval.go +2 -2
  160. package/linthost/rules_finally.go +2 -2
  161. package/linthost/rules_format_arrow_parens.go +167 -0
  162. package/linthost/rules_format_bracket_spacing.go +117 -0
  163. package/linthost/rules_format_clause_join.go +172 -0
  164. package/linthost/rules_format_declaration_header.go +595 -0
  165. package/linthost/rules_format_indent.go +372 -0
  166. package/linthost/rules_format_jsdoc.go +5 -5
  167. package/linthost/rules_format_orphan_semi.go +106 -0
  168. package/linthost/rules_format_parameter_properties.go +175 -0
  169. package/linthost/rules_format_print_width.go +66 -55
  170. package/linthost/rules_format_quote_props.go +169 -0
  171. package/linthost/rules_format_quotes.go +76 -30
  172. package/linthost/rules_format_semi.go +186 -11
  173. package/linthost/rules_format_sort_imports.go +437 -118
  174. package/linthost/rules_format_statement_split.go +343 -0
  175. package/linthost/rules_format_ternary_nullish_parens.go +77 -0
  176. package/linthost/rules_format_trailing_comma.go +22 -3
  177. package/linthost/rules_format_whitespace.go +336 -0
  178. package/linthost/rules_functional.go +967 -0
  179. package/linthost/rules_gap.go +24 -45
  180. package/linthost/rules_grouped_accessor_pairs.go +87 -0
  181. package/linthost/rules_guard_for_in.go +198 -0
  182. package/linthost/rules_id_length.go +77 -0
  183. package/linthost/rules_imports.go +70 -2
  184. package/linthost/rules_init_declarations.go +53 -0
  185. package/linthost/rules_jest.go +618 -0
  186. package/linthost/rules_jsdoc.go +502 -0
  187. package/linthost/rules_jsx_a11y.go +1264 -0
  188. package/linthost/rules_logic.go +12 -12
  189. package/linthost/rules_loops.go +1 -1
  190. package/linthost/rules_max_classes_per_file.go +58 -0
  191. package/linthost/rules_max_depth.go +83 -0
  192. package/linthost/rules_max_lines.go +101 -0
  193. package/linthost/rules_max_lines_per_function.go +57 -0
  194. package/linthost/rules_max_nested_callbacks.go +61 -0
  195. package/linthost/rules_max_params.go +49 -0
  196. package/linthost/rules_max_statements.go +59 -0
  197. package/linthost/rules_misc.go +1 -1
  198. package/linthost/rules_nextjs.go +697 -0
  199. package/linthost/rules_no_else_return.go +75 -0
  200. package/linthost/rules_no_empty_named_blocks.go +91 -0
  201. package/linthost/rules_no_extend_native.go +51 -0
  202. package/linthost/rules_no_import_assign.go +140 -0
  203. package/linthost/rules_no_invalid_this.go +52 -0
  204. package/linthost/rules_no_loop_func.go +85 -0
  205. package/linthost/rules_no_magic_numbers.go +123 -0
  206. package/linthost/rules_no_mixed_operators.go +80 -0
  207. package/linthost/rules_no_param_reassign.go +98 -0
  208. package/linthost/rules_no_redeclare.go +270 -0
  209. package/linthost/rules_no_restricted_imports.go +105 -0
  210. package/linthost/rules_no_restricted_syntax.go +49 -0
  211. package/linthost/rules_no_shadow.go +147 -0
  212. package/linthost/rules_no_unreachable.go +77 -0
  213. package/linthost/rules_no_useless_assignment.go +120 -0
  214. package/linthost/rules_no_useless_constructor.go +245 -0
  215. package/linthost/rules_no_useless_return.go +51 -0
  216. package/linthost/rules_params.go +1 -1
  217. package/linthost/rules_playwright.go +788 -0
  218. package/linthost/rules_prefer_arrow_callback.go +124 -0
  219. package/linthost/rules_prefer_destructuring.go +98 -0
  220. package/linthost/rules_prefer_named_capture_group.go +129 -0
  221. package/linthost/rules_prefer_rest_params.go +94 -0
  222. package/linthost/rules_problems.go +41 -30
  223. package/linthost/rules_promise.go +1057 -2
  224. package/linthost/rules_protos.go +2 -2
  225. package/linthost/rules_react.go +773 -0
  226. package/linthost/rules_react_extras.go +227 -0
  227. package/linthost/rules_react_hooks.go +848 -0
  228. package/linthost/rules_react_perf.go +293 -0
  229. package/linthost/rules_react_refresh.go +583 -0
  230. package/linthost/rules_regexp.go +410 -0
  231. package/linthost/rules_security.go +830 -0
  232. package/linthost/rules_self.go +2 -2
  233. package/linthost/rules_solid.go +1073 -0
  234. package/linthost/rules_sort_imports.go +69 -0
  235. package/linthost/rules_sort_keys.go +134 -0
  236. package/linthost/rules_storybook.go +1176 -0
  237. package/linthost/rules_strings.go +4 -4
  238. package/linthost/rules_suggestions.go +38 -38
  239. package/linthost/rules_tanstack_query.go +844 -0
  240. package/linthost/rules_testing_library.go +1204 -0
  241. package/linthost/rules_throw.go +1 -1
  242. package/linthost/rules_ts.go +19 -19
  243. package/linthost/rules_ts_async.go +399 -0
  244. package/linthost/rules_ts_class_literal_property_style.go +115 -0
  245. package/linthost/rules_ts_consistent_type_exports.go +256 -0
  246. package/linthost/rules_ts_explicit_function_return_type.go +67 -0
  247. package/linthost/rules_ts_extra.go +159 -36
  248. package/linthost/rules_ts_no_base_to_string.go +218 -0
  249. package/linthost/rules_ts_no_confusing_void.go +72 -0
  250. package/linthost/rules_ts_no_deprecated.go +195 -0
  251. package/linthost/rules_ts_no_for_in_array.go +84 -0
  252. package/linthost/rules_ts_no_magic_numbers.go +124 -0
  253. package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
  254. package/linthost/rules_ts_no_misused_spread.go +104 -0
  255. package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
  256. package/linthost/rules_ts_no_restricted_types.go +62 -0
  257. package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
  258. package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
  259. package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
  260. package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
  261. package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
  262. package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
  263. package/linthost/rules_ts_no_unsafe_argument.go +82 -0
  264. package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
  265. package/linthost/rules_ts_no_unsafe_call.go +82 -0
  266. package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
  267. package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
  268. package/linthost/rules_ts_no_unsafe_return.go +126 -0
  269. package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
  270. package/linthost/rules_ts_no_useless_constructor.go +52 -0
  271. package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
  272. package/linthost/rules_ts_parameter_properties.go +38 -0
  273. package/linthost/rules_ts_prefer_find.go +178 -0
  274. package/linthost/rules_ts_prefer_includes.go +255 -0
  275. package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
  276. package/linthost/rules_ts_prefer_optional_chain.go +228 -0
  277. package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
  278. package/linthost/rules_ts_prefer_readonly.go +73 -0
  279. package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
  280. package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
  281. package/linthost/rules_ts_prefer_return_this_type.go +135 -0
  282. package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
  283. package/linthost/rules_ts_promise_function_async.go +77 -0
  284. package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
  285. package/linthost/rules_ts_require_array_sort_compare.go +96 -0
  286. package/linthost/rules_ts_restrict_plus_operands.go +127 -0
  287. package/linthost/rules_ts_restrict_template_expressions.go +95 -0
  288. package/linthost/rules_ts_simple.go +387 -0
  289. package/linthost/rules_ts_sort_type_constituents.go +144 -0
  290. package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
  291. package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
  292. package/linthost/rules_ts_unbound_method.go +126 -0
  293. package/linthost/rules_tsdoc.go +136 -0
  294. package/linthost/rules_unicorn_better_regex.go +27 -0
  295. package/linthost/rules_unicorn_catch_error_name.go +46 -0
  296. package/linthost/rules_unicorn_consistent_assert.go +47 -0
  297. package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
  298. package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
  299. package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
  300. package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
  301. package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
  302. package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
  303. package/linthost/rules_unicorn_custom_error_definition.go +138 -0
  304. package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
  305. package/linthost/rules_unicorn_error_message.go +64 -0
  306. package/linthost/rules_unicorn_escape_case.go +51 -0
  307. package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
  308. package/linthost/rules_unicorn_explicit_length_check.go +88 -0
  309. package/linthost/rules_unicorn_filename_case.go +29 -0
  310. package/linthost/rules_unicorn_import_style.go +28 -0
  311. package/linthost/rules_unicorn_isolated_functions.go +29 -0
  312. package/linthost/rules_unicorn_new_for_builtins.go +87 -0
  313. package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
  314. package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
  315. package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
  316. package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
  317. package/linthost/rules_unicorn_no_array_for_each.go +40 -0
  318. package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
  319. package/linthost/rules_unicorn_no_array_reduce.go +41 -0
  320. package/linthost/rules_unicorn_no_array_reverse.go +44 -0
  321. package/linthost/rules_unicorn_no_array_sort.go +43 -0
  322. package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
  323. package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
  324. package/linthost/rules_unicorn_no_console_spaces.go +61 -0
  325. package/linthost/rules_unicorn_no_document_cookie.go +41 -0
  326. package/linthost/rules_unicorn_no_empty_file.go +44 -0
  327. package/linthost/rules_unicorn_no_for_loop.go +102 -0
  328. package/linthost/rules_unicorn_no_hex_escape.go +42 -0
  329. package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
  330. package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
  331. package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
  332. package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
  333. package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
  334. package/linthost/rules_unicorn_no_lonely_if.go +44 -0
  335. package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
  336. package/linthost/rules_unicorn_no_named_default.go +54 -0
  337. package/linthost/rules_unicorn_no_negated_condition.go +85 -0
  338. package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
  339. package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
  340. package/linthost/rules_unicorn_no_new_array.go +30 -0
  341. package/linthost/rules_unicorn_no_new_buffer.go +31 -0
  342. package/linthost/rules_unicorn_no_null.go +24 -0
  343. package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
  344. package/linthost/rules_unicorn_no_process_exit.go +43 -0
  345. package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
  346. package/linthost/rules_unicorn_no_static_only_class.go +56 -0
  347. package/linthost/rules_unicorn_no_thenable.go +74 -0
  348. package/linthost/rules_unicorn_no_this_assignment.go +35 -0
  349. package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
  350. package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
  351. package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
  352. package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
  353. package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
  354. package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
  355. package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
  356. package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
  357. package/linthost/rules_unicorn_no_unused_properties.go +30 -0
  358. package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
  359. package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
  360. package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
  361. package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
  362. package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
  363. package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
  364. package/linthost/rules_unicorn_no_useless_spread.go +67 -0
  365. package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
  366. package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
  367. package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
  368. package/linthost/rules_unicorn_number_literal_case.go +69 -0
  369. package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
  370. package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
  371. package/linthost/rules_unicorn_prefer_array_find.go +51 -0
  372. package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
  373. package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
  374. package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
  375. package/linthost/rules_unicorn_prefer_array_some.go +67 -0
  376. package/linthost/rules_unicorn_prefer_at.go +77 -0
  377. package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
  378. package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
  379. package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
  380. package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
  381. package/linthost/rules_unicorn_prefer_code_point.go +49 -0
  382. package/linthost/rules_unicorn_prefer_date_now.go +78 -0
  383. package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
  384. package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
  385. package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
  386. package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
  387. package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
  388. package/linthost/rules_unicorn_prefer_event_target.go +36 -0
  389. package/linthost/rules_unicorn_prefer_export_from.go +129 -0
  390. package/linthost/rules_unicorn_prefer_global_this.go +127 -0
  391. package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
  392. package/linthost/rules_unicorn_prefer_includes.go +149 -0
  393. package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
  394. package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
  395. package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
  396. package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
  397. package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
  398. package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
  399. package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
  400. package/linthost/rules_unicorn_prefer_module.go +50 -0
  401. package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
  402. package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
  403. package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
  404. package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
  405. package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
  406. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
  407. package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
  408. package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
  409. package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
  410. package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
  411. package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
  412. package/linthost/rules_unicorn_prefer_set_has.go +42 -0
  413. package/linthost/rules_unicorn_prefer_set_size.go +48 -0
  414. package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
  415. package/linthost/rules_unicorn_prefer_single_call.go +96 -0
  416. package/linthost/rules_unicorn_prefer_spread.go +51 -0
  417. package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
  418. package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
  419. package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
  420. package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
  421. package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
  422. package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
  423. package/linthost/rules_unicorn_prefer_switch.go +103 -0
  424. package/linthost/rules_unicorn_prefer_ternary.go +71 -0
  425. package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
  426. package/linthost/rules_unicorn_prefer_type_error.go +127 -0
  427. package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
  428. package/linthost/rules_unicorn_relative_url_style.go +49 -0
  429. package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
  430. package/linthost/rules_unicorn_require_module_attributes.go +54 -0
  431. package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
  432. package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
  433. package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
  434. package/linthost/rules_unicorn_string_content.go +27 -0
  435. package/linthost/rules_unicorn_switch_case_braces.go +42 -0
  436. package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
  437. package/linthost/rules_unicorn_template_indent.go +28 -0
  438. package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
  439. package/linthost/rules_unicorn_throw_new_error.go +61 -0
  440. package/linthost/rules_var.go +10 -4
  441. package/linthost/rules_vitest.go +568 -0
  442. package/package.json +3 -3
  443. package/plugin/main.go +49 -3
  444. package/rule/astutil/astutil.go +10 -3
  445. package/rule/rule.go +12 -10
  446. package/src/defaultFormat.ts +17 -10
  447. package/src/index.ts +65 -43
  448. package/src/structures/ITtscLintConfig.ts +14 -8
  449. package/src/structures/TtscLintRuleSetting.ts +55 -0
  450. package/src/structures/format/ITtscLintFormat.ts +141 -0
  451. package/src/structures/format/ITtscLintFormatJsDoc.ts +18 -0
  452. package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
  453. package/src/structures/format/index.ts +3 -0
  454. package/src/structures/index.ts +3 -4
  455. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +117 -0
  456. package/src/structures/rules/ITtscLintBoundariesRules.ts +91 -0
  457. package/src/structures/rules/ITtscLintContributorRules.ts +20 -0
  458. package/src/structures/rules/ITtscLintCoreRules.ts +1378 -0
  459. package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
  460. package/src/structures/rules/ITtscLintCypressRules.ts +141 -0
  461. package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +200 -0
  462. package/src/structures/rules/ITtscLintFunctionalRules.ts +197 -0
  463. package/src/structures/rules/ITtscLintJestRules.ts +209 -0
  464. package/src/structures/rules/ITtscLintJsdocRules.ts +146 -0
  465. package/src/structures/rules/ITtscLintJsxA11yRules.ts +331 -0
  466. package/src/structures/rules/ITtscLintNextjsRules.ts +201 -0
  467. package/src/structures/rules/ITtscLintPlaywrightRules.ts +343 -0
  468. package/src/structures/rules/ITtscLintPromiseRules.ts +196 -0
  469. package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
  470. package/src/structures/rules/ITtscLintReactPerfRules.ts +53 -0
  471. package/src/structures/rules/ITtscLintReactRuleOptions.ts +41 -0
  472. package/src/structures/rules/ITtscLintReactRules.ts +308 -0
  473. package/src/structures/rules/ITtscLintRegexpRules.ts +204 -0
  474. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -0
  475. package/src/structures/rules/ITtscLintRules.ts +77 -0
  476. package/src/structures/rules/ITtscLintSecurityRules.ts +155 -0
  477. package/src/structures/rules/ITtscLintSolidRules.ts +199 -0
  478. package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +22 -0
  479. package/src/structures/rules/ITtscLintStorybookRules.ts +184 -0
  480. package/src/structures/rules/ITtscLintTanstackQueryRules.ts +96 -0
  481. package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +23 -0
  482. package/src/structures/rules/ITtscLintTestingLibraryRules.ts +325 -0
  483. package/src/structures/rules/ITtscLintTypeScriptRules.ts +1172 -0
  484. package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
  485. package/src/structures/rules/ITtscLintVitestRules.ts +146 -0
  486. package/src/structures/rules/index.ts +31 -0
  487. package/lib/structures/ITtscLintFormatConfig.d.ts +0 -153
  488. package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
  489. package/lib/structures/TtscLintRule.d.ts +0 -17
  490. package/lib/structures/TtscLintRule.js.map +0 -1
  491. package/lib/structures/TtscLintRuleMap.d.ts +0 -46
  492. package/lib/structures/TtscLintRuleMap.js.map +0 -1
  493. package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
  494. package/lib/structures/TtscLintRuleOptions.js.map +0 -1
  495. package/src/structures/ITtscLintFormatConfig.ts +0 -168
  496. package/src/structures/TtscLintRule.ts +0 -160
  497. package/src/structures/TtscLintRuleMap.ts +0 -55
  498. package/src/structures/TtscLintRuleOptions.ts +0 -151
@@ -0,0 +1,127 @@
1
+ // typescript/restrict-plus-operands: the `+` operator is overloaded in
2
+ // JavaScript — it numerically adds two numbers, lexically concatenates
3
+ // two strings, and silently coerces every other combination. `1 + "a"`
4
+ // becomes `"1a"`, `null + 5` becomes `5`, `{} + 1` becomes `"[object
5
+ // Object]1"`. Each of these is almost always a bug: the author meant
6
+ // either numeric addition or explicit string concatenation, not the
7
+ // runtime's lossy fallback. typescript-eslint:
8
+ // https://typescript-eslint.io/rules/restrict-plus-operands/
9
+ package linthost
10
+
11
+ import (
12
+ shimast "github.com/microsoft/typescript-go/shim/ast"
13
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
14
+ )
15
+
16
+ // restrictPlusOperands fires on `<lhs> + <rhs>` when the operands are
17
+ // not both number-like, both string-like, or both bigint-like. The
18
+ // rule is type-aware: without a Checker it cannot prove the operand
19
+ // kinds, so it bails out to avoid false positives on plain JS or on
20
+ // files that opt out of typechecking. `any` / `unknown` / `never`
21
+ // operands are treated as unrestricted to keep false positives off
22
+ // generic helpers; the upstream rule does the same.
23
+ type restrictPlusOperands struct{}
24
+
25
+ func (restrictPlusOperands) Name() string { return "typescript/restrict-plus-operands" }
26
+ func (restrictPlusOperands) NeedsTypeChecker() bool {
27
+ return true
28
+ }
29
+ func (restrictPlusOperands) Visits() []shimast.Kind {
30
+ return []shimast.Kind{shimast.KindBinaryExpression}
31
+ }
32
+ func (restrictPlusOperands) Check(ctx *Context, node *shimast.Node) {
33
+ if ctx.Checker == nil {
34
+ return
35
+ }
36
+ expr := node.AsBinaryExpression()
37
+ if expr == nil || expr.OperatorToken == nil {
38
+ return
39
+ }
40
+ if expr.OperatorToken.Kind != shimast.KindPlusToken {
41
+ return
42
+ }
43
+ if expr.Left == nil || expr.Right == nil {
44
+ return
45
+ }
46
+ left := ctx.Checker.GetTypeAtLocation(expr.Left)
47
+ right := ctx.Checker.GetTypeAtLocation(expr.Right)
48
+ if left == nil || right == nil {
49
+ return
50
+ }
51
+ leftKind := restrictPlusOperandsKind(left)
52
+ rightKind := restrictPlusOperandsKind(right)
53
+ // Skip when either side is unconstrained (any / unknown / never /
54
+ // generic) — the rule would otherwise fire on every generic helper
55
+ // that accepts `T extends number | string`.
56
+ if leftKind == restrictPlusOperandsAny || rightKind == restrictPlusOperandsAny {
57
+ return
58
+ }
59
+ if leftKind == rightKind && leftKind != restrictPlusOperandsOther {
60
+ return
61
+ }
62
+ ctx.Report(node, "Operands of `+` must both be `number`, both `string`, or both `bigint`. Mixed or non-primitive operands are silently coerced by the runtime and almost always a bug.")
63
+ }
64
+
65
+ // restrictPlusOperandsKind classifies t as one of the four buckets the
66
+ // rule cares about. A union is accepted only when every constituent
67
+ // lands in the same primitive bucket — `string | number` is
68
+ // deliberately rejected because each branch would coerce the other
69
+ // side differently at runtime.
70
+ type restrictPlusOperandsBucket int
71
+
72
+ const (
73
+ restrictPlusOperandsOther restrictPlusOperandsBucket = iota
74
+ restrictPlusOperandsAny
75
+ restrictPlusOperandsNumber
76
+ restrictPlusOperandsString
77
+ restrictPlusOperandsBigInt
78
+ )
79
+
80
+ func restrictPlusOperandsKind(t *shimchecker.Type) restrictPlusOperandsBucket {
81
+ if t == nil {
82
+ return restrictPlusOperandsOther
83
+ }
84
+ flags := t.Flags()
85
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
86
+ return restrictPlusOperandsAny
87
+ }
88
+ if flags&shimchecker.TypeFlagsStringLike != 0 {
89
+ return restrictPlusOperandsString
90
+ }
91
+ if flags&shimchecker.TypeFlagsNumberLike != 0 {
92
+ return restrictPlusOperandsNumber
93
+ }
94
+ if flags&shimchecker.TypeFlagsBigIntLike != 0 {
95
+ return restrictPlusOperandsBigInt
96
+ }
97
+ if flags&shimchecker.TypeFlagsUnion != 0 {
98
+ var seen restrictPlusOperandsBucket
99
+ for _, part := range t.Types() {
100
+ if part == nil {
101
+ continue
102
+ }
103
+ kind := restrictPlusOperandsKind(part)
104
+ if kind == restrictPlusOperandsAny {
105
+ return restrictPlusOperandsAny
106
+ }
107
+ if kind == restrictPlusOperandsOther {
108
+ return restrictPlusOperandsOther
109
+ }
110
+ if seen == 0 {
111
+ seen = kind
112
+ continue
113
+ }
114
+ if seen != kind {
115
+ return restrictPlusOperandsOther
116
+ }
117
+ }
118
+ if seen != 0 {
119
+ return seen
120
+ }
121
+ }
122
+ return restrictPlusOperandsOther
123
+ }
124
+
125
+ func init() {
126
+ Register(restrictPlusOperands{})
127
+ }
@@ -0,0 +1,95 @@
1
+ // typescript/restrict-template-expressions: every interpolation inside a
2
+ // template literal coerces its value through `String()` at runtime, so
3
+ // non-string-friendly types silently render as `"[object Object]"`,
4
+ // `"null"`, or `"undefined"`. The rule requires each embedded expression
5
+ // to be statically known as `string`, `number`, `bigint`, `boolean`, or
6
+ // a union of those — anything else (object types, `null`, `undefined`,
7
+ // `void`) must be converted explicitly at the call site.
8
+ // typescript-eslint:
9
+ // https://typescript-eslint.io/rules/restrict-template-expressions/
10
+ package linthost
11
+
12
+ import (
13
+ shimast "github.com/microsoft/typescript-go/shim/ast"
14
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
15
+ )
16
+
17
+ // restrictTemplateExpressions reports each `${expr}` span inside a
18
+ // template literal whose expression has a non-stringy static type.
19
+ // Type-aware: without a Checker the rule cannot tell `string | number`
20
+ // apart from `string | null`, so it bails — the AST alone never has
21
+ // enough information to decide this case.
22
+ //
23
+ // `any` / `unknown` / `never` pass through on purpose. They propagate
24
+ // from generic helpers and a strict rejection would explode the
25
+ // false-positive volume; the upstream rule makes the same choice
26
+ // behind its `allowAny` / `allowNever` options, which default to true.
27
+ type restrictTemplateExpressions struct{}
28
+
29
+ func (restrictTemplateExpressions) Name() string {
30
+ return "typescript/restrict-template-expressions"
31
+ }
32
+ func (restrictTemplateExpressions) NeedsTypeChecker() bool {
33
+ return true
34
+ }
35
+ func (restrictTemplateExpressions) Visits() []shimast.Kind {
36
+ return []shimast.Kind{shimast.KindTemplateExpression}
37
+ }
38
+ func (restrictTemplateExpressions) Check(ctx *Context, node *shimast.Node) {
39
+ if ctx.Checker == nil {
40
+ return
41
+ }
42
+ expr := node.AsTemplateExpression()
43
+ if expr == nil || expr.TemplateSpans == nil {
44
+ return
45
+ }
46
+ for _, spanNode := range expr.TemplateSpans.Nodes {
47
+ span := spanNode.AsTemplateSpan()
48
+ if span == nil || span.Expression == nil {
49
+ continue
50
+ }
51
+ t := ctx.Checker.GetTypeAtLocation(span.Expression)
52
+ if t == nil {
53
+ continue
54
+ }
55
+ if restrictTemplateExpressionsIsStringy(ctx.Checker, t) {
56
+ continue
57
+ }
58
+ ctx.Report(span.Expression, "Template interpolations must be string-like (`string`, `number`, `bigint`, or `boolean`) — convert the value explicitly to avoid coercing to `\"[object Object]\"`, `\"null\"`, or `\"undefined\"`.")
59
+ }
60
+ }
61
+
62
+ // restrictTemplateExpressionsIsStringy reports whether t is safe to
63
+ // drop into a template-literal slot — string / number / bigint /
64
+ // boolean, or a union/intersection whose every constituent is.
65
+ // `any` / `unknown` / `never` pass through (return true) so generic
66
+ // helpers propagate without lighting up the rule everywhere.
67
+ func restrictTemplateExpressionsIsStringy(checker *shimchecker.Checker, t *shimchecker.Type) bool {
68
+ if checker == nil || t == nil {
69
+ return false
70
+ }
71
+ flags := t.Flags()
72
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
73
+ return true
74
+ }
75
+ if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
76
+ for _, part := range t.Types() {
77
+ if part == nil {
78
+ continue
79
+ }
80
+ if !restrictTemplateExpressionsIsStringy(checker, part) {
81
+ return false
82
+ }
83
+ }
84
+ return true
85
+ }
86
+ const stringyMask = shimchecker.TypeFlagsStringLike |
87
+ shimchecker.TypeFlagsNumberLike |
88
+ shimchecker.TypeFlagsBigIntLike |
89
+ shimchecker.TypeFlagsBooleanLike
90
+ return flags&stringyMask != 0
91
+ }
92
+
93
+ func init() {
94
+ Register(restrictTemplateExpressions{})
95
+ }
@@ -0,0 +1,387 @@
1
+ // Additional AST-only `typescript/*` rules from
2
+ // typescript-eslint. Each rule is a small pattern match — no Checker,
3
+ // no scope analysis — and corresponds 1:1 with the upstream rule of
4
+ // the same name.
5
+ //
6
+ // Implemented here:
7
+ // - typescript/no-array-for-each
8
+ // - typescript/no-extraneous-class
9
+ // - typescript/no-invalid-void-type
10
+ package linthost
11
+
12
+ import (
13
+ shimast "github.com/microsoft/typescript-go/shim/ast"
14
+ )
15
+
16
+ // noArrayForEach reports `arr.forEach(...)` calls and suggests
17
+ // `for ... of` instead. The for-of form supports early termination
18
+ // (`break`/`return`) and `await`, while `forEach` swallows both. The
19
+ // rule does not confirm that the receiver is actually an array — the
20
+ // syntactic shape is the signal, matching the upstream rule's behavior.
21
+ // https://typescript-eslint.io/rules/no-array-for-each/
22
+ type noArrayForEach struct{}
23
+
24
+ func (noArrayForEach) Name() string { return "typescript/no-array-for-each" }
25
+ func (noArrayForEach) Visits() []shimast.Kind {
26
+ return []shimast.Kind{shimast.KindCallExpression}
27
+ }
28
+ func (noArrayForEach) Check(ctx *Context, node *shimast.Node) {
29
+ call := node.AsCallExpression()
30
+ if call == nil || call.Expression == nil {
31
+ return
32
+ }
33
+ _, method, ok := promisePropertyAccessParts(call.Expression)
34
+ if !ok || method != "forEach" {
35
+ return
36
+ }
37
+ ctx.Report(node, "Prefer `for ... of` over `Array.forEach()` — `forEach` does not support `await` or `break`.")
38
+ }
39
+
40
+ // noExtraneousClass reports class declarations that exist purely as a
41
+ // namespace for static members or are entirely empty. A namespace
42
+ // import or a plain function is almost always clearer than `class Util
43
+ // { static foo() { … } }`, and the class adds a layer of indirection
44
+ // without providing any instance behavior.
45
+ // https://typescript-eslint.io/rules/no-extraneous-class/
46
+ //
47
+ // Trigger:
48
+ // - the class has no `extends` heritage,
49
+ // - no constructor with a non-empty body, and
50
+ // - every member is `static` (or the class has no members at all).
51
+ type noExtraneousClass struct{}
52
+
53
+ func (noExtraneousClass) Name() string { return "typescript/no-extraneous-class" }
54
+ func (noExtraneousClass) Visits() []shimast.Kind {
55
+ return []shimast.Kind{shimast.KindClassDeclaration, shimast.KindClassExpression}
56
+ }
57
+ func (noExtraneousClass) Check(ctx *Context, node *shimast.Node) {
58
+ if classExtendsAnother(node) {
59
+ return
60
+ }
61
+ if classImplementsAnInterface(node) {
62
+ return
63
+ }
64
+ members := classMembers(node)
65
+ if len(members) == 0 {
66
+ ctx.Report(node, "Empty class — prefer a plain function or namespace.")
67
+ return
68
+ }
69
+ hasInstanceMember := false
70
+ hasNonTrivialConstructor := false
71
+ for _, member := range members {
72
+ if member == nil {
73
+ continue
74
+ }
75
+ if member.Kind == shimast.KindConstructor {
76
+ ctor := member.AsConstructorDeclaration()
77
+ if ctor != nil && ctor.Body != nil && len(ctor.Body.Statements()) > 0 {
78
+ hasNonTrivialConstructor = true
79
+ }
80
+ continue
81
+ }
82
+ if !hasModifier(member, shimast.KindStaticKeyword) {
83
+ hasInstanceMember = true
84
+ break
85
+ }
86
+ }
87
+ if !hasInstanceMember && !hasNonTrivialConstructor {
88
+ ctx.Report(node, "Class only declares static members — prefer a namespace or top-level functions.")
89
+ }
90
+ }
91
+
92
+ // classImplementsAnInterface reports whether the class has an
93
+ // `implements …` heritage clause. Classes that implement an interface
94
+ // are intentionally polymorphic at runtime, so noExtraneousClass
95
+ // should not fire on them.
96
+ func classImplementsAnInterface(class *shimast.Node) bool {
97
+ var clauses []*shimast.Node
98
+ switch class.Kind {
99
+ case shimast.KindClassDeclaration:
100
+ decl := class.AsClassDeclaration()
101
+ if decl == nil || decl.HeritageClauses == nil {
102
+ return false
103
+ }
104
+ clauses = decl.HeritageClauses.Nodes
105
+ case shimast.KindClassExpression:
106
+ expr := class.AsClassExpression()
107
+ if expr == nil || expr.HeritageClauses == nil {
108
+ return false
109
+ }
110
+ clauses = expr.HeritageClauses.Nodes
111
+ default:
112
+ return false
113
+ }
114
+ for _, clause := range clauses {
115
+ if clause == nil {
116
+ continue
117
+ }
118
+ hc := clause.AsHeritageClause()
119
+ if hc == nil || hc.Token != shimast.KindImplementsKeyword {
120
+ continue
121
+ }
122
+ if hc.Types != nil && len(hc.Types.Nodes) > 0 {
123
+ return true
124
+ }
125
+ }
126
+ return false
127
+ }
128
+
129
+ // noInvalidVoidType reports a `void` type used as a union constituent
130
+ // or as a generic-type argument. `void` is meaningful only as the sole
131
+ // return type of a function — `void | string` and `Promise<void>` are
132
+ // fine, but `string | void` is almost always a confusion with
133
+ // `undefined`.
134
+ // https://typescript-eslint.io/rules/no-invalid-void-type/
135
+ //
136
+ // Allowed positions:
137
+ // - the return type annotation of a function-like (Function/Method/
138
+ // Arrow/Constructor/CallSignature/MethodSignature/FunctionType);
139
+ // - inside `Promise<void>`, `Generator<void, …, …>`, etc. — these
140
+ // are the established generic exceptions in typescript-eslint.
141
+ type noInvalidVoidType struct{}
142
+
143
+ func (noInvalidVoidType) Name() string { return "typescript/no-invalid-void-type" }
144
+ func (noInvalidVoidType) Visits() []shimast.Kind {
145
+ return []shimast.Kind{shimast.KindVoidKeyword}
146
+ }
147
+ func (noInvalidVoidType) Check(ctx *Context, node *shimast.Node) {
148
+ // The `void` keyword shows up both as a type node and as the unary
149
+ // `void X` expression operator. Filter by parent kind — the
150
+ // expression operator's parent is VoidExpression, not a type position.
151
+ parent := node.Parent
152
+ if parent == nil || parent.Kind == shimast.KindVoidExpression {
153
+ return
154
+ }
155
+ if isValidVoidPosition(node) {
156
+ return
157
+ }
158
+ ctx.Report(node, "`void` is only valid as the return type annotation of a function or as a known generic argument.")
159
+ }
160
+
161
+ // isValidVoidPosition reports whether a `void` type node sits in one
162
+ // of the approved positions: a function return type or an
163
+ // allow-listed generic type argument (Promise/Generator/AsyncGenerator/
164
+ // Iterator/AsyncIterator/IterableIterator).
165
+ func isValidVoidPosition(node *shimast.Node) bool {
166
+ parent := node.Parent
167
+ if parent == nil {
168
+ return false
169
+ }
170
+ switch parent.Kind {
171
+ case shimast.KindFunctionDeclaration,
172
+ shimast.KindFunctionExpression,
173
+ shimast.KindArrowFunction,
174
+ shimast.KindMethodDeclaration,
175
+ shimast.KindMethodSignature,
176
+ shimast.KindConstructor,
177
+ shimast.KindGetAccessor,
178
+ shimast.KindSetAccessor,
179
+ shimast.KindCallSignature,
180
+ shimast.KindConstructSignature,
181
+ shimast.KindFunctionType,
182
+ shimast.KindConstructorType,
183
+ shimast.KindIndexSignature:
184
+ return parent.Type() == node
185
+ case shimast.KindTypeReference:
186
+ // `void` as a generic argument — allowed inside the typescript-
187
+ // eslint approved set.
188
+ grand := parent.Parent
189
+ if grand == nil {
190
+ return false
191
+ }
192
+ if grand.Kind == shimast.KindTypeReference {
193
+ ref := grand.AsTypeReferenceNode()
194
+ if ref == nil {
195
+ return false
196
+ }
197
+ name := identifierText(ref.TypeName)
198
+ switch name {
199
+ case "Promise", "Generator", "AsyncGenerator", "Iterator", "AsyncIterator", "IterableIterator", "AsyncIterableIterator":
200
+ return true
201
+ }
202
+ }
203
+ }
204
+ // Walk up: if the parent chain leads directly to an allow-listed
205
+ // generic type reference's typeArguments list, accept.
206
+ for cur := parent; cur != nil; cur = cur.Parent {
207
+ if cur.Kind == shimast.KindTypeReference {
208
+ ref := cur.AsTypeReferenceNode()
209
+ if ref == nil {
210
+ return false
211
+ }
212
+ name := identifierText(ref.TypeName)
213
+ switch name {
214
+ case "Promise", "Generator", "AsyncGenerator", "Iterator", "AsyncIterator", "IterableIterator", "AsyncIterableIterator":
215
+ return true
216
+ }
217
+ return false
218
+ }
219
+ // Stop walking past statement boundaries — `void` in
220
+ // `let x: string | void;` should still fire.
221
+ switch cur.Kind {
222
+ case shimast.KindVariableDeclaration,
223
+ shimast.KindParameter,
224
+ shimast.KindPropertyDeclaration,
225
+ shimast.KindPropertySignature:
226
+ return false
227
+ }
228
+ }
229
+ return false
230
+ }
231
+
232
+ // explicitMemberAccessibility requires every class member declaration
233
+ // to carry a `public` / `private` / `protected` modifier. Implicit
234
+ // public is permitted by TypeScript but obscures intent — explicit
235
+ // keywords make the encapsulation contract self-documenting and
236
+ // catch the common bug of "I forgot to make this private."
237
+ // https://typescript-eslint.io/rules/explicit-member-accessibility/
238
+ //
239
+ // Class fields whose name starts with `#` are exempt — the private
240
+ // hash already carries the same meaning. The constructor is exempt;
241
+ // upstream allows omitting accessibility on the constructor itself.
242
+ type explicitMemberAccessibility struct{}
243
+
244
+ func (explicitMemberAccessibility) Name() string {
245
+ return "typescript/explicit-member-accessibility"
246
+ }
247
+ func (explicitMemberAccessibility) Visits() []shimast.Kind {
248
+ return []shimast.Kind{
249
+ shimast.KindMethodDeclaration,
250
+ shimast.KindPropertyDeclaration,
251
+ shimast.KindGetAccessor,
252
+ shimast.KindSetAccessor,
253
+ }
254
+ }
255
+ func (explicitMemberAccessibility) Check(ctx *Context, node *shimast.Node) {
256
+ // Skip non-class-scoped members.
257
+ parent := node.Parent
258
+ if parent == nil ||
259
+ (parent.Kind != shimast.KindClassDeclaration && parent.Kind != shimast.KindClassExpression) {
260
+ return
261
+ }
262
+ // Skip private hash identifiers.
263
+ if name := node.Name(); name != nil && name.Kind == shimast.KindPrivateIdentifier {
264
+ return
265
+ }
266
+ if classMemberHasAccessibility(node) {
267
+ return
268
+ }
269
+ ctx.Report(node, "Class member is missing an explicit accessibility modifier (`public`, `private`, or `protected`).")
270
+ }
271
+
272
+ // classMemberHasAccessibility reports whether the member carries an
273
+ // explicit `public` / `private` / `protected` modifier.
274
+ func classMemberHasAccessibility(node *shimast.Node) bool {
275
+ if node == nil {
276
+ return false
277
+ }
278
+ mods := node.Modifiers()
279
+ if mods == nil {
280
+ return false
281
+ }
282
+ for _, m := range mods.Nodes {
283
+ if m == nil {
284
+ continue
285
+ }
286
+ switch m.Kind {
287
+ case shimast.KindPublicKeyword,
288
+ shimast.KindPrivateKeyword,
289
+ shimast.KindProtectedKeyword:
290
+ return true
291
+ }
292
+ }
293
+ return false
294
+ }
295
+
296
+ // consistentGenericConstructors reports the redundant pattern where a
297
+ // variable is annotated with a generic type AND the same generic
298
+ // arguments are repeated on the constructor call:
299
+ //
300
+ // const m: Map<string, number> = new Map<string, number>();
301
+ //
302
+ // One of the two type-argument lists is enough. The upstream default
303
+ // prefers the constructor form; the annotation form is also valid but
304
+ // stating both is noise.
305
+ // https://typescript-eslint.io/rules/consistent-generic-constructors/
306
+ type consistentGenericConstructors struct{}
307
+
308
+ func (consistentGenericConstructors) Name() string {
309
+ return "typescript/consistent-generic-constructors"
310
+ }
311
+ func (consistentGenericConstructors) Visits() []shimast.Kind {
312
+ return []shimast.Kind{shimast.KindVariableDeclaration}
313
+ }
314
+ func (consistentGenericConstructors) Check(ctx *Context, node *shimast.Node) {
315
+ decl := node.AsVariableDeclaration()
316
+ if decl == nil || decl.Type == nil || decl.Initializer == nil {
317
+ return
318
+ }
319
+ if decl.Type.Kind != shimast.KindTypeReference {
320
+ return
321
+ }
322
+ typeRef := decl.Type.AsTypeReferenceNode()
323
+ if typeRef == nil || typeRef.TypeArguments == nil {
324
+ return
325
+ }
326
+ initializer := stripParens(decl.Initializer)
327
+ if initializer == nil || initializer.Kind != shimast.KindNewExpression {
328
+ return
329
+ }
330
+ ne := initializer.AsNewExpression()
331
+ if ne == nil || ne.TypeArguments == nil {
332
+ return
333
+ }
334
+ ctx.Report(initializer, "Redundant generic arguments — the annotation already pins the type parameters; drop them from the constructor or vice versa.")
335
+ }
336
+
337
+ // preferNumericLiterals reports `parseInt(literal, radix)` calls that
338
+ // could be written as an ES2015+ numeric literal (binary `0b…`, octal
339
+ // `0o…`, hex `0x…`). The literal form is shorter, type-safe, and not
340
+ // subject to runtime radix mismatches.
341
+ // https://eslint.org/docs/latest/rules/prefer-numeric-literals
342
+ type preferNumericLiterals struct{}
343
+
344
+ func (preferNumericLiterals) Name() string { return "prefer-numeric-literals" }
345
+ func (preferNumericLiterals) Visits() []shimast.Kind {
346
+ return []shimast.Kind{shimast.KindCallExpression}
347
+ }
348
+ func (preferNumericLiterals) Check(ctx *Context, node *shimast.Node) {
349
+ call := node.AsCallExpression()
350
+ if call == nil || call.Expression == nil || call.Arguments == nil {
351
+ return
352
+ }
353
+ calleeName := identifierText(call.Expression)
354
+ if calleeName != "parseInt" && calleeName != "Number" {
355
+ return
356
+ }
357
+ args := call.Arguments.Nodes
358
+ if calleeName == "parseInt" && len(args) != 2 {
359
+ return
360
+ }
361
+ if calleeName == "Number" && len(args) != 1 {
362
+ return
363
+ }
364
+ first := stripParens(args[0])
365
+ if first == nil || first.Kind != shimast.KindStringLiteral {
366
+ return
367
+ }
368
+ if calleeName == "parseInt" {
369
+ radix := stripParens(args[1])
370
+ if radix == nil || radix.Kind != shimast.KindNumericLiteral {
371
+ return
372
+ }
373
+ switch numericLiteralText(radix) {
374
+ case "2", "8", "16":
375
+ ctx.Report(node, "Use a numeric literal (`0b…` / `0o…` / `0x…`) instead of `parseInt(\""+stringLiteralText(first)+"\", "+numericLiteralText(radix)+")`.")
376
+ }
377
+ }
378
+ }
379
+
380
+ func init() {
381
+ Register(noArrayForEach{})
382
+ Register(noExtraneousClass{})
383
+ Register(noInvalidVoidType{})
384
+ Register(explicitMemberAccessibility{})
385
+ Register(consistentGenericConstructors{})
386
+ Register(preferNumericLiterals{})
387
+ }