@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,52 @@
1
+ // typescript/no-useless-constructor: TS-aware extension of the core
2
+ // `no-useless-constructor` rule. A class constructor with an empty body
3
+ // and no parameter properties is noise — the engine generates the same
4
+ // default constructor anyway.
5
+ //
6
+ // The TS variant differs from the core rule in one detail: a
7
+ // parameter-property declaration (`constructor(public foo: number) {}`)
8
+ // carries a semantic side effect — it implicitly declares the class
9
+ // field and assigns the argument to it. Removing the constructor would
10
+ // remove the field. So an otherwise-empty body is NOT useless when at
11
+ // least one parameter is a parameter property.
12
+ // typescript-eslint strict:
13
+ // https://typescript-eslint.io/rules/no-useless-constructor/
14
+ //
15
+ // AST-only. The trigger is a `KindConstructor` whose body is an empty
16
+ // block and whose parameter list contains no `public` / `private` /
17
+ // `protected` / `readonly` / `override` parameter property.
18
+ package linthost
19
+
20
+ import (
21
+ shimast "github.com/microsoft/typescript-go/shim/ast"
22
+ )
23
+
24
+ type tsNoUselessConstructor struct{}
25
+
26
+ func (tsNoUselessConstructor) Name() string { return "typescript/no-useless-constructor" }
27
+ func (tsNoUselessConstructor) Visits() []shimast.Kind {
28
+ return []shimast.Kind{shimast.KindConstructor}
29
+ }
30
+ func (tsNoUselessConstructor) Check(ctx *Context, node *shimast.Node) {
31
+ ctor := node.AsConstructorDeclaration()
32
+ if ctor == nil || ctor.Body == nil {
33
+ return
34
+ }
35
+ body := ctor.Body.AsBlock()
36
+ if body == nil || body.Statements == nil || len(body.Statements.Nodes) != 0 {
37
+ return
38
+ }
39
+ // Any parameter property keeps the constructor meaningful: the
40
+ // shorthand IS the field declaration. Removing the constructor
41
+ // would silently delete the field, so this is not "useless".
42
+ for _, param := range node.Parameters() {
43
+ if isParameterProperty(param) {
44
+ return
45
+ }
46
+ }
47
+ ctx.Report(node, "Useless constructor with no parameter properties.")
48
+ }
49
+
50
+ func init() {
51
+ Register(tsNoUselessConstructor{})
52
+ }
@@ -0,0 +1,108 @@
1
+ // typescript/non-nullable-type-assertion-style: when `x as T` strips
2
+ // exactly the `null`/`undefined` constituents from the static type of
3
+ // `x`, the assertion is equivalent to the non-null assertion `x!`. The
4
+ // `!` form is shorter and communicates "I am asserting non-null"
5
+ // explicitly, while `as T` may be read as "I am narrowing to a
6
+ // different type". typescript-eslint stylistic-type-checked:
7
+ // https://typescript-eslint.io/rules/non-nullable-type-assertion-style/
8
+ package linthost
9
+
10
+ import (
11
+ shimast "github.com/microsoft/typescript-go/shim/ast"
12
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
13
+ )
14
+
15
+ // nonNullableTypeAssertionStyle reports `expr as T` where `T` equals the
16
+ // non-nullable version of `expr`'s static type. Implementation notes:
17
+ //
18
+ // - Type-aware: requires the Checker to compute the non-nullable form
19
+ // of the source expression and to compare it against the asserted
20
+ // type. The shim re-exports the unexported `GetNonNullableType` and
21
+ // `GetTypeFromTypeNode` methods directly.
22
+ // - Symmetric assignability is used instead of literal type identity
23
+ // because the Checker may widen literal types differently between
24
+ // the two sides (e.g. the source `string | undefined` becomes
25
+ // `string` after non-null stripping, and the asserted node `string`
26
+ // resolves to the same primitive — both directions of assignability
27
+ // hold and identity is unnecessary).
28
+ // - The rule only fires when the source type was actually nullable;
29
+ // `42 as number` is left alone because removing nothing from
30
+ // `number` still yields `number` and the assertion is not
31
+ // equivalent to `42!` (which would be a syntax error on a literal).
32
+ type nonNullableTypeAssertionStyle struct{}
33
+
34
+ func (nonNullableTypeAssertionStyle) Name() string {
35
+ return "typescript/non-nullable-type-assertion-style"
36
+ }
37
+ func (nonNullableTypeAssertionStyle) NeedsTypeChecker() bool {
38
+ return true
39
+ }
40
+ func (nonNullableTypeAssertionStyle) Visits() []shimast.Kind {
41
+ return []shimast.Kind{shimast.KindAsExpression}
42
+ }
43
+ func (nonNullableTypeAssertionStyle) Check(ctx *Context, node *shimast.Node) {
44
+ if ctx.Checker == nil {
45
+ return
46
+ }
47
+ as := node.AsAsExpression()
48
+ if as == nil || as.Expression == nil || as.Type == nil {
49
+ return
50
+ }
51
+ sourceType := ctx.Checker.GetTypeAtLocation(as.Expression)
52
+ if sourceType == nil {
53
+ return
54
+ }
55
+ // Only consider expressions whose static type actually carries
56
+ // `null` or `undefined`; otherwise `x!` is not the same as `x as T`.
57
+ if !nonNullableTypeAssertionStyleIsNullable(sourceType) {
58
+ return
59
+ }
60
+ nonNullable := ctx.Checker.GetNonNullableType(sourceType)
61
+ if nonNullable == nil {
62
+ return
63
+ }
64
+ assertedType := ctx.Checker.GetTypeFromTypeNode(as.Type)
65
+ if assertedType == nil {
66
+ return
67
+ }
68
+ // Bidirectional assignability stands in for type identity: the
69
+ // stripped source type must coincide with the asserted type up to
70
+ // structural equivalence. Both sides have to hold so that
71
+ // `x as SomeSupertype` or `x as SomeSubtype` does not get rewritten
72
+ // to `x!` and silently lose information.
73
+ if !ctx.Checker.IsTypeAssignableTo(nonNullable, assertedType) {
74
+ return
75
+ }
76
+ if !ctx.Checker.IsTypeAssignableTo(assertedType, nonNullable) {
77
+ return
78
+ }
79
+ ctx.Report(node, "Use a `!` assertion to more succinctly remove `null` and `undefined` from the type.")
80
+ }
81
+
82
+ // nonNullableTypeAssertionStyleIsNullable reports whether t carries
83
+ // `null` or `undefined` either at the top level (for direct
84
+ // `T | null` / `T | undefined` shapes) or inside a union constituent.
85
+ func nonNullableTypeAssertionStyleIsNullable(t *shimchecker.Type) bool {
86
+ if t == nil {
87
+ return false
88
+ }
89
+ flags := t.Flags()
90
+ if flags&(shimchecker.TypeFlagsNull|shimchecker.TypeFlagsUndefined) != 0 {
91
+ return true
92
+ }
93
+ if flags&shimchecker.TypeFlagsUnion != 0 {
94
+ for _, part := range t.Types() {
95
+ if part == nil {
96
+ continue
97
+ }
98
+ if nonNullableTypeAssertionStyleIsNullable(part) {
99
+ return true
100
+ }
101
+ }
102
+ }
103
+ return false
104
+ }
105
+
106
+ func init() {
107
+ Register(nonNullableTypeAssertionStyle{})
108
+ }
@@ -0,0 +1,38 @@
1
+ // typescript/parameter-properties reports TypeScript parameter
2
+ // properties — constructor parameters prefixed with `public`,
3
+ // `private`, `protected`, `readonly`, or `override` that implicitly
4
+ // declare a class field. The rule's default policy
5
+ // (`prefer: "class-property"`) flags the shorthand so the class
6
+ // member list stays the single source of truth for the class shape;
7
+ // fields buried in the constructor signature are easy to miss.
8
+ // https://typescript-eslint.io/rules/parameter-properties/
9
+ //
10
+ // AST-only — the trigger is a syntactic modifier on a `KindParameter`
11
+ // whose parent is a `KindConstructor`. The shared `isParameterProperty`
12
+ // helper (also used by `no-unnecessary-parameter-property-assignment`)
13
+ // is the single decoding point for the modifier set.
14
+ package linthost
15
+
16
+ import (
17
+ shimast "github.com/microsoft/typescript-go/shim/ast"
18
+ )
19
+
20
+ type parameterProperties struct{}
21
+
22
+ func (parameterProperties) Name() string { return "typescript/parameter-properties" }
23
+ func (parameterProperties) Visits() []shimast.Kind {
24
+ return []shimast.Kind{shimast.KindParameter}
25
+ }
26
+ func (parameterProperties) Check(ctx *Context, node *shimast.Node) {
27
+ if node == nil || node.Parent == nil || node.Parent.Kind != shimast.KindConstructor {
28
+ return
29
+ }
30
+ if !isParameterProperty(node) {
31
+ return
32
+ }
33
+ ctx.Report(node, "Prefer a plain class field declaration over a constructor parameter property.")
34
+ }
35
+
36
+ func init() {
37
+ Register(parameterProperties{})
38
+ }
@@ -0,0 +1,178 @@
1
+ // typescript/prefer-find: prefer `arr.find(predicate)` over the
2
+ // `arr.filter(predicate)[0]` and `arr.filter(predicate).at(0)` shapes.
3
+ // `find` short-circuits on the first match instead of materializing the
4
+ // whole filtered array, so for sufficiently large inputs it is strictly
5
+ // faster — and at every input size it expresses the intent ("get me
6
+ // the first match") more directly than reading the head of a filtered
7
+ // list. typescript-eslint:
8
+ // https://typescript-eslint.io/rules/prefer-find/
9
+ //
10
+ // Type-aware. Without a Checker the rule cannot prove the receiver of
11
+ // `filter` is array-like, so Context.Checker == nil short-circuits each
12
+ // Check to a no-op the way `no-for-in-array` and `prefer-includes` do.
13
+ // The receiver type must be a provable array or tuple — generic, `any`,
14
+ // `unknown`, and `never` pass through so generic helpers don't explode
15
+ // with false positives on user-defined `filter` methods.
16
+ package linthost
17
+
18
+ import (
19
+ shimast "github.com/microsoft/typescript-go/shim/ast"
20
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
21
+ )
22
+
23
+ type preferFind struct{}
24
+
25
+ func (preferFind) Name() string { return "typescript/prefer-find" }
26
+ func (preferFind) NeedsTypeChecker() bool {
27
+ return true
28
+ }
29
+ func (preferFind) Visits() []shimast.Kind {
30
+ return []shimast.Kind{
31
+ shimast.KindElementAccessExpression,
32
+ shimast.KindCallExpression,
33
+ }
34
+ }
35
+ func (preferFind) Check(ctx *Context, node *shimast.Node) {
36
+ if ctx.Checker == nil {
37
+ return
38
+ }
39
+ switch node.Kind {
40
+ case shimast.KindElementAccessExpression:
41
+ access := node.AsElementAccessExpression()
42
+ if access == nil || access.Expression == nil || access.ArgumentExpression == nil {
43
+ return
44
+ }
45
+ // Index must be the literal `0`.
46
+ if !preferFindIsZeroLiteral(access.ArgumentExpression) {
47
+ return
48
+ }
49
+ if !preferFindIsArrayFilterCall(ctx, access.Expression) {
50
+ return
51
+ }
52
+ ctx.Report(node, preferFindMessage)
53
+ case shimast.KindCallExpression:
54
+ call := node.AsCallExpression()
55
+ if call == nil || call.Expression == nil {
56
+ return
57
+ }
58
+ // Match `<filter-call>.at(0)`.
59
+ receiver, method, ok := promisePropertyAccessParts(call.Expression)
60
+ if !ok || method != "at" {
61
+ return
62
+ }
63
+ if call.Arguments == nil || len(call.Arguments.Nodes) != 1 {
64
+ return
65
+ }
66
+ if !preferFindIsZeroLiteral(call.Arguments.Nodes[0]) {
67
+ return
68
+ }
69
+ if !preferFindIsArrayFilterCall(ctx, receiver) {
70
+ return
71
+ }
72
+ ctx.Report(node, preferFindMessage)
73
+ }
74
+ }
75
+
76
+ const preferFindMessage = "Prefer `.find(predicate)` over `.filter(predicate)[0]` / `.filter(predicate).at(0)` — `find` short-circuits on the first match and avoids materializing the full filtered array."
77
+
78
+ // preferFindIsZeroLiteral reports whether `node` (after stripping
79
+ // parens) is the numeric literal `0` — the only index `find` can
80
+ // replace. `+0` and `0` are both accepted; `-0` is rejected because it
81
+ // is technically a separate value at the language level even though
82
+ // `arr[-0]` resolves the same. Keeps the rule's noise floor narrow.
83
+ func preferFindIsZeroLiteral(node *shimast.Node) bool {
84
+ node = stripParens(node)
85
+ if node == nil {
86
+ return false
87
+ }
88
+ if node.Kind == shimast.KindNumericLiteral {
89
+ return numericLiteralText(node) == "0"
90
+ }
91
+ if node.Kind == shimast.KindPrefixUnaryExpression {
92
+ prefix := node.AsPrefixUnaryExpression()
93
+ if prefix == nil || prefix.Operand == nil {
94
+ return false
95
+ }
96
+ if prefix.Operator != shimast.KindPlusToken {
97
+ return false
98
+ }
99
+ return prefix.Operand.Kind == shimast.KindNumericLiteral &&
100
+ numericLiteralText(prefix.Operand) == "0"
101
+ }
102
+ return false
103
+ }
104
+
105
+ // preferFindIsArrayFilterCall reports whether `node` (after stripping
106
+ // parens) is a `<receiver>.filter(predicate)` CallExpression whose
107
+ // receiver type is provably an array or tuple. Mirrors the shape used
108
+ // by `prefer-includes` for `.indexOf(x)`: a user type with a custom
109
+ // `filter` method should NOT trigger the rule.
110
+ func preferFindIsArrayFilterCall(ctx *Context, node *shimast.Node) bool {
111
+ node = stripParens(node)
112
+ if node == nil || node.Kind != shimast.KindCallExpression {
113
+ return false
114
+ }
115
+ call := node.AsCallExpression()
116
+ if call == nil || call.Expression == nil {
117
+ return false
118
+ }
119
+ receiver, method, ok := promisePropertyAccessParts(call.Expression)
120
+ if !ok || method != "filter" {
121
+ return false
122
+ }
123
+ if receiver == nil {
124
+ return false
125
+ }
126
+ // `.filter` accepts an optional `thisArg`, so require at least one
127
+ // argument (the predicate) — a zero-arg call would not parse on the
128
+ // real lib.es5 declaration and is conservatively skipped.
129
+ if call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
130
+ return false
131
+ }
132
+ t := ctx.Checker.GetTypeAtLocation(receiver)
133
+ if t == nil {
134
+ return false
135
+ }
136
+ return preferFindIsArrayLike(ctx.Checker, t)
137
+ }
138
+
139
+ // preferFindIsArrayLike reports whether t is provably an array or
140
+ // tuple. The constituent-recursion shape mirrors
141
+ // `preferIncludesIsArrayOrString`: a union like `T[] | T[]` is still
142
+ // accepted because every constituent is rewritable. `any` / `unknown` /
143
+ // `never` are intentionally NOT treated as matching — they leak from
144
+ // generic helpers and would explode the false-positive volume on
145
+ // user-defined `filter` methods. Strings are NOT included here even
146
+ // though they expose a `.filter`-shaped method via lib polyfills,
147
+ // because the upstream rule only fires on the genuine `Array#filter`.
148
+ func preferFindIsArrayLike(checker *shimchecker.Checker, t *shimchecker.Type) bool {
149
+ if checker == nil || t == nil {
150
+ return false
151
+ }
152
+ flags := t.Flags()
153
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
154
+ return false
155
+ }
156
+ if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
157
+ for _, part := range t.Types() {
158
+ if part == nil {
159
+ continue
160
+ }
161
+ if !preferFindIsArrayLike(checker, part) {
162
+ return false
163
+ }
164
+ }
165
+ return true
166
+ }
167
+ if shimchecker.Checker_isArrayType(checker, t) {
168
+ return true
169
+ }
170
+ if shimchecker.IsTupleType(t) {
171
+ return true
172
+ }
173
+ return false
174
+ }
175
+
176
+ func init() {
177
+ Register(preferFind{})
178
+ }
@@ -0,0 +1,255 @@
1
+ // typescript/prefer-includes: prefer `array.includes(x)` over the
2
+ // `array.indexOf(x) !== -1` (and the related `=== -1`, `>= 0`, `< 0`,
3
+ // `> -1`) idioms. The `includes` form states the intent directly —
4
+ // "does the collection contain this value?" — and avoids the
5
+ // sentinel-vs-position confusion that comes with comparing an
6
+ // `indexOf` return value against `-1`. typescript-eslint:
7
+ // https://typescript-eslint.io/rules/prefer-includes/
8
+ //
9
+ // Type-aware. Without a Checker the rule cannot prove the receiver of
10
+ // `indexOf` is array-like or string-like, so Context.Checker == nil
11
+ // short-circuits each Check to a no-op the way `no-for-in-array` and
12
+ // `require-array-sort-compare` do. The receiver type must be a
13
+ // provable array, tuple, or string — generic, `any`, `unknown`, and
14
+ // `never` pass through so generic helpers don't explode with false
15
+ // positives.
16
+ package linthost
17
+
18
+ import (
19
+ shimast "github.com/microsoft/typescript-go/shim/ast"
20
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
21
+ )
22
+
23
+ type preferIncludes struct{}
24
+
25
+ func (preferIncludes) Name() string { return "typescript/prefer-includes" }
26
+ func (preferIncludes) NeedsTypeChecker() bool {
27
+ return true
28
+ }
29
+ func (preferIncludes) Visits() []shimast.Kind {
30
+ return []shimast.Kind{shimast.KindBinaryExpression}
31
+ }
32
+ func (preferIncludes) Check(ctx *Context, node *shimast.Node) {
33
+ if ctx.Checker == nil {
34
+ return
35
+ }
36
+ bin := node.AsBinaryExpression()
37
+ if bin == nil || bin.OperatorToken == nil {
38
+ return
39
+ }
40
+ // One side of the comparison must be a `.indexOf(...)` call; the
41
+ // other side must be a numeric sentinel (-1 or 0) and the operator
42
+ // chosen so the boolean meaning is "is the value present".
43
+ if !preferIncludesIsTargetedComparison(bin.OperatorToken.Kind) {
44
+ return
45
+ }
46
+ if preferIncludesCheckSide(ctx, bin.Left, bin.Right, bin.OperatorToken.Kind, false) {
47
+ ctx.Report(node, preferIncludesMessage)
48
+ return
49
+ }
50
+ if preferIncludesCheckSide(ctx, bin.Right, bin.Left, bin.OperatorToken.Kind, true) {
51
+ ctx.Report(node, preferIncludesMessage)
52
+ }
53
+ }
54
+
55
+ const preferIncludesMessage = "Prefer `.includes(x)` over `.indexOf(x)` compared against `-1` / `0` — `.includes` states the containment intent directly."
56
+
57
+ // preferIncludesIsTargetedComparison reports whether the operator is
58
+ // one of the equality / ordering tokens the rule cares about. The
59
+ // rule fires on `===`, `!==`, `==`, `!=`, `<`, `<=`, `>`, `>=`; other
60
+ // operators leave the binary alone.
61
+ func preferIncludesIsTargetedComparison(kind shimast.Kind) bool {
62
+ switch kind {
63
+ case shimast.KindEqualsEqualsToken,
64
+ shimast.KindEqualsEqualsEqualsToken,
65
+ shimast.KindExclamationEqualsToken,
66
+ shimast.KindExclamationEqualsEqualsToken,
67
+ shimast.KindLessThanToken,
68
+ shimast.KindLessThanEqualsToken,
69
+ shimast.KindGreaterThanToken,
70
+ shimast.KindGreaterThanEqualsToken:
71
+ return true
72
+ }
73
+ return false
74
+ }
75
+
76
+ // preferIncludesCheckSide reports whether `call` is the
77
+ // `<receiver>.indexOf(arg)` call and `sentinel` is the numeric
78
+ // constant the comparison is paired with. `reversed` flips the
79
+ // direction of ordering operators so `arr.indexOf(x) > -1` and
80
+ // `-1 < arr.indexOf(x)` both match.
81
+ func preferIncludesCheckSide(
82
+ ctx *Context,
83
+ call, sentinel *shimast.Node,
84
+ op shimast.Kind,
85
+ reversed bool,
86
+ ) bool {
87
+ call = stripParens(call)
88
+ sentinel = stripParens(sentinel)
89
+ if call == nil || sentinel == nil {
90
+ return false
91
+ }
92
+ if call.Kind != shimast.KindCallExpression {
93
+ return false
94
+ }
95
+ callExpr := call.AsCallExpression()
96
+ if callExpr == nil || callExpr.Expression == nil {
97
+ return false
98
+ }
99
+ receiver, method, ok := promisePropertyAccessParts(callExpr.Expression)
100
+ if !ok || method != "indexOf" {
101
+ return false
102
+ }
103
+ if callExpr.Arguments == nil || len(callExpr.Arguments.Nodes) != 1 {
104
+ return false
105
+ }
106
+ value, ok := preferIncludesSentinelValue(sentinel)
107
+ if !ok {
108
+ return false
109
+ }
110
+ effectiveOp := op
111
+ if reversed {
112
+ effectiveOp = preferIncludesFlipOperator(op)
113
+ }
114
+ if !preferIncludesIsPresenceComparison(effectiveOp, value) {
115
+ return false
116
+ }
117
+ if receiver == nil {
118
+ return false
119
+ }
120
+ t := ctx.Checker.GetTypeAtLocation(receiver)
121
+ if t == nil {
122
+ return false
123
+ }
124
+ return preferIncludesIsArrayOrString(ctx.Checker, t)
125
+ }
126
+
127
+ // preferIncludesSentinelValue returns the numeric sentinel encoded by
128
+ // `node`, recognizing the literals `-1`, `0`, and `1` (the only
129
+ // constants the rule's shapes reduce to). Returns ok=false for any
130
+ // other expression.
131
+ func preferIncludesSentinelValue(node *shimast.Node) (int, bool) {
132
+ if node == nil {
133
+ return 0, false
134
+ }
135
+ if node.Kind == shimast.KindNumericLiteral {
136
+ switch numericLiteralText(node) {
137
+ case "0":
138
+ return 0, true
139
+ case "1":
140
+ return 1, true
141
+ }
142
+ return 0, false
143
+ }
144
+ if node.Kind != shimast.KindPrefixUnaryExpression {
145
+ return 0, false
146
+ }
147
+ prefix := node.AsPrefixUnaryExpression()
148
+ if prefix == nil || prefix.Operand == nil {
149
+ return 0, false
150
+ }
151
+ if prefix.Operand.Kind != shimast.KindNumericLiteral {
152
+ return 0, false
153
+ }
154
+ text := numericLiteralText(prefix.Operand)
155
+ switch prefix.Operator {
156
+ case shimast.KindMinusToken:
157
+ if text == "1" {
158
+ return -1, true
159
+ }
160
+ if text == "0" {
161
+ return 0, true
162
+ }
163
+ case shimast.KindPlusToken:
164
+ if text == "0" {
165
+ return 0, true
166
+ }
167
+ if text == "1" {
168
+ return 1, true
169
+ }
170
+ }
171
+ return 0, false
172
+ }
173
+
174
+ // preferIncludesFlipOperator returns the operator that has the same
175
+ // boolean meaning when the operands are swapped. `a < b` flipped is
176
+ // `b > a`, `a >= b` flipped is `b <= a`, and equality operators are
177
+ // symmetric so they are returned unchanged.
178
+ func preferIncludesFlipOperator(kind shimast.Kind) shimast.Kind {
179
+ switch kind {
180
+ case shimast.KindLessThanToken:
181
+ return shimast.KindGreaterThanToken
182
+ case shimast.KindLessThanEqualsToken:
183
+ return shimast.KindGreaterThanEqualsToken
184
+ case shimast.KindGreaterThanToken:
185
+ return shimast.KindLessThanToken
186
+ case shimast.KindGreaterThanEqualsToken:
187
+ return shimast.KindLessThanEqualsToken
188
+ }
189
+ return kind
190
+ }
191
+
192
+ // preferIncludesIsPresenceComparison reports whether `op` paired with
193
+ // `value` is one of the equivalences for "the element is present":
194
+ // `!= -1`, `>= 0`, `> -1` mean "present"; `== -1`, `< 0`, `<= -1`
195
+ // mean "absent". Either polarity is rewritable to `includes(x)` (the
196
+ // "absent" cases negate the call), so both pass.
197
+ func preferIncludesIsPresenceComparison(op shimast.Kind, value int) bool {
198
+ switch op {
199
+ case shimast.KindExclamationEqualsToken, shimast.KindExclamationEqualsEqualsToken:
200
+ return value == -1
201
+ case shimast.KindEqualsEqualsToken, shimast.KindEqualsEqualsEqualsToken:
202
+ return value == -1
203
+ case shimast.KindGreaterThanEqualsToken:
204
+ return value == 0
205
+ case shimast.KindGreaterThanToken:
206
+ return value == -1
207
+ case shimast.KindLessThanToken:
208
+ return value == 0
209
+ case shimast.KindLessThanEqualsToken:
210
+ return value == -1
211
+ }
212
+ return false
213
+ }
214
+
215
+ // preferIncludesIsArrayOrString reports whether t is provably an
216
+ // array, tuple, or string. The constituent-recursion shape mirrors
217
+ // `requireArraySortCompareIsArrayLike`: a union like `string[] |
218
+ // string` is still accepted because every constituent is rewritable.
219
+ // `any` / `unknown` / `never` are intentionally NOT treated as
220
+ // matching — they leak from generic helpers and would explode the
221
+ // false-positive volume on user-defined `indexOf` methods.
222
+ func preferIncludesIsArrayOrString(checker *shimchecker.Checker, t *shimchecker.Type) bool {
223
+ if checker == nil || t == nil {
224
+ return false
225
+ }
226
+ flags := t.Flags()
227
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
228
+ return false
229
+ }
230
+ if flags&shimchecker.TypeFlagsStringLike != 0 {
231
+ return true
232
+ }
233
+ if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
234
+ for _, part := range t.Types() {
235
+ if part == nil {
236
+ continue
237
+ }
238
+ if !preferIncludesIsArrayOrString(checker, part) {
239
+ return false
240
+ }
241
+ }
242
+ return true
243
+ }
244
+ if shimchecker.Checker_isArrayType(checker, t) {
245
+ return true
246
+ }
247
+ if shimchecker.IsTupleType(t) {
248
+ return true
249
+ }
250
+ return false
251
+ }
252
+
253
+ func init() {
254
+ Register(preferIncludes{})
255
+ }