@ttsc/lint 0.13.1 → 0.14.0-dev.20260528.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 (464) hide show
  1. package/README.md +948 -69
  2. package/lib/defaultFormat.d.ts +9 -6
  3. package/lib/defaultFormat.js +9 -6
  4. package/lib/defaultFormat.js.map +1 -1
  5. package/lib/index.d.ts +46 -0
  6. package/lib/index.js +35 -10
  7. package/lib/index.js.map +1 -1
  8. package/lib/structures/ITtscLintConfig.d.ts +12 -6
  9. package/lib/structures/{ITtscLintFormatConfig.d.ts → ITtscLintFormat.d.ts} +2 -2
  10. package/lib/structures/{TtscLintRuleMap.js → ITtscLintFormat.js} +1 -1
  11. package/lib/structures/ITtscLintFormat.js.map +1 -0
  12. package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
  13. package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
  14. package/lib/structures/TtscLintRuleSetting.js.map +1 -0
  15. package/lib/structures/index.d.ts +3 -4
  16. package/lib/structures/index.js +3 -4
  17. package/lib/structures/index.js.map +1 -1
  18. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +104 -0
  19. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +14 -0
  20. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
  21. package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +79 -0
  22. package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
  23. package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
  24. package/lib/structures/rules/ITtscLintContributorRules.d.ts +17 -0
  25. package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
  26. package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
  27. package/lib/structures/rules/ITtscLintCoreRules.d.ts +1257 -0
  28. package/lib/structures/{ITtscLintFormatConfig.js → rules/ITtscLintCoreRules.js} +1 -1
  29. package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
  30. package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
  31. package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
  32. package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
  33. package/lib/structures/rules/ITtscLintCypressRules.d.ts +129 -0
  34. package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
  35. package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
  36. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +157 -0
  37. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
  38. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
  39. package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +167 -0
  40. package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
  41. package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
  42. package/lib/structures/rules/ITtscLintJestRules.d.ts +201 -0
  43. package/lib/structures/rules/ITtscLintJestRules.js +3 -0
  44. package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
  45. package/lib/structures/rules/ITtscLintJsdocRules.d.ts +140 -0
  46. package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
  47. package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
  48. package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +302 -0
  49. package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
  50. package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
  51. package/lib/structures/rules/ITtscLintNextjsRules.d.ts +185 -0
  52. package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
  53. package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
  54. package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +330 -0
  55. package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
  56. package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
  57. package/lib/structures/rules/ITtscLintPromiseRules.d.ts +188 -0
  58. package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
  59. package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
  60. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
  61. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
  62. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
  63. package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +51 -0
  64. package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
  65. package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
  66. package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +39 -0
  67. package/lib/structures/rules/ITtscLintReactRuleOptions.js +12 -0
  68. package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
  69. package/lib/structures/rules/ITtscLintReactRules.d.ts +289 -0
  70. package/lib/structures/rules/ITtscLintReactRules.js +3 -0
  71. package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
  72. package/lib/structures/rules/ITtscLintRegexpRules.d.ts +190 -0
  73. package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
  74. package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
  75. package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +66 -0
  76. package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
  77. package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
  78. package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
  79. package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
  80. package/lib/structures/rules/ITtscLintRules.js.map +1 -0
  81. package/lib/structures/rules/ITtscLintSecurityRules.d.ts +148 -0
  82. package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
  83. package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
  84. package/lib/structures/rules/ITtscLintSolidRules.d.ts +181 -0
  85. package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
  86. package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
  87. package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +21 -0
  88. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
  89. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
  90. package/lib/structures/rules/ITtscLintStorybookRules.d.ts +174 -0
  91. package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
  92. package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
  93. package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +94 -0
  94. package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
  95. package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
  96. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +22 -0
  97. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
  98. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
  99. package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +310 -0
  100. package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
  101. package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
  102. package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1132 -0
  103. package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
  104. package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
  105. package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
  106. package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
  107. package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
  108. package/lib/structures/rules/ITtscLintVitestRules.d.ts +141 -0
  109. package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
  110. package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
  111. package/lib/structures/rules/index.d.ts +31 -0
  112. package/lib/structures/rules/index.js +48 -0
  113. package/lib/structures/rules/index.js.map +1 -0
  114. package/linthost/ast_helpers.go +30 -5
  115. package/linthost/config.go +48 -17
  116. package/linthost/config_format.go +9 -9
  117. package/linthost/directives.go +67 -25
  118. package/linthost/dispatch.go +14 -3
  119. package/linthost/engine.go +152 -31
  120. package/linthost/fix.go +2 -2
  121. package/linthost/lsp.go +747 -0
  122. package/linthost/print_dispatch.go +2 -2
  123. package/linthost/print_nodes_function.go +2 -2
  124. package/linthost/print_nodes_object.go +1 -1
  125. package/linthost/rule_names.go +14 -0
  126. package/linthost/rules_arrays.go +2 -2
  127. package/linthost/rules_boundaries.go +532 -0
  128. package/linthost/rules_camelcase.go +133 -0
  129. package/linthost/rules_complexity.go +94 -0
  130. package/linthost/rules_consistent_return.go +130 -0
  131. package/linthost/rules_console.go +1 -1
  132. package/linthost/rules_core_extra.go +739 -0
  133. package/linthost/rules_curly.go +70 -0
  134. package/linthost/rules_cypress.go +608 -0
  135. package/linthost/rules_debugger.go +2 -2
  136. package/linthost/rules_default_case.go +39 -0
  137. package/linthost/rules_default_case_last.go +46 -0
  138. package/linthost/rules_dupes.go +3 -3
  139. package/linthost/rules_empty.go +3 -3
  140. package/linthost/rules_escape.go +44 -24
  141. package/linthost/rules_eval.go +2 -2
  142. package/linthost/rules_finally.go +2 -2
  143. package/linthost/rules_format_jsdoc.go +1 -1
  144. package/linthost/rules_format_print_width.go +9 -9
  145. package/linthost/rules_format_quotes.go +1 -1
  146. package/linthost/rules_format_semi.go +1 -1
  147. package/linthost/rules_format_sort_imports.go +1 -1
  148. package/linthost/rules_format_trailing_comma.go +1 -1
  149. package/linthost/rules_functional.go +967 -0
  150. package/linthost/rules_gap.go +24 -45
  151. package/linthost/rules_grouped_accessor_pairs.go +87 -0
  152. package/linthost/rules_guard_for_in.go +198 -0
  153. package/linthost/rules_id_length.go +77 -0
  154. package/linthost/rules_imports.go +70 -2
  155. package/linthost/rules_init_declarations.go +53 -0
  156. package/linthost/rules_jest.go +618 -0
  157. package/linthost/rules_jsdoc.go +502 -0
  158. package/linthost/rules_jsx_a11y.go +1264 -0
  159. package/linthost/rules_logic.go +12 -12
  160. package/linthost/rules_loops.go +1 -1
  161. package/linthost/rules_max_classes_per_file.go +58 -0
  162. package/linthost/rules_max_depth.go +83 -0
  163. package/linthost/rules_max_lines.go +101 -0
  164. package/linthost/rules_max_lines_per_function.go +57 -0
  165. package/linthost/rules_max_nested_callbacks.go +61 -0
  166. package/linthost/rules_max_params.go +49 -0
  167. package/linthost/rules_max_statements.go +59 -0
  168. package/linthost/rules_misc.go +1 -1
  169. package/linthost/rules_nextjs.go +697 -0
  170. package/linthost/rules_no_else_return.go +75 -0
  171. package/linthost/rules_no_empty_named_blocks.go +91 -0
  172. package/linthost/rules_no_extend_native.go +51 -0
  173. package/linthost/rules_no_import_assign.go +140 -0
  174. package/linthost/rules_no_invalid_this.go +52 -0
  175. package/linthost/rules_no_loop_func.go +85 -0
  176. package/linthost/rules_no_magic_numbers.go +123 -0
  177. package/linthost/rules_no_mixed_operators.go +80 -0
  178. package/linthost/rules_no_param_reassign.go +98 -0
  179. package/linthost/rules_no_redeclare.go +270 -0
  180. package/linthost/rules_no_restricted_imports.go +105 -0
  181. package/linthost/rules_no_restricted_syntax.go +49 -0
  182. package/linthost/rules_no_shadow.go +147 -0
  183. package/linthost/rules_no_unreachable.go +77 -0
  184. package/linthost/rules_no_useless_assignment.go +120 -0
  185. package/linthost/rules_no_useless_constructor.go +245 -0
  186. package/linthost/rules_no_useless_return.go +51 -0
  187. package/linthost/rules_params.go +1 -1
  188. package/linthost/rules_playwright.go +788 -0
  189. package/linthost/rules_prefer_arrow_callback.go +124 -0
  190. package/linthost/rules_prefer_destructuring.go +98 -0
  191. package/linthost/rules_prefer_named_capture_group.go +129 -0
  192. package/linthost/rules_prefer_rest_params.go +94 -0
  193. package/linthost/rules_problems.go +41 -30
  194. package/linthost/rules_promise.go +1128 -73
  195. package/linthost/rules_protos.go +2 -2
  196. package/linthost/rules_react.go +773 -0
  197. package/linthost/rules_react_extras.go +227 -0
  198. package/linthost/rules_react_hooks.go +848 -0
  199. package/linthost/rules_react_perf.go +293 -0
  200. package/linthost/rules_react_refresh.go +583 -0
  201. package/linthost/rules_regexp.go +410 -0
  202. package/linthost/rules_security.go +830 -0
  203. package/linthost/rules_self.go +2 -2
  204. package/linthost/rules_solid.go +1073 -0
  205. package/linthost/rules_sort_imports.go +69 -0
  206. package/linthost/rules_sort_keys.go +134 -0
  207. package/linthost/rules_storybook.go +1176 -0
  208. package/linthost/rules_strings.go +4 -4
  209. package/linthost/rules_suggestions.go +38 -38
  210. package/linthost/rules_tanstack_query.go +844 -0
  211. package/linthost/rules_testing_library.go +1204 -0
  212. package/linthost/rules_throw.go +1 -1
  213. package/linthost/rules_ts.go +19 -19
  214. package/linthost/rules_ts_async.go +399 -0
  215. package/linthost/rules_ts_class_literal_property_style.go +115 -0
  216. package/linthost/rules_ts_consistent_type_exports.go +256 -0
  217. package/linthost/rules_ts_explicit_function_return_type.go +67 -0
  218. package/linthost/rules_ts_extra.go +155 -36
  219. package/linthost/rules_ts_no_base_to_string.go +218 -0
  220. package/linthost/rules_ts_no_confusing_void.go +72 -0
  221. package/linthost/rules_ts_no_deprecated.go +195 -0
  222. package/linthost/rules_ts_no_for_in_array.go +84 -0
  223. package/linthost/rules_ts_no_magic_numbers.go +124 -0
  224. package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
  225. package/linthost/rules_ts_no_misused_spread.go +104 -0
  226. package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
  227. package/linthost/rules_ts_no_restricted_types.go +62 -0
  228. package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
  229. package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
  230. package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
  231. package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
  232. package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
  233. package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
  234. package/linthost/rules_ts_no_unsafe_argument.go +82 -0
  235. package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
  236. package/linthost/rules_ts_no_unsafe_call.go +82 -0
  237. package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
  238. package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
  239. package/linthost/rules_ts_no_unsafe_return.go +126 -0
  240. package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
  241. package/linthost/rules_ts_no_useless_constructor.go +52 -0
  242. package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
  243. package/linthost/rules_ts_parameter_properties.go +38 -0
  244. package/linthost/rules_ts_prefer_find.go +178 -0
  245. package/linthost/rules_ts_prefer_includes.go +255 -0
  246. package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
  247. package/linthost/rules_ts_prefer_optional_chain.go +228 -0
  248. package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
  249. package/linthost/rules_ts_prefer_readonly.go +73 -0
  250. package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
  251. package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
  252. package/linthost/rules_ts_prefer_return_this_type.go +135 -0
  253. package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
  254. package/linthost/rules_ts_promise_function_async.go +77 -0
  255. package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
  256. package/linthost/rules_ts_require_array_sort_compare.go +96 -0
  257. package/linthost/rules_ts_restrict_plus_operands.go +127 -0
  258. package/linthost/rules_ts_restrict_template_expressions.go +95 -0
  259. package/linthost/rules_ts_simple.go +387 -0
  260. package/linthost/rules_ts_sort_type_constituents.go +144 -0
  261. package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
  262. package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
  263. package/linthost/rules_ts_unbound_method.go +126 -0
  264. package/linthost/rules_tsdoc.go +136 -0
  265. package/linthost/rules_unicorn_better_regex.go +27 -0
  266. package/linthost/rules_unicorn_catch_error_name.go +46 -0
  267. package/linthost/rules_unicorn_consistent_assert.go +47 -0
  268. package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
  269. package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
  270. package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
  271. package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
  272. package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
  273. package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
  274. package/linthost/rules_unicorn_custom_error_definition.go +138 -0
  275. package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
  276. package/linthost/rules_unicorn_error_message.go +64 -0
  277. package/linthost/rules_unicorn_escape_case.go +51 -0
  278. package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
  279. package/linthost/rules_unicorn_explicit_length_check.go +88 -0
  280. package/linthost/rules_unicorn_filename_case.go +29 -0
  281. package/linthost/rules_unicorn_import_style.go +28 -0
  282. package/linthost/rules_unicorn_isolated_functions.go +29 -0
  283. package/linthost/rules_unicorn_new_for_builtins.go +87 -0
  284. package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
  285. package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
  286. package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
  287. package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
  288. package/linthost/rules_unicorn_no_array_for_each.go +40 -0
  289. package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
  290. package/linthost/rules_unicorn_no_array_reduce.go +41 -0
  291. package/linthost/rules_unicorn_no_array_reverse.go +44 -0
  292. package/linthost/rules_unicorn_no_array_sort.go +43 -0
  293. package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
  294. package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
  295. package/linthost/rules_unicorn_no_console_spaces.go +61 -0
  296. package/linthost/rules_unicorn_no_document_cookie.go +41 -0
  297. package/linthost/rules_unicorn_no_empty_file.go +44 -0
  298. package/linthost/rules_unicorn_no_for_loop.go +102 -0
  299. package/linthost/rules_unicorn_no_hex_escape.go +42 -0
  300. package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
  301. package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
  302. package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
  303. package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
  304. package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
  305. package/linthost/rules_unicorn_no_lonely_if.go +44 -0
  306. package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
  307. package/linthost/rules_unicorn_no_named_default.go +54 -0
  308. package/linthost/rules_unicorn_no_negated_condition.go +85 -0
  309. package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
  310. package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
  311. package/linthost/rules_unicorn_no_new_array.go +30 -0
  312. package/linthost/rules_unicorn_no_new_buffer.go +31 -0
  313. package/linthost/rules_unicorn_no_null.go +24 -0
  314. package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
  315. package/linthost/rules_unicorn_no_process_exit.go +43 -0
  316. package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
  317. package/linthost/rules_unicorn_no_static_only_class.go +56 -0
  318. package/linthost/rules_unicorn_no_thenable.go +74 -0
  319. package/linthost/rules_unicorn_no_this_assignment.go +35 -0
  320. package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
  321. package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
  322. package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
  323. package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
  324. package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
  325. package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
  326. package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
  327. package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
  328. package/linthost/rules_unicorn_no_unused_properties.go +30 -0
  329. package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
  330. package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
  331. package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
  332. package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
  333. package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
  334. package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
  335. package/linthost/rules_unicorn_no_useless_spread.go +67 -0
  336. package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
  337. package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
  338. package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
  339. package/linthost/rules_unicorn_number_literal_case.go +69 -0
  340. package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
  341. package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
  342. package/linthost/rules_unicorn_prefer_array_find.go +51 -0
  343. package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
  344. package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
  345. package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
  346. package/linthost/rules_unicorn_prefer_array_some.go +67 -0
  347. package/linthost/rules_unicorn_prefer_at.go +77 -0
  348. package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
  349. package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
  350. package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
  351. package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
  352. package/linthost/rules_unicorn_prefer_code_point.go +49 -0
  353. package/linthost/rules_unicorn_prefer_date_now.go +78 -0
  354. package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
  355. package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
  356. package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
  357. package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
  358. package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
  359. package/linthost/rules_unicorn_prefer_event_target.go +36 -0
  360. package/linthost/rules_unicorn_prefer_export_from.go +129 -0
  361. package/linthost/rules_unicorn_prefer_global_this.go +127 -0
  362. package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
  363. package/linthost/rules_unicorn_prefer_includes.go +149 -0
  364. package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
  365. package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
  366. package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
  367. package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
  368. package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
  369. package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
  370. package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
  371. package/linthost/rules_unicorn_prefer_module.go +50 -0
  372. package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
  373. package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
  374. package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
  375. package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
  376. package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
  377. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
  378. package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
  379. package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
  380. package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
  381. package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
  382. package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
  383. package/linthost/rules_unicorn_prefer_set_has.go +42 -0
  384. package/linthost/rules_unicorn_prefer_set_size.go +48 -0
  385. package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
  386. package/linthost/rules_unicorn_prefer_single_call.go +96 -0
  387. package/linthost/rules_unicorn_prefer_spread.go +51 -0
  388. package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
  389. package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
  390. package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
  391. package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
  392. package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
  393. package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
  394. package/linthost/rules_unicorn_prefer_switch.go +103 -0
  395. package/linthost/rules_unicorn_prefer_ternary.go +71 -0
  396. package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
  397. package/linthost/rules_unicorn_prefer_type_error.go +127 -0
  398. package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
  399. package/linthost/rules_unicorn_relative_url_style.go +49 -0
  400. package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
  401. package/linthost/rules_unicorn_require_module_attributes.go +54 -0
  402. package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
  403. package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
  404. package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
  405. package/linthost/rules_unicorn_string_content.go +27 -0
  406. package/linthost/rules_unicorn_switch_case_braces.go +42 -0
  407. package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
  408. package/linthost/rules_unicorn_template_indent.go +28 -0
  409. package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
  410. package/linthost/rules_unicorn_throw_new_error.go +61 -0
  411. package/linthost/rules_var.go +4 -4
  412. package/linthost/rules_vitest.go +568 -0
  413. package/package.json +3 -3
  414. package/plugin/main.go +49 -3
  415. package/rule/astutil/astutil.go +10 -3
  416. package/rule/rule.go +12 -10
  417. package/src/defaultFormat.ts +11 -8
  418. package/src/index.ts +40 -16
  419. package/src/structures/ITtscLintConfig.ts +12 -6
  420. package/src/structures/{ITtscLintFormatConfig.ts → ITtscLintFormat.ts} +2 -2
  421. package/src/structures/TtscLintRuleSetting.ts +55 -0
  422. package/src/structures/index.ts +3 -4
  423. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +128 -0
  424. package/src/structures/rules/ITtscLintBoundariesRules.ts +95 -0
  425. package/src/structures/rules/ITtscLintContributorRules.ts +21 -0
  426. package/src/structures/rules/ITtscLintCoreRules.ts +1406 -0
  427. package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
  428. package/src/structures/rules/ITtscLintCypressRules.ts +145 -0
  429. package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +213 -0
  430. package/src/structures/rules/ITtscLintFunctionalRules.ts +202 -0
  431. package/src/structures/rules/ITtscLintJestRules.ts +220 -0
  432. package/src/structures/rules/ITtscLintJsdocRules.ts +153 -0
  433. package/src/structures/rules/ITtscLintJsxA11yRules.ts +339 -0
  434. package/src/structures/rules/ITtscLintNextjsRules.ts +206 -0
  435. package/src/structures/rules/ITtscLintPlaywrightRules.ts +361 -0
  436. package/src/structures/rules/ITtscLintPromiseRules.ts +205 -0
  437. package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
  438. package/src/structures/rules/ITtscLintReactPerfRules.ts +55 -0
  439. package/src/structures/rules/ITtscLintReactRuleOptions.ts +43 -0
  440. package/src/structures/rules/ITtscLintReactRules.ts +321 -0
  441. package/src/structures/rules/ITtscLintRegexpRules.ts +212 -0
  442. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +89 -0
  443. package/src/structures/rules/ITtscLintRules.ts +77 -0
  444. package/src/structures/rules/ITtscLintSecurityRules.ts +162 -0
  445. package/src/structures/rules/ITtscLintSolidRules.ts +202 -0
  446. package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +23 -0
  447. package/src/structures/rules/ITtscLintStorybookRules.ts +193 -0
  448. package/src/structures/rules/ITtscLintTanstackQueryRules.ts +102 -0
  449. package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +24 -0
  450. package/src/structures/rules/ITtscLintTestingLibraryRules.ts +342 -0
  451. package/src/structures/rules/ITtscLintTypeScriptRules.ts +1230 -0
  452. package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
  453. package/src/structures/rules/ITtscLintVitestRules.ts +154 -0
  454. package/src/structures/rules/index.ts +31 -0
  455. package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
  456. package/lib/structures/TtscLintRule.d.ts +0 -17
  457. package/lib/structures/TtscLintRule.js.map +0 -1
  458. package/lib/structures/TtscLintRuleMap.d.ts +0 -46
  459. package/lib/structures/TtscLintRuleMap.js.map +0 -1
  460. package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
  461. package/lib/structures/TtscLintRuleOptions.js.map +0 -1
  462. package/src/structures/TtscLintRule.ts +0 -160
  463. package/src/structures/TtscLintRuleMap.ts +0 -55
  464. package/src/structures/TtscLintRuleOptions.ts +0 -151
