@ttsc/lint 0.13.0 → 0.14.0-dev.20250530.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (498) hide show
  1. package/README.md +955 -85
  2. package/lib/defaultFormat.d.ts +15 -8
  3. package/lib/defaultFormat.js +15 -8
  4. package/lib/defaultFormat.js.map +1 -1
  5. package/lib/index.d.ts +46 -0
  6. package/lib/index.js +60 -37
  7. package/lib/index.js.map +1 -1
  8. package/lib/structures/ITtscLintConfig.d.ts +12 -6
  9. package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
  10. package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
  11. package/lib/structures/TtscLintRuleSetting.js.map +1 -0
  12. package/lib/structures/format/ITtscLintFormat.d.ts +128 -0
  13. package/lib/structures/{TtscLintRuleMap.js → format/ITtscLintFormat.js} +1 -1
  14. package/lib/structures/format/ITtscLintFormat.js.map +1 -0
  15. package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +17 -0
  16. package/lib/structures/{ITtscLintFormatConfig.js → format/ITtscLintFormatJsDoc.js} +1 -1
  17. package/lib/structures/format/ITtscLintFormatJsDoc.js.map +1 -0
  18. package/lib/structures/format/ITtscLintFormatSortImports.d.ts +54 -0
  19. package/lib/structures/format/ITtscLintFormatSortImports.js +3 -0
  20. package/lib/structures/format/ITtscLintFormatSortImports.js.map +1 -0
  21. package/lib/structures/format/index.d.ts +3 -0
  22. package/lib/structures/format/index.js +20 -0
  23. package/lib/structures/format/index.js.map +1 -0
  24. package/lib/structures/index.d.ts +3 -4
  25. package/lib/structures/index.js +3 -4
  26. package/lib/structures/index.js.map +1 -1
  27. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +95 -0
  28. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +13 -0
  29. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
  30. package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +75 -0
  31. package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
  32. package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
  33. package/lib/structures/rules/ITtscLintContributorRules.d.ts +16 -0
  34. package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
  35. package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
  36. package/lib/structures/rules/ITtscLintCoreRules.d.ts +1229 -0
  37. package/lib/structures/rules/ITtscLintCoreRules.js +3 -0
  38. package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
  39. package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
  40. package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
  41. package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
  42. package/lib/structures/rules/ITtscLintCypressRules.d.ts +125 -0
  43. package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
  44. package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
  45. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +154 -0
  46. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
  47. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
  48. package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +162 -0
  49. package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
  50. package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
  51. package/lib/structures/rules/ITtscLintJestRules.d.ts +190 -0
  52. package/lib/structures/rules/ITtscLintJestRules.js +3 -0
  53. package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
  54. package/lib/structures/rules/ITtscLintJsdocRules.d.ts +133 -0
  55. package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
  56. package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
  57. package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +294 -0
  58. package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
  59. package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
  60. package/lib/structures/rules/ITtscLintNextjsRules.d.ts +180 -0
  61. package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
  62. package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
  63. package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +312 -0
  64. package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
  65. package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
  66. package/lib/structures/rules/ITtscLintPromiseRules.d.ts +179 -0
  67. package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
  68. package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
  69. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
  70. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
  71. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
  72. package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +49 -0
  73. package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
  74. package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
  75. package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +37 -0
  76. package/lib/structures/rules/ITtscLintReactRuleOptions.js +11 -0
  77. package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
  78. package/lib/structures/rules/ITtscLintReactRules.d.ts +276 -0
  79. package/lib/structures/rules/ITtscLintReactRules.js +3 -0
  80. package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
  81. package/lib/structures/rules/ITtscLintRegexpRules.d.ts +182 -0
  82. package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
  83. package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
  84. package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +65 -0
  85. package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
  86. package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
  87. package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
  88. package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
  89. package/lib/structures/rules/ITtscLintRules.js.map +1 -0
  90. package/lib/structures/rules/ITtscLintSecurityRules.d.ts +141 -0
  91. package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
  92. package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
  93. package/lib/structures/rules/ITtscLintSolidRules.d.ts +178 -0
  94. package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
  95. package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
  96. package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +20 -0
  97. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
  98. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
  99. package/lib/structures/rules/ITtscLintStorybookRules.d.ts +165 -0
  100. package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
  101. package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
  102. package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +88 -0
  103. package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
  104. package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
  105. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +21 -0
  106. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
  107. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
  108. package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +293 -0
  109. package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
  110. package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
  111. package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1074 -0
  112. package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
  113. package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
  114. package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
  115. package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
  116. package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
  117. package/lib/structures/rules/ITtscLintVitestRules.d.ts +133 -0
  118. package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
  119. package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
  120. package/lib/structures/rules/index.d.ts +31 -0
  121. package/lib/structures/rules/index.js +48 -0
  122. package/lib/structures/rules/index.js.map +1 -0
  123. package/linthost/ast_helpers.go +30 -5
  124. package/linthost/compile.go +33 -2
  125. package/linthost/config.go +118 -71
  126. package/linthost/config_format.go +270 -104
  127. package/linthost/directives.go +67 -25
  128. package/linthost/dispatch.go +14 -3
  129. package/linthost/engine.go +160 -40
  130. package/linthost/fix.go +10 -3
  131. package/linthost/flags_gen.go +17 -15
  132. package/linthost/format.go +222 -25
  133. package/linthost/format_editor_settings.go +262 -0
  134. package/linthost/host.go +40 -3
  135. package/linthost/lsp.go +898 -0
  136. package/linthost/print_dispatch.go +5 -2
  137. package/linthost/print_engine.go +5 -5
  138. package/linthost/print_nodes_call.go +149 -67
  139. package/linthost/print_nodes_function.go +27 -2
  140. package/linthost/print_nodes_list.go +40 -5
  141. package/linthost/print_nodes_object.go +1 -1
  142. package/linthost/print_nodes_ternary.go +86 -0
  143. package/linthost/rule_names.go +14 -0
  144. package/linthost/rules_arrays.go +2 -2
  145. package/linthost/rules_boundaries.go +532 -0
  146. package/linthost/rules_camelcase.go +133 -0
  147. package/linthost/rules_complexity.go +95 -0
  148. package/linthost/rules_consistent_return.go +130 -0
  149. package/linthost/rules_console.go +1 -1
  150. package/linthost/rules_core_extra.go +739 -0
  151. package/linthost/rules_curly.go +70 -0
  152. package/linthost/rules_cypress.go +608 -0
  153. package/linthost/rules_debugger.go +2 -2
  154. package/linthost/rules_default_case.go +39 -0
  155. package/linthost/rules_default_case_last.go +46 -0
  156. package/linthost/rules_dupes.go +3 -3
  157. package/linthost/rules_empty.go +3 -3
  158. package/linthost/rules_escape.go +44 -24
  159. package/linthost/rules_eval.go +2 -2
  160. package/linthost/rules_finally.go +2 -2
  161. package/linthost/rules_format_arrow_parens.go +167 -0
  162. package/linthost/rules_format_bracket_spacing.go +117 -0
  163. package/linthost/rules_format_clause_join.go +172 -0
  164. package/linthost/rules_format_declaration_header.go +595 -0
  165. package/linthost/rules_format_indent.go +372 -0
  166. package/linthost/rules_format_jsdoc.go +5 -5
  167. package/linthost/rules_format_orphan_semi.go +106 -0
  168. package/linthost/rules_format_parameter_properties.go +175 -0
  169. package/linthost/rules_format_print_width.go +66 -55
  170. package/linthost/rules_format_quote_props.go +169 -0
  171. package/linthost/rules_format_quotes.go +76 -30
  172. package/linthost/rules_format_semi.go +186 -11
  173. package/linthost/rules_format_sort_imports.go +437 -118
  174. package/linthost/rules_format_statement_split.go +343 -0
  175. package/linthost/rules_format_ternary_nullish_parens.go +77 -0
  176. package/linthost/rules_format_trailing_comma.go +22 -3
  177. package/linthost/rules_format_whitespace.go +336 -0
  178. package/linthost/rules_functional.go +967 -0
  179. package/linthost/rules_gap.go +24 -45
  180. package/linthost/rules_grouped_accessor_pairs.go +87 -0
  181. package/linthost/rules_guard_for_in.go +198 -0
  182. package/linthost/rules_id_length.go +77 -0
  183. package/linthost/rules_imports.go +70 -2
  184. package/linthost/rules_init_declarations.go +53 -0
  185. package/linthost/rules_jest.go +618 -0
  186. package/linthost/rules_jsdoc.go +502 -0
  187. package/linthost/rules_jsx_a11y.go +1264 -0
  188. package/linthost/rules_logic.go +12 -12
  189. package/linthost/rules_loops.go +1 -1
  190. package/linthost/rules_max_classes_per_file.go +58 -0
  191. package/linthost/rules_max_depth.go +83 -0
  192. package/linthost/rules_max_lines.go +101 -0
  193. package/linthost/rules_max_lines_per_function.go +57 -0
  194. package/linthost/rules_max_nested_callbacks.go +61 -0
  195. package/linthost/rules_max_params.go +49 -0
  196. package/linthost/rules_max_statements.go +59 -0
  197. package/linthost/rules_misc.go +1 -1
  198. package/linthost/rules_nextjs.go +697 -0
  199. package/linthost/rules_no_else_return.go +75 -0
  200. package/linthost/rules_no_empty_named_blocks.go +91 -0
  201. package/linthost/rules_no_extend_native.go +51 -0
  202. package/linthost/rules_no_import_assign.go +140 -0
  203. package/linthost/rules_no_invalid_this.go +52 -0
  204. package/linthost/rules_no_loop_func.go +85 -0
  205. package/linthost/rules_no_magic_numbers.go +123 -0
  206. package/linthost/rules_no_mixed_operators.go +80 -0
  207. package/linthost/rules_no_param_reassign.go +98 -0
  208. package/linthost/rules_no_redeclare.go +270 -0
  209. package/linthost/rules_no_restricted_imports.go +105 -0
  210. package/linthost/rules_no_restricted_syntax.go +49 -0
  211. package/linthost/rules_no_shadow.go +147 -0
  212. package/linthost/rules_no_unreachable.go +77 -0
  213. package/linthost/rules_no_useless_assignment.go +120 -0
  214. package/linthost/rules_no_useless_constructor.go +245 -0
  215. package/linthost/rules_no_useless_return.go +51 -0
  216. package/linthost/rules_params.go +1 -1
  217. package/linthost/rules_playwright.go +788 -0
  218. package/linthost/rules_prefer_arrow_callback.go +124 -0
  219. package/linthost/rules_prefer_destructuring.go +98 -0
  220. package/linthost/rules_prefer_named_capture_group.go +129 -0
  221. package/linthost/rules_prefer_rest_params.go +94 -0
  222. package/linthost/rules_problems.go +41 -30
  223. package/linthost/rules_promise.go +1057 -2
  224. package/linthost/rules_protos.go +2 -2
  225. package/linthost/rules_react.go +773 -0
  226. package/linthost/rules_react_extras.go +227 -0
  227. package/linthost/rules_react_hooks.go +848 -0
  228. package/linthost/rules_react_perf.go +293 -0
  229. package/linthost/rules_react_refresh.go +583 -0
  230. package/linthost/rules_regexp.go +410 -0
  231. package/linthost/rules_security.go +830 -0
  232. package/linthost/rules_self.go +2 -2
  233. package/linthost/rules_solid.go +1073 -0
  234. package/linthost/rules_sort_imports.go +69 -0
  235. package/linthost/rules_sort_keys.go +134 -0
  236. package/linthost/rules_storybook.go +1176 -0
  237. package/linthost/rules_strings.go +4 -4
  238. package/linthost/rules_suggestions.go +38 -38
  239. package/linthost/rules_tanstack_query.go +844 -0
  240. package/linthost/rules_testing_library.go +1204 -0
  241. package/linthost/rules_throw.go +1 -1
  242. package/linthost/rules_ts.go +19 -19
  243. package/linthost/rules_ts_async.go +399 -0
  244. package/linthost/rules_ts_class_literal_property_style.go +115 -0
  245. package/linthost/rules_ts_consistent_type_exports.go +256 -0
  246. package/linthost/rules_ts_explicit_function_return_type.go +67 -0
  247. package/linthost/rules_ts_extra.go +159 -36
  248. package/linthost/rules_ts_no_base_to_string.go +218 -0
  249. package/linthost/rules_ts_no_confusing_void.go +72 -0
  250. package/linthost/rules_ts_no_deprecated.go +195 -0
  251. package/linthost/rules_ts_no_for_in_array.go +84 -0
  252. package/linthost/rules_ts_no_magic_numbers.go +124 -0
  253. package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
  254. package/linthost/rules_ts_no_misused_spread.go +104 -0
  255. package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
  256. package/linthost/rules_ts_no_restricted_types.go +62 -0
  257. package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
  258. package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
  259. package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
  260. package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
  261. package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
  262. package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
  263. package/linthost/rules_ts_no_unsafe_argument.go +82 -0
  264. package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
  265. package/linthost/rules_ts_no_unsafe_call.go +82 -0
  266. package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
  267. package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
  268. package/linthost/rules_ts_no_unsafe_return.go +126 -0
  269. package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
  270. package/linthost/rules_ts_no_useless_constructor.go +52 -0
  271. package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
  272. package/linthost/rules_ts_parameter_properties.go +38 -0
  273. package/linthost/rules_ts_prefer_find.go +178 -0
  274. package/linthost/rules_ts_prefer_includes.go +255 -0
  275. package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
  276. package/linthost/rules_ts_prefer_optional_chain.go +228 -0
  277. package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
  278. package/linthost/rules_ts_prefer_readonly.go +73 -0
  279. package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
  280. package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
  281. package/linthost/rules_ts_prefer_return_this_type.go +135 -0
  282. package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
  283. package/linthost/rules_ts_promise_function_async.go +77 -0
  284. package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
  285. package/linthost/rules_ts_require_array_sort_compare.go +96 -0
  286. package/linthost/rules_ts_restrict_plus_operands.go +127 -0
  287. package/linthost/rules_ts_restrict_template_expressions.go +95 -0
  288. package/linthost/rules_ts_simple.go +387 -0
  289. package/linthost/rules_ts_sort_type_constituents.go +144 -0
  290. package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
  291. package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
  292. package/linthost/rules_ts_unbound_method.go +126 -0
  293. package/linthost/rules_tsdoc.go +136 -0
  294. package/linthost/rules_unicorn_better_regex.go +27 -0
  295. package/linthost/rules_unicorn_catch_error_name.go +46 -0
  296. package/linthost/rules_unicorn_consistent_assert.go +47 -0
  297. package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
  298. package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
  299. package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
  300. package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
  301. package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
  302. package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
  303. package/linthost/rules_unicorn_custom_error_definition.go +138 -0
  304. package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
  305. package/linthost/rules_unicorn_error_message.go +64 -0
  306. package/linthost/rules_unicorn_escape_case.go +51 -0
  307. package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
  308. package/linthost/rules_unicorn_explicit_length_check.go +88 -0
  309. package/linthost/rules_unicorn_filename_case.go +29 -0
  310. package/linthost/rules_unicorn_import_style.go +28 -0
  311. package/linthost/rules_unicorn_isolated_functions.go +29 -0
  312. package/linthost/rules_unicorn_new_for_builtins.go +87 -0
  313. package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
  314. package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
  315. package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
  316. package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
  317. package/linthost/rules_unicorn_no_array_for_each.go +40 -0
  318. package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
  319. package/linthost/rules_unicorn_no_array_reduce.go +41 -0
  320. package/linthost/rules_unicorn_no_array_reverse.go +44 -0
  321. package/linthost/rules_unicorn_no_array_sort.go +43 -0
  322. package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
  323. package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
  324. package/linthost/rules_unicorn_no_console_spaces.go +61 -0
  325. package/linthost/rules_unicorn_no_document_cookie.go +41 -0
  326. package/linthost/rules_unicorn_no_empty_file.go +44 -0
  327. package/linthost/rules_unicorn_no_for_loop.go +102 -0
  328. package/linthost/rules_unicorn_no_hex_escape.go +42 -0
  329. package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
  330. package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
  331. package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
  332. package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
  333. package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
  334. package/linthost/rules_unicorn_no_lonely_if.go +44 -0
  335. package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
  336. package/linthost/rules_unicorn_no_named_default.go +54 -0
  337. package/linthost/rules_unicorn_no_negated_condition.go +85 -0
  338. package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
  339. package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
  340. package/linthost/rules_unicorn_no_new_array.go +30 -0
  341. package/linthost/rules_unicorn_no_new_buffer.go +31 -0
  342. package/linthost/rules_unicorn_no_null.go +24 -0
  343. package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
  344. package/linthost/rules_unicorn_no_process_exit.go +43 -0
  345. package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
  346. package/linthost/rules_unicorn_no_static_only_class.go +56 -0
  347. package/linthost/rules_unicorn_no_thenable.go +74 -0
  348. package/linthost/rules_unicorn_no_this_assignment.go +35 -0
  349. package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
  350. package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
  351. package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
  352. package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
  353. package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
  354. package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
  355. package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
  356. package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
  357. package/linthost/rules_unicorn_no_unused_properties.go +30 -0
  358. package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
  359. package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
  360. package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
  361. package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
  362. package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
  363. package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
  364. package/linthost/rules_unicorn_no_useless_spread.go +67 -0
  365. package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
  366. package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
  367. package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
  368. package/linthost/rules_unicorn_number_literal_case.go +69 -0
  369. package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
  370. package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
  371. package/linthost/rules_unicorn_prefer_array_find.go +51 -0
  372. package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
  373. package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
  374. package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
  375. package/linthost/rules_unicorn_prefer_array_some.go +67 -0
  376. package/linthost/rules_unicorn_prefer_at.go +77 -0
  377. package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
  378. package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
  379. package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
  380. package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
  381. package/linthost/rules_unicorn_prefer_code_point.go +49 -0
  382. package/linthost/rules_unicorn_prefer_date_now.go +78 -0
  383. package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
  384. package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
  385. package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
  386. package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
  387. package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
  388. package/linthost/rules_unicorn_prefer_event_target.go +36 -0
  389. package/linthost/rules_unicorn_prefer_export_from.go +129 -0
  390. package/linthost/rules_unicorn_prefer_global_this.go +127 -0
  391. package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
  392. package/linthost/rules_unicorn_prefer_includes.go +149 -0
  393. package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
  394. package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
  395. package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
  396. package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
  397. package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
  398. package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
  399. package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
  400. package/linthost/rules_unicorn_prefer_module.go +50 -0
  401. package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
  402. package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
  403. package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
  404. package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
  405. package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
  406. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
  407. package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
  408. package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
  409. package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
  410. package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
  411. package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
  412. package/linthost/rules_unicorn_prefer_set_has.go +42 -0
  413. package/linthost/rules_unicorn_prefer_set_size.go +48 -0
  414. package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
  415. package/linthost/rules_unicorn_prefer_single_call.go +96 -0
  416. package/linthost/rules_unicorn_prefer_spread.go +51 -0
  417. package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
  418. package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
  419. package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
  420. package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
  421. package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
  422. package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
  423. package/linthost/rules_unicorn_prefer_switch.go +103 -0
  424. package/linthost/rules_unicorn_prefer_ternary.go +71 -0
  425. package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
  426. package/linthost/rules_unicorn_prefer_type_error.go +127 -0
  427. package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
  428. package/linthost/rules_unicorn_relative_url_style.go +49 -0
  429. package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
  430. package/linthost/rules_unicorn_require_module_attributes.go +54 -0
  431. package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
  432. package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
  433. package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
  434. package/linthost/rules_unicorn_string_content.go +27 -0
  435. package/linthost/rules_unicorn_switch_case_braces.go +42 -0
  436. package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
  437. package/linthost/rules_unicorn_template_indent.go +28 -0
  438. package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
  439. package/linthost/rules_unicorn_throw_new_error.go +61 -0
  440. package/linthost/rules_var.go +10 -4
  441. package/linthost/rules_vitest.go +568 -0
  442. package/package.json +3 -3
  443. package/plugin/main.go +49 -3
  444. package/rule/astutil/astutil.go +10 -3
  445. package/rule/rule.go +12 -10
  446. package/src/defaultFormat.ts +17 -10
  447. package/src/index.ts +65 -43
  448. package/src/structures/ITtscLintConfig.ts +14 -8
  449. package/src/structures/TtscLintRuleSetting.ts +55 -0
  450. package/src/structures/format/ITtscLintFormat.ts +141 -0
  451. package/src/structures/format/ITtscLintFormatJsDoc.ts +18 -0
  452. package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
  453. package/src/structures/format/index.ts +3 -0
  454. package/src/structures/index.ts +3 -4
  455. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +117 -0
  456. package/src/structures/rules/ITtscLintBoundariesRules.ts +91 -0
  457. package/src/structures/rules/ITtscLintContributorRules.ts +20 -0
  458. package/src/structures/rules/ITtscLintCoreRules.ts +1378 -0
  459. package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
  460. package/src/structures/rules/ITtscLintCypressRules.ts +141 -0
  461. package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +200 -0
  462. package/src/structures/rules/ITtscLintFunctionalRules.ts +197 -0
  463. package/src/structures/rules/ITtscLintJestRules.ts +209 -0
  464. package/src/structures/rules/ITtscLintJsdocRules.ts +146 -0
  465. package/src/structures/rules/ITtscLintJsxA11yRules.ts +331 -0
  466. package/src/structures/rules/ITtscLintNextjsRules.ts +201 -0
  467. package/src/structures/rules/ITtscLintPlaywrightRules.ts +343 -0
  468. package/src/structures/rules/ITtscLintPromiseRules.ts +196 -0
  469. package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
  470. package/src/structures/rules/ITtscLintReactPerfRules.ts +53 -0
  471. package/src/structures/rules/ITtscLintReactRuleOptions.ts +41 -0
  472. package/src/structures/rules/ITtscLintReactRules.ts +308 -0
  473. package/src/structures/rules/ITtscLintRegexpRules.ts +204 -0
  474. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -0
  475. package/src/structures/rules/ITtscLintRules.ts +77 -0
  476. package/src/structures/rules/ITtscLintSecurityRules.ts +155 -0
  477. package/src/structures/rules/ITtscLintSolidRules.ts +199 -0
  478. package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +22 -0
  479. package/src/structures/rules/ITtscLintStorybookRules.ts +184 -0
  480. package/src/structures/rules/ITtscLintTanstackQueryRules.ts +96 -0
  481. package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +23 -0
  482. package/src/structures/rules/ITtscLintTestingLibraryRules.ts +325 -0
  483. package/src/structures/rules/ITtscLintTypeScriptRules.ts +1172 -0
  484. package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
  485. package/src/structures/rules/ITtscLintVitestRules.ts +146 -0
  486. package/src/structures/rules/index.ts +31 -0
  487. package/lib/structures/ITtscLintFormatConfig.d.ts +0 -153
  488. package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
  489. package/lib/structures/TtscLintRule.d.ts +0 -17
  490. package/lib/structures/TtscLintRule.js.map +0 -1
  491. package/lib/structures/TtscLintRuleMap.d.ts +0 -46
  492. package/lib/structures/TtscLintRuleMap.js.map +0 -1
  493. package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
  494. package/lib/structures/TtscLintRuleOptions.js.map +0 -1
  495. package/src/structures/ITtscLintFormatConfig.ts +0 -168
  496. package/src/structures/TtscLintRule.ts +0 -160
  497. package/src/structures/TtscLintRuleMap.ts +0 -55
  498. package/src/structures/TtscLintRuleOptions.ts +0 -151
