@ttsc/lint 0.13.0 → 0.14.0-dev.20250530.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (498) hide show
  1. package/README.md +955 -85
  2. package/lib/defaultFormat.d.ts +15 -8
  3. package/lib/defaultFormat.js +15 -8
  4. package/lib/defaultFormat.js.map +1 -1
  5. package/lib/index.d.ts +46 -0
  6. package/lib/index.js +60 -37
  7. package/lib/index.js.map +1 -1
  8. package/lib/structures/ITtscLintConfig.d.ts +12 -6
  9. package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
  10. package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
  11. package/lib/structures/TtscLintRuleSetting.js.map +1 -0
  12. package/lib/structures/format/ITtscLintFormat.d.ts +128 -0
  13. package/lib/structures/{TtscLintRuleMap.js → format/ITtscLintFormat.js} +1 -1
  14. package/lib/structures/format/ITtscLintFormat.js.map +1 -0
  15. package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +17 -0
  16. package/lib/structures/{ITtscLintFormatConfig.js → format/ITtscLintFormatJsDoc.js} +1 -1
  17. package/lib/structures/format/ITtscLintFormatJsDoc.js.map +1 -0
  18. package/lib/structures/format/ITtscLintFormatSortImports.d.ts +54 -0
  19. package/lib/structures/format/ITtscLintFormatSortImports.js +3 -0
  20. package/lib/structures/format/ITtscLintFormatSortImports.js.map +1 -0
  21. package/lib/structures/format/index.d.ts +3 -0
  22. package/lib/structures/format/index.js +20 -0
  23. package/lib/structures/format/index.js.map +1 -0
  24. package/lib/structures/index.d.ts +3 -4
  25. package/lib/structures/index.js +3 -4
  26. package/lib/structures/index.js.map +1 -1
  27. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +95 -0
  28. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +13 -0
  29. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
  30. package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +75 -0
  31. package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
  32. package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
  33. package/lib/structures/rules/ITtscLintContributorRules.d.ts +16 -0
  34. package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
  35. package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
  36. package/lib/structures/rules/ITtscLintCoreRules.d.ts +1229 -0
  37. package/lib/structures/rules/ITtscLintCoreRules.js +3 -0
  38. package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
  39. package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
  40. package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
  41. package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
  42. package/lib/structures/rules/ITtscLintCypressRules.d.ts +125 -0
  43. package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
  44. package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
  45. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +154 -0
  46. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
  47. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
  48. package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +162 -0
  49. package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
  50. package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
  51. package/lib/structures/rules/ITtscLintJestRules.d.ts +190 -0
  52. package/lib/structures/rules/ITtscLintJestRules.js +3 -0
  53. package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
  54. package/lib/structures/rules/ITtscLintJsdocRules.d.ts +133 -0
  55. package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
  56. package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
  57. package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +294 -0
  58. package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
  59. package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
  60. package/lib/structures/rules/ITtscLintNextjsRules.d.ts +180 -0
  61. package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
  62. package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
  63. package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +312 -0
  64. package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
  65. package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
  66. package/lib/structures/rules/ITtscLintPromiseRules.d.ts +179 -0
  67. package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
  68. package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
  69. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
  70. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
  71. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
  72. package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +49 -0
  73. package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
  74. package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
  75. package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +37 -0
  76. package/lib/structures/rules/ITtscLintReactRuleOptions.js +11 -0
  77. package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
  78. package/lib/structures/rules/ITtscLintReactRules.d.ts +276 -0
  79. package/lib/structures/rules/ITtscLintReactRules.js +3 -0
  80. package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
  81. package/lib/structures/rules/ITtscLintRegexpRules.d.ts +182 -0
  82. package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
  83. package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
  84. package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +65 -0
  85. package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
  86. package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
  87. package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
  88. package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
  89. package/lib/structures/rules/ITtscLintRules.js.map +1 -0
  90. package/lib/structures/rules/ITtscLintSecurityRules.d.ts +141 -0
  91. package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
  92. package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
  93. package/lib/structures/rules/ITtscLintSolidRules.d.ts +178 -0
  94. package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
  95. package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
  96. package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +20 -0
  97. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
  98. package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
  99. package/lib/structures/rules/ITtscLintStorybookRules.d.ts +165 -0
  100. package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
  101. package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
  102. package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +88 -0
  103. package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
  104. package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
  105. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +21 -0
  106. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
  107. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
  108. package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +293 -0
  109. package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
  110. package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
  111. package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1074 -0
  112. package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
  113. package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
  114. package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
  115. package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
  116. package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
  117. package/lib/structures/rules/ITtscLintVitestRules.d.ts +133 -0
  118. package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
  119. package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
  120. package/lib/structures/rules/index.d.ts +31 -0
  121. package/lib/structures/rules/index.js +48 -0
  122. package/lib/structures/rules/index.js.map +1 -0
  123. package/linthost/ast_helpers.go +30 -5
  124. package/linthost/compile.go +33 -2
  125. package/linthost/config.go +118 -71
  126. package/linthost/config_format.go +270 -104
  127. package/linthost/directives.go +67 -25
  128. package/linthost/dispatch.go +14 -3
  129. package/linthost/engine.go +160 -40
  130. package/linthost/fix.go +10 -3
  131. package/linthost/flags_gen.go +17 -15
  132. package/linthost/format.go +222 -25
  133. package/linthost/format_editor_settings.go +262 -0
  134. package/linthost/host.go +40 -3
  135. package/linthost/lsp.go +898 -0
  136. package/linthost/print_dispatch.go +5 -2
  137. package/linthost/print_engine.go +5 -5
  138. package/linthost/print_nodes_call.go +149 -67
  139. package/linthost/print_nodes_function.go +27 -2
  140. package/linthost/print_nodes_list.go +40 -5
  141. package/linthost/print_nodes_object.go +1 -1
  142. package/linthost/print_nodes_ternary.go +86 -0
  143. package/linthost/rule_names.go +14 -0
  144. package/linthost/rules_arrays.go +2 -2
  145. package/linthost/rules_boundaries.go +532 -0
  146. package/linthost/rules_camelcase.go +133 -0
  147. package/linthost/rules_complexity.go +95 -0
  148. package/linthost/rules_consistent_return.go +130 -0
  149. package/linthost/rules_console.go +1 -1
  150. package/linthost/rules_core_extra.go +739 -0
  151. package/linthost/rules_curly.go +70 -0
  152. package/linthost/rules_cypress.go +608 -0
  153. package/linthost/rules_debugger.go +2 -2
  154. package/linthost/rules_default_case.go +39 -0
  155. package/linthost/rules_default_case_last.go +46 -0
  156. package/linthost/rules_dupes.go +3 -3
  157. package/linthost/rules_empty.go +3 -3
  158. package/linthost/rules_escape.go +44 -24
  159. package/linthost/rules_eval.go +2 -2
  160. package/linthost/rules_finally.go +2 -2
  161. package/linthost/rules_format_arrow_parens.go +167 -0
  162. package/linthost/rules_format_bracket_spacing.go +117 -0
  163. package/linthost/rules_format_clause_join.go +172 -0
  164. package/linthost/rules_format_declaration_header.go +595 -0
  165. package/linthost/rules_format_indent.go +372 -0
  166. package/linthost/rules_format_jsdoc.go +5 -5
  167. package/linthost/rules_format_orphan_semi.go +106 -0
  168. package/linthost/rules_format_parameter_properties.go +175 -0
  169. package/linthost/rules_format_print_width.go +66 -55
  170. package/linthost/rules_format_quote_props.go +169 -0
  171. package/linthost/rules_format_quotes.go +76 -30
  172. package/linthost/rules_format_semi.go +186 -11
  173. package/linthost/rules_format_sort_imports.go +437 -118
  174. package/linthost/rules_format_statement_split.go +343 -0
  175. package/linthost/rules_format_ternary_nullish_parens.go +77 -0
  176. package/linthost/rules_format_trailing_comma.go +22 -3
  177. package/linthost/rules_format_whitespace.go +336 -0
  178. package/linthost/rules_functional.go +967 -0
  179. package/linthost/rules_gap.go +24 -45
  180. package/linthost/rules_grouped_accessor_pairs.go +87 -0
  181. package/linthost/rules_guard_for_in.go +198 -0
  182. package/linthost/rules_id_length.go +77 -0
  183. package/linthost/rules_imports.go +70 -2
  184. package/linthost/rules_init_declarations.go +53 -0
  185. package/linthost/rules_jest.go +618 -0
  186. package/linthost/rules_jsdoc.go +502 -0
  187. package/linthost/rules_jsx_a11y.go +1264 -0
  188. package/linthost/rules_logic.go +12 -12
  189. package/linthost/rules_loops.go +1 -1
  190. package/linthost/rules_max_classes_per_file.go +58 -0
  191. package/linthost/rules_max_depth.go +83 -0
  192. package/linthost/rules_max_lines.go +101 -0
  193. package/linthost/rules_max_lines_per_function.go +57 -0
  194. package/linthost/rules_max_nested_callbacks.go +61 -0
  195. package/linthost/rules_max_params.go +49 -0
  196. package/linthost/rules_max_statements.go +59 -0
  197. package/linthost/rules_misc.go +1 -1
  198. package/linthost/rules_nextjs.go +697 -0
  199. package/linthost/rules_no_else_return.go +75 -0
  200. package/linthost/rules_no_empty_named_blocks.go +91 -0
  201. package/linthost/rules_no_extend_native.go +51 -0
  202. package/linthost/rules_no_import_assign.go +140 -0
  203. package/linthost/rules_no_invalid_this.go +52 -0
  204. package/linthost/rules_no_loop_func.go +85 -0
  205. package/linthost/rules_no_magic_numbers.go +123 -0
  206. package/linthost/rules_no_mixed_operators.go +80 -0
  207. package/linthost/rules_no_param_reassign.go +98 -0
  208. package/linthost/rules_no_redeclare.go +270 -0
  209. package/linthost/rules_no_restricted_imports.go +105 -0
  210. package/linthost/rules_no_restricted_syntax.go +49 -0
  211. package/linthost/rules_no_shadow.go +147 -0
  212. package/linthost/rules_no_unreachable.go +77 -0
  213. package/linthost/rules_no_useless_assignment.go +120 -0
  214. package/linthost/rules_no_useless_constructor.go +245 -0
  215. package/linthost/rules_no_useless_return.go +51 -0
  216. package/linthost/rules_params.go +1 -1
  217. package/linthost/rules_playwright.go +788 -0
  218. package/linthost/rules_prefer_arrow_callback.go +124 -0
  219. package/linthost/rules_prefer_destructuring.go +98 -0
  220. package/linthost/rules_prefer_named_capture_group.go +129 -0
  221. package/linthost/rules_prefer_rest_params.go +94 -0
  222. package/linthost/rules_problems.go +41 -30
  223. package/linthost/rules_promise.go +1057 -2
  224. package/linthost/rules_protos.go +2 -2
  225. package/linthost/rules_react.go +773 -0
  226. package/linthost/rules_react_extras.go +227 -0
  227. package/linthost/rules_react_hooks.go +848 -0
  228. package/linthost/rules_react_perf.go +293 -0
  229. package/linthost/rules_react_refresh.go +583 -0
  230. package/linthost/rules_regexp.go +410 -0
  231. package/linthost/rules_security.go +830 -0
  232. package/linthost/rules_self.go +2 -2
  233. package/linthost/rules_solid.go +1073 -0
  234. package/linthost/rules_sort_imports.go +69 -0
  235. package/linthost/rules_sort_keys.go +134 -0
  236. package/linthost/rules_storybook.go +1176 -0
  237. package/linthost/rules_strings.go +4 -4
  238. package/linthost/rules_suggestions.go +38 -38
  239. package/linthost/rules_tanstack_query.go +844 -0
  240. package/linthost/rules_testing_library.go +1204 -0
  241. package/linthost/rules_throw.go +1 -1
  242. package/linthost/rules_ts.go +19 -19
  243. package/linthost/rules_ts_async.go +399 -0
  244. package/linthost/rules_ts_class_literal_property_style.go +115 -0
  245. package/linthost/rules_ts_consistent_type_exports.go +256 -0
  246. package/linthost/rules_ts_explicit_function_return_type.go +67 -0
  247. package/linthost/rules_ts_extra.go +159 -36
  248. package/linthost/rules_ts_no_base_to_string.go +218 -0
  249. package/linthost/rules_ts_no_confusing_void.go +72 -0
  250. package/linthost/rules_ts_no_deprecated.go +195 -0
  251. package/linthost/rules_ts_no_for_in_array.go +84 -0
  252. package/linthost/rules_ts_no_magic_numbers.go +124 -0
  253. package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
  254. package/linthost/rules_ts_no_misused_spread.go +104 -0
  255. package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
  256. package/linthost/rules_ts_no_restricted_types.go +62 -0
  257. package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
  258. package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
  259. package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
  260. package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
  261. package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
  262. package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
  263. package/linthost/rules_ts_no_unsafe_argument.go +82 -0
  264. package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
  265. package/linthost/rules_ts_no_unsafe_call.go +82 -0
  266. package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
  267. package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
  268. package/linthost/rules_ts_no_unsafe_return.go +126 -0
  269. package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
  270. package/linthost/rules_ts_no_useless_constructor.go +52 -0
  271. package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
  272. package/linthost/rules_ts_parameter_properties.go +38 -0
  273. package/linthost/rules_ts_prefer_find.go +178 -0
  274. package/linthost/rules_ts_prefer_includes.go +255 -0
  275. package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
  276. package/linthost/rules_ts_prefer_optional_chain.go +228 -0
  277. package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
  278. package/linthost/rules_ts_prefer_readonly.go +73 -0
  279. package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
  280. package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
  281. package/linthost/rules_ts_prefer_return_this_type.go +135 -0
  282. package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
  283. package/linthost/rules_ts_promise_function_async.go +77 -0
  284. package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
  285. package/linthost/rules_ts_require_array_sort_compare.go +96 -0
  286. package/linthost/rules_ts_restrict_plus_operands.go +127 -0
  287. package/linthost/rules_ts_restrict_template_expressions.go +95 -0
  288. package/linthost/rules_ts_simple.go +387 -0
  289. package/linthost/rules_ts_sort_type_constituents.go +144 -0
  290. package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
  291. package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
  292. package/linthost/rules_ts_unbound_method.go +126 -0
  293. package/linthost/rules_tsdoc.go +136 -0
  294. package/linthost/rules_unicorn_better_regex.go +27 -0
  295. package/linthost/rules_unicorn_catch_error_name.go +46 -0
  296. package/linthost/rules_unicorn_consistent_assert.go +47 -0
  297. package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
  298. package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
  299. package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
  300. package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
  301. package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
  302. package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
  303. package/linthost/rules_unicorn_custom_error_definition.go +138 -0
  304. package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
  305. package/linthost/rules_unicorn_error_message.go +64 -0
  306. package/linthost/rules_unicorn_escape_case.go +51 -0
  307. package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
  308. package/linthost/rules_unicorn_explicit_length_check.go +88 -0
  309. package/linthost/rules_unicorn_filename_case.go +29 -0
  310. package/linthost/rules_unicorn_import_style.go +28 -0
  311. package/linthost/rules_unicorn_isolated_functions.go +29 -0
  312. package/linthost/rules_unicorn_new_for_builtins.go +87 -0
  313. package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
  314. package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
  315. package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
  316. package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
  317. package/linthost/rules_unicorn_no_array_for_each.go +40 -0
  318. package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
  319. package/linthost/rules_unicorn_no_array_reduce.go +41 -0
  320. package/linthost/rules_unicorn_no_array_reverse.go +44 -0
  321. package/linthost/rules_unicorn_no_array_sort.go +43 -0
  322. package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
  323. package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
  324. package/linthost/rules_unicorn_no_console_spaces.go +61 -0
  325. package/linthost/rules_unicorn_no_document_cookie.go +41 -0
  326. package/linthost/rules_unicorn_no_empty_file.go +44 -0
  327. package/linthost/rules_unicorn_no_for_loop.go +102 -0
  328. package/linthost/rules_unicorn_no_hex_escape.go +42 -0
  329. package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
  330. package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
  331. package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
  332. package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
  333. package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
  334. package/linthost/rules_unicorn_no_lonely_if.go +44 -0
  335. package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
  336. package/linthost/rules_unicorn_no_named_default.go +54 -0
  337. package/linthost/rules_unicorn_no_negated_condition.go +85 -0
  338. package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
  339. package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
  340. package/linthost/rules_unicorn_no_new_array.go +30 -0
  341. package/linthost/rules_unicorn_no_new_buffer.go +31 -0
  342. package/linthost/rules_unicorn_no_null.go +24 -0
  343. package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
  344. package/linthost/rules_unicorn_no_process_exit.go +43 -0
  345. package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
  346. package/linthost/rules_unicorn_no_static_only_class.go +56 -0
  347. package/linthost/rules_unicorn_no_thenable.go +74 -0
  348. package/linthost/rules_unicorn_no_this_assignment.go +35 -0
  349. package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
  350. package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
  351. package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
  352. package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
  353. package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
  354. package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
  355. package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
  356. package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
  357. package/linthost/rules_unicorn_no_unused_properties.go +30 -0
  358. package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
  359. package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
  360. package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
  361. package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
  362. package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
  363. package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
  364. package/linthost/rules_unicorn_no_useless_spread.go +67 -0
  365. package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
  366. package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
  367. package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
  368. package/linthost/rules_unicorn_number_literal_case.go +69 -0
  369. package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
  370. package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
  371. package/linthost/rules_unicorn_prefer_array_find.go +51 -0
  372. package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
  373. package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
  374. package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
  375. package/linthost/rules_unicorn_prefer_array_some.go +67 -0
  376. package/linthost/rules_unicorn_prefer_at.go +77 -0
  377. package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
  378. package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
  379. package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
  380. package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
  381. package/linthost/rules_unicorn_prefer_code_point.go +49 -0
  382. package/linthost/rules_unicorn_prefer_date_now.go +78 -0
  383. package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
  384. package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
  385. package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
  386. package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
  387. package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
  388. package/linthost/rules_unicorn_prefer_event_target.go +36 -0
  389. package/linthost/rules_unicorn_prefer_export_from.go +129 -0
  390. package/linthost/rules_unicorn_prefer_global_this.go +127 -0
  391. package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
  392. package/linthost/rules_unicorn_prefer_includes.go +149 -0
  393. package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
  394. package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
  395. package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
  396. package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
  397. package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
  398. package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
  399. package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
  400. package/linthost/rules_unicorn_prefer_module.go +50 -0
  401. package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
  402. package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
  403. package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
  404. package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
  405. package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
  406. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
  407. package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
  408. package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
  409. package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
  410. package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
  411. package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
  412. package/linthost/rules_unicorn_prefer_set_has.go +42 -0
  413. package/linthost/rules_unicorn_prefer_set_size.go +48 -0
  414. package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
  415. package/linthost/rules_unicorn_prefer_single_call.go +96 -0
  416. package/linthost/rules_unicorn_prefer_spread.go +51 -0
  417. package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
  418. package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
  419. package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
  420. package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
  421. package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
  422. package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
  423. package/linthost/rules_unicorn_prefer_switch.go +103 -0
  424. package/linthost/rules_unicorn_prefer_ternary.go +71 -0
  425. package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
  426. package/linthost/rules_unicorn_prefer_type_error.go +127 -0
  427. package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
  428. package/linthost/rules_unicorn_relative_url_style.go +49 -0
  429. package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
  430. package/linthost/rules_unicorn_require_module_attributes.go +54 -0
  431. package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
  432. package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
  433. package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
  434. package/linthost/rules_unicorn_string_content.go +27 -0
  435. package/linthost/rules_unicorn_switch_case_braces.go +42 -0
  436. package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
  437. package/linthost/rules_unicorn_template_indent.go +28 -0
  438. package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
  439. package/linthost/rules_unicorn_throw_new_error.go +61 -0
  440. package/linthost/rules_var.go +10 -4
  441. package/linthost/rules_vitest.go +568 -0
  442. package/package.json +3 -3
  443. package/plugin/main.go +49 -3
  444. package/rule/astutil/astutil.go +10 -3
  445. package/rule/rule.go +12 -10
  446. package/src/defaultFormat.ts +17 -10
  447. package/src/index.ts +65 -43
  448. package/src/structures/ITtscLintConfig.ts +14 -8
  449. package/src/structures/TtscLintRuleSetting.ts +55 -0
  450. package/src/structures/format/ITtscLintFormat.ts +141 -0
  451. package/src/structures/format/ITtscLintFormatJsDoc.ts +18 -0
  452. package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
  453. package/src/structures/format/index.ts +3 -0
  454. package/src/structures/index.ts +3 -4
  455. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +117 -0
  456. package/src/structures/rules/ITtscLintBoundariesRules.ts +91 -0
  457. package/src/structures/rules/ITtscLintContributorRules.ts +20 -0
  458. package/src/structures/rules/ITtscLintCoreRules.ts +1378 -0
  459. package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
  460. package/src/structures/rules/ITtscLintCypressRules.ts +141 -0
  461. package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +200 -0
  462. package/src/structures/rules/ITtscLintFunctionalRules.ts +197 -0
  463. package/src/structures/rules/ITtscLintJestRules.ts +209 -0
  464. package/src/structures/rules/ITtscLintJsdocRules.ts +146 -0
  465. package/src/structures/rules/ITtscLintJsxA11yRules.ts +331 -0
  466. package/src/structures/rules/ITtscLintNextjsRules.ts +201 -0
  467. package/src/structures/rules/ITtscLintPlaywrightRules.ts +343 -0
  468. package/src/structures/rules/ITtscLintPromiseRules.ts +196 -0
  469. package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
  470. package/src/structures/rules/ITtscLintReactPerfRules.ts +53 -0
  471. package/src/structures/rules/ITtscLintReactRuleOptions.ts +41 -0
  472. package/src/structures/rules/ITtscLintReactRules.ts +308 -0
  473. package/src/structures/rules/ITtscLintRegexpRules.ts +204 -0
  474. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -0
  475. package/src/structures/rules/ITtscLintRules.ts +77 -0
  476. package/src/structures/rules/ITtscLintSecurityRules.ts +155 -0
  477. package/src/structures/rules/ITtscLintSolidRules.ts +199 -0
  478. package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +22 -0
  479. package/src/structures/rules/ITtscLintStorybookRules.ts +184 -0
  480. package/src/structures/rules/ITtscLintTanstackQueryRules.ts +96 -0
  481. package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +23 -0
  482. package/src/structures/rules/ITtscLintTestingLibraryRules.ts +325 -0
  483. package/src/structures/rules/ITtscLintTypeScriptRules.ts +1172 -0
  484. package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
  485. package/src/structures/rules/ITtscLintVitestRules.ts +146 -0
  486. package/src/structures/rules/index.ts +31 -0
  487. package/lib/structures/ITtscLintFormatConfig.d.ts +0 -153
  488. package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
  489. package/lib/structures/TtscLintRule.d.ts +0 -17
  490. package/lib/structures/TtscLintRule.js.map +0 -1
  491. package/lib/structures/TtscLintRuleMap.d.ts +0 -46
  492. package/lib/structures/TtscLintRuleMap.js.map +0 -1
  493. package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
  494. package/lib/structures/TtscLintRuleOptions.js.map +0 -1
  495. package/src/structures/ITtscLintFormatConfig.ts +0 -168
  496. package/src/structures/TtscLintRule.ts +0 -160
  497. package/src/structures/TtscLintRuleMap.ts +0 -55
  498. package/src/structures/TtscLintRuleOptions.ts +0 -151
