@ttsc/lint 0.13.0 → 0.14.0-dev.20260528

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 (467) 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 +60 -37
  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/compile.go +33 -2
  116. package/linthost/config.go +48 -17
  117. package/linthost/config_format.go +9 -9
  118. package/linthost/directives.go +67 -25
  119. package/linthost/dispatch.go +14 -3
  120. package/linthost/engine.go +160 -40
  121. package/linthost/fix.go +2 -2
  122. package/linthost/flags_gen.go +17 -15
  123. package/linthost/host.go +40 -3
  124. package/linthost/lsp.go +747 -0
  125. package/linthost/print_dispatch.go +2 -2
  126. package/linthost/print_nodes_function.go +2 -2
  127. package/linthost/print_nodes_object.go +1 -1
  128. package/linthost/rule_names.go +14 -0
  129. package/linthost/rules_arrays.go +2 -2
  130. package/linthost/rules_boundaries.go +532 -0
  131. package/linthost/rules_camelcase.go +133 -0
  132. package/linthost/rules_complexity.go +94 -0
  133. package/linthost/rules_consistent_return.go +130 -0
  134. package/linthost/rules_console.go +1 -1
  135. package/linthost/rules_core_extra.go +739 -0
  136. package/linthost/rules_curly.go +70 -0
  137. package/linthost/rules_cypress.go +608 -0
  138. package/linthost/rules_debugger.go +2 -2
  139. package/linthost/rules_default_case.go +39 -0
  140. package/linthost/rules_default_case_last.go +46 -0
  141. package/linthost/rules_dupes.go +3 -3
  142. package/linthost/rules_empty.go +3 -3
  143. package/linthost/rules_escape.go +44 -24
  144. package/linthost/rules_eval.go +2 -2
  145. package/linthost/rules_finally.go +2 -2
  146. package/linthost/rules_format_jsdoc.go +1 -1
  147. package/linthost/rules_format_print_width.go +9 -9
  148. package/linthost/rules_format_quotes.go +1 -1
  149. package/linthost/rules_format_semi.go +1 -1
  150. package/linthost/rules_format_sort_imports.go +1 -1
  151. package/linthost/rules_format_trailing_comma.go +1 -1
  152. package/linthost/rules_functional.go +967 -0
  153. package/linthost/rules_gap.go +24 -45
  154. package/linthost/rules_grouped_accessor_pairs.go +87 -0
  155. package/linthost/rules_guard_for_in.go +198 -0
  156. package/linthost/rules_id_length.go +77 -0
  157. package/linthost/rules_imports.go +70 -2
  158. package/linthost/rules_init_declarations.go +53 -0
  159. package/linthost/rules_jest.go +618 -0
  160. package/linthost/rules_jsdoc.go +502 -0
  161. package/linthost/rules_jsx_a11y.go +1264 -0
  162. package/linthost/rules_logic.go +12 -12
  163. package/linthost/rules_loops.go +1 -1
  164. package/linthost/rules_max_classes_per_file.go +58 -0
  165. package/linthost/rules_max_depth.go +83 -0
  166. package/linthost/rules_max_lines.go +101 -0
  167. package/linthost/rules_max_lines_per_function.go +57 -0
  168. package/linthost/rules_max_nested_callbacks.go +61 -0
  169. package/linthost/rules_max_params.go +49 -0
  170. package/linthost/rules_max_statements.go +59 -0
  171. package/linthost/rules_misc.go +1 -1
  172. package/linthost/rules_nextjs.go +697 -0
  173. package/linthost/rules_no_else_return.go +75 -0
  174. package/linthost/rules_no_empty_named_blocks.go +91 -0
  175. package/linthost/rules_no_extend_native.go +51 -0
  176. package/linthost/rules_no_import_assign.go +140 -0
  177. package/linthost/rules_no_invalid_this.go +52 -0
  178. package/linthost/rules_no_loop_func.go +85 -0
  179. package/linthost/rules_no_magic_numbers.go +123 -0
  180. package/linthost/rules_no_mixed_operators.go +80 -0
  181. package/linthost/rules_no_param_reassign.go +98 -0
  182. package/linthost/rules_no_redeclare.go +270 -0
  183. package/linthost/rules_no_restricted_imports.go +105 -0
  184. package/linthost/rules_no_restricted_syntax.go +49 -0
  185. package/linthost/rules_no_shadow.go +147 -0
  186. package/linthost/rules_no_unreachable.go +77 -0
  187. package/linthost/rules_no_useless_assignment.go +120 -0
  188. package/linthost/rules_no_useless_constructor.go +245 -0
  189. package/linthost/rules_no_useless_return.go +51 -0
  190. package/linthost/rules_params.go +1 -1
  191. package/linthost/rules_playwright.go +788 -0
  192. package/linthost/rules_prefer_arrow_callback.go +124 -0
  193. package/linthost/rules_prefer_destructuring.go +98 -0
  194. package/linthost/rules_prefer_named_capture_group.go +129 -0
  195. package/linthost/rules_prefer_rest_params.go +94 -0
  196. package/linthost/rules_problems.go +41 -30
  197. package/linthost/rules_promise.go +1128 -73
  198. package/linthost/rules_protos.go +2 -2
  199. package/linthost/rules_react.go +773 -0
  200. package/linthost/rules_react_extras.go +227 -0
  201. package/linthost/rules_react_hooks.go +848 -0
  202. package/linthost/rules_react_perf.go +293 -0
  203. package/linthost/rules_react_refresh.go +583 -0
  204. package/linthost/rules_regexp.go +410 -0
  205. package/linthost/rules_security.go +830 -0
  206. package/linthost/rules_self.go +2 -2
  207. package/linthost/rules_solid.go +1073 -0
  208. package/linthost/rules_sort_imports.go +69 -0
  209. package/linthost/rules_sort_keys.go +134 -0
  210. package/linthost/rules_storybook.go +1176 -0
  211. package/linthost/rules_strings.go +4 -4
  212. package/linthost/rules_suggestions.go +38 -38
  213. package/linthost/rules_tanstack_query.go +844 -0
  214. package/linthost/rules_testing_library.go +1204 -0
  215. package/linthost/rules_throw.go +1 -1
  216. package/linthost/rules_ts.go +19 -19
  217. package/linthost/rules_ts_async.go +399 -0
  218. package/linthost/rules_ts_class_literal_property_style.go +115 -0
  219. package/linthost/rules_ts_consistent_type_exports.go +256 -0
  220. package/linthost/rules_ts_explicit_function_return_type.go +67 -0
  221. package/linthost/rules_ts_extra.go +155 -36
  222. package/linthost/rules_ts_no_base_to_string.go +218 -0
  223. package/linthost/rules_ts_no_confusing_void.go +72 -0
  224. package/linthost/rules_ts_no_deprecated.go +195 -0
  225. package/linthost/rules_ts_no_for_in_array.go +84 -0
  226. package/linthost/rules_ts_no_magic_numbers.go +124 -0
  227. package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
  228. package/linthost/rules_ts_no_misused_spread.go +104 -0
  229. package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
  230. package/linthost/rules_ts_no_restricted_types.go +62 -0
  231. package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
  232. package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
  233. package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
  234. package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
  235. package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
  236. package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
  237. package/linthost/rules_ts_no_unsafe_argument.go +82 -0
  238. package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
  239. package/linthost/rules_ts_no_unsafe_call.go +82 -0
  240. package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
  241. package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
  242. package/linthost/rules_ts_no_unsafe_return.go +126 -0
  243. package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
  244. package/linthost/rules_ts_no_useless_constructor.go +52 -0
  245. package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
  246. package/linthost/rules_ts_parameter_properties.go +38 -0
  247. package/linthost/rules_ts_prefer_find.go +178 -0
  248. package/linthost/rules_ts_prefer_includes.go +255 -0
  249. package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
  250. package/linthost/rules_ts_prefer_optional_chain.go +228 -0
  251. package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
  252. package/linthost/rules_ts_prefer_readonly.go +73 -0
  253. package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
  254. package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
  255. package/linthost/rules_ts_prefer_return_this_type.go +135 -0
  256. package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
  257. package/linthost/rules_ts_promise_function_async.go +77 -0
  258. package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
  259. package/linthost/rules_ts_require_array_sort_compare.go +96 -0
  260. package/linthost/rules_ts_restrict_plus_operands.go +127 -0
  261. package/linthost/rules_ts_restrict_template_expressions.go +95 -0
  262. package/linthost/rules_ts_simple.go +387 -0
  263. package/linthost/rules_ts_sort_type_constituents.go +144 -0
  264. package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
  265. package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
  266. package/linthost/rules_ts_unbound_method.go +126 -0
  267. package/linthost/rules_tsdoc.go +136 -0
  268. package/linthost/rules_unicorn_better_regex.go +27 -0
  269. package/linthost/rules_unicorn_catch_error_name.go +46 -0
  270. package/linthost/rules_unicorn_consistent_assert.go +47 -0
  271. package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
  272. package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
  273. package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
  274. package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
  275. package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
  276. package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
  277. package/linthost/rules_unicorn_custom_error_definition.go +138 -0
  278. package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
  279. package/linthost/rules_unicorn_error_message.go +64 -0
  280. package/linthost/rules_unicorn_escape_case.go +51 -0
  281. package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
  282. package/linthost/rules_unicorn_explicit_length_check.go +88 -0
  283. package/linthost/rules_unicorn_filename_case.go +29 -0
  284. package/linthost/rules_unicorn_import_style.go +28 -0
  285. package/linthost/rules_unicorn_isolated_functions.go +29 -0
  286. package/linthost/rules_unicorn_new_for_builtins.go +87 -0
  287. package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
  288. package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
  289. package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
  290. package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
  291. package/linthost/rules_unicorn_no_array_for_each.go +40 -0
  292. package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
  293. package/linthost/rules_unicorn_no_array_reduce.go +41 -0
  294. package/linthost/rules_unicorn_no_array_reverse.go +44 -0
  295. package/linthost/rules_unicorn_no_array_sort.go +43 -0
  296. package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
  297. package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
  298. package/linthost/rules_unicorn_no_console_spaces.go +61 -0
  299. package/linthost/rules_unicorn_no_document_cookie.go +41 -0
  300. package/linthost/rules_unicorn_no_empty_file.go +44 -0
  301. package/linthost/rules_unicorn_no_for_loop.go +102 -0
  302. package/linthost/rules_unicorn_no_hex_escape.go +42 -0
  303. package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
  304. package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
  305. package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
  306. package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
  307. package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
  308. package/linthost/rules_unicorn_no_lonely_if.go +44 -0
  309. package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
  310. package/linthost/rules_unicorn_no_named_default.go +54 -0
  311. package/linthost/rules_unicorn_no_negated_condition.go +85 -0
  312. package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
  313. package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
  314. package/linthost/rules_unicorn_no_new_array.go +30 -0
  315. package/linthost/rules_unicorn_no_new_buffer.go +31 -0
  316. package/linthost/rules_unicorn_no_null.go +24 -0
  317. package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
  318. package/linthost/rules_unicorn_no_process_exit.go +43 -0
  319. package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
  320. package/linthost/rules_unicorn_no_static_only_class.go +56 -0
  321. package/linthost/rules_unicorn_no_thenable.go +74 -0
  322. package/linthost/rules_unicorn_no_this_assignment.go +35 -0
  323. package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
  324. package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
  325. package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
  326. package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
  327. package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
  328. package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
  329. package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
  330. package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
  331. package/linthost/rules_unicorn_no_unused_properties.go +30 -0
  332. package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
  333. package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
  334. package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
  335. package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
  336. package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
  337. package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
  338. package/linthost/rules_unicorn_no_useless_spread.go +67 -0
  339. package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
  340. package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
  341. package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
  342. package/linthost/rules_unicorn_number_literal_case.go +69 -0
  343. package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
  344. package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
  345. package/linthost/rules_unicorn_prefer_array_find.go +51 -0
  346. package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
  347. package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
  348. package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
  349. package/linthost/rules_unicorn_prefer_array_some.go +67 -0
  350. package/linthost/rules_unicorn_prefer_at.go +77 -0
  351. package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
  352. package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
  353. package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
  354. package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
  355. package/linthost/rules_unicorn_prefer_code_point.go +49 -0
  356. package/linthost/rules_unicorn_prefer_date_now.go +78 -0
  357. package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
  358. package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
  359. package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
  360. package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
  361. package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
  362. package/linthost/rules_unicorn_prefer_event_target.go +36 -0
  363. package/linthost/rules_unicorn_prefer_export_from.go +129 -0
  364. package/linthost/rules_unicorn_prefer_global_this.go +127 -0
  365. package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
  366. package/linthost/rules_unicorn_prefer_includes.go +149 -0
  367. package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
  368. package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
  369. package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
  370. package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
  371. package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
  372. package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
  373. package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
  374. package/linthost/rules_unicorn_prefer_module.go +50 -0
  375. package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
  376. package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
  377. package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
  378. package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
  379. package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
  380. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
  381. package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
  382. package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
  383. package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
  384. package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
  385. package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
  386. package/linthost/rules_unicorn_prefer_set_has.go +42 -0
  387. package/linthost/rules_unicorn_prefer_set_size.go +48 -0
  388. package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
  389. package/linthost/rules_unicorn_prefer_single_call.go +96 -0
  390. package/linthost/rules_unicorn_prefer_spread.go +51 -0
  391. package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
  392. package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
  393. package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
  394. package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
  395. package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
  396. package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
  397. package/linthost/rules_unicorn_prefer_switch.go +103 -0
  398. package/linthost/rules_unicorn_prefer_ternary.go +71 -0
  399. package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
  400. package/linthost/rules_unicorn_prefer_type_error.go +127 -0
  401. package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
  402. package/linthost/rules_unicorn_relative_url_style.go +49 -0
  403. package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
  404. package/linthost/rules_unicorn_require_module_attributes.go +54 -0
  405. package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
  406. package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
  407. package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
  408. package/linthost/rules_unicorn_string_content.go +27 -0
  409. package/linthost/rules_unicorn_switch_case_braces.go +42 -0
  410. package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
  411. package/linthost/rules_unicorn_template_indent.go +28 -0
  412. package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
  413. package/linthost/rules_unicorn_throw_new_error.go +61 -0
  414. package/linthost/rules_var.go +10 -4
  415. package/linthost/rules_vitest.go +568 -0
  416. package/package.json +3 -3
  417. package/plugin/main.go +49 -3
  418. package/rule/astutil/astutil.go +10 -3
  419. package/rule/rule.go +12 -10
  420. package/src/defaultFormat.ts +11 -8
  421. package/src/index.ts +65 -43
  422. package/src/structures/ITtscLintConfig.ts +12 -6
  423. package/src/structures/{ITtscLintFormatConfig.ts → ITtscLintFormat.ts} +2 -2
  424. package/src/structures/TtscLintRuleSetting.ts +55 -0
  425. package/src/structures/index.ts +3 -4
  426. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +128 -0
  427. package/src/structures/rules/ITtscLintBoundariesRules.ts +95 -0
  428. package/src/structures/rules/ITtscLintContributorRules.ts +21 -0
  429. package/src/structures/rules/ITtscLintCoreRules.ts +1406 -0
  430. package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
  431. package/src/structures/rules/ITtscLintCypressRules.ts +145 -0
  432. package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +213 -0
  433. package/src/structures/rules/ITtscLintFunctionalRules.ts +202 -0
  434. package/src/structures/rules/ITtscLintJestRules.ts +220 -0
  435. package/src/structures/rules/ITtscLintJsdocRules.ts +153 -0
  436. package/src/structures/rules/ITtscLintJsxA11yRules.ts +339 -0
  437. package/src/structures/rules/ITtscLintNextjsRules.ts +206 -0
  438. package/src/structures/rules/ITtscLintPlaywrightRules.ts +361 -0
  439. package/src/structures/rules/ITtscLintPromiseRules.ts +205 -0
  440. package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
  441. package/src/structures/rules/ITtscLintReactPerfRules.ts +55 -0
  442. package/src/structures/rules/ITtscLintReactRuleOptions.ts +43 -0
  443. package/src/structures/rules/ITtscLintReactRules.ts +321 -0
  444. package/src/structures/rules/ITtscLintRegexpRules.ts +212 -0
  445. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +89 -0
  446. package/src/structures/rules/ITtscLintRules.ts +77 -0
  447. package/src/structures/rules/ITtscLintSecurityRules.ts +162 -0
  448. package/src/structures/rules/ITtscLintSolidRules.ts +202 -0
  449. package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +23 -0
  450. package/src/structures/rules/ITtscLintStorybookRules.ts +193 -0
  451. package/src/structures/rules/ITtscLintTanstackQueryRules.ts +102 -0
  452. package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +24 -0
  453. package/src/structures/rules/ITtscLintTestingLibraryRules.ts +342 -0
  454. package/src/structures/rules/ITtscLintTypeScriptRules.ts +1230 -0
  455. package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
  456. package/src/structures/rules/ITtscLintVitestRules.ts +154 -0
  457. package/src/structures/rules/index.ts +31 -0
  458. package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
  459. package/lib/structures/TtscLintRule.d.ts +0 -17
  460. package/lib/structures/TtscLintRule.js.map +0 -1
  461. package/lib/structures/TtscLintRuleMap.d.ts +0 -46
  462. package/lib/structures/TtscLintRuleMap.js.map +0 -1
  463. package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
  464. package/lib/structures/TtscLintRuleOptions.js.map +0 -1
  465. package/src/structures/TtscLintRule.ts +0 -160
  466. package/src/structures/TtscLintRuleMap.ts +0 -55
  467. package/src/structures/TtscLintRuleOptions.ts +0 -151
