@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,61 @@
1
+ // unicorn/throw-new-error: `throw Foo(...)` and `throw new Foo(...)` both
2
+ // produce an Error instance because the built-in Error constructors are
3
+ // callable without `new`, but the call-form is a footgun — readers expect
4
+ // `throw` to be paired with `new`, and some tooling (notably custom Error
5
+ // subclasses) stops working when the call-form is mixed in. The rule
6
+ // requires `throw new` whenever the operand is a direct call to one of the
7
+ // eight built-in Error constructor names.
8
+ //
9
+ // AST-only: visit each `ThrowStatement`, peel parentheses off its operand,
10
+ // and fire when the operand is a `CallExpression` (NOT a `NewExpression`)
11
+ // whose callee is an `Identifier` matching the built-in allowlist. Shadowed
12
+ // bindings and type-aware widening are intentionally out of scope — the
13
+ // rule is a syntactic nudge, not a full Error-tracking pass.
14
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/throw-new-error.md
15
+ package linthost
16
+
17
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
18
+
19
+ var unicornThrowNewErrorBuiltinNames = map[string]struct{}{
20
+ "Error": {},
21
+ "TypeError": {},
22
+ "RangeError": {},
23
+ "SyntaxError": {},
24
+ "ReferenceError": {},
25
+ "EvalError": {},
26
+ "URIError": {},
27
+ "AggregateError": {},
28
+ }
29
+
30
+ type unicornThrowNewError struct{}
31
+
32
+ func (unicornThrowNewError) Name() string { return "unicorn/throw-new-error" }
33
+ func (unicornThrowNewError) Visits() []shimast.Kind {
34
+ return []shimast.Kind{shimast.KindThrowStatement}
35
+ }
36
+ func (unicornThrowNewError) Check(ctx *Context, node *shimast.Node) {
37
+ throw := node.AsThrowStatement()
38
+ if throw == nil {
39
+ return
40
+ }
41
+ expr := stripParens(throw.Expression)
42
+ if expr == nil || expr.Kind != shimast.KindCallExpression {
43
+ return
44
+ }
45
+ call := expr.AsCallExpression()
46
+ if call == nil {
47
+ return
48
+ }
49
+ name := identifierText(call.Expression)
50
+ if name == "" {
51
+ return
52
+ }
53
+ if _, ok := unicornThrowNewErrorBuiltinNames[name]; !ok {
54
+ return
55
+ }
56
+ ctx.Report(expr, "Use `new` when throwing an error.")
57
+ }
58
+
59
+ func init() {
60
+ Register(unicornThrowNewError{})
61
+ }
@@ -2,7 +2,7 @@ package linthost
2
2
 
3
3
  import shimast "github.com/microsoft/typescript-go/shim/ast"
4
4
 
5
- // no-var: ban `var` declarations. ESLint canonical:
5
+ // noVar: ban `var` declarations. ESLint canonical:
6
6
  // https://eslint.org/docs/latest/rules/no-var
7
7
  type noVar struct{}
8
8
 
@@ -34,7 +34,7 @@ func (noVar) Check(ctx *Context, node *shimast.Node) {
34
34
  }
35
35
  }
36
36
 
37
- // prefer-const: flag `let` declarations whose binding is never reassigned.
37
+ // preferConst: flag `let` declarations whose binding is never reassigned.
38
38
  // This follows ESLint's core rule for the common AST-local cases. It is
39
39
  // intentionally conservative: destructuring and declaration-only `let`
40
40
  // variables (those without an initializer and not in a for-of/for-in
@@ -135,7 +135,7 @@ func isSingleDeclarationList(node *shimast.Node) bool {
135
135
  }
136
136
 
137
137
  // isConstEligibleLetDeclaration reports whether a `let` VariableDeclaration
138
- // node is eligible for prefer-const analysis. A declaration is eligible when:
138
+ // node is eligible for preferConst analysis. A declaration is eligible when:
139
139
  // - it has an initializer (the value is set immediately), or
140
140
  // - it is the loop variable of a for-in or for-of statement (e.g. `for (let k of m)`).
141
141
  //