@@ -0,0 +1,81 @@
1
+ // unicorn/no-useless-fallback-in-spread: spreading `null` or `undefined`
2
+ // into an object literal is already a runtime no-op, so the common
3
+ // defensive shape `...(x ?? {})` adds an allocation and a comparison
4
+ // that change nothing. The same goes for `...(x || {})` and the
5
+ // array-literal variants. Drop the fallback and spread the value
6
+ // directly.
7
+ //
8
+ // AST-only: visit each spread node — `SpreadElement` only when its
9
+ // parent is an `ArrayLiteralExpression` (call-argument spread is
10
+ // excluded because spreading `null` / `undefined` into a function call
11
+ // throws a `TypeError`, so the fallback is load-bearing there) and
12
+ // `SpreadAssignment` for object spread. After stripping parentheses,
13
+ // the spread's operand must be a binary expression using `??` or `||`
14
+ // whose right-hand side is an empty object or array literal. The
15
+ // diagnostic anchors on the spread node so editors highlight the
16
+ // redundant fallback together with its `...`.
17
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-fallback-in-spread.md
18
+ package linthost
19
+
20
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
21
+
22
+ type unicornNoUselessFallbackInSpread struct{}
23
+
24
+ func (unicornNoUselessFallbackInSpread) Name() string {
25
+ return "unicorn/no-useless-fallback-in-spread"
26
+ }
27
+ func (unicornNoUselessFallbackInSpread) Visits() []shimast.Kind {
28
+ return []shimast.Kind{shimast.KindSpreadElement, shimast.KindSpreadAssignment}
29
+ }
30
+ func (unicornNoUselessFallbackInSpread) Check(ctx *Context, node *shimast.Node) {
31
+ var operand *shimast.Node
32
+ switch node.Kind {
33
+ case shimast.KindSpreadElement:
34
+ // Only flag array-literal spread. Call-argument spread of a
35
+ // null/undefined operand throws TypeError at runtime, so the
36
+ // `?? []` / `|| []` fallback is load-bearing in that position.
37
+ if node.Parent == nil || node.Parent.Kind != shimast.KindArrayLiteralExpression {
38
+ return
39
+ }
40
+ if spread := node.AsSpreadElement(); spread != nil {
41
+ operand = spread.Expression
42
+ }
43
+ case shimast.KindSpreadAssignment:
44
+ if spread := node.AsSpreadAssignment(); spread != nil {
45
+ operand = spread.Expression
46
+ }
47
+ }
48
+ inner := stripParens(operand)
49
+ if inner == nil || inner.Kind != shimast.KindBinaryExpression {
50
+ return
51
+ }
52
+ bin := inner.AsBinaryExpression()
53
+ if bin == nil || bin.OperatorToken == nil {
54
+ return
55
+ }
56
+ switch bin.OperatorToken.Kind {
57
+ case shimast.KindQuestionQuestionToken, shimast.KindBarBarToken:
58
+ default:
59
+ return
60
+ }
61
+ right := stripParens(bin.Right)
62
+ if right == nil {
63
+ return
64
+ }
65
+ switch right.Kind {
66
+ case shimast.KindObjectLiteralExpression:
67
+ if obj := right.AsObjectLiteralExpression(); obj != nil &&
68
+ (obj.Properties == nil || len(obj.Properties.Nodes) == 0) {
69
+ ctx.Report(node, "Don't use a useless `?? {}` or `?? []` fallback when spreading — `...null` and `...undefined` are no-ops.")
70
+ }
71
+ case shimast.KindArrayLiteralExpression:
72
+ if arr := right.AsArrayLiteralExpression(); arr != nil &&
73
+ (arr.Elements == nil || len(arr.Elements.Nodes) == 0) {
74
+ ctx.Report(node, "Don't use a useless `?? {}` or `?? []` fallback when spreading — `...null` and `...undefined` are no-ops.")
75
+ }
76
+ }
77
+ }
78
+
79
+ func init() {
80
+ Register(unicornNoUselessFallbackInSpread{})
81
+ }
@@ -0,0 +1,72 @@
1
+ // unicorn/no-useless-iterator-to-array: wrapping an iterator-producing
2
+ // call in an array-literal spread (`[...arr.entries()]`) materializes
3
+ // every element into a throwaway array just to walk through it again.
4
+ // The wrappers `.entries()`, `.keys()`, `.values()` already return
5
+ // iterables that any iteration consumer can consume directly.
6
+ //
7
+ // AST-only and conservative: visit each `ArrayLiteralExpression` whose
8
+ // only element is a `SpreadElement` wrapping a `CallExpression` whose
9
+ // callee is `PropertyAccess(_, name)` with `name ∈ {entries, keys,
10
+ // values}`. The array literal must also be in an iterator-consuming
11
+ // parent position — currently only `for…of` is matched, since materializing
12
+ // an array to iterate it once is the rule's textbook case. Using the
13
+ // materialized array as data (`[...iter][0]`, `[...iter].map(…)`,
14
+ // `const arr = [...iter]`) is NOT flagged because the author wants the
15
+ // array, not a fresh walk.
16
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-iterator-to-array.md
17
+ package linthost
18
+
19
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
20
+
21
+ type unicornNoUselessIteratorToArray struct{}
22
+
23
+ func (unicornNoUselessIteratorToArray) Name() string {
24
+ return "unicorn/no-useless-iterator-to-array"
25
+ }
26
+ func (unicornNoUselessIteratorToArray) Visits() []shimast.Kind {
27
+ return []shimast.Kind{shimast.KindArrayLiteralExpression}
28
+ }
29
+ func (unicornNoUselessIteratorToArray) Check(ctx *Context, node *shimast.Node) {
30
+ // Only fire when the array literal is the iterable of a `for…of`
31
+ // loop — that's the canonical wasted-materialization shape. Other
32
+ // uses (`[...iter][0]`, `const arr = [...iter]`, `.map`, etc.)
33
+ // genuinely need the materialized array.
34
+ if node.Parent == nil || node.Parent.Kind != shimast.KindForOfStatement {
35
+ return
36
+ }
37
+ arr := node.AsArrayLiteralExpression()
38
+ if arr == nil || arr.Elements == nil || len(arr.Elements.Nodes) != 1 {
39
+ return
40
+ }
41
+ only := arr.Elements.Nodes[0]
42
+ if only == nil || only.Kind != shimast.KindSpreadElement {
43
+ return
44
+ }
45
+ spread := only.AsSpreadElement()
46
+ if spread == nil {
47
+ return
48
+ }
49
+ inner := stripParens(spread.Expression)
50
+ if inner == nil || inner.Kind != shimast.KindCallExpression {
51
+ return
52
+ }
53
+ call := inner.AsCallExpression()
54
+ if call == nil || call.Expression == nil ||
55
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
56
+ return
57
+ }
58
+ access := call.Expression.AsPropertyAccessExpression()
59
+ if access == nil {
60
+ return
61
+ }
62
+ switch identifierText(access.Name()) {
63
+ case "entries", "keys", "values":
64
+ default:
65
+ return
66
+ }
67
+ ctx.Report(node, "Don't wrap an iterator with `[...iter]` when iterating directly works.")
68
+ }
69
+
70
+ func init() {
71
+ Register(unicornNoUselessIteratorToArray{})
72
+ }
@@ -0,0 +1,144 @@
1
+ // unicorn/no-useless-length-check: `arr.length > 0 && arr.some(…)`
2
+ // short-circuits on an empty array, but `arr.some(…)` already returns
3
+ // `false` for the empty case, so the leading length check is redundant.
4
+ // The same goes for `forEach` (returns `undefined` either way). The
5
+ // rule prunes the dead check so the call shape is the only thing the
6
+ // reader has to track.
7
+ //
8
+ // `every`, `map`, and `filter` are deliberately excluded from the `&&`
9
+ // set: `every` returns `true` on an empty array (so the length check
10
+ // IS load-bearing); `map` and `filter` return `[]` which is truthy
11
+ // (the length check changes the truthiness of the whole expression).
12
+ // Upstream covers those under the complementary `||` pattern
13
+ // (`array.length === 0 || array.every(…)`), which this MVP does not
14
+ // implement yet.
15
+ //
16
+ // AST-only MVP: visit each `BinaryExpression`, match operator `&&`,
17
+ // require LHS to be `PropertyAccess(X, length) > 0` or `!== 0`, and
18
+ // require RHS to be `CallExpression(PropertyAccess(X, name), …)` where
19
+ // `name` is one of `some` / `forEach` and the textual form of the two
20
+ // `X` expressions matches. Fire on the binary expression.
21
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-length-check.md
22
+ package linthost
23
+
24
+ import (
25
+ "fmt"
26
+
27
+ shimast "github.com/microsoft/typescript-go/shim/ast"
28
+ )
29
+
30
+ var unicornNoUselessLengthCheckMethods = map[string]struct{}{
31
+ "some": {},
32
+ "forEach": {},
33
+ }
34
+
35
+ type unicornNoUselessLengthCheck struct{}
36
+
37
+ func (unicornNoUselessLengthCheck) Name() string { return "unicorn/no-useless-length-check" }
38
+ func (unicornNoUselessLengthCheck) Visits() []shimast.Kind {
39
+ return []shimast.Kind{shimast.KindBinaryExpression}
40
+ }
41
+ func (unicornNoUselessLengthCheck) Check(ctx *Context, node *shimast.Node) {
42
+ bin := node.AsBinaryExpression()
43
+ if bin == nil || bin.OperatorToken == nil ||
44
+ bin.OperatorToken.Kind != shimast.KindAmpersandAmpersandToken {
45
+ return
46
+ }
47
+ left := stripParens(bin.Left)
48
+ right := stripParens(bin.Right)
49
+ if left == nil || right == nil {
50
+ return
51
+ }
52
+ lengthReceiver := unicornUselessLengthCheckLHSReceiver(ctx, left)
53
+ if lengthReceiver == "" {
54
+ return
55
+ }
56
+ method, callReceiver := unicornUselessLengthCheckRHSReceiver(ctx, right)
57
+ if method == "" || callReceiver == "" {
58
+ return
59
+ }
60
+ if lengthReceiver != callReceiver {
61
+ return
62
+ }
63
+ ctx.Report(node, fmt.Sprintf("Useless `.length` check — `%s` already handles empty arrays correctly.", method))
64
+ }
65
+
66
+ // unicornUselessLengthCheckLHSReceiver returns the textual form of `X`
67
+ // when `node` is `X.length > 0` or `X.length !== 0` (either operand
68
+ // order); returns "" otherwise.
69
+ func unicornUselessLengthCheckLHSReceiver(ctx *Context, node *shimast.Node) string {
70
+ bin := node.AsBinaryExpression()
71
+ if bin == nil || bin.OperatorToken == nil || bin.Left == nil || bin.Right == nil {
72
+ return ""
73
+ }
74
+ op := bin.OperatorToken.Kind
75
+ if op != shimast.KindGreaterThanToken &&
76
+ op != shimast.KindExclamationEqualsEqualsToken &&
77
+ op != shimast.KindExclamationEqualsToken {
78
+ return ""
79
+ }
80
+ lhs := stripParens(bin.Left)
81
+ rhs := stripParens(bin.Right)
82
+ // Try `X.length <op> 0`.
83
+ if recv := unicornUselessLengthCheckMatchLengthAccess(ctx, lhs); recv != "" &&
84
+ unicornUselessLengthCheckIsZero(rhs) {
85
+ return recv
86
+ }
87
+ // `0 !== X.length` (no `<` form because `>` is asymmetric — covered
88
+ // by the LHS branch above).
89
+ if op == shimast.KindExclamationEqualsEqualsToken || op == shimast.KindExclamationEqualsToken {
90
+ if recv := unicornUselessLengthCheckMatchLengthAccess(ctx, rhs); recv != "" &&
91
+ unicornUselessLengthCheckIsZero(lhs) {
92
+ return recv
93
+ }
94
+ }
95
+ return ""
96
+ }
97
+
98
+ // unicornUselessLengthCheckMatchLengthAccess returns the receiver text
99
+ // when `node` is a `PropertyAccessExpression(X, length)`; "" otherwise.
100
+ func unicornUselessLengthCheckMatchLengthAccess(ctx *Context, node *shimast.Node) string {
101
+ if node == nil || node.Kind != shimast.KindPropertyAccessExpression {
102
+ return ""
103
+ }
104
+ access := node.AsPropertyAccessExpression()
105
+ if access == nil || identifierText(access.Name()) != "length" {
106
+ return ""
107
+ }
108
+ return nodeText(ctx.File, access.Expression)
109
+ }
110
+
111
+ // unicornUselessLengthCheckIsZero reports whether `node` is the numeric
112
+ // literal `0`.
113
+ func unicornUselessLengthCheckIsZero(node *shimast.Node) bool {
114
+ return node != nil &&
115
+ node.Kind == shimast.KindNumericLiteral &&
116
+ numericLiteralText(node) == "0"
117
+ }
118
+
119
+ // unicornUselessLengthCheckRHSReceiver returns (method, receiverText)
120
+ // when `node` is `X.method(...)` for one of the empty-safe iteration
121
+ // methods; ("", "") otherwise.
122
+ func unicornUselessLengthCheckRHSReceiver(ctx *Context, node *shimast.Node) (string, string) {
123
+ if node == nil || node.Kind != shimast.KindCallExpression {
124
+ return "", ""
125
+ }
126
+ call := node.AsCallExpression()
127
+ if call == nil || call.Expression == nil ||
128
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
129
+ return "", ""
130
+ }
131
+ access := call.Expression.AsPropertyAccessExpression()
132
+ if access == nil {
133
+ return "", ""
134
+ }
135
+ method := identifierText(access.Name())
136
+ if _, ok := unicornNoUselessLengthCheckMethods[method]; !ok {
137
+ return "", ""
138
+ }
139
+ return method, nodeText(ctx.File, access.Expression)
140
+ }
141
+
142
+ func init() {
143
+ Register(unicornNoUselessLengthCheck{})
144
+ }
@@ -0,0 +1,81 @@
1
+ // unicorn/no-useless-promise-resolve-reject: inside an `async`
2
+ // function, `return x` already wraps the value in a resolved promise
3
+ // and `throw err` already produces a rejected one. Writing `return
4
+ // Promise.resolve(x)` or `return Promise.reject(err)` rebuilds the
5
+ // wrapper the runtime would build anyway, hides the actual value
6
+ // behind an extra call, and reads as if the author forgot the
7
+ // function was async.
8
+ //
9
+ // AST-only and parent-walking: visit each `ReturnStatement`, find the
10
+ // nearest enclosing function-like ancestor, and require it to carry
11
+ // the `async` modifier. The return's expression after `stripParens`
12
+ // must be a `CallExpression` whose callee is
13
+ // `PropertyAccess(Identifier("Promise"), name)` with
14
+ // `name ∈ {resolve, reject}`. Arrow concise bodies are not handled
15
+ // here because the rule's contract anchors on the `return` keyword.
16
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-promise-resolve-reject.md
17
+ package linthost
18
+
19
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
20
+
21
+ type unicornNoUselessPromiseResolveReject struct{}
22
+
23
+ func (unicornNoUselessPromiseResolveReject) Name() string {
24
+ return "unicorn/no-useless-promise-resolve-reject"
25
+ }
26
+ func (unicornNoUselessPromiseResolveReject) Visits() []shimast.Kind {
27
+ return []shimast.Kind{shimast.KindReturnStatement}
28
+ }
29
+ func (unicornNoUselessPromiseResolveReject) Check(ctx *Context, node *shimast.Node) {
30
+ ret := node.AsReturnStatement()
31
+ if ret == nil || ret.Expression == nil {
32
+ return
33
+ }
34
+ if !unicornNoUselessPromiseResolveRejectInAsync(node) {
35
+ return
36
+ }
37
+ expr := stripParens(ret.Expression)
38
+ if expr == nil || expr.Kind != shimast.KindCallExpression {
39
+ return
40
+ }
41
+ call := expr.AsCallExpression()
42
+ if call == nil || call.Expression == nil ||
43
+ call.Expression.Kind != shimast.KindPropertyAccessExpression {
44
+ return
45
+ }
46
+ access := call.Expression.AsPropertyAccessExpression()
47
+ if access == nil {
48
+ return
49
+ }
50
+ if identifierText(access.Expression) != "Promise" {
51
+ return
52
+ }
53
+ switch identifierText(access.Name()) {
54
+ case "resolve", "reject":
55
+ default:
56
+ return
57
+ }
58
+ ctx.Report(node, "In `async` functions, `return x` and `throw e` work identically — drop the `Promise.<method>` wrapper.")
59
+ }
60
+
61
+ // unicornNoUselessPromiseResolveRejectInAsync walks ancestors of `node`
62
+ // and reports whether the nearest enclosing function-like declaration
63
+ // is marked `async`. Crossing a function boundary that is not async
64
+ // stops the walk — a nested non-async function shadows the outer
65
+ // async context.
66
+ func unicornNoUselessPromiseResolveRejectInAsync(node *shimast.Node) bool {
67
+ for cur := node.Parent; cur != nil; cur = cur.Parent {
68
+ switch cur.Kind {
69
+ case shimast.KindFunctionDeclaration,
70
+ shimast.KindFunctionExpression,
71
+ shimast.KindArrowFunction,
72
+ shimast.KindMethodDeclaration:
73
+ return hasModifier(cur, shimast.KindAsyncKeyword)
74
+ }
75
+ }
76
+ return false
77
+ }
78
+
79
+ func init() {
80
+ Register(unicornNoUselessPromiseResolveReject{})
81
+ }
@@ -0,0 +1,67 @@
1
+ // unicorn/no-useless-spread: wrapping an already-spread literal in
2
+ // another spread produces the original literal — `[...[1, 2, 3]]` is
3
+ // just `[1, 2, 3]`, and `{...{a: 1}}` is `{a: 1}`. The extra spread
4
+ // reads like an attempted clone but allocates an intermediate literal
5
+ // for no observable effect.
6
+ //
7
+ // AST-only and conservative: visit every `ArrayLiteralExpression` and
8
+ // `ObjectLiteralExpression`; match when the literal contains exactly
9
+ // one element that is a `SpreadElement` / `SpreadAssignment` whose
10
+ // operand (after `stripParens`) is itself a literal of the same kind.
11
+ // The receiver expressions are not inspected — the syntactic shape
12
+ // `[...[…]]` / `{...{…}}` is the signal regardless of the inner
13
+ // literal's contents. Mirrors the conservative dispatch used by
14
+ // `unicorn/prefer-set-size`.
15
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-spread.md
16
+ package linthost
17
+
18
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
19
+
20
+ type unicornNoUselessSpread struct{}
21
+
22
+ func (unicornNoUselessSpread) Name() string { return "unicorn/no-useless-spread" }
23
+ func (unicornNoUselessSpread) Visits() []shimast.Kind {
24
+ return []shimast.Kind{shimast.KindArrayLiteralExpression, shimast.KindObjectLiteralExpression}
25
+ }
26
+ func (unicornNoUselessSpread) Check(ctx *Context, node *shimast.Node) {
27
+ switch node.Kind {
28
+ case shimast.KindArrayLiteralExpression:
29
+ arr := node.AsArrayLiteralExpression()
30
+ if arr == nil || arr.Elements == nil || len(arr.Elements.Nodes) != 1 {
31
+ return
32
+ }
33
+ only := arr.Elements.Nodes[0]
34
+ if only == nil || only.Kind != shimast.KindSpreadElement {
35
+ return
36
+ }
37
+ spread := only.AsSpreadElement()
38
+ if spread == nil {
39
+ return
40
+ }
41
+ inner := stripParens(spread.Expression)
42
+ if inner != nil && inner.Kind == shimast.KindArrayLiteralExpression {
43
+ ctx.Report(node, "Don't wrap an already-spread literal in another spread.")
44
+ }
45
+ case shimast.KindObjectLiteralExpression:
46
+ obj := node.AsObjectLiteralExpression()
47
+ if obj == nil || obj.Properties == nil || len(obj.Properties.Nodes) != 1 {
48
+ return
49
+ }
50
+ only := obj.Properties.Nodes[0]
51
+ if only == nil || only.Kind != shimast.KindSpreadAssignment {
52
+ return
53
+ }
54
+ spread := only.AsSpreadAssignment()
55
+ if spread == nil {
56
+ return
57
+ }
58
+ inner := stripParens(spread.Expression)
59
+ if inner != nil && inner.Kind == shimast.KindObjectLiteralExpression {
60
+ ctx.Report(node, "Don't wrap an already-spread literal in another spread.")
61
+ }
62
+ }
63
+ }
64
+
65
+ func init() {
66
+ Register(unicornNoUselessSpread{})
67
+ }
@@ -0,0 +1,55 @@
1
+ // unicorn/no-useless-switch-case: a `case` clause with no statements
2
+ // that sits immediately above the `default` clause falls through to
3
+ // `default` for free — the value it matches would have hit `default`
4
+ // regardless. Keeping the empty case adds noise without changing the
5
+ // switch's behavior, so the rule reports it.
6
+ //
7
+ // AST-only: visit each `SwitchStatement`, walk its case-block clauses,
8
+ // and report any non-default `CaseClause` whose statements list is
9
+ // empty and whose immediate next sibling is the `DefaultClause`. The
10
+ // empty-body check distinguishes intentional grouped cases that share a
11
+ // non-trivial body from the redundant fall-into-default shape.
12
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-switch-case.md
13
+ package linthost
14
+
15
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
16
+
17
+ type unicornNoUselessSwitchCase struct{}
18
+
19
+ func (unicornNoUselessSwitchCase) Name() string { return "unicorn/no-useless-switch-case" }
20
+ func (unicornNoUselessSwitchCase) Visits() []shimast.Kind {
21
+ return []shimast.Kind{shimast.KindSwitchStatement}
22
+ }
23
+ func (unicornNoUselessSwitchCase) Check(ctx *Context, node *shimast.Node) {
24
+ sw := node.AsSwitchStatement()
25
+ if sw == nil || sw.CaseBlock == nil {
26
+ return
27
+ }
28
+ block := sw.CaseBlock.AsCaseBlock()
29
+ if block == nil || block.Clauses == nil {
30
+ return
31
+ }
32
+ clauses := block.Clauses.Nodes
33
+ for i := 0; i < len(clauses)-1; i++ {
34
+ clause := clauses[i]
35
+ if clause == nil || clause.Kind != shimast.KindCaseClause {
36
+ continue
37
+ }
38
+ next := clauses[i+1]
39
+ if next == nil || next.Kind != shimast.KindDefaultClause {
40
+ continue
41
+ }
42
+ cd := clause.AsCaseOrDefaultClause()
43
+ if cd == nil {
44
+ continue
45
+ }
46
+ if cd.Statements != nil && len(cd.Statements.Nodes) != 0 {
47
+ continue
48
+ }
49
+ ctx.Report(clause, "Useless `case` clause — it falls through to the `default` which would handle this value anyway.")
50
+ }
51
+ }
52
+
53
+ func init() {
54
+ Register(unicornNoUselessSwitchCase{})
55
+ }
@@ -0,0 +1,55 @@
1
+ // unicorn/no-useless-undefined: `return undefined;` produces the same
2
+ // value as the bare `return;` form, and `void 0` is the canonical
3
+ // roundabout spelling of the same constant. Writing the keyword
4
+ // explicitly adds noise without changing behavior.
5
+ //
6
+ // Minimum-viable port: only the `return` statement shape fires. The
7
+ // call-argument case is intentionally skipped because matching it
8
+ // safely requires knowing which callees accept omission, and the
9
+ // parameter-default case (`function f(x = undefined)`) is deferred.
10
+ //
11
+ // AST-only: visit each `ReturnStatement` whose expression after
12
+ // `stripParens` is either the `undefined` keyword/identifier or the
13
+ // `void 0` shape (a `VoidExpression` whose operand is the numeric
14
+ // literal `0`). Reports on the return statement itself so the
15
+ // diagnostic anchors on the keyword rather than the operand.
16
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-undefined.md
17
+ package linthost
18
+
19
+ import shimast "github.com/microsoft/typescript-go/shim/ast"
20
+
21
+ type unicornNoUselessUndefined struct{}
22
+
23
+ func (unicornNoUselessUndefined) Name() string { return "unicorn/no-useless-undefined" }
24
+ func (unicornNoUselessUndefined) Visits() []shimast.Kind {
25
+ return []shimast.Kind{shimast.KindReturnStatement}
26
+ }
27
+ func (unicornNoUselessUndefined) Check(ctx *Context, node *shimast.Node) {
28
+ ret := node.AsReturnStatement()
29
+ if ret == nil || ret.Expression == nil {
30
+ return
31
+ }
32
+ expr := stripParens(ret.Expression)
33
+ if expr == nil {
34
+ return
35
+ }
36
+ if expr.Kind == shimast.KindUndefinedKeyword || identifierText(expr) == "undefined" {
37
+ ctx.Report(node, "Don't `return undefined;` — `return undefined;` and bare `return;` have the same effect.")
38
+ return
39
+ }
40
+ if expr.Kind == shimast.KindVoidExpression {
41
+ void := expr.AsVoidExpression()
42
+ if void == nil || void.Expression == nil {
43
+ return
44
+ }
45
+ operand := stripParens(void.Expression)
46
+ if operand != nil && operand.Kind == shimast.KindNumericLiteral &&
47
+ numericLiteralText(operand) == "0" {
48
+ ctx.Report(node, "Don't `return undefined;` — `return undefined;` and bare `return;` have the same effect.")
49
+ }
50
+ }
51
+ }
52
+
53
+ func init() {
54
+ Register(unicornNoUselessUndefined{})
55
+ }
@@ -0,0 +1,52 @@
1
+ // unicorn/no-zero-fractions: numeric literals such as `1.0`, `1.`, and
2
+ // `.0` carry a redundant fractional component or a trailing dot whose
3
+ // only visual effect is to mislead the reader into thinking the value
4
+ // needs floating-point semantics. The rule rewrites the source pattern
5
+ // out by reporting on the literal node.
6
+ //
7
+ // AST-only: visit `KindNumericLiteral`, read the raw source text via
8
+ // `nodeText` so the parser-normalized `.Text` (which drops the trailing
9
+ // dot and zero-pad) doesn't mask the smell, and match three regular
10
+ // expressions covering the canonical shapes:
11
+ //
12
+ // - `1.0`, `1.00`, `-1.0e5` — fractional part is all zeros.
13
+ // - `1.` — trailing dot with no fractional digits.
14
+ // - `.0`, `-.0e3` — leading dot with an all-zero fractional part.
15
+ //
16
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-zero-fractions.md
17
+ package linthost
18
+
19
+ import (
20
+ "regexp"
21
+ "strings"
22
+
23
+ shimast "github.com/microsoft/typescript-go/shim/ast"
24
+ )
25
+
26
+ var (
27
+ unicornNoZeroFractionsTrailingZero = regexp.MustCompile(`^-?\d+\.0+([eE][+-]?\d+)?$`)
28
+ unicornNoZeroFractionsTrailingDot = regexp.MustCompile(`^-?\d+\.$`)
29
+ unicornNoZeroFractionsLeadingDot = regexp.MustCompile(`^-?\.0+([eE][+-]?\d+)?$`)
30
+ )
31
+
32
+ type unicornNoZeroFractions struct{}
33
+
34
+ func (unicornNoZeroFractions) Name() string { return "unicorn/no-zero-fractions" }
35
+ func (unicornNoZeroFractions) Visits() []shimast.Kind {
36
+ return []shimast.Kind{shimast.KindNumericLiteral}
37
+ }
38
+ func (unicornNoZeroFractions) Check(ctx *Context, node *shimast.Node) {
39
+ source := strings.TrimSpace(nodeText(ctx.File, node))
40
+ if source == "" {
41
+ return
42
+ }
43
+ if unicornNoZeroFractionsTrailingZero.MatchString(source) ||
44
+ unicornNoZeroFractionsTrailingDot.MatchString(source) ||
45
+ unicornNoZeroFractionsLeadingDot.MatchString(source) {
46
+ ctx.Report(node, "Don't use a redundant `.0` fraction or trailing dot on a number literal.")
47
+ }
48
+ }
49
+
50
+ func init() {
51
+ Register(unicornNoZeroFractions{})
52
+ }
@@ -0,0 +1,69 @@
1
+ // unicorn/number-literal-case: hex / binary / octal numeric literals
2
+ // have a conventional canonical form — the radix prefix is lowercase
3
+ // (`0x`, `0b`, `0o`) while hex digits are uppercase (`0xFF`). Mixed-case
4
+ // alternatives (`0Xff`, `0xff`, `0xFf`, `0XFF`) read inconsistently and
5
+ // the rule normalizes the codebase by reporting every literal that
6
+ // isn't already canonical.
7
+ //
8
+ // AST-only: visit `KindNumericLiteral` and `KindBigIntLiteral`, read
9
+ // the raw source text via `nodeText` so the prefix and digit casing
10
+ // survive the parser's normalization, and report when the prefix letter
11
+ // is uppercase OR any hex digit is lowercase. Decimal literals lack a
12
+ // prefix and never fire.
13
+ //
14
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/number-literal-case.md
15
+ package linthost
16
+
17
+ import (
18
+ "strings"
19
+
20
+ shimast "github.com/microsoft/typescript-go/shim/ast"
21
+ )
22
+
23
+ type unicornNumberLiteralCase struct{}
24
+
25
+ func (unicornNumberLiteralCase) Name() string { return "unicorn/number-literal-case" }
26
+ func (unicornNumberLiteralCase) Visits() []shimast.Kind {
27
+ return []shimast.Kind{shimast.KindNumericLiteral, shimast.KindBigIntLiteral}
28
+ }
29
+ func (unicornNumberLiteralCase) Check(ctx *Context, node *shimast.Node) {
30
+ source := strings.TrimSpace(nodeText(ctx.File, node))
31
+ if len(source) < 2 || source[0] != '0' {
32
+ return
33
+ }
34
+ prefix := source[1]
35
+ switch prefix {
36
+ case 'x', 'X':
37
+ if unicornNumberLiteralCaseHexNeedsFix(source, prefix) {
38
+ ctx.Report(node, "Number literals should use a lowercase prefix and uppercase digits — e.g. `0xFF` instead of `0xff`.")
39
+ }
40
+ case 'b', 'B', 'o', 'O':
41
+ // Binary / octal digits are 0-1 / 0-7; only the prefix letter
42
+ // can be in the wrong case.
43
+ if prefix == 'B' || prefix == 'O' {
44
+ ctx.Report(node, "Number literals should use a lowercase prefix and uppercase digits — e.g. `0xFF` instead of `0xff`.")
45
+ }
46
+ }
47
+ }
48
+
49
+ // unicornNumberLiteralCaseHexNeedsFix reports whether the hex literal's
50
+ // raw source text deviates from `0x` + uppercase digits. The trailing
51
+ // `n` of a hex bigint literal (`0xFFn`) is allowed.
52
+ func unicornNumberLiteralCaseHexNeedsFix(source string, prefix byte) bool {
53
+ if prefix != 'x' {
54
+ return true
55
+ }
56
+ digits := source[2:]
57
+ digits = strings.TrimSuffix(digits, "n")
58
+ for i := 0; i < len(digits); i++ {
59
+ ch := digits[i]
60
+ if ch >= 'a' && ch <= 'f' {
61
+ return true
62
+ }
63
+ }
64
+ return false
65
+ }
66
+
67
+ func init() {
68
+ Register(unicornNumberLiteralCase{})
69
+ }