@@ -0,0 +1,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.0",
3
+ "version": "0.14.0-dev.20250530.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.0"
39
+ "ttsc": "0.14.0-dev.20250530.1"
40
40
  },
41
41
  "repository": {
42
42
  "type": "git",
package/plugin/main.go CHANGED
@@ -1,7 +1,7 @@
1
1
  // Command @ttsc/lint is the native backend for the `@ttsc/lint` plugin.
2
2
  //
3
- // The plugin host (ttsc / ttsx) spawns this binary with one of six
4
- // subcommands:
3
+ // The plugin host (ttsc / ttsx) spawns this binary with one of these
4
+ // subcommands (canonical list lives in `linthost/dispatch.go`):
5
5
  //
6
6
  // - `version` / `-v` / `--version` — print the binary banner.
7
7
  // - `check` — typecheck + lint without emit. Failure exit code if any
@@ -13,6 +13,13 @@
13
13
  // - `build` — typecheck + lint, then run the standard tsgo emit pipeline
14
14
  // so JS files land on disk.
15
15
  // - `transform --file=PATH` — single-file emit with the same lint pass.
16
+ // - `lsp-command-ids` — print workspace/executeCommand ids owned by
17
+ // `@ttsc/lint`.
18
+ // - `lsp-code-action-kinds` — print CodeActionKind values offered.
19
+ // - `lsp-diagnostics` — produce LSP diagnostic JSON for one file URI.
20
+ // - `lsp-code-actions` — produce LSP code actions for one file URI.
21
+ // - `lsp-execute-command` — return a WorkspaceEdit for a lint-owned
22
+ // command.
16
23
  //
17
24
  // Diagnostics share the renderer with tsgo's own output, so warnings come
18
25
  // out yellow, errors come out red, and the trailing `Found N errors`
@@ -25,11 +32,50 @@
25
32
  package main
26
33
 
27
34
  import (
35
+ "fmt"
28
36
  "os"
37
+ "runtime"
38
+ "runtime/pprof"
29
39
 
30
40
  "github.com/samchon/ttsc/packages/lint/linthost"
31
41
  )
32
42
 
33
43
  func main() {
34
- os.Exit(linthost.Main(os.Args[1:]))
44
+ // Opt-in CPU profile capture for the lint binary. Set
45
+ // `TTSC_LINT_CPUPROFILE=/path/to/out.prof` before running `ttsc check`
46
+ // to record where the in-process lint engine spends time on a real
47
+ // project. The file is flushed before the process exits; the binary's
48
+ // exit code is unchanged. NOTE: `os.Exit` skips deferred calls, so the
49
+ // profile must be stopped explicitly before exit — `defer
50
+ // pprof.StopCPUProfile()` would silently produce a zero-byte file.
51
+ var profileFile *os.File
52
+ if path := os.Getenv("TTSC_LINT_CPUPROFILE"); path != "" {
53
+ f, err := os.Create(path)
54
+ if err != nil {
55
+ fmt.Fprintf(os.Stderr, "@ttsc/lint: cannot create cpuprofile %q: %v\n", path, err)
56
+ } else if err := pprof.StartCPUProfile(f); err != nil {
57
+ fmt.Fprintf(os.Stderr, "@ttsc/lint: pprof.StartCPUProfile: %v\n", err)
58
+ f.Close()
59
+ } else {
60
+ profileFile = f
61
+ }
62
+ }
63
+ code := linthost.Main(os.Args[1:])
64
+ if profileFile != nil {
65
+ pprof.StopCPUProfile()
66
+ profileFile.Close()
67
+ }
68
+ if path := os.Getenv("TTSC_LINT_MEMPROFILE"); path != "" {
69
+ f, err := os.Create(path)
70
+ if err != nil {
71
+ fmt.Fprintf(os.Stderr, "@ttsc/lint: cannot create memprofile %q: %v\n", path, err)
72
+ } else {
73
+ runtime.GC()
74
+ if err := pprof.WriteHeapProfile(f); err != nil {
75
+ fmt.Fprintf(os.Stderr, "@ttsc/lint: pprof.WriteHeapProfile: %v\n", err)
76
+ }
77
+ f.Close()
78
+ }
79
+ }
80
+ os.Exit(code)
35
81
  }
@@ -19,10 +19,17 @@ import (
19
19
  )
20
20
 
21
21
  // NodeText returns the source text under `node` with leading trivia
22
- // (whitespace + comments) stripped. Mirrors `nodeText` in the built-in
22
+ // (whitespace + comments) stripped AND trailing ASCII whitespace
23
+ // (` `, `\t`, `\r`, `\n`) trimmed. Mirrors `nodeText` in the built-in
23
24
  // engine — useful for rules that compare textual identity (the
24
- // `no-self-assign` / `no-self-compare` shape) or that splice a sub-node's
25
- // text into a fix string.
25
+ // `no-self-assign` / `no-self-compare` shape) or that splice a
26
+ // sub-node's text into a fix string.
27
+ //
28
+ // The trailing trim is deliberate so callers using the returned text
29
+ // as the right-hand side of a `TextEdit{End: ...}` splice don't drag
30
+ // in a node's trailing newline. Callers that need the literal byte
31
+ // range without trimming should call `TokenRange` and read `file.Text()`
32
+ // directly.
26
33
  //
27
34
  // Returns "" when `file` or `node` is nil, or when the computed range
28
35
  // falls outside the file (defensive — shouldn't happen for engine-supplied