@@ -0,0 +1,147 @@
1
+ // switchExhaustivenessCheck reports `switch (e)` statements where the
2
+ // discriminant is a union of literal types or an enum and at least one
3
+ // constituent has no matching `case` clause AND the switch carries no
4
+ // `default` clause. Either covering every member explicitly or adding a
5
+ // `default` arm makes the intent visible and forces the compiler to
6
+ // flag any future addition to the union/enum at every switch site.
7
+ // typescript-eslint strict-type-checked:
8
+ // https://typescript-eslint.io/rules/switch-exhaustiveness-check/
9
+ package linthost
10
+
11
+ import (
12
+ shimast "github.com/microsoft/typescript-go/shim/ast"
13
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
14
+ )
15
+
16
+ // switchExhaustivenessCheck is type-aware: the discriminant is resolved
17
+ // via the Checker, and uncovered members are computed by removing every
18
+ // case-clause expression's type from the union's constituent set. The
19
+ // rule only fires when the discriminant resolves to a union — plain
20
+ // `string` or `number` discriminants are open-ended and outside the
21
+ // rule's scope, matching typescript-eslint's behavior.
22
+ //
23
+ // Identity is established by `*Type` pointer comparison rather than
24
+ // literal value comparison: TypeScript canonicalizes string and number
25
+ // literal types (`stringLiteralTypes` / `numberLiteralTypes` maps inside
26
+ // the checker), so two references to `"a"` resolve to the same `*Type`
27
+ // instance. Enum literal types are likewise canonicalized per enum
28
+ // member, so `case E.A:` and the `E.A` constituent of the discriminant's
29
+ // union share their `*Type` pointer.
30
+ type switchExhaustivenessCheck struct{}
31
+
32
+ func (switchExhaustivenessCheck) Name() string { return "typescript/switch-exhaustiveness-check" }
33
+ func (switchExhaustivenessCheck) NeedsTypeChecker() bool {
34
+ return true
35
+ }
36
+ func (switchExhaustivenessCheck) Visits() []shimast.Kind {
37
+ return []shimast.Kind{shimast.KindSwitchStatement}
38
+ }
39
+ func (switchExhaustivenessCheck) Check(ctx *Context, node *shimast.Node) {
40
+ if ctx.Checker == nil {
41
+ return
42
+ }
43
+ sw := node.AsSwitchStatement()
44
+ if sw == nil || sw.Expression == nil || sw.CaseBlock == nil {
45
+ return
46
+ }
47
+ block := sw.CaseBlock.AsCaseBlock()
48
+ if block == nil || block.Clauses == nil {
49
+ return
50
+ }
51
+ // A `default` clause covers anything not enumerated above, so the
52
+ // rule has nothing to add. typescript-eslint also exits early in
53
+ // this case.
54
+ for _, clause := range block.Clauses.Nodes {
55
+ if clause != nil && clause.Kind == shimast.KindDefaultClause {
56
+ return
57
+ }
58
+ }
59
+ discriminantType := ctx.Checker.GetTypeAtLocation(sw.Expression)
60
+ if discriminantType == nil {
61
+ return
62
+ }
63
+ // Only consider discriminants whose static type is a finite union of
64
+ // literal-like constituents. Plain `string` / `number` / `unknown`
65
+ // are open-ended and never exhaustively coverable.
66
+ members := switchExhaustivenessCheckCollectMembers(discriminantType)
67
+ if len(members) == 0 {
68
+ return
69
+ }
70
+ covered := make(map[*shimchecker.Type]bool, len(members))
71
+ for _, clause := range block.Clauses.Nodes {
72
+ if clause == nil || clause.Kind != shimast.KindCaseClause {
73
+ continue
74
+ }
75
+ caseClause := clause.AsCaseOrDefaultClause()
76
+ if caseClause == nil || caseClause.Expression == nil {
77
+ continue
78
+ }
79
+ caseType := ctx.Checker.GetTypeAtLocation(caseClause.Expression)
80
+ if caseType == nil {
81
+ continue
82
+ }
83
+ covered[caseType] = true
84
+ }
85
+ missing := 0
86
+ for _, member := range members {
87
+ if !covered[member] {
88
+ missing++
89
+ }
90
+ }
91
+ if missing == 0 {
92
+ return
93
+ }
94
+ ctx.Report(node, "Switch is not exhaustive. Cases not matched: add a `case` for every union/enum member, or include a `default` clause.")
95
+ }
96
+
97
+ // switchExhaustivenessCheckCollectMembers returns the finite literal /
98
+ // enum-literal constituents of t when t is a discriminable union, and
99
+ // nil when t is open-ended (plain `string`, `number`, `any`, `unknown`,
100
+ // etc.). A union whose constituents are all literals or enum literals
101
+ // is treated as exhaustively coverable; any non-literal constituent
102
+ // (e.g. `string` mixed into `"a" | "b" | string`) widens the union and
103
+ // disqualifies the whole discriminant.
104
+ func switchExhaustivenessCheckCollectMembers(t *shimchecker.Type) []*shimchecker.Type {
105
+ if t == nil {
106
+ return nil
107
+ }
108
+ flags := t.Flags()
109
+ if flags&shimchecker.TypeFlagsUnion == 0 {
110
+ return nil
111
+ }
112
+ parts := t.Types()
113
+ if len(parts) == 0 {
114
+ return nil
115
+ }
116
+ members := make([]*shimchecker.Type, 0, len(parts))
117
+ for _, part := range parts {
118
+ if part == nil {
119
+ return nil
120
+ }
121
+ if !switchExhaustivenessCheckIsLiteralLike(part) {
122
+ return nil
123
+ }
124
+ members = append(members, part)
125
+ }
126
+ return members
127
+ }
128
+
129
+ // switchExhaustivenessCheckIsLiteralLike reports whether t is a
130
+ // constituent that participates in finite enumeration: a unit type
131
+ // (string/number/bigint/boolean literal), an enum literal, or one of
132
+ // the nullish singletons. The matching set mirrors typescript-eslint's
133
+ // `lib.isTypeFlagSet(constituent, TypeFlags.Literal | ...)` filter.
134
+ func switchExhaustivenessCheckIsLiteralLike(t *shimchecker.Type) bool {
135
+ flags := t.Flags()
136
+ if flags&shimchecker.TypeFlagsLiteral != 0 {
137
+ return true
138
+ }
139
+ if flags&(shimchecker.TypeFlagsUndefined|shimchecker.TypeFlagsNull|shimchecker.TypeFlagsVoid) != 0 {
140
+ return true
141
+ }
142
+ return false
143
+ }
144
+
145
+ func init() {
146
+ Register(switchExhaustivenessCheck{})
147
+ }
@@ -0,0 +1,126 @@
1
+ // unboundMethod reports a property access that names a class instance
2
+ // method but is used as a value instead of being immediately invoked.
3
+ // JavaScript methods are not bound to their receiver — `obj.method`,
4
+ // once extracted, loses the `this` binding the body relies on, so
5
+ // passing it as a callback (`setTimeout(obj.method, 0)`) or aliasing
6
+ // it (`const f = obj.method`) silently breaks at the first `this.x`
7
+ // dereference. typescript-eslint:
8
+ // https://typescript-eslint.io/rules/unbound-method/
9
+ //
10
+ // Type-aware. The Checker resolves the property's symbol; the rule
11
+ // fires when any of the symbol's declarations is a class
12
+ // MethodDeclaration. The conservative baseline skips:
13
+ //
14
+ // - the callee position of a call (`obj.method()` is fine);
15
+ // - the left-hand side of an assignment (`obj.method = fn`);
16
+ // - the operand of `typeof`, `delete`, `instanceof`, and `in`;
17
+ // - tagged-template tag positions;
18
+ // - static methods (the constructor that owns them is stably bound);
19
+ // - methods declared only as MethodSignature on an interface or
20
+ // type literal (those are structural — the runtime value may be a
21
+ // plain function property, and flagging them at every consumer
22
+ // produces too many false positives).
23
+ package linthost
24
+
25
+ import (
26
+ shimast "github.com/microsoft/typescript-go/shim/ast"
27
+ )
28
+
29
+ type unboundMethod struct{}
30
+
31
+ func (unboundMethod) Name() string { return "typescript/unbound-method" }
32
+ func (unboundMethod) NeedsTypeChecker() bool {
33
+ return true
34
+ }
35
+ func (unboundMethod) Visits() []shimast.Kind {
36
+ return []shimast.Kind{shimast.KindPropertyAccessExpression}
37
+ }
38
+ func (unboundMethod) Check(ctx *Context, node *shimast.Node) {
39
+ if ctx.Checker == nil {
40
+ return
41
+ }
42
+ access := node.AsPropertyAccessExpression()
43
+ if access == nil || access.Name() == nil {
44
+ return
45
+ }
46
+ if unboundMethodSafePosition(node) {
47
+ return
48
+ }
49
+ symbol := ctx.Checker.GetSymbolAtLocation(access.Name())
50
+ if symbol == nil {
51
+ return
52
+ }
53
+ if !unboundMethodSymbolIsClassMethod(symbol) {
54
+ return
55
+ }
56
+ ctx.Report(node, "Avoid referencing an unbound method which may cause unintentional scoping of `this`.")
57
+ }
58
+
59
+ // unboundMethodSafePosition reports whether the property access sits in
60
+ // a syntactic position that already discharges the unbound-method risk.
61
+ // The list mirrors typescript-eslint's safe-position whitelist: an
62
+ // immediately-invoked call, an assignment target, a typeof / delete
63
+ // operand, an instanceof / in operand, and a tagged-template tag are
64
+ // all positions where the method reference is consumed in place rather
65
+ // than carried away as a free function value.
66
+ func unboundMethodSafePosition(node *shimast.Node) bool {
67
+ parent := node.Parent
68
+ if parent == nil {
69
+ return false
70
+ }
71
+ switch parent.Kind {
72
+ case shimast.KindCallExpression:
73
+ call := parent.AsCallExpression()
74
+ if call != nil && call.Expression == node {
75
+ return true
76
+ }
77
+ case shimast.KindTaggedTemplateExpression:
78
+ return true
79
+ case shimast.KindBinaryExpression:
80
+ bin := parent.AsBinaryExpression()
81
+ if bin == nil || bin.OperatorToken == nil {
82
+ return false
83
+ }
84
+ switch bin.OperatorToken.Kind {
85
+ case shimast.KindEqualsToken,
86
+ shimast.KindInstanceOfKeyword,
87
+ shimast.KindInKeyword:
88
+ return true
89
+ }
90
+ case shimast.KindTypeOfExpression, shimast.KindDeleteExpression:
91
+ return true
92
+ }
93
+ return false
94
+ }
95
+
96
+ // unboundMethodSymbolIsClassMethod reports whether symbol denotes a
97
+ // non-static class instance method. The rule ignores plain method
98
+ // signatures on interfaces and type literals because those are
99
+ // structural — the runtime value may be a regular function rather
100
+ // than a bound class member, and flagging them at every consumer
101
+ // would produce a high false-positive volume. Static methods slip
102
+ // past this check because they are accessed through the class
103
+ // constructor itself, which is bound for the lifetime of the
104
+ // program.
105
+ func unboundMethodSymbolIsClassMethod(symbol *shimast.Symbol) bool {
106
+ if symbol == nil {
107
+ return false
108
+ }
109
+ for _, decl := range symbol.Declarations {
110
+ if decl == nil {
111
+ continue
112
+ }
113
+ if decl.Kind != shimast.KindMethodDeclaration {
114
+ continue
115
+ }
116
+ if hasModifier(decl, shimast.KindStaticKeyword) {
117
+ continue
118
+ }
119
+ return true
120
+ }
121
+ return false
122
+ }
123
+
124
+ func init() {
125
+ Register(unboundMethod{})
126
+ }
@@ -0,0 +1,136 @@
1
+ package linthost
2
+
3
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
4
+
5
+ // tsdocSyntax validates a conservative subset of eslint-plugin-tsdoc's
6
+ // `tsdoc/syntax` rule. It intentionally starts with structural diagnostics
7
+ // that can be checked from source text alone: malformed top-level block tags
8
+ // and malformed or unclosed inline tags.
9
+ type tsdocSyntax struct{}
10
+
11
+ func (tsdocSyntax) Name() string { return "jsdoc/tsdoc-syntax" }
12
+ func (tsdocSyntax) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
13
+
14
+ func (tsdocSyntax) Check(ctx *Context, node *shimast.Node) {
15
+ if ctx == nil || ctx.File == nil {
16
+ return
17
+ }
18
+ src := ctx.File.Text()
19
+ for _, block := range findJSDocBlocks(src) {
20
+ checkTSDocBlockTags(ctx, src, block)
21
+ checkTSDocInlineTags(ctx, src, block)
22
+ }
23
+ }
24
+
25
+ func checkTSDocBlockTags(ctx *Context, src string, block jsdocBlock) {
26
+ walkJSDocLines(src, block, func(contentStart, lineEnd int, inFence bool) {
27
+ if inFence || contentStart >= lineEnd || src[contentStart] != '@' {
28
+ return
29
+ }
30
+ tagStart := contentStart + 1
31
+ if tagStart >= lineEnd || !isTSDocTagStart(src[tagStart]) {
32
+ ctx.ReportRange(contentStart, minInt(lineEnd, contentStart+2), "Malformed TSDoc block tag.")
33
+ }
34
+ })
35
+ }
36
+
37
+ func checkTSDocInlineTags(ctx *Context, src string, block jsdocBlock) {
38
+ walkJSDocLines(src, block, func(contentStart, lineEnd int, inFence bool) {
39
+ if inFence {
40
+ return
41
+ }
42
+ for i := contentStart; i+1 < lineEnd; i++ {
43
+ if src[i] != '{' || src[i+1] != '@' {
44
+ continue
45
+ }
46
+ tagStart := i + 2
47
+ if tagStart >= lineEnd || !isTSDocTagStart(src[tagStart]) {
48
+ ctx.ReportRange(i, minInt(lineEnd, i+2), "Malformed TSDoc inline tag.")
49
+ continue
50
+ }
51
+ tagEnd := tagStart + 1
52
+ for tagEnd < lineEnd && isTSDocTagContinue(src[tagEnd]) {
53
+ tagEnd++
54
+ }
55
+ close := findByteInRange(src, '}', tagEnd, block.bodyEnd)
56
+ if close < 0 {
57
+ ctx.ReportRange(i, tagEnd, "Unclosed TSDoc inline tag.")
58
+ i = tagEnd - 1
59
+ continue
60
+ }
61
+ i = close
62
+ }
63
+ })
64
+ }
65
+
66
+ func walkJSDocLines(src string, block jsdocBlock, visit func(contentStart, lineEnd int, inFence bool)) {
67
+ inFence := false
68
+ for lineStart := block.bodyStart; lineStart < block.bodyEnd; {
69
+ lineEnd := lineStart
70
+ for lineEnd < block.bodyEnd && src[lineEnd] != '\n' {
71
+ lineEnd++
72
+ }
73
+ contentStart := tsdocLineContentStart(src, lineStart, lineEnd)
74
+ visit(contentStart, trimLineEnd(src, lineEnd), inFence)
75
+ if startsWithFenceMarker(src, contentStart, trimLineEnd(src, lineEnd)) {
76
+ inFence = !inFence
77
+ }
78
+ if lineEnd >= block.bodyEnd {
79
+ break
80
+ }
81
+ lineStart = lineEnd + 1
82
+ }
83
+ }
84
+
85
+ func tsdocLineContentStart(src string, lineStart, lineEnd int) int {
86
+ i := lineStart
87
+ for i < lineEnd && (src[i] == ' ' || src[i] == '\t' || src[i] == '\r') {
88
+ i++
89
+ }
90
+ if i < lineEnd && src[i] == '*' {
91
+ i++
92
+ if i < lineEnd && src[i] == ' ' {
93
+ i++
94
+ }
95
+ }
96
+ return i
97
+ }
98
+
99
+ func trimLineEnd(src string, lineEnd int) int {
100
+ for lineEnd > 0 && src[lineEnd-1] == '\r' {
101
+ lineEnd--
102
+ }
103
+ return lineEnd
104
+ }
105
+
106
+ func startsWithFenceMarker(src string, start, end int) bool {
107
+ return end-start >= 3 && src[start] == '`' && src[start+1] == '`' && src[start+2] == '`'
108
+ }
109
+
110
+ func findByteInRange(src string, target byte, start, end int) int {
111
+ for i := start; i < end; i++ {
112
+ if src[i] == target {
113
+ return i
114
+ }
115
+ }
116
+ return -1
117
+ }
118
+
119
+ func isTSDocTagStart(b byte) bool {
120
+ return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')
121
+ }
122
+
123
+ func isTSDocTagContinue(b byte) bool {
124
+ return isTSDocTagStart(b) || (b >= '0' && b <= '9') || b == '-'
125
+ }
126
+
127
+ func minInt(a, b int) int {
128
+ if a < b {
129
+ return a
130
+ }
131
+ return b
132
+ }
133
+
134
+ func init() {
135
+ Register(tsdocSyntax{})
136
+ }
@@ -0,0 +1,27 @@
1
+ // unicorn/better-regex: the upstream rule rewrites regex literals into
2
+ // the shortest equivalent form (e.g. `[0-9]` -> `\d`, `[^\W\D]` -> `\d`,
3
+ // dedupes character classes, collapses redundant quantifiers). That
4
+ // rewrite requires a full regex parser with character-class semantics —
5
+ // far beyond the AST-only scope of this slice — so the rule is
6
+ // registered as a no-op stub to keep `TestTypedKeysMatchRegisteredRules`
7
+ // honest with the typed `ITtscLintUnicornRules` surface.
8
+ //
9
+ // Replace this stub with a real implementation when a regex AST helper
10
+ // lands; the matching fixture under
11
+ // `tests/test-lint/src/cases/unicorn-better-regex.ts` carries the
12
+ // `@ttsc-corpus-skip` directive so the corpus test suite walks past it.
13
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/better-regex.md
14
+ package linthost
15
+
16
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
17
+
18
+ type unicornBetterRegex struct{}
19
+
20
+ func (unicornBetterRegex) Name() string { return "unicorn/better-regex" }
21
+ func (unicornBetterRegex) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindSourceFile} }
22
+ func (unicornBetterRegex) Check(_ *Context, _ *shimast.Node) {
23
+ }
24
+
25
+ func init() {
26
+ Register(unicornBetterRegex{})
27
+ }
@@ -0,0 +1,46 @@
1
+ // unicorn/catch-error-name: a `catch (err)` clause whose binding is
2
+ // anything other than `error` violates the project convention. The
3
+ // stylistic point is that readers should see `catch (error)` and
4
+ // immediately know the binding is the thrown value — bespoke names
5
+ // like `e`, `err`, or `exception` create one-character variance for
6
+ // no semantic gain.
7
+ //
8
+ // AST-only: visit each `CatchClause`, skip clauses with no binding
9
+ // (optional catch-binding) and clauses whose binding is a destructuring
10
+ // pattern (out of scope — the rule cannot rename a pattern in place).
11
+ // When the binding identifier text is not `error`, report on the
12
+ // identifier node so the diagnostic underlines the offending name.
13
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/catch-error-name.md
14
+ package linthost
15
+
16
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
17
+
18
+ type unicornCatchErrorName struct{}
19
+
20
+ func (unicornCatchErrorName) Name() string { return "unicorn/catch-error-name" }
21
+ func (unicornCatchErrorName) Visits() []shimast.Kind {
22
+ return []shimast.Kind{shimast.KindCatchClause}
23
+ }
24
+ func (unicornCatchErrorName) Check(ctx *Context, node *shimast.Node) {
25
+ catch := node.AsCatchClause()
26
+ if catch == nil || catch.VariableDeclaration == nil {
27
+ return
28
+ }
29
+ binding := catch.VariableDeclaration.Name()
30
+ if binding == nil {
31
+ return
32
+ }
33
+ // Destructuring (object/array binding pattern) is out of scope.
34
+ if binding.Kind != shimast.KindIdentifier {
35
+ return
36
+ }
37
+ name := identifierText(binding)
38
+ if name == "" || name == "error" {
39
+ return
40
+ }
41
+ ctx.Report(binding, "The catch parameter should be named `error`.")
42
+ }
43
+
44
+ func init() {
45
+ Register(unicornCatchErrorName{})
46
+ }
@@ -0,0 +1,47 @@
1
+ // unicorn/consistent-assert: `assert.equal` and `assert.notEqual` perform
2
+ // loose equality (`==` / `!=`) at the runtime layer. The Node `assert`
3
+ // module ships strict counterparts — `assert.strictEqual` and
4
+ // `assert.notStrictEqual` — that read identically at the call site but
5
+ // hold the stronger invariant. The rule pins the strict variants so
6
+ // equality assertions don't silently accept type coercions.
7
+ //
8
+ // AST-only: visit each `CallExpression`. Match a callee of the shape
9
+ // `assert.equal` or `assert.notEqual` (a `PropertyAccessExpression`
10
+ // whose object identifier is `assert` and method name is one of the
11
+ // loose-equality pair). The diagnostic anchors on the call so editors
12
+ // can offer a strict-variant fix at the same position.
13
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-assert.md
14
+ package linthost
15
+
16
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
17
+
18
+ type unicornConsistentAssert struct{}
19
+
20
+ func (unicornConsistentAssert) Name() string { return "unicorn/consistent-assert" }
21
+ func (unicornConsistentAssert) Visits() []shimast.Kind {
22
+ return []shimast.Kind{shimast.KindCallExpression}
23
+ }
24
+ func (unicornConsistentAssert) Check(ctx *Context, node *shimast.Node) {
25
+ call := node.AsCallExpression()
26
+ if call == nil || call.Expression == nil ||
27
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
28
+ return
29
+ }
30
+ access := call.Expression.AsPropertyAccessExpression()
31
+ if access == nil || access.Expression == nil {
32
+ return
33
+ }
34
+ if identifierText(access.Expression) != "assert" {
35
+ return
36
+ }
37
+ switch identifierText(access.Name()) {
38
+ case "equal", "notEqual":
39
+ default:
40
+ return
41
+ }
42
+ ctx.Report(node, "Use the strict variant — `assert.strictEqual` / `assert.notStrictEqual`.")
43
+ }
44
+
45
+ func init() {
46
+ Register(unicornConsistentAssert{})
47
+ }
@@ -0,0 +1,54 @@
1
+ // unicorn/consistent-date-clone: the `Date` constructor copies a date
2
+ // directly when handed another `Date` instance, so the common
3
+ // `new Date(other.getTime())` shape adds a redundant `getTime()` hop
4
+ // that yields the same instant. The shorter `new Date(other)` form is
5
+ // the canonical clone.
6
+ //
7
+ // AST-only: visit each `NewExpression` whose callee identifier is
8
+ // `Date` and whose single argument is `<receiver>.getTime()` with no
9
+ // arguments. The receiver itself is opaque — only the call shape
10
+ // matters because any `Date`-valued expression yields the same clone
11
+ // when passed directly. The diagnostic anchors on the new-expression.
12
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-date-clone.md
13
+ package linthost
14
+
15
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
16
+
17
+ type unicornConsistentDateClone struct{}
18
+
19
+ func (unicornConsistentDateClone) Name() string {
20
+ return "unicorn/consistent-date-clone"
21
+ }
22
+ func (unicornConsistentDateClone) Visits() []shimast.Kind {
23
+ return []shimast.Kind{shimast.KindNewExpression}
24
+ }
25
+ func (unicornConsistentDateClone) Check(ctx *Context, node *shimast.Node) {
26
+ ne := node.AsNewExpression()
27
+ if ne == nil || identifierText(ne.Expression) != "Date" {
28
+ return
29
+ }
30
+ if ne.Arguments == nil || len(ne.Arguments.Nodes) != 1 {
31
+ return
32
+ }
33
+ arg := stripParens(ne.Arguments.Nodes[0])
34
+ if arg == nil || arg.Kind != shimast.KindCallExpression {
35
+ return
36
+ }
37
+ call := arg.AsCallExpression()
38
+ if call == nil || call.Expression == nil ||
39
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
40
+ return
41
+ }
42
+ access := call.Expression.AsPropertyAccessExpression()
43
+ if access == nil || identifierText(access.Name()) != "getTime" {
44
+ return
45
+ }
46
+ if call.Arguments != nil && len(call.Arguments.Nodes) != 0 {
47
+ return
48
+ }
49
+ ctx.Report(node, "Pass the `Date` directly to `new Date(...)` — `getTime()` is redundant.")
50
+ }
51
+
52
+ func init() {
53
+ Register(unicornConsistentDateClone{})
54
+ }
@@ -0,0 +1,25 @@
1
+ // MVP: registers the rule so the typed-key parity test passes; the
2
+ // upstream behavior needs scope analysis (track each destructured
3
+ // binding through subsequent member-access sites in the same scope),
4
+ // which is out of scope for this AST-only port.
5
+ //
6
+ // unicorn/consistent-destructuring:
7
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-destructuring.md
8
+ package linthost
9
+
10
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
11
+
12
+ type unicornConsistentDestructuring struct{}
13
+
14
+ func (unicornConsistentDestructuring) Name() string {
15
+ return "unicorn/consistent-destructuring"
16
+ }
17
+ func (unicornConsistentDestructuring) Visits() []shimast.Kind {
18
+ return []shimast.Kind{shimast.KindSourceFile}
19
+ }
20
+ func (unicornConsistentDestructuring) Check(ctx *Context, node *shimast.Node) {
21
+ }
22
+
23
+ func init() {
24
+ Register(unicornConsistentDestructuring{})
25
+ }
@@ -0,0 +1,62 @@
1
+ // unicorn/consistent-empty-array-spread: when an array literal contains
2
+ // a spread of a ternary, both branches should be arrays so the runtime
3
+ // shape of the parent literal stays uniform. The lopsided form
4
+ // `[1, ...(cond ? [x] : 2)]` mixes "spread an array" and "spread a
5
+ // non-array" — only one branch yields the structural shape the reader
6
+ // expects.
7
+ //
8
+ // AST-only: visit each `ArrayLiteralExpression`. For every element
9
+ // that is a `SpreadElement` wrapping a `ConditionalExpression`, fire
10
+ // when exactly one of the two branches is itself an array literal
11
+ // (the other branch is anything else). The diagnostic anchors on the
12
+ // spread so the editor highlights both the `...` and the ternary.
13
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-empty-array-spread.md
14
+ package linthost
15
+
16
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
17
+
18
+ type unicornConsistentEmptyArraySpread struct{}
19
+
20
+ func (unicornConsistentEmptyArraySpread) Name() string {
21
+ return "unicorn/consistent-empty-array-spread"
22
+ }
23
+ func (unicornConsistentEmptyArraySpread) Visits() []shimast.Kind {
24
+ return []shimast.Kind{shimast.KindArrayLiteralExpression}
25
+ }
26
+ func (unicornConsistentEmptyArraySpread) Check(ctx *Context, node *shimast.Node) {
27
+ arr := node.AsArrayLiteralExpression()
28
+ if arr == nil || arr.Elements == nil {
29
+ return
30
+ }
31
+ for _, el := range arr.Elements.Nodes {
32
+ if el == nil || el.Kind != shimast.KindSpreadElement {
33
+ continue
34
+ }
35
+ spread := el.AsSpreadElement()
36
+ if spread == nil {
37
+ continue
38
+ }
39
+ inner := stripParens(spread.Expression)
40
+ if inner == nil || inner.Kind != shimast.KindConditionalExpression {
41
+ continue
42
+ }
43
+ cond := inner.AsConditionalExpression()
44
+ if cond == nil {
45
+ continue
46
+ }
47
+ whenTrue := stripParens(cond.WhenTrue)
48
+ whenFalse := stripParens(cond.WhenFalse)
49
+ if whenTrue == nil || whenFalse == nil {
50
+ continue
51
+ }
52
+ trueIsArr := whenTrue.Kind == shimast.KindArrayLiteralExpression
53
+ falseIsArr := whenFalse.Kind == shimast.KindArrayLiteralExpression
54
+ if trueIsArr != falseIsArr {
55
+ ctx.Report(el, "When spreading a ternary in an array literal, both branches should be arrays.")
56
+ }
57
+ }
58
+ }
59
+
60
+ func init() {
61
+ Register(unicornConsistentEmptyArraySpread{})
62
+ }