@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,148 @@
1
+ // unicorn/prefer-string-starts-ends-with: `s.slice(0, 4) === "http"` and
2
+ // `s.slice(-3) === "abc"` are the legacy spellings of `s.startsWith(...)`
3
+ // and `s.endsWith(...)`. The String methods are clearer about intent, do
4
+ // not allocate the intermediate substring, and have been available for
5
+ // over a decade.
6
+ //
7
+ // AST-only: visit each `BinaryExpression` whose operator is `===` or
8
+ // `!==`. One operand must be a `CallExpression` of the shape
9
+ // `_.slice(0, N)` or `_.slice(-N)` (the `-N` form being a unary minus
10
+ // over a numeric literal) and the other operand must be a string literal
11
+ // whose text length matches N. Reports on the binary expression.
12
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-starts-ends-with.md
13
+ package linthost
14
+
15
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
16
+
17
+ type unicornPreferStringStartsEndsWith struct{}
18
+
19
+ func (unicornPreferStringStartsEndsWith) Name() string {
20
+ return "unicorn/prefer-string-starts-ends-with"
21
+ }
22
+ func (unicornPreferStringStartsEndsWith) Visits() []shimast.Kind {
23
+ return []shimast.Kind{shimast.KindBinaryExpression}
24
+ }
25
+ func (unicornPreferStringStartsEndsWith) Check(ctx *Context, node *shimast.Node) {
26
+ bin := node.AsBinaryExpression()
27
+ if bin == nil || bin.OperatorToken == nil || bin.Left == nil || bin.Right == nil {
28
+ return
29
+ }
30
+ switch bin.OperatorToken.Kind {
31
+ case shimast.KindEqualsEqualsEqualsToken,
32
+ shimast.KindExclamationEqualsEqualsToken:
33
+ default:
34
+ return
35
+ }
36
+ left := stripParens(bin.Left)
37
+ right := stripParens(bin.Right)
38
+ if unicornPreferStringStartsEndsWithMatches(left, right) ||
39
+ unicornPreferStringStartsEndsWithMatches(right, left) {
40
+ ctx.Report(node, "Prefer `String#startsWith()` / `String#endsWith()` over slice-and-compare.")
41
+ }
42
+ }
43
+
44
+ // unicornPreferStringStartsEndsWithMatches reports whether `callSide` is
45
+ // the slice call and `literalSide` is a matching string literal.
46
+ func unicornPreferStringStartsEndsWithMatches(callSide, literalSide *shimast.Node) bool {
47
+ if callSide == nil || literalSide == nil {
48
+ return false
49
+ }
50
+ if callSide.Kind != shimast.KindCallExpression {
51
+ return false
52
+ }
53
+ if literalSide.Kind != shimast.KindStringLiteral &&
54
+ literalSide.Kind != shimast.KindNoSubstitutionTemplateLiteral {
55
+ return false
56
+ }
57
+ call := callSide.AsCallExpression()
58
+ if call == nil || call.Expression == nil ||
59
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
60
+ return false
61
+ }
62
+ access := call.Expression.AsPropertyAccessExpression()
63
+ if access == nil || identifierText(access.Name()) != "slice" {
64
+ return false
65
+ }
66
+ if call.Arguments == nil {
67
+ return false
68
+ }
69
+ args := call.Arguments.Nodes
70
+ wantLen := -1
71
+ switch len(args) {
72
+ case 2:
73
+ first := stripParens(args[0])
74
+ second := stripParens(args[1])
75
+ if first == nil || first.Kind != shimast.KindNumericLiteral ||
76
+ numericLiteralText(first) != "0" {
77
+ return false
78
+ }
79
+ if second == nil || second.Kind != shimast.KindNumericLiteral {
80
+ return false
81
+ }
82
+ if !unicornPreferStringStartsEndsWithDigits(numericLiteralText(second)) {
83
+ return false
84
+ }
85
+ wantLen = unicornPreferStringStartsEndsWithToInt(numericLiteralText(second))
86
+ case 1:
87
+ // `.slice(-N)` — a unary minus over a positive numeric literal.
88
+ only := stripParens(args[0])
89
+ if only == nil || only.Kind != shimast.KindPrefixUnaryExpression {
90
+ return false
91
+ }
92
+ prefix := only.AsPrefixUnaryExpression()
93
+ if prefix == nil || prefix.Operator != shimast.KindMinusToken ||
94
+ prefix.Operand == nil ||
95
+ prefix.Operand.Kind != shimast.KindNumericLiteral {
96
+ return false
97
+ }
98
+ text := numericLiteralText(prefix.Operand)
99
+ if !unicornPreferStringStartsEndsWithDigits(text) {
100
+ return false
101
+ }
102
+ wantLen = unicornPreferStringStartsEndsWithToInt(text)
103
+ default:
104
+ return false
105
+ }
106
+ if wantLen <= 0 {
107
+ return false
108
+ }
109
+ return len(stringLiteralText(literalSide)) == wantLen
110
+ }
111
+
112
+ // unicornPreferStringStartsEndsWithDigits reports whether `text` is a
113
+ // non-empty ASCII decimal-integer literal. Decimals, hex, and `e`-notation
114
+ // are rejected since the rule only handles fixed-length prefixes.
115
+ func unicornPreferStringStartsEndsWithDigits(text string) bool {
116
+ if text == "" {
117
+ return false
118
+ }
119
+ for i := 0; i < len(text); i++ {
120
+ c := text[i]
121
+ if c < '0' || c > '9' {
122
+ return false
123
+ }
124
+ }
125
+ return true
126
+ }
127
+
128
+ // unicornPreferStringStartsEndsWithToInt parses an ASCII decimal-integer
129
+ // literal into an int. Callers must have validated the input first; this
130
+ // helper returns -1 only as a defensive fallback for an overflow guard.
131
+ func unicornPreferStringStartsEndsWithToInt(text string) int {
132
+ n := 0
133
+ for i := 0; i < len(text); i++ {
134
+ c := text[i]
135
+ if c < '0' || c > '9' {
136
+ return -1
137
+ }
138
+ n = n*10 + int(c-'0')
139
+ if n > 1<<30 {
140
+ return -1
141
+ }
142
+ }
143
+ return n
144
+ }
145
+
146
+ func init() {
147
+ Register(unicornPreferStringStartsEndsWith{})
148
+ }
@@ -0,0 +1,48 @@
1
+ // unicorn/prefer-string-trim-start-end: `String#trimLeft` and
2
+ // `String#trimRight` are the deprecated names for what
3
+ // `String#trimStart` / `String#trimEnd` express directly. The deprecated
4
+ // names are still callable but should be replaced for consistency with
5
+ // the modern naming. The rule fires on zero-argument calls to either
6
+ // deprecated method.
7
+ //
8
+ // AST-only: a `CallExpression` whose callee is `.trimLeft` or
9
+ // `.trimRight` and whose argument list is empty matches. Arguments are
10
+ // theoretically not allowed on either method, but the AST does not
11
+ // know that — the rule defends against the syntactic shape only.
12
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-trim-start-end.md
13
+ package linthost
14
+
15
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
16
+
17
+ type unicornPreferStringTrimStartEnd struct{}
18
+
19
+ func (unicornPreferStringTrimStartEnd) Name() string {
20
+ return "unicorn/prefer-string-trim-start-end"
21
+ }
22
+ func (unicornPreferStringTrimStartEnd) Visits() []shimast.Kind {
23
+ return []shimast.Kind{shimast.KindCallExpression}
24
+ }
25
+ func (unicornPreferStringTrimStartEnd) Check(ctx *Context, node *shimast.Node) {
26
+ call := node.AsCallExpression()
27
+ if call == nil || call.Expression == nil ||
28
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
29
+ return
30
+ }
31
+ access := call.Expression.AsPropertyAccessExpression()
32
+ if access == nil {
33
+ return
34
+ }
35
+ switch identifierText(access.Name()) {
36
+ case "trimLeft", "trimRight":
37
+ default:
38
+ return
39
+ }
40
+ if call.Arguments != nil && len(call.Arguments.Nodes) > 0 {
41
+ return
42
+ }
43
+ ctx.Report(node, "Prefer `String#trimStart` / `String#trimEnd` over the deprecated `trimLeft` / `trimRight`.")
44
+ }
45
+
46
+ func init() {
47
+ Register(unicornPreferStringTrimStartEnd{})
48
+ }
@@ -0,0 +1,71 @@
1
+ // unicorn/prefer-structured-clone: `JSON.parse(JSON.stringify(x))` is
2
+ // the historical deep-clone idiom. It silently drops everything JSON
3
+ // cannot round-trip — `Date`, `Map`, `Set`, typed arrays, cyclic
4
+ // references — and re-allocates a large intermediate string. The
5
+ // platform-native `structuredClone(x)` handles every transferable type,
6
+ // supports cycles, and avoids the string round-trip entirely.
7
+ //
8
+ // AST-only: visit each `CallExpression`, match `JSON.parse(arg)` whose
9
+ // single `arg` is itself a `JSON.stringify(...)` call. Both gates lock
10
+ // the receiver to the bare `JSON` identifier so member-access chains
11
+ // reading `parse`/`stringify` on a renamed alias do not trip the rule.
12
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-structured-clone.md
13
+ package linthost
14
+
15
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
16
+
17
+ type unicornPreferStructuredClone struct{}
18
+
19
+ func (unicornPreferStructuredClone) Name() string {
20
+ return "unicorn/prefer-structured-clone"
21
+ }
22
+ func (unicornPreferStructuredClone) Visits() []shimast.Kind {
23
+ return []shimast.Kind{shimast.KindCallExpression}
24
+ }
25
+ func (unicornPreferStructuredClone) Check(ctx *Context, node *shimast.Node) {
26
+ if !isJSONMethodCall(node, "parse") {
27
+ return
28
+ }
29
+ outer := node.AsCallExpression()
30
+ if outer == nil || outer.Arguments == nil || len(outer.Arguments.Nodes) != 1 {
31
+ return
32
+ }
33
+ arg := stripParens(outer.Arguments.Nodes[0])
34
+ if arg == nil || arg.Kind != shimast.KindCallExpression {
35
+ return
36
+ }
37
+ if !isJSONMethodCall(arg, "stringify") {
38
+ return
39
+ }
40
+ ctx.Report(node, "Prefer `structuredClone(x)` over `JSON.parse(JSON.stringify(x))`.")
41
+ }
42
+
43
+ // isJSONMethodCall reports whether `node` is a CallExpression whose
44
+ // callee is `JSON.<method>` — a property access reading `method` on a
45
+ // bare `JSON` identifier. The bare-identifier gate keeps the rule from
46
+ // firing on `aliased.parse(...)` shapes that happen to share the
47
+ // method name.
48
+ func isJSONMethodCall(node *shimast.Node, method string) bool {
49
+ if node == nil || node.Kind != shimast.KindCallExpression {
50
+ return false
51
+ }
52
+ call := node.AsCallExpression()
53
+ if call == nil || call.Expression == nil {
54
+ return false
55
+ }
56
+ if call.Expression.Kind != shimast.KindPropertyAccessExpression {
57
+ return false
58
+ }
59
+ access := call.Expression.AsPropertyAccessExpression()
60
+ if access == nil {
61
+ return false
62
+ }
63
+ if identifierText(access.Name()) != method {
64
+ return false
65
+ }
66
+ return identifierText(stripParens(access.Expression)) == "JSON"
67
+ }
68
+
69
+ func init() {
70
+ Register(unicornPreferStructuredClone{})
71
+ }
@@ -0,0 +1,103 @@
1
+ // unicorn/prefer-switch: a long `if (x === "a") {…} else if (x === "b")
2
+ // {…} else if (x === "c") {…}` ladder repeats both the discriminant and
3
+ // the equality check on every branch; `switch (x)` collapses the cascade
4
+ // into one labelled lookup and signals intent ("dispatch on the value of
5
+ // x") more directly. The cliff for the rewrite is at three branches —
6
+ // fewer than that, the if-cascade and the switch are about equally
7
+ // readable.
8
+ //
9
+ // AST-only minimum-viable port: visit `IfStatement` and only fire on
10
+ // the outermost `if` of a chain. Walk the else-chain and require it to
11
+ // contain THREE OR MORE `else if` clauses whose condition is a
12
+ // `BinaryExpression` with `===` (or `==`) AND whose left operand is
13
+ // textually identical to the outermost if's left operand AND whose
14
+ // right operand is a string-or-numeric literal. The outermost `if`
15
+ // itself must satisfy the same shape. The shape constraint is
16
+ // intentionally conservative — switch can only dispatch on equality
17
+ // against literal labels.
18
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-switch.md
19
+ package linthost
20
+
21
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
22
+
23
+ type unicornPreferSwitch struct{}
24
+
25
+ func (unicornPreferSwitch) Name() string { return "unicorn/prefer-switch" }
26
+ func (unicornPreferSwitch) Visits() []shimast.Kind {
27
+ return []shimast.Kind{shimast.KindIfStatement}
28
+ }
29
+ func (unicornPreferSwitch) Check(ctx *Context, node *shimast.Node) {
30
+ // Only fire on the outermost if — if our parent is also an
31
+ // `IfStatement` whose else-branch is `node`, this is a middle of the
32
+ // chain and a higher-up visit will report it once.
33
+ if node.Parent != nil && node.Parent.Kind == shimast.KindIfStatement {
34
+ parent := node.Parent.AsIfStatement()
35
+ if parent != nil && parent.ElseStatement == node {
36
+ return
37
+ }
38
+ }
39
+ stmt := node.AsIfStatement()
40
+ if stmt == nil || stmt.Expression == nil {
41
+ return
42
+ }
43
+ discriminant, ok := unicornPreferSwitchDiscriminant(ctx, stmt.Expression)
44
+ if !ok {
45
+ return
46
+ }
47
+ // Count the outermost `if` plus every well-shaped `else if` that
48
+ // compares against the same discriminant.
49
+ branches := 1
50
+ cur := stmt.ElseStatement
51
+ for cur != nil && cur.Kind == shimast.KindIfStatement {
52
+ inner := cur.AsIfStatement()
53
+ if inner == nil || inner.Expression == nil {
54
+ return
55
+ }
56
+ next, ok := unicornPreferSwitchDiscriminant(ctx, inner.Expression)
57
+ if !ok || next != discriminant {
58
+ return
59
+ }
60
+ branches++
61
+ cur = inner.ElseStatement
62
+ }
63
+ if branches >= 3 {
64
+ ctx.Report(node, "Three or more `else if` clauses comparing the same value should be a `switch`.")
65
+ }
66
+ }
67
+
68
+ // unicornPreferSwitchDiscriminant returns the textual form of the left
69
+ // operand of an `===`/`==` comparison against a string-or-numeric
70
+ // literal. Returns ok=false for any other shape.
71
+ func unicornPreferSwitchDiscriminant(ctx *Context, expr *shimast.Node) (string, bool) {
72
+ expr = stripParens(expr)
73
+ if expr == nil || expr.Kind != shimast.KindBinaryExpression {
74
+ return "", false
75
+ }
76
+ bin := expr.AsBinaryExpression()
77
+ if bin == nil || bin.OperatorToken == nil {
78
+ return "", false
79
+ }
80
+ switch bin.OperatorToken.Kind {
81
+ case shimast.KindEqualsEqualsEqualsToken, shimast.KindEqualsEqualsToken:
82
+ default:
83
+ return "", false
84
+ }
85
+ right := stripParens(bin.Right)
86
+ if right == nil {
87
+ return "", false
88
+ }
89
+ switch right.Kind {
90
+ case shimast.KindStringLiteral, shimast.KindNumericLiteral:
91
+ default:
92
+ return "", false
93
+ }
94
+ left := stripParens(bin.Left)
95
+ if left == nil {
96
+ return "", false
97
+ }
98
+ return nodeText(ctx.File, left), true
99
+ }
100
+
101
+ func init() {
102
+ Register(unicornPreferSwitch{})
103
+ }
@@ -0,0 +1,71 @@
1
+ // unicorn/prefer-ternary: when an `if`/`else` pair only differs in the
2
+ // value being returned (or, in the upstream rule, assigned), the
3
+ // equivalent `return cond ? a : b` is one line, removes the
4
+ // duplicated `return` keyword, and matches the shape of every other
5
+ // "pick one of two values" expression in the language.
6
+ //
7
+ // AST-only minimum-viable port: visit `IfStatement` and match only the
8
+ // return-statement case. Both then- and else-branches must each be a
9
+ // single `ReturnStatement` with a non-nil expression — either a bare
10
+ // `return …;` directly under the if, or a block wrapping exactly one
11
+ // such return. The assignment shape (`if (cond) x = a; else x = b;`)
12
+ // from the upstream rule is out of scope for this MVP; both call sites
13
+ // look syntactically symmetric, so adding the assignment branch later
14
+ // is a straightforward extension.
15
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-ternary.md
16
+ package linthost
17
+
18
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
19
+
20
+ type unicornPreferTernary struct{}
21
+
22
+ func (unicornPreferTernary) Name() string { return "unicorn/prefer-ternary" }
23
+ func (unicornPreferTernary) Visits() []shimast.Kind {
24
+ return []shimast.Kind{shimast.KindIfStatement}
25
+ }
26
+ func (unicornPreferTernary) Check(ctx *Context, node *shimast.Node) {
27
+ stmt := node.AsIfStatement()
28
+ if stmt == nil || stmt.ThenStatement == nil || stmt.ElseStatement == nil {
29
+ return
30
+ }
31
+ // Reject `else if` — an `if`/`else if`/`else` ladder is a different
32
+ // rewrite target (it becomes nested ternaries, which the upstream
33
+ // rule explicitly does not require).
34
+ if stmt.ElseStatement.Kind == shimast.KindIfStatement {
35
+ return
36
+ }
37
+ if !unicornPreferTernaryIsSingleReturn(stmt.ThenStatement) {
38
+ return
39
+ }
40
+ if !unicornPreferTernaryIsSingleReturn(stmt.ElseStatement) {
41
+ return
42
+ }
43
+ ctx.Report(node, "Use a ternary instead of `if`/`else` whose branches differ only in the returned value.")
44
+ }
45
+
46
+ // unicornPreferTernaryIsSingleReturn reports whether `branch` is a
47
+ // single `return expr;` — either directly or wrapped in a one-statement
48
+ // block. Returns false for empty returns (`return;`); ternary cannot
49
+ // fold those because both arms have to produce a value.
50
+ func unicornPreferTernaryIsSingleReturn(branch *shimast.Node) bool {
51
+ if branch == nil {
52
+ return false
53
+ }
54
+ stmt := branch
55
+ if branch.Kind == shimast.KindBlock {
56
+ block := branch.AsBlock()
57
+ if block == nil || block.Statements == nil || len(block.Statements.Nodes) != 1 {
58
+ return false
59
+ }
60
+ stmt = block.Statements.Nodes[0]
61
+ }
62
+ if stmt == nil || stmt.Kind != shimast.KindReturnStatement {
63
+ return false
64
+ }
65
+ ret := stmt.AsReturnStatement()
66
+ return ret != nil && ret.Expression != nil
67
+ }
68
+
69
+ func init() {
70
+ Register(unicornPreferTernary{})
71
+ }
@@ -0,0 +1,72 @@
1
+ // unicorn/prefer-top-level-await: ES modules support top-level `await`,
2
+ // which produces a flat synchronous-looking sequence and surfaces
3
+ // rejections through the host. A `.then(cb)` continuation at the module
4
+ // scope re-introduces the callback shape the host could have flattened
5
+ // for free, and silently swallows rejections unless the author wires up
6
+ // an explicit `.catch`.
7
+ //
8
+ // AST-only minimum-viable port: visit `CallExpression` and fire when the
9
+ // callee is `PropertyAccess(_, then)` AND the call sits at the top
10
+ // level of the source file — i.e., walking parents from the call's
11
+ // enclosing statement, the first statement-ancestor's parent is a
12
+ // `SourceFile`. Calls inside a function, class, namespace body, or
13
+ // inside any nested block are excluded; top-level `await` only applies
14
+ // to the module body.
15
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-top-level-await.md
16
+ package linthost
17
+
18
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
19
+
20
+ type unicornPreferTopLevelAwait struct{}
21
+
22
+ func (unicornPreferTopLevelAwait) Name() string { return "unicorn/prefer-top-level-await" }
23
+ func (unicornPreferTopLevelAwait) Visits() []shimast.Kind {
24
+ return []shimast.Kind{shimast.KindCallExpression}
25
+ }
26
+ func (unicornPreferTopLevelAwait) Check(ctx *Context, node *shimast.Node) {
27
+ call := node.AsCallExpression()
28
+ if call == nil || call.Expression == nil ||
29
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
30
+ return
31
+ }
32
+ access := call.Expression.AsPropertyAccessExpression()
33
+ if access == nil || identifierText(access.Name()) != "then" {
34
+ return
35
+ }
36
+ if !unicornPreferTopLevelAwaitIsTopLevel(node) {
37
+ return
38
+ }
39
+ ctx.Report(node, "Prefer top-level `await` over `.then` chains in ES modules.")
40
+ }
41
+
42
+ // unicornPreferTopLevelAwaitIsTopLevel walks ancestors and reports
43
+ // whether `node` is positioned in the top-level statement list of a
44
+ // `SourceFile`. The walk crosses parenthesized expressions and
45
+ // expression statements; it stops the moment it sees any function-like,
46
+ // class-body, block, or module-block boundary, which would push the call
47
+ // out of module scope.
48
+ func unicornPreferTopLevelAwaitIsTopLevel(node *shimast.Node) bool {
49
+ for cur := node.Parent; cur != nil; cur = cur.Parent {
50
+ switch cur.Kind {
51
+ case shimast.KindSourceFile:
52
+ return true
53
+ case shimast.KindFunctionDeclaration,
54
+ shimast.KindFunctionExpression,
55
+ shimast.KindArrowFunction,
56
+ shimast.KindMethodDeclaration,
57
+ shimast.KindGetAccessor,
58
+ shimast.KindSetAccessor,
59
+ shimast.KindConstructor,
60
+ shimast.KindClassDeclaration,
61
+ shimast.KindClassExpression,
62
+ shimast.KindModuleBlock,
63
+ shimast.KindBlock:
64
+ return false
65
+ }
66
+ }
67
+ return false
68
+ }
69
+
70
+ func init() {
71
+ Register(unicornPreferTopLevelAwait{})
72
+ }
@@ -0,0 +1,127 @@
1
+ // unicorn/prefer-type-error: a guard whose condition is a runtime
2
+ // `typeof` / `instanceof` check throws to signal "wrong type", not
3
+ // "wrong value". JavaScript's `TypeError` exists precisely for that
4
+ // distinction, and tooling (e.g. assertion libraries) treats the two
5
+ // error classes differently. The rule asks throwers to switch from
6
+ // `Error` to `TypeError` whenever the surrounding check is a type
7
+ // check.
8
+ //
9
+ // AST-only: visit every `IfStatement`, require its condition (after
10
+ // `stripParens`, optionally unwrapping a `!` prefix) to be a runtime
11
+ // type check — either a `KindTypeOfExpression`, a `KindBinaryExpression`
12
+ // with the `instanceof` operator, or a `==` / `===` / `!=` / `!==`
13
+ // comparison where one side is a `typeof` expression. The then-branch
14
+ // must be a single `KindThrowStatement` of `new Error(...)`. Fire on
15
+ // the throw.
16
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-type-error.md
17
+ package linthost
18
+
19
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
20
+
21
+ type unicornPreferTypeError struct{}
22
+
23
+ func (unicornPreferTypeError) Name() string { return "unicorn/prefer-type-error" }
24
+ func (unicornPreferTypeError) Visits() []shimast.Kind {
25
+ return []shimast.Kind{shimast.KindIfStatement}
26
+ }
27
+ func (unicornPreferTypeError) Check(ctx *Context, node *shimast.Node) {
28
+ stmt := node.AsIfStatement()
29
+ if stmt == nil || stmt.Expression == nil || stmt.ThenStatement == nil {
30
+ return
31
+ }
32
+ cond := stripParens(stmt.Expression)
33
+ if cond == nil {
34
+ return
35
+ }
36
+ // Accept either the bare type check (`typeof x !== "number"`) or a
37
+ // negation of one (`!(x instanceof Foo)`).
38
+ if cond.Kind == shimast.KindPrefixUnaryExpression {
39
+ prefix := cond.AsPrefixUnaryExpression()
40
+ if prefix == nil || prefix.Operator != shimast.KindExclamationToken {
41
+ return
42
+ }
43
+ cond = stripParens(prefix.Operand)
44
+ }
45
+ if !unicornPreferTypeErrorIsTypeCheck(cond) {
46
+ return
47
+ }
48
+ throw := unicornPreferTypeErrorSingleThrow(stmt.ThenStatement)
49
+ if throw == nil {
50
+ return
51
+ }
52
+ throwStmt := throw.AsThrowStatement()
53
+ if throwStmt == nil {
54
+ return
55
+ }
56
+ expr := stripParens(throwStmt.Expression)
57
+ if expr == nil || expr.Kind != shimast.KindNewExpression {
58
+ return
59
+ }
60
+ ne := expr.AsNewExpression()
61
+ if ne == nil || identifierText(ne.Expression) != "Error" {
62
+ return
63
+ }
64
+ ctx.Report(throw, "Throw `TypeError` (not `Error`) when the surrounding check is a runtime type check.")
65
+ }
66
+
67
+ // unicornPreferTypeErrorIsTypeCheck reports whether `node` is a
68
+ // `typeof x` expression or `x instanceof Y` BinaryExpression. Both
69
+ // shapes encode a runtime type test, which is what the rule keys off.
70
+ func unicornPreferTypeErrorIsTypeCheck(node *shimast.Node) bool {
71
+ if node == nil {
72
+ return false
73
+ }
74
+ switch node.Kind {
75
+ case shimast.KindTypeOfExpression:
76
+ return true
77
+ case shimast.KindBinaryExpression:
78
+ bin := node.AsBinaryExpression()
79
+ if bin == nil || bin.OperatorToken == nil {
80
+ return false
81
+ }
82
+ if bin.OperatorToken.Kind == shimast.KindInstanceOfKeyword {
83
+ return true
84
+ }
85
+ // `typeof x !== "string"` style — covers the common idiom.
86
+ switch bin.OperatorToken.Kind {
87
+ case shimast.KindEqualsEqualsEqualsToken,
88
+ shimast.KindEqualsEqualsToken,
89
+ shimast.KindExclamationEqualsEqualsToken,
90
+ shimast.KindExclamationEqualsToken:
91
+ left := stripParens(bin.Left)
92
+ right := stripParens(bin.Right)
93
+ return (left != nil && left.Kind == shimast.KindTypeOfExpression) ||
94
+ (right != nil && right.Kind == shimast.KindTypeOfExpression)
95
+ }
96
+ }
97
+ return false
98
+ }
99
+
100
+ // unicornPreferTypeErrorSingleThrow returns the single `throw`
101
+ // statement inside `branch` — accepting either a bare ThrowStatement
102
+ // or a Block wrapping exactly one ThrowStatement. Returns nil for any
103
+ // other shape.
104
+ func unicornPreferTypeErrorSingleThrow(branch *shimast.Node) *shimast.Node {
105
+ if branch == nil {
106
+ return nil
107
+ }
108
+ if branch.Kind == shimast.KindThrowStatement {
109
+ return branch
110
+ }
111
+ if branch.Kind != shimast.KindBlock {
112
+ return nil
113
+ }
114
+ block := branch.AsBlock()
115
+ if block == nil || block.Statements == nil || len(block.Statements.Nodes) != 1 {
116
+ return nil
117
+ }
118
+ stmt := block.Statements.Nodes[0]
119
+ if stmt == nil || stmt.Kind != shimast.KindThrowStatement {
120
+ return nil
121
+ }
122
+ return stmt
123
+ }
124
+
125
+ func init() {
126
+ Register(unicornPreferTypeError{})
127
+ }