@@ -154,7 +154,7 @@ func isConstEligibleLetDeclaration(node *shimast.Node, decl *shimast.VariableDec
154
154
  (node.Parent.Parent.Kind == shimast.KindForInStatement || node.Parent.Parent.Kind == shimast.KindForOfStatement)
155
155
  }
156
156
 
157
- // no-undef-init: forbid `let x = undefined` and `var x = undefined`.
157
+ // noUndefInit: forbid `let x = undefined` and `var x = undefined`.
158
158
  // ESLint canonical: https://eslint.org/docs/latest/rules/no-undef-init
159
159
  type noUndefInit struct{}
160
160
 
@@ -0,0 +1,568 @@
1
+ package linthost
2
+
3
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
4
+
5
+ type vitestExpectExpect struct{}
6
+ type vitestNoConditionalExpect struct{}
7
+ type vitestNoConditionalTests struct{}
8
+ type vitestNoDisabledTests struct{}
9
+ type vitestNoDoneCallback struct{}
10
+ type vitestNoFocusedTests struct{}
11
+ type vitestNoIdenticalTitle struct{}
12
+ type vitestNoStandaloneExpect struct{}
13
+ type vitestNoTestReturnStatement struct{}
14
+ type vitestPreferToHaveLength struct{}
15
+ type vitestValidDescribeCallback struct{}
16
+ type vitestValidExpect struct{}
17
+ type vitestValidTitle struct{}
18
+
19
+ func (vitestExpectExpect) Name() string { return "vitest/expect-expect" }
20
+ func (vitestExpectExpect) Visits() []shimast.Kind {
21
+ return []shimast.Kind{shimast.KindCallExpression}
22
+ }
23
+ func (vitestExpectExpect) Check(ctx *Context, node *shimast.Node) {
24
+ call := node.AsCallExpression()
25
+ if call == nil || vitestIsNestedCalleeCallNode(node) || !vitestIsTestCall(call) {
26
+ return
27
+ }
28
+ body := vitestCallbackBody(call)
29
+ if body == nil || vitestBodyHasAssertion(body) {
30
+ return
31
+ }
32
+ ctx.Report(node, "Test has no expectation.")
33
+ }
34
+
35
+ func (vitestNoConditionalExpect) Name() string { return "vitest/no-conditional-expect" }
36
+ func (vitestNoConditionalExpect) Visits() []shimast.Kind {
37
+ return []shimast.Kind{shimast.KindCallExpression}
38
+ }
39
+ func (vitestNoConditionalExpect) Check(ctx *Context, node *shimast.Node) {
40
+ call := node.AsCallExpression()
41
+ if call == nil || !vitestIsExpectCall(call) || !vitestIsInsideTestFunction(node) {
42
+ return
43
+ }
44
+ if vitestHasConditionalAncestorBeforeTest(node) {
45
+ ctx.Report(node, "Avoid calling expect conditionally.")
46
+ }
47
+ }
48
+
49
+ func (vitestNoConditionalTests) Name() string { return "vitest/no-conditional-tests" }
50
+ func (vitestNoConditionalTests) Visits() []shimast.Kind {
51
+ return []shimast.Kind{shimast.KindCallExpression}
52
+ }
53
+ func (vitestNoConditionalTests) Check(ctx *Context, node *shimast.Node) {
54
+ call := node.AsCallExpression()
55
+ if call == nil || vitestIsNestedCalleeCallNode(node) || !vitestIsAnyTestLikeCall(call) {
56
+ return
57
+ }
58
+ if vitestHasConditionalAncestorBeforeFunction(node) {
59
+ ctx.Report(node, "Do not declare Vitest tests conditionally.")
60
+ }
61
+ }
62
+
63
+ func (vitestNoDisabledTests) Name() string { return "vitest/no-disabled-tests" }
64
+ func (vitestNoDisabledTests) Visits() []shimast.Kind {
65
+ return []shimast.Kind{shimast.KindCallExpression}
66
+ }
67
+ func (vitestNoDisabledTests) Check(ctx *Context, node *shimast.Node) {
68
+ call := node.AsCallExpression()
69
+ if vitestIsNestedCalleeCallNode(node) {
70
+ return
71
+ }
72
+ info := vitestCallInfoOf(call)
73
+ if !info.testLike {
74
+ return
75
+ }
76
+ if info.has("skip") || info.has("todo") || info.root == "xit" || info.root == "xtest" || info.root == "xdescribe" {
77
+ ctx.Report(node, "Disabled Vitest test.")
78
+ }
79
+ }
80
+
81
+ func (vitestNoDoneCallback) Name() string { return "vitest/no-done-callback" }
82
+ func (vitestNoDoneCallback) Visits() []shimast.Kind {
83
+ return []shimast.Kind{shimast.KindCallExpression}
84
+ }
85
+ func (vitestNoDoneCallback) Check(ctx *Context, node *shimast.Node) {
86
+ call := node.AsCallExpression()
87
+ if call == nil || vitestIsNestedCalleeCallNode(node) || !vitestIsRunnableCall(call) {
88
+ return
89
+ }
90
+ fn := vitestCallbackFunction(call)
91
+ if fn == nil || len(fn.Parameters()) == 0 {
92
+ return
93
+ }
94
+ ctx.Report(fn.Parameters()[0], "Do not use done callbacks in Vitest tests or hooks.")
95
+ }
96
+
97
+ func (vitestNoFocusedTests) Name() string { return "vitest/no-focused-tests" }
98
+ func (vitestNoFocusedTests) Visits() []shimast.Kind {
99
+ return []shimast.Kind{shimast.KindCallExpression}
100
+ }
101
+ func (vitestNoFocusedTests) Check(ctx *Context, node *shimast.Node) {
102
+ call := node.AsCallExpression()
103
+ if vitestIsNestedCalleeCallNode(node) {
104
+ return
105
+ }
106
+ info := vitestCallInfoOf(call)
107
+ if !info.testLike {
108
+ return
109
+ }
110
+ if info.has("only") || info.root == "fit" || info.root == "fdescribe" {
111
+ ctx.Report(node, "Unexpected focused Vitest test.")
112
+ }
113
+ }
114
+
115
+ func (vitestNoIdenticalTitle) Name() string { return "vitest/no-identical-title" }
116
+ func (vitestNoIdenticalTitle) Visits() []shimast.Kind {
117
+ return []shimast.Kind{shimast.KindSourceFile}
118
+ }
119
+ func (vitestNoIdenticalTitle) Check(ctx *Context, node *shimast.Node) {
120
+ vitestCheckDuplicateTitlesInScope(ctx, node, map[string]*shimast.Node{})
121
+ }
122
+
123
+ func (vitestNoStandaloneExpect) Name() string { return "vitest/no-standalone-expect" }
124
+ func (vitestNoStandaloneExpect) Visits() []shimast.Kind {
125
+ return []shimast.Kind{shimast.KindCallExpression}
126
+ }
127
+ func (vitestNoStandaloneExpect) Check(ctx *Context, node *shimast.Node) {
128
+ call := node.AsCallExpression()
129
+ if call == nil || !vitestIsExpectCall(call) {
130
+ return
131
+ }
132
+ if !vitestIsInsideRunnableFunction(node) {
133
+ ctx.Report(node, "Expect must be inside a Vitest test or hook.")
134
+ }
135
+ }
136
+
137
+ func (vitestNoTestReturnStatement) Name() string { return "vitest/no-test-return-statement" }
138
+ func (vitestNoTestReturnStatement) Visits() []shimast.Kind {
139
+ return []shimast.Kind{shimast.KindReturnStatement}
140
+ }
141
+ func (vitestNoTestReturnStatement) Check(ctx *Context, node *shimast.Node) {
142
+ if vitestIsInsideTestFunction(node) {
143
+ ctx.Report(node, "Do not return from Vitest tests.")
144
+ }
145
+ }
146
+
147
+ func (vitestPreferToHaveLength) Name() string { return "vitest/prefer-to-have-length" }
148
+ func (vitestPreferToHaveLength) Visits() []shimast.Kind {
149
+ return []shimast.Kind{shimast.KindCallExpression}
150
+ }
151
+ func (vitestPreferToHaveLength) Check(ctx *Context, node *shimast.Node) {
152
+ call := node.AsCallExpression()
153
+ if call == nil || call.Expression == nil || call.Expression.Kind != shimast.KindPropertyAccessExpression {
154
+ return
155
+ }
156
+ access := call.Expression.AsPropertyAccessExpression()
157
+ if access == nil {
158
+ return
159
+ }
160
+ switch identifierText(access.Name()) {
161
+ case "toBe", "toEqual", "toStrictEqual":
162
+ default:
163
+ return
164
+ }
165
+ receiver := stripParens(access.Expression)
166
+ expectCall := vitestExpectCallFromMatcherReceiver(receiver)
167
+ if expectCall == nil || expectCall.Arguments == nil || len(expectCall.Arguments.Nodes) != 1 {
168
+ return
169
+ }
170
+ arg := stripParens(expectCall.Arguments.Nodes[0])
171
+ if arg == nil || arg.Kind != shimast.KindPropertyAccessExpression {
172
+ return
173
+ }
174
+ prop := arg.AsPropertyAccessExpression()
175
+ if prop != nil && identifierText(prop.Name()) == "length" {
176
+ ctx.Report(node, "Use toHaveLength() instead of asserting on .length.")
177
+ }
178
+ }
179
+
180
+ func (vitestValidDescribeCallback) Name() string { return "vitest/valid-describe-callback" }
181
+ func (vitestValidDescribeCallback) Visits() []shimast.Kind {
182
+ return []shimast.Kind{shimast.KindCallExpression}
183
+ }
184
+ func (vitestValidDescribeCallback) Check(ctx *Context, node *shimast.Node) {
185
+ call := node.AsCallExpression()
186
+ if call == nil || vitestIsNestedCalleeCallNode(node) || !vitestIsDescribeCall(call) {
187
+ return
188
+ }
189
+ fn := vitestCallbackFunction(call)
190
+ if fn == nil {
191
+ ctx.Report(node, "Describe must receive a callback function.")
192
+ return
193
+ }
194
+ if hasAsyncModifier(fn) {
195
+ ctx.Report(fn, "Describe callbacks must not be async.")
196
+ }
197
+ }
198
+
199
+ func (vitestValidExpect) Name() string { return "vitest/valid-expect" }
200
+ func (vitestValidExpect) Visits() []shimast.Kind {
201
+ return []shimast.Kind{shimast.KindCallExpression}
202
+ }
203
+ func (vitestValidExpect) Check(ctx *Context, node *shimast.Node) {
204
+ call := node.AsCallExpression()
205
+ if call == nil || !vitestIsExpectSubjectCall(call) {
206
+ return
207
+ }
208
+ if call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
209
+ ctx.Report(node, "Expect requires an argument.")
210
+ return
211
+ }
212
+ if !vitestExpectCallHasMatcher(node) {
213
+ ctx.Report(node, "Expect must be followed by a matcher call.")
214
+ }
215
+ }
216
+
217
+ func (vitestValidTitle) Name() string { return "vitest/valid-title" }
218
+ func (vitestValidTitle) Visits() []shimast.Kind {
219
+ return []shimast.Kind{shimast.KindCallExpression}
220
+ }
221
+ func (vitestValidTitle) Check(ctx *Context, node *shimast.Node) {
222
+ call := node.AsCallExpression()
223
+ if call == nil || vitestIsNestedCalleeCallNode(node) || !vitestIsAnyTestLikeCall(call) {
224
+ return
225
+ }
226
+ title := vitestTitleArg(call)
227
+ if title == nil {
228
+ ctx.Report(node, "Vitest test and describe calls require a title.")
229
+ return
230
+ }
231
+ if vitestStaticTitle(title) == "" {
232
+ ctx.Report(title, "Vitest titles must be non-empty static strings.")
233
+ }
234
+ }
235
+
236
+ type vitestCallInfo struct {
237
+ root string
238
+ mods []string
239
+ testLike bool
240
+ }
241
+
242
+ func (i vitestCallInfo) has(mod string) bool {
243
+ for _, item := range i.mods {
244
+ if item == mod {
245
+ return true
246
+ }
247
+ }
248
+ return false
249
+ }
250
+
251
+ func vitestCallInfoOf(call *shimast.CallExpression) vitestCallInfo {
252
+ if call == nil || call.Expression == nil {
253
+ return vitestCallInfo{}
254
+ }
255
+ root, mods := vitestCalleeRootAndMods(call.Expression)
256
+ info := vitestCallInfo{root: root, mods: mods}
257
+ switch root {
258
+ case "describe", "test", "it", "suite", "fdescribe", "fit", "xdescribe", "xit", "xtest":
259
+ info.testLike = true
260
+ }
261
+ return info
262
+ }
263
+
264
+ func vitestCalleeRootAndMods(node *shimast.Node) (string, []string) {
265
+ node = stripParens(node)
266
+ if node == nil {
267
+ return "", nil
268
+ }
269
+ switch node.Kind {
270
+ case shimast.KindIdentifier:
271
+ return identifierText(node), nil
272
+ case shimast.KindPropertyAccessExpression:
273
+ access := node.AsPropertyAccessExpression()
274
+ if access == nil {
275
+ return "", nil
276
+ }
277
+ root, mods := vitestCalleeRootAndMods(access.Expression)
278
+ if name := identifierText(access.Name()); name != "" {
279
+ mods = append(mods, name)
280
+ }
281
+ return root, mods
282
+ case shimast.KindCallExpression:
283
+ inner := node.AsCallExpression()
284
+ if inner == nil {
285
+ return "", nil
286
+ }
287
+ return vitestCalleeRootAndMods(inner.Expression)
288
+ }
289
+ return "", nil
290
+ }
291
+
292
+ func vitestIsAnyTestLikeCall(call *shimast.CallExpression) bool {
293
+ return vitestCallInfoOf(call).testLike
294
+ }
295
+
296
+ func vitestIsTestCall(call *shimast.CallExpression) bool {
297
+ switch vitestCallInfoOf(call).root {
298
+ case "test", "it", "fit", "xit", "xtest":
299
+ return true
300
+ }
301
+ return false
302
+ }
303
+
304
+ func vitestIsDescribeCall(call *shimast.CallExpression) bool {
305
+ switch vitestCallInfoOf(call).root {
306
+ case "describe", "suite", "fdescribe", "xdescribe":
307
+ return true
308
+ }
309
+ return false
310
+ }
311
+
312
+ func vitestIsHookCall(call *shimast.CallExpression) bool {
313
+ switch vitestCallInfoOf(call).root {
314
+ case "beforeAll", "beforeEach", "afterAll", "afterEach":
315
+ return true
316
+ }
317
+ return false
318
+ }
319
+
320
+ func vitestIsRunnableCall(call *shimast.CallExpression) bool {
321
+ return vitestIsTestCall(call) || vitestIsHookCall(call)
322
+ }
323
+
324
+ func vitestTitleArg(call *shimast.CallExpression) *shimast.Node {
325
+ if call == nil || call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
326
+ return nil
327
+ }
328
+ return call.Arguments.Nodes[0]
329
+ }
330
+
331
+ func vitestCallbackFunction(call *shimast.CallExpression) *shimast.Node {
332
+ if call == nil || call.Arguments == nil {
333
+ return nil
334
+ }
335
+ for i := len(call.Arguments.Nodes) - 1; i >= 0; i-- {
336
+ arg := stripParens(call.Arguments.Nodes[i])
337
+ if arg == nil {
338
+ continue
339
+ }
340
+ switch arg.Kind {
341
+ case shimast.KindArrowFunction, shimast.KindFunctionExpression:
342
+ return arg
343
+ }
344
+ }
345
+ return nil
346
+ }
347
+
348
+ func vitestCallbackBody(call *shimast.CallExpression) *shimast.Node {
349
+ fn := vitestCallbackFunction(call)
350
+ if fn == nil {
351
+ return nil
352
+ }
353
+ return fn.Body()
354
+ }
355
+
356
+ func vitestStaticTitle(node *shimast.Node) string {
357
+ return stringLiteralText(stripParens(node))
358
+ }
359
+
360
+ func vitestIsExpectCall(call *shimast.CallExpression) bool {
361
+ if call == nil || call.Expression == nil {
362
+ return false
363
+ }
364
+ root, mods := vitestCalleeRootAndMods(call.Expression)
365
+ if root == "expect" {
366
+ return len(mods) == 0 || len(mods) == 1 && mods[0] == "soft"
367
+ }
368
+ return root == "expectTypeOf" || root == "assert"
369
+ }
370
+
371
+ func vitestIsExpectSubjectCall(call *shimast.CallExpression) bool {
372
+ if call == nil || call.Expression == nil {
373
+ return false
374
+ }
375
+ root, mods := vitestCalleeRootAndMods(call.Expression)
376
+ if root == "expect" {
377
+ return len(mods) == 0 || len(mods) == 1 && mods[0] == "soft"
378
+ }
379
+ return root == "expectTypeOf"
380
+ }
381
+
382
+ func vitestBodyHasAssertion(body *shimast.Node) bool {
383
+ found := false
384
+ walkDescendants(body, func(child *shimast.Node) {
385
+ if found || child == nil || child.Kind != shimast.KindCallExpression {
386
+ return
387
+ }
388
+ call := child.AsCallExpression()
389
+ if call != nil && vitestIsExpectCall(call) {
390
+ found = true
391
+ }
392
+ })
393
+ return found
394
+ }
395
+
396
+ func vitestIsInsideRunnableFunction(node *shimast.Node) bool {
397
+ return vitestEnclosingRunnableCall(node, true) != nil
398
+ }
399
+
400
+ func vitestIsInsideTestFunction(node *shimast.Node) bool {
401
+ call := vitestEnclosingRunnableCall(node, false)
402
+ return call != nil && vitestIsTestCall(call.AsCallExpression())
403
+ }
404
+
405
+ func vitestEnclosingRunnableCall(node *shimast.Node, allowHooks bool) *shimast.Node {
406
+ for p := node.Parent; p != nil; p = p.Parent {
407
+ if !isFunctionLikeKind(p) {
408
+ continue
409
+ }
410
+ if p.Parent == nil || p.Parent.Kind != shimast.KindCallExpression {
411
+ return nil
412
+ }
413
+ call := p.Parent.AsCallExpression()
414
+ if call == nil {
415
+ return nil
416
+ }
417
+ if vitestIsTestCall(call) || allowHooks && vitestIsHookCall(call) {
418
+ return p.Parent
419
+ }
420
+ return nil
421
+ }
422
+ return nil
423
+ }
424
+
425
+ func vitestHasConditionalAncestorBeforeTest(node *shimast.Node) bool {
426
+ for p := node.Parent; p != nil; p = p.Parent {
427
+ if vitestIsConditionalNode(p) {
428
+ return true
429
+ }
430
+ if isFunctionLikeKind(p) {
431
+ return vitestIsInsideTestFunction(p)
432
+ }
433
+ }
434
+ return false
435
+ }
436
+
437
+ func vitestHasConditionalAncestorBeforeFunction(node *shimast.Node) bool {
438
+ for p := node.Parent; p != nil; p = p.Parent {
439
+ if vitestIsConditionalNode(p) {
440
+ return true
441
+ }
442
+ if isFunctionLikeKind(p) {
443
+ return false
444
+ }
445
+ }
446
+ return false
447
+ }
448
+
449
+ func vitestIsConditionalNode(node *shimast.Node) bool {
450
+ if node == nil {
451
+ return false
452
+ }
453
+ switch node.Kind {
454
+ case shimast.KindIfStatement,
455
+ shimast.KindConditionalExpression,
456
+ shimast.KindSwitchStatement,
457
+ shimast.KindForStatement,
458
+ shimast.KindForInStatement,
459
+ shimast.KindForOfStatement,
460
+ shimast.KindWhileStatement,
461
+ shimast.KindDoStatement:
462
+ return true
463
+ }
464
+ return false
465
+ }
466
+
467
+ func vitestExpectCallHasMatcher(expectNode *shimast.Node) bool {
468
+ for p := expectNode.Parent; p != nil; p = p.Parent {
469
+ if p.Kind == shimast.KindCallExpression {
470
+ return p != expectNode
471
+ }
472
+ if p.Kind != shimast.KindPropertyAccessExpression {
473
+ return false
474
+ }
475
+ access := p.AsPropertyAccessExpression()
476
+ if access == nil {
477
+ return false
478
+ }
479
+ switch identifierText(access.Name()) {
480
+ case "not", "resolves", "rejects":
481
+ continue
482
+ default:
483
+ return p.Parent != nil && p.Parent.Kind == shimast.KindCallExpression
484
+ }
485
+ }
486
+ return false
487
+ }
488
+
489
+ func vitestExpectCallFromMatcherReceiver(node *shimast.Node) *shimast.CallExpression {
490
+ node = stripParens(node)
491
+ for node != nil && node.Kind == shimast.KindPropertyAccessExpression {
492
+ access := node.AsPropertyAccessExpression()
493
+ if access == nil {
494
+ return nil
495
+ }
496
+ node = stripParens(access.Expression)
497
+ }
498
+ if node == nil || node.Kind != shimast.KindCallExpression {
499
+ return nil
500
+ }
501
+ call := node.AsCallExpression()
502
+ if vitestIsExpectSubjectCall(call) {
503
+ return call
504
+ }
505
+ return nil
506
+ }
507
+
508
+ func vitestIsNestedCalleeCallNode(node *shimast.Node) bool {
509
+ if node == nil || node.Parent == nil || node.Parent.Kind != shimast.KindCallExpression {
510
+ return false
511
+ }
512
+ parent := node.Parent.AsCallExpression()
513
+ return parent != nil && parent.Expression == node
514
+ }
515
+
516
+ func vitestCheckDuplicateTitlesInScope(ctx *Context, node *shimast.Node, seen map[string]*shimast.Node) {
517
+ if node == nil {
518
+ return
519
+ }
520
+ if node.Kind == shimast.KindCallExpression {
521
+ call := node.AsCallExpression()
522
+ if call != nil && !vitestIsNestedCalleeCallNode(node) && vitestIsAnyTestLikeCall(call) {
523
+ titleNode := vitestTitleArg(call)
524
+ title := vitestStaticTitle(titleNode)
525
+ if title != "" {
526
+ key := vitestTitleKind(call) + "\x00" + title
527
+ if seen[key] != nil {
528
+ ctx.Report(titleNode, "Duplicate Vitest title '"+title+"'.")
529
+ } else {
530
+ seen[key] = titleNode
531
+ }
532
+ }
533
+ if vitestIsDescribeCall(call) {
534
+ if body := vitestCallbackBody(call); body != nil {
535
+ vitestCheckDuplicateTitlesInScope(ctx, body, map[string]*shimast.Node{})
536
+ }
537
+ }
538
+ return
539
+ }
540
+ }
541
+ node.ForEachChild(func(child *shimast.Node) bool {
542
+ vitestCheckDuplicateTitlesInScope(ctx, child, seen)
543
+ return false
544
+ })
545
+ }
546
+
547
+ func vitestTitleKind(call *shimast.CallExpression) string {
548
+ if vitestIsDescribeCall(call) {
549
+ return "describe"
550
+ }
551
+ return "test"
552
+ }
553
+
554
+ func init() {
555
+ Register(vitestExpectExpect{})
556
+ Register(vitestNoConditionalExpect{})
557
+ Register(vitestNoConditionalTests{})
558
+ Register(vitestNoDisabledTests{})
559
+ Register(vitestNoDoneCallback{})
560
+ Register(vitestNoFocusedTests{})
561
+ Register(vitestNoIdenticalTitle{})
562
+ Register(vitestNoStandaloneExpect{})
563
+ Register(vitestNoTestReturnStatement{})
564
+ Register(vitestPreferToHaveLength{})
565
+ Register(vitestValidDescribeCallback{})
566
+ Register(vitestValidExpect{})
567
+ Register(vitestValidTitle{})
568
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/lint",
3
- "version": "0.13.1",
3
+ "version": "0.14.0-dev.20260528.1",
4
4
  "description": "Reference ttsc plugin: ESLint-style lint rules hosted in the same Program/Checker as the type-check pass.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -33,10 +33,10 @@
33
33
  "src"
34
34
  ],
35
35
  "devDependencies": {
36
- "@typescript/native-preview": "7.0.0-dev.20260522.1",
36
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
37
37
  "@types/node": "^25.3.0",
38
38
  "rimraf": "^6.1.2",
39
- "ttsc": "0.13.1"
39
+ "ttsc": "0.14.0-dev.20260528.1"
40
40
  },
41
41
  "repository": {
42
42
  "type": "git",