@@ -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
+ }
@@ -0,0 +1,144 @@
1
+ // typescript/sort-type-constituents: union and intersection type
2
+ // constituents render the same set of values regardless of the order
3
+ // the author chose, so two authors writing the same type can disagree
4
+ // on the spelling. The rule pins one canonical ordering — primitives
5
+ // alphabetized first, then named / object types alphabetized, then
6
+ // `null` / `undefined` last — so reviewers don't have to argue about
7
+ // which spelling to land. typescript-eslint:
8
+ // https://typescript-eslint.io/rules/sort-type-constituents/
9
+ package linthost
10
+
11
+ import (
12
+ "sort"
13
+ "strings"
14
+
15
+ shimast "github.com/microsoft/typescript-go/shim/ast"
16
+ )
17
+
18
+ // sortTypeConstituents fires on `UnionType` and `IntersectionType` when
19
+ // the constituent order does not match the canonical ordering. The
20
+ // check is AST-only: ordering is decided by syntactic group (keyword
21
+ // primitive vs. named reference vs. nullish) and a within-group source
22
+ // sort, none of which need the Checker.
23
+ //
24
+ // The diagnostic anchors to the union / intersection node so the
25
+ // rendered location names the whole type, not just one constituent.
26
+ // One report per misordered type is enough — the autofixer would
27
+ // rewrite the entire list together anyway.
28
+ type sortTypeConstituents struct{}
29
+
30
+ func (sortTypeConstituents) Name() string {
31
+ return "typescript/sort-type-constituents"
32
+ }
33
+ func (sortTypeConstituents) Visits() []shimast.Kind {
34
+ return []shimast.Kind{
35
+ shimast.KindUnionType,
36
+ shimast.KindIntersectionType,
37
+ }
38
+ }
39
+ func (sortTypeConstituents) Check(ctx *Context, node *shimast.Node) {
40
+ types := unionOrIntersectionTypes(node)
41
+ if len(types) < 2 {
42
+ return
43
+ }
44
+ // Skip nested unions/intersections — the outermost shape is the one
45
+ // the user wrote, and reporting on every nesting level would
46
+ // double-fire on `(A | B) | C` shapes.
47
+ if node.Parent != nil &&
48
+ (node.Parent.Kind == shimast.KindUnionType || node.Parent.Kind == shimast.KindIntersectionType) {
49
+ return
50
+ }
51
+ entries := make([]sortTypeConstituentsEntry, len(types))
52
+ for i, t := range types {
53
+ entries[i] = sortTypeConstituentsEntry{
54
+ index: i,
55
+ group: sortTypeConstituentsClassify(t),
56
+ text: strings.TrimSpace(nodeText(ctx.File, t)),
57
+ }
58
+ }
59
+ sorted := make([]sortTypeConstituentsEntry, len(entries))
60
+ copy(sorted, entries)
61
+ sort.SliceStable(sorted, func(i, j int) bool {
62
+ if sorted[i].group != sorted[j].group {
63
+ return sorted[i].group < sorted[j].group
64
+ }
65
+ return sorted[i].text < sorted[j].text
66
+ })
67
+ for i := range entries {
68
+ if entries[i].index != sorted[i].index {
69
+ label := "union"
70
+ if node.Kind == shimast.KindIntersectionType {
71
+ label = "intersection"
72
+ }
73
+ ctx.Report(node, "Constituents of the "+label+" are not in the canonical order — primitives alphabetized first, named types alphabetized next, `null` / `undefined` last.")
74
+ return
75
+ }
76
+ }
77
+ }
78
+
79
+ // sortTypeConstituentsEntry is one constituent's sort key. `index`
80
+ // records the original position so the reorder check can compare the
81
+ // before/after sequences without losing identity.
82
+ type sortTypeConstituentsEntry struct {
83
+ index int
84
+ group int
85
+ text string
86
+ }
87
+
88
+ // sortTypeConstituentsClassify buckets a constituent into one of the
89
+ // canonical groups. Smaller numbers come first in the canonical order.
90
+ func sortTypeConstituentsClassify(node *shimast.Node) int {
91
+ if node == nil {
92
+ return sortTypeConstituentsGroupNamed
93
+ }
94
+ switch node.Kind {
95
+ case shimast.KindStringKeyword,
96
+ shimast.KindNumberKeyword,
97
+ shimast.KindBooleanKeyword,
98
+ shimast.KindBigIntKeyword,
99
+ shimast.KindSymbolKeyword,
100
+ shimast.KindAnyKeyword,
101
+ shimast.KindUnknownKeyword,
102
+ shimast.KindVoidKeyword,
103
+ shimast.KindNeverKeyword,
104
+ shimast.KindObjectKeyword:
105
+ return sortTypeConstituentsGroupPrimitive
106
+ case shimast.KindLiteralType:
107
+ // `null` and `undefined` parse as LiteralType / undefined
108
+ // keyword inside type position — surface them as the nullish
109
+ // group so the canonical order keeps them at the end.
110
+ if sortTypeConstituentsIsNullish(node) {
111
+ return sortTypeConstituentsGroupNullish
112
+ }
113
+ return sortTypeConstituentsGroupLiteral
114
+ case shimast.KindUndefinedKeyword, shimast.KindNullKeyword:
115
+ return sortTypeConstituentsGroupNullish
116
+ }
117
+ return sortTypeConstituentsGroupNamed
118
+ }
119
+
120
+ const (
121
+ sortTypeConstituentsGroupPrimitive = iota
122
+ sortTypeConstituentsGroupLiteral
123
+ sortTypeConstituentsGroupNamed
124
+ sortTypeConstituentsGroupNullish
125
+ )
126
+
127
+ // sortTypeConstituentsIsNullish reports whether a LiteralType node
128
+ // wraps the `null` keyword token. The `undefined` keyword in type
129
+ // position is a regular Identifier-shaped reference and is handled by
130
+ // the named group, not by this helper.
131
+ func sortTypeConstituentsIsNullish(node *shimast.Node) bool {
132
+ if node == nil || node.Kind != shimast.KindLiteralType {
133
+ return false
134
+ }
135
+ lit := node.AsLiteralTypeNode()
136
+ if lit == nil || lit.Literal == nil {
137
+ return false
138
+ }
139
+ return lit.Literal.Kind == shimast.KindNullKeyword
140
+ }
141
+
142
+ func init() {
143
+ Register(sortTypeConstituents{})
144
+ }
@@ -0,0 +1,157 @@
1
+ // strictBooleanExpressions fires when a non-boolean value is used in
2
+ // a boolean context — the test of an `if` / `while` / `do` / `for` /
3
+ // ternary, the operand of `!`, or either side of `&&` / `||`.
4
+ // JavaScript coerces every truthy / falsy shape silently:
5
+ //
6
+ // - numbers: `0`, `-0`, and `NaN` are falsy; every other number is
7
+ // truthy. `if (count)` therefore skips a legitimate zero.
8
+ // - strings: `""` is falsy; every other string is truthy.
9
+ // `if (name)` therefore skips a legitimate empty string.
10
+ // - nullable objects: `null` / `undefined` are falsy, the object is
11
+ // truthy. `if (obj)` collapses the present-vs-absent and
12
+ // present-but-empty cases together.
13
+ //
14
+ // The fix is always an explicit comparison naming the intent —
15
+ // `count !== 0`, `str.length > 0`, `obj != null`. typescript-eslint:
16
+ // https://typescript-eslint.io/rules/strict-boolean-expressions/
17
+ //
18
+ // Type-aware. Without a Checker the rule cannot tell a `boolean` apart
19
+ // from a `string`, so Context.Checker == nil short-circuits each Check
20
+ // to a no-op the way `no-for-in-array` and `no-misused-promises` do.
21
+ package linthost
22
+
23
+ import (
24
+ shimast "github.com/microsoft/typescript-go/shim/ast"
25
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
26
+ )
27
+
28
+ type strictBooleanExpressions struct{}
29
+
30
+ func (strictBooleanExpressions) Name() string { return "typescript/strict-boolean-expressions" }
31
+ func (strictBooleanExpressions) NeedsTypeChecker() bool {
32
+ return true
33
+ }
34
+ func (strictBooleanExpressions) Visits() []shimast.Kind {
35
+ return []shimast.Kind{
36
+ shimast.KindIfStatement,
37
+ shimast.KindWhileStatement,
38
+ shimast.KindDoStatement,
39
+ shimast.KindForStatement,
40
+ shimast.KindConditionalExpression,
41
+ shimast.KindPrefixUnaryExpression,
42
+ shimast.KindBinaryExpression,
43
+ }
44
+ }
45
+ func (strictBooleanExpressions) Check(ctx *Context, node *shimast.Node) {
46
+ if ctx.Checker == nil {
47
+ return
48
+ }
49
+ switch node.Kind {
50
+ case shimast.KindIfStatement:
51
+ if stmt := node.AsIfStatement(); stmt != nil {
52
+ strictBooleanExpressionsReport(ctx, stmt.Expression)
53
+ }
54
+ case shimast.KindWhileStatement:
55
+ if stmt := node.AsWhileStatement(); stmt != nil {
56
+ strictBooleanExpressionsReport(ctx, stmt.Expression)
57
+ }
58
+ case shimast.KindDoStatement:
59
+ if stmt := node.AsDoStatement(); stmt != nil {
60
+ strictBooleanExpressionsReport(ctx, stmt.Expression)
61
+ }
62
+ case shimast.KindForStatement:
63
+ if stmt := node.AsForStatement(); stmt != nil {
64
+ strictBooleanExpressionsReport(ctx, stmt.Condition)
65
+ }
66
+ case shimast.KindConditionalExpression:
67
+ if expr := node.AsConditionalExpression(); expr != nil {
68
+ strictBooleanExpressionsReport(ctx, expr.Condition)
69
+ }
70
+ case shimast.KindPrefixUnaryExpression:
71
+ expr := node.AsPrefixUnaryExpression()
72
+ if expr != nil && expr.Operator == shimast.KindExclamationToken {
73
+ strictBooleanExpressionsReport(ctx, expr.Operand)
74
+ }
75
+ case shimast.KindBinaryExpression:
76
+ bin := node.AsBinaryExpression()
77
+ if bin == nil || bin.OperatorToken == nil {
78
+ return
79
+ }
80
+ // Only `&&` / `||` test their left operand for truthiness.
81
+ // `??` short-circuits on nullish, not on falsy, so a non-boolean
82
+ // left operand is exactly the point of `??` and is not flagged.
83
+ switch bin.OperatorToken.Kind {
84
+ case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
85
+ strictBooleanExpressionsReport(ctx, bin.Left)
86
+ }
87
+ }
88
+ }
89
+
90
+ // strictBooleanExpressionsReport flags `expr` when its static type is
91
+ // not pure boolean-like. The recursion arm peels through `&&` / `||`
92
+ // chains so `if (a && b)` reports both `a` and `b`, mirroring the
93
+ // upstream rule. Parenthesized wrappers are skipped via stripParens
94
+ // so `if ((x))` resolves to `x`.
95
+ func strictBooleanExpressionsReport(ctx *Context, expr *shimast.Node) {
96
+ if expr == nil {
97
+ return
98
+ }
99
+ expr = stripParens(expr)
100
+ if expr == nil {
101
+ return
102
+ }
103
+ // Descend through `&&` / `||` — each conjunct/disjunct sits in
104
+ // boolean position too. The outer BinaryExpression visit only
105
+ // checks Left; the descent here finds Right as well.
106
+ if expr.Kind == shimast.KindBinaryExpression {
107
+ bin := expr.AsBinaryExpression()
108
+ if bin != nil && bin.OperatorToken != nil {
109
+ switch bin.OperatorToken.Kind {
110
+ case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
111
+ strictBooleanExpressionsReport(ctx, bin.Left)
112
+ strictBooleanExpressionsReport(ctx, bin.Right)
113
+ return
114
+ }
115
+ }
116
+ }
117
+ t := ctx.Checker.GetTypeAtLocation(expr)
118
+ if t == nil {
119
+ return
120
+ }
121
+ if strictBooleanExpressionsIsBoolean(t) {
122
+ return
123
+ }
124
+ ctx.Report(expr, "Unexpected non-boolean value in a boolean conditional position. Use an explicit comparison (`!== 0`, `.length > 0`, `!= null`) to name the intent.")
125
+ }
126
+
127
+ // strictBooleanExpressionsIsBoolean reports whether t is pure
128
+ // boolean-like. `any` / `unknown` / `never` are intentionally NOT
129
+ // considered boolean — they leak through generic helpers and would
130
+ // suppress the rule everywhere a value of unknown origin lands in a
131
+ // conditional. Union and intersection types must have every
132
+ // constituent boolean for the whole type to count.
133
+ func strictBooleanExpressionsIsBoolean(t *shimchecker.Type) bool {
134
+ if t == nil {
135
+ return false
136
+ }
137
+ flags := t.Flags()
138
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
139
+ return false
140
+ }
141
+ if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
142
+ for _, part := range t.Types() {
143
+ if part == nil {
144
+ continue
145
+ }
146
+ if !strictBooleanExpressionsIsBoolean(part) {
147
+ return false
148
+ }
149
+ }
150
+ return true
151
+ }
152
+ return flags&shimchecker.TypeFlagsBooleanLike != 0
153
+ }
154
+
155
+ func init() {
156
+ Register(strictBooleanExpressions{})
157
+ }