@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,104 @@
1
+ // AST-only baseline of typescript-eslint's `prefer-nullish-coalescing`.
2
+ //
3
+ // The rule discourages `x || y`, `x ||= y`, and the ternary `x ? x : y`
4
+ // pattern when the intent is to substitute a default for `null` /
5
+ // `undefined`. `||` short-circuits on every falsy value (0, "", false,
6
+ // NaN), so what reads as "default this if missing" silently coerces
7
+ // legitimate zeros and empty strings. The ES2020 `??` operator
8
+ // short-circuits only on nullish values and is almost always what the
9
+ // author meant.
10
+ //
11
+ // Without the Checker the rule cannot prove `x` actually admits
12
+ // `null | undefined`, so the conservative AST-only baseline skips
13
+ // operands that the surrounding context already coerces to boolean —
14
+ // `if (a || b)`, `!(a || b)`, `cond ? a || b : …`, etc. — and fires on
15
+ // the remaining value-producing positions. This mirrors the upstream
16
+ // rule's behavior on plain JS where strictNullChecks is off and the
17
+ // rule still flags the same shapes.
18
+ // https://typescript-eslint.io/rules/prefer-nullish-coalescing/
19
+ package linthost
20
+
21
+ import (
22
+ shimast "github.com/microsoft/typescript-go/shim/ast"
23
+ )
24
+
25
+ type preferNullishCoalescing struct{}
26
+
27
+ func (preferNullishCoalescing) Name() string { return "typescript/prefer-nullish-coalescing" }
28
+ func (preferNullishCoalescing) Visits() []shimast.Kind {
29
+ return []shimast.Kind{
30
+ shimast.KindBinaryExpression,
31
+ shimast.KindConditionalExpression,
32
+ }
33
+ }
34
+ func (preferNullishCoalescing) Check(ctx *Context, node *shimast.Node) {
35
+ switch node.Kind {
36
+ case shimast.KindBinaryExpression:
37
+ expr := node.AsBinaryExpression()
38
+ if expr == nil || expr.OperatorToken == nil {
39
+ return
40
+ }
41
+ switch expr.OperatorToken.Kind {
42
+ case shimast.KindBarBarToken:
43
+ if isInBooleanContext(node) {
44
+ return
45
+ }
46
+ reportPreferNullishCoalescing(ctx, expr.OperatorToken, "Prefer `??` over `||` when the intent is to default `null` / `undefined` — `||` also short-circuits on falsy values like 0, \"\", and false.")
47
+ case shimast.KindBarBarEqualsToken:
48
+ reportPreferNullishCoalescing(ctx, expr.OperatorToken, "Prefer `??=` over `||=` when the intent is to default `null` / `undefined` — `||=` also assigns on falsy values like 0, \"\", and false.")
49
+ }
50
+ case shimast.KindConditionalExpression:
51
+ cond := node.AsConditionalExpression()
52
+ if cond == nil || cond.Condition == nil || cond.WhenTrue == nil {
53
+ return
54
+ }
55
+ // `x ? x : y` — the `whenTrue` branch is the same expression as
56
+ // the test. Compare canonical text after stripping parentheses
57
+ // from both sides so `(x) ? x : y` still matches.
58
+ if !ternarySelfTest(ctx, cond) {
59
+ return
60
+ }
61
+ ctx.Report(node, "Prefer `??` over `x ? x : y` when the intent is to default `null` / `undefined` — the ternary form also falls through on falsy values like 0, \"\", and false.")
62
+ }
63
+ }
64
+
65
+ // reportPreferNullishCoalescing pins the diagnostic range to the
66
+ // operator token (`||` / `||=`) rather than the whole binary expression
67
+ // so the squiggle highlights the offending operator and editor "go to
68
+ // fix" actions hover over the token the rule is about.
69
+ func reportPreferNullishCoalescing(ctx *Context, operator *shimast.Node, message string) {
70
+ pos, end := tokenRange(ctx.File, operator)
71
+ if pos < 0 {
72
+ ctx.Report(operator, message)
73
+ return
74
+ }
75
+ ctx.ReportRange(pos, end, message)
76
+ }
77
+
78
+ // ternarySelfTest reports whether `cond ? whenTrue : whenFalse` has the
79
+ // shape `x ? x : y` — i.e. the truthy branch repeats the condition. The
80
+ // comparison uses `nodeText` so parenthesized variants (`(x) ? x : y`)
81
+ // and member-access chains (`a.b ? a.b : c`) both match. Side-effecting
82
+ // expressions are intentionally not excluded here: the upstream rule
83
+ // fires on `f() ? f() : g()` too and lets the author decide whether the
84
+ // transform is safe.
85
+ func ternarySelfTest(ctx *Context, cond *shimast.ConditionalExpression) bool {
86
+ if ctx == nil || ctx.File == nil || cond == nil {
87
+ return false
88
+ }
89
+ test := stripParens(cond.Condition)
90
+ whenTrue := stripParens(cond.WhenTrue)
91
+ if test == nil || whenTrue == nil {
92
+ return false
93
+ }
94
+ testText := nodeText(ctx.File, test)
95
+ whenTrueText := nodeText(ctx.File, whenTrue)
96
+ if testText == "" || whenTrueText == "" {
97
+ return false
98
+ }
99
+ return testText == whenTrueText
100
+ }
101
+
102
+ func init() {
103
+ Register(preferNullishCoalescing{})
104
+ }
@@ -0,0 +1,228 @@
1
+ // preferOptionalChain reports `a && a.b` / `a && a.b && a.b.c` and
2
+ // `a != null && a.b` chained boolean patterns and suggests `a?.b?.c`.
3
+ // The optional-chain form is shorter and short-circuits to `undefined`
4
+ // instead of the leftmost falsy value, which is almost always what the
5
+ // author wanted when guarding a property access against a nullish base.
6
+ //
7
+ // This is the AST-only baseline: the rule fires when the receiver of
8
+ // the right-hand member access textually starts with the left-hand
9
+ // guard expression. Cases where the chain crosses through a call
10
+ // expression with arguments are skipped — those have observable side
11
+ // effects, so the `?.` form is not equivalent.
12
+ // https://typescript-eslint.io/rules/prefer-optional-chain/
13
+ package linthost
14
+
15
+ import (
16
+ "strings"
17
+
18
+ shimast "github.com/microsoft/typescript-go/shim/ast"
19
+ )
20
+
21
+ type preferOptionalChain struct{}
22
+
23
+ func (preferOptionalChain) Name() string { return "typescript/prefer-optional-chain" }
24
+ func (preferOptionalChain) Visits() []shimast.Kind {
25
+ return []shimast.Kind{shimast.KindBinaryExpression}
26
+ }
27
+ func (preferOptionalChain) Check(ctx *Context, node *shimast.Node) {
28
+ expr := node.AsBinaryExpression()
29
+ if expr == nil || expr.OperatorToken == nil {
30
+ return
31
+ }
32
+ if expr.OperatorToken.Kind != shimast.KindAmpersandAmpersandToken {
33
+ return
34
+ }
35
+ // Skip when the binary expression is itself the left side of an
36
+ // outer `&&` — the outer node will be visited and report the full
37
+ // chain. Reporting at every inner conjunct would flood `a && a.b
38
+ // && a.b.c` with two diagnostics on the same chain.
39
+ if parent := node.Parent; parent != nil && parent.Kind == shimast.KindBinaryExpression {
40
+ pe := parent.AsBinaryExpression()
41
+ if pe != nil && pe.OperatorToken != nil &&
42
+ pe.OperatorToken.Kind == shimast.KindAmpersandAmpersandToken &&
43
+ pe.Left == node {
44
+ return
45
+ }
46
+ }
47
+ guardText, ok := preferOptionalChainGuardText(ctx, expr.Left)
48
+ if !ok {
49
+ return
50
+ }
51
+ right := stripParens(expr.Right)
52
+ if !preferOptionalChainRightMatches(ctx, right, guardText) {
53
+ return
54
+ }
55
+ ctx.Report(node, "Prefer an optional chain (`a?.b`) over `a && a.b` — shorter and short-circuits to `undefined` instead of the leftmost falsy value.")
56
+ }
57
+
58
+ // preferOptionalChainRightmostConjunct returns the rightmost operand
59
+ // of a left-associative `&&` chain. For `(a && a.b) && a.b.c` the
60
+ // rightmost conjunct of the left is `a.b`, which is the immediate
61
+ // guard the outer `&&` was extending.
62
+ func preferOptionalChainRightmostConjunct(node *shimast.Node) *shimast.Node {
63
+ node = stripParens(node)
64
+ for node != nil && node.Kind == shimast.KindBinaryExpression {
65
+ inner := node.AsBinaryExpression()
66
+ if inner == nil || inner.OperatorToken == nil ||
67
+ inner.OperatorToken.Kind != shimast.KindAmpersandAmpersandToken ||
68
+ inner.Right == nil {
69
+ return node
70
+ }
71
+ node = stripParens(inner.Right)
72
+ }
73
+ return node
74
+ }
75
+
76
+ // preferOptionalChainGuardText returns the textual identity of the
77
+ // guard expression on the left of `&&`. The guard may be an identifier
78
+ // (`a && a.b`), a property access (`a.b && a.b.c`), or a `!= null` /
79
+ // `!== null` / `!== undefined` comparison (`a != null && a.b`). For the
80
+ // comparison form, the returned text is the non-null side, which is
81
+ // what the right-hand access must start with.
82
+ func preferOptionalChainGuardText(ctx *Context, left *shimast.Node) (string, bool) {
83
+ left = stripParens(left)
84
+ if left == nil {
85
+ return "", false
86
+ }
87
+ switch left.Kind {
88
+ case shimast.KindIdentifier, shimast.KindPropertyAccessExpression:
89
+ text := nodeText(ctx.File, left)
90
+ return text, text != ""
91
+ case shimast.KindBinaryExpression:
92
+ inner := left.AsBinaryExpression()
93
+ if inner == nil || inner.OperatorToken == nil {
94
+ return "", false
95
+ }
96
+ // Chain extension: `(x && a.b) && a.b.c` — peel down to the
97
+ // rightmost conjunct (`a.b`) and use it as the guard against
98
+ // the outer right side.
99
+ if inner.OperatorToken.Kind == shimast.KindAmpersandAmpersandToken {
100
+ conjunct := preferOptionalChainRightmostConjunct(left)
101
+ if conjunct == nil {
102
+ return "", false
103
+ }
104
+ switch conjunct.Kind {
105
+ case shimast.KindIdentifier, shimast.KindPropertyAccessExpression:
106
+ text := nodeText(ctx.File, conjunct)
107
+ return text, text != ""
108
+ }
109
+ return "", false
110
+ }
111
+ if inner.OperatorToken.Kind != shimast.KindExclamationEqualsToken &&
112
+ inner.OperatorToken.Kind != shimast.KindExclamationEqualsEqualsToken {
113
+ return "", false
114
+ }
115
+ lhs := stripParens(inner.Left)
116
+ rhs := stripParens(inner.Right)
117
+ if subject, ok := preferOptionalChainNullishCompareSubject(ctx, lhs, rhs); ok {
118
+ return subject, true
119
+ }
120
+ if subject, ok := preferOptionalChainNullishCompareSubject(ctx, rhs, lhs); ok {
121
+ return subject, true
122
+ }
123
+ }
124
+ return "", false
125
+ }
126
+
127
+ // preferOptionalChainNullishCompareSubject returns the textual identity
128
+ // of `subject` when `nullish` is `null` or `undefined` and `subject` is
129
+ // an identifier or property access. Returns the empty text otherwise.
130
+ func preferOptionalChainNullishCompareSubject(
131
+ ctx *Context,
132
+ subject, nullish *shimast.Node,
133
+ ) (string, bool) {
134
+ if subject == nil || nullish == nil {
135
+ return "", false
136
+ }
137
+ if !preferOptionalChainIsNullOrUndefined(nullish) {
138
+ return "", false
139
+ }
140
+ switch subject.Kind {
141
+ case shimast.KindIdentifier, shimast.KindPropertyAccessExpression:
142
+ text := nodeText(ctx.File, subject)
143
+ return text, text != ""
144
+ }
145
+ return "", false
146
+ }
147
+
148
+ // preferOptionalChainIsNullOrUndefined reports whether node is the
149
+ // `null` keyword or the `undefined` identifier.
150
+ func preferOptionalChainIsNullOrUndefined(node *shimast.Node) bool {
151
+ if node == nil {
152
+ return false
153
+ }
154
+ if node.Kind == shimast.KindNullKeyword {
155
+ return true
156
+ }
157
+ if node.Kind == shimast.KindIdentifier {
158
+ return identifierText(node) == "undefined"
159
+ }
160
+ return false
161
+ }
162
+
163
+ // preferOptionalChainRightMatches reports whether `right` is a
164
+ // property access or call expression whose receiver textually starts
165
+ // with `guardText` followed by `.` or `[`. Calls with arguments are
166
+ // rejected — the `?.` rewrite would not preserve side-effect ordering
167
+ // when the arguments themselves can have side effects.
168
+ func preferOptionalChainRightMatches(
169
+ ctx *Context,
170
+ right *shimast.Node,
171
+ guardText string,
172
+ ) bool {
173
+ if right == nil || guardText == "" {
174
+ return false
175
+ }
176
+ switch right.Kind {
177
+ case shimast.KindPropertyAccessExpression:
178
+ access := right.AsPropertyAccessExpression()
179
+ if access == nil || access.Expression == nil {
180
+ return false
181
+ }
182
+ return preferOptionalChainHasPrefix(ctx, right, guardText)
183
+ case shimast.KindCallExpression:
184
+ call := right.AsCallExpression()
185
+ if call == nil || call.Expression == nil {
186
+ return false
187
+ }
188
+ // Skip calls with arguments — their evaluation cannot be
189
+ // observed identically through `?.()`.
190
+ if call.Arguments != nil && len(call.Arguments.Nodes) > 0 {
191
+ return false
192
+ }
193
+ // The callee receiver must itself be a property access; a
194
+ // bare identifier call (`a()`) has no chain to fold.
195
+ callee := stripParens(call.Expression)
196
+ if callee == nil || callee.Kind != shimast.KindPropertyAccessExpression {
197
+ return false
198
+ }
199
+ return preferOptionalChainHasPrefix(ctx, right, guardText)
200
+ }
201
+ return false
202
+ }
203
+
204
+ // preferOptionalChainHasPrefix returns whether the textual form of
205
+ // `node` begins with `guard` followed by a `.` or `[` — the only
206
+ // continuations that mean "a property of the guarded value".
207
+ func preferOptionalChainHasPrefix(
208
+ ctx *Context,
209
+ node *shimast.Node,
210
+ guard string,
211
+ ) bool {
212
+ text := nodeText(ctx.File, node)
213
+ if !strings.HasPrefix(text, guard) {
214
+ return false
215
+ }
216
+ if len(text) == len(guard) {
217
+ return false
218
+ }
219
+ switch text[len(guard)] {
220
+ case '.', '[', '(':
221
+ return true
222
+ }
223
+ return false
224
+ }
225
+
226
+ func init() {
227
+ Register(preferOptionalChain{})
228
+ }
@@ -0,0 +1,176 @@
1
+ // TypeScript-aware analog of typescript/only-throw-error for Promise
2
+ // rejection sites: `Promise.reject(value)` should hand callers an Error
3
+ // instance, not a primitive or other non-Error value. A non-Error
4
+ // rejection loses the structured stack trace and breaks downstream
5
+ // `instanceof Error` checks in `.catch(...)` / `try { await … } catch
6
+ // (err)` handlers. typescript-eslint:
7
+ // https://typescript-eslint.io/rules/prefer-promise-reject-errors/
8
+ package linthost
9
+
10
+ import (
11
+ shimast "github.com/microsoft/typescript-go/shim/ast"
12
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
13
+ )
14
+
15
+ // preferPromiseRejectErrors reports `Promise.reject(arg)`, `p.reject(arg)`
16
+ // on a Promise-typed receiver, and `reject(arg)` calls to the second
17
+ // parameter of a `new Promise((_, reject) => …)` executor when `arg`'s
18
+ // static type is a primitive (string / number / boolean / bigint / void
19
+ // / undefined / null). Mirrors `onlyThrowError` for `throw` statements.
20
+ //
21
+ // Type-aware. `any` / `unknown` / `never` pass through — they propagate
22
+ // from generic helpers and a strict rejection would explode at every
23
+ // re-reject of a caught `unknown`. Object types (including plain object
24
+ // literals) are conservatively allowed by this baseline; the practical
25
+ // effect is that `Promise.reject("boom")` and `Promise.reject(42)` are
26
+ // caught but `Promise.reject({ code: 1 })` slips through.
27
+ type preferPromiseRejectErrors struct{}
28
+
29
+ func (preferPromiseRejectErrors) Name() string {
30
+ return "typescript/prefer-promise-reject-errors"
31
+ }
32
+ func (preferPromiseRejectErrors) NeedsTypeChecker() bool {
33
+ return true
34
+ }
35
+ func (preferPromiseRejectErrors) Visits() []shimast.Kind {
36
+ return []shimast.Kind{shimast.KindCallExpression}
37
+ }
38
+ func (preferPromiseRejectErrors) Check(ctx *Context, node *shimast.Node) {
39
+ if ctx.Checker == nil {
40
+ return
41
+ }
42
+ call := node.AsCallExpression()
43
+ if call == nil || call.Expression == nil {
44
+ return
45
+ }
46
+ if !preferPromiseRejectErrorsIsRejectCall(ctx, call, node) {
47
+ return
48
+ }
49
+ if call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
50
+ return
51
+ }
52
+ arg := stripParens(call.Arguments.Nodes[0])
53
+ if arg == nil {
54
+ return
55
+ }
56
+ t := ctx.Checker.GetTypeAtLocation(arg)
57
+ if t == nil {
58
+ return
59
+ }
60
+ if preferPromiseRejectErrorsIsNonError(ctx.Checker, t) {
61
+ ctx.Report(node, "Reject promises with an Error object instead of a non-Error value.")
62
+ }
63
+ }
64
+
65
+ // preferPromiseRejectErrorsIsRejectCall returns true when `call` is one of
66
+ // - `Promise.reject(arg)`
67
+ // - `<promise-typed-receiver>.reject(arg)`
68
+ // - a bare `reject(arg)` call to the second parameter name of an
69
+ // enclosing `new Promise((_, reject) => …)` executor.
70
+ //
71
+ // `node` is the AST node form of `call`, used for the parent walk.
72
+ func preferPromiseRejectErrorsIsRejectCall(ctx *Context, call *shimast.CallExpression, node *shimast.Node) bool {
73
+ receiver, method, ok := promisePropertyAccessParts(call.Expression)
74
+ if ok && method == "reject" {
75
+ if identifierText(receiver) == "Promise" {
76
+ return true
77
+ }
78
+ if ctx.Checker != nil && receiver != nil {
79
+ if t := ctx.Checker.GetTypeAtLocation(receiver); t != nil &&
80
+ isPromiseTypedExpression(ctx.Checker, t) {
81
+ return true
82
+ }
83
+ }
84
+ return false
85
+ }
86
+ // Bare identifier call — check Promise executor binding.
87
+ name := callCalleeName(call)
88
+ if name == "" {
89
+ return false
90
+ }
91
+ return preferPromiseRejectErrorsIsExecutorReject(node, name)
92
+ }
93
+
94
+ // preferPromiseRejectErrorsIsExecutorReject walks parent function-like
95
+ // scopes from `node` and reports true when one of those scopes is the
96
+ // executor parameter of `new Promise(...)` and the executor's second
97
+ // parameter is named `name`. Mirrors the param walking used by
98
+ // `promiseNoMultipleResolved`.
99
+ func preferPromiseRejectErrorsIsExecutorReject(node *shimast.Node, name string) bool {
100
+ for fn := nearestFunctionLike(node); fn != nil; fn = nearestFunctionLike(fn) {
101
+ if !preferPromiseRejectErrorsIsPromiseExecutorFn(fn) {
102
+ continue
103
+ }
104
+ params := fn.Parameters()
105
+ if len(params) < 2 {
106
+ continue
107
+ }
108
+ if parameterIdentifierName(params[1]) == name {
109
+ return true
110
+ }
111
+ }
112
+ return false
113
+ }
114
+
115
+ // preferPromiseRejectErrorsIsPromiseExecutorFn reports whether `fn` is
116
+ // the first argument of an enclosing `new Promise(...)` expression. The
117
+ // walk strips parentheses the same way `isPromiseCallbackFunctionFor`
118
+ // does in rules_promise.go so `new Promise(((_, reject) => …))` still
119
+ // matches.
120
+ func preferPromiseRejectErrorsIsPromiseExecutorFn(fn *shimast.Node) bool {
121
+ if fn == nil || !isFunctionLikeKind(fn) {
122
+ return false
123
+ }
124
+ cur := fn
125
+ for parent := cur.Parent; parent != nil && parent.Kind == shimast.KindParenthesizedExpression; parent = parent.Parent {
126
+ cur = parent
127
+ }
128
+ newExpr := cur.Parent
129
+ if newExpr == nil || newExpr.Kind != shimast.KindNewExpression {
130
+ return false
131
+ }
132
+ ne := newExpr.AsNewExpression()
133
+ if ne == nil || identifierText(ne.Expression) != "Promise" || ne.Arguments == nil || len(ne.Arguments.Nodes) == 0 {
134
+ return false
135
+ }
136
+ return stripParens(ne.Arguments.Nodes[0]) == fn
137
+ }
138
+
139
+ // preferPromiseRejectErrorsIsNonError mirrors `onlyThrowErrorIsPrimitive`
140
+ // in rules_ts_async.go. `any` / `unknown` / `never` are intentionally
141
+ // NOT flagged because they propagate from generic helpers; an Error
142
+ // instance fed through such a helper would otherwise produce noise.
143
+ // Union and intersection types recurse: a constituent that is primitive
144
+ // is enough to fire, matching the throw-side baseline.
145
+ func preferPromiseRejectErrorsIsNonError(checker *shimchecker.Checker, t *shimchecker.Type) bool {
146
+ if checker == nil || t == nil {
147
+ return false
148
+ }
149
+ flags := t.Flags()
150
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
151
+ return false
152
+ }
153
+ if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
154
+ for _, part := range t.Types() {
155
+ if part == nil {
156
+ continue
157
+ }
158
+ if preferPromiseRejectErrorsIsNonError(checker, part) {
159
+ return true
160
+ }
161
+ }
162
+ return false
163
+ }
164
+ const primitiveMask = shimchecker.TypeFlagsStringLike |
165
+ shimchecker.TypeFlagsNumberLike |
166
+ shimchecker.TypeFlagsBigIntLike |
167
+ shimchecker.TypeFlagsBooleanLike |
168
+ shimchecker.TypeFlagsVoid |
169
+ shimchecker.TypeFlagsUndefined |
170
+ shimchecker.TypeFlagsNull
171
+ return flags&primitiveMask != 0
172
+ }
173
+
174
+ func init() {
175
+ Register(preferPromiseRejectErrors{})
176
+ }
@@ -0,0 +1,73 @@
1
+ // preferReadonly reports private class fields that are initialized at
2
+ // the declaration site (so the constructor has nothing left to assign)
3
+ // and could safely carry the `readonly` modifier. Locking the field as
4
+ // readonly catches accidental reassignments and signals the field's
5
+ // intent to readers without changing runtime behavior.
6
+ //
7
+ // AST-only baseline. Without a full body walk the rule cannot prove that
8
+ // no other method writes to the field, so the conservative trigger is:
9
+ //
10
+ // - the member is a PropertyDeclaration sitting in a class body,
11
+ // - it carries `private` or uses the `#name` private-hash form,
12
+ // - it does not already carry `readonly`,
13
+ // - it has a value initializer at declaration time.
14
+ //
15
+ // A property initialized at declaration time gets its value before the
16
+ // constructor runs, and a field that is also reassigned elsewhere
17
+ // usually does not bother to initialize at the declaration site. The
18
+ // pattern is the noisy upstream subset of the rule that is safe to
19
+ // flag without scope analysis.
20
+ // https://typescript-eslint.io/rules/prefer-readonly/
21
+ package linthost
22
+
23
+ import (
24
+ shimast "github.com/microsoft/typescript-go/shim/ast"
25
+ )
26
+
27
+ type preferReadonly struct{}
28
+
29
+ func (preferReadonly) Name() string { return "typescript/prefer-readonly" }
30
+ func (preferReadonly) Visits() []shimast.Kind {
31
+ return []shimast.Kind{shimast.KindPropertyDeclaration}
32
+ }
33
+ func (preferReadonly) Check(ctx *Context, node *shimast.Node) {
34
+ // Skip non-class-scoped properties; PropertyDeclaration also appears
35
+ // inside object literals in some grammars, but the readonly modifier
36
+ // is a class-only concern.
37
+ parent := node.Parent
38
+ if parent == nil ||
39
+ (parent.Kind != shimast.KindClassDeclaration && parent.Kind != shimast.KindClassExpression) {
40
+ return
41
+ }
42
+ if hasModifier(node, shimast.KindReadonlyKeyword) {
43
+ return
44
+ }
45
+ if !preferReadonlyIsPrivate(node) {
46
+ return
47
+ }
48
+ decl := node.AsPropertyDeclaration()
49
+ if decl == nil || decl.Initializer == nil {
50
+ return
51
+ }
52
+ // Static fields are still candidates — `private static readonly` is
53
+ // the canonical form for class-scoped constants.
54
+ ctx.Report(node, "Private field is only initialized at declaration time — mark it `readonly`.")
55
+ }
56
+
57
+ // preferReadonlyIsPrivate reports whether the property is private either
58
+ // through the `private` modifier or through the `#name` private-hash
59
+ // identifier form. Both make the field inaccessible from outside the
60
+ // class, so `readonly` is a safe local refinement.
61
+ func preferReadonlyIsPrivate(node *shimast.Node) bool {
62
+ if hasModifier(node, shimast.KindPrivateKeyword) {
63
+ return true
64
+ }
65
+ if name := node.Name(); name != nil && name.Kind == shimast.KindPrivateIdentifier {
66
+ return true
67
+ }
68
+ return false
69
+ }
70
+
71
+ func init() {
72
+ Register(preferReadonly{})
73
+ }
@@ -0,0 +1,116 @@
1
+ // typescript/prefer-reduce-type-parameter: when `arr.reduce(cb, init)`
2
+ // is called with an `as`-asserted initial value, fix the accumulator
3
+ // type at the call site via `arr.reduce<T>(cb, init)` instead. The
4
+ // type-parameter form binds the accumulator before the callback infers
5
+ // its parameter types from the seed, so the callback sees the intended
6
+ // type instead of the seed's widened literal shape. typescript-eslint:
7
+ // https://typescript-eslint.io/rules/prefer-reduce-type-parameter/
8
+ //
9
+ // Type-aware. Without a Checker the rule cannot prove the receiver of
10
+ // `.reduce` is an array or tuple — user types named `reduce` are
11
+ // common (`Map#reduce`, custom accumulators, etc.) and assertion-on-
12
+ // initial-value is occasionally idiomatic there. The receiver must be
13
+ // a provable array or tuple; generics, `any`, `unknown`, and `never`
14
+ // pass through to keep generic helpers quiet.
15
+ package linthost
16
+
17
+ import (
18
+ shimast "github.com/microsoft/typescript-go/shim/ast"
19
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
20
+ )
21
+
22
+ type preferReduceTypeParameter struct{}
23
+
24
+ func (preferReduceTypeParameter) Name() string {
25
+ return "typescript/prefer-reduce-type-parameter"
26
+ }
27
+ func (preferReduceTypeParameter) NeedsTypeChecker() bool {
28
+ return true
29
+ }
30
+ func (preferReduceTypeParameter) Visits() []shimast.Kind {
31
+ return []shimast.Kind{shimast.KindCallExpression}
32
+ }
33
+ func (preferReduceTypeParameter) Check(ctx *Context, node *shimast.Node) {
34
+ if ctx.Checker == nil {
35
+ return
36
+ }
37
+ call := node.AsCallExpression()
38
+ if call == nil || call.Expression == nil {
39
+ return
40
+ }
41
+ // `arr.reduce<T>(...)` already pins the accumulator at the call
42
+ // site — the rule has nothing left to suggest.
43
+ if call.TypeArguments != nil && len(call.TypeArguments.Nodes) > 0 {
44
+ return
45
+ }
46
+ // The call must be `<receiver>.reduce(callback, initial)` — the
47
+ // two-argument form whose seed is the accumulator. The single-
48
+ // argument `arr.reduce(cb)` shape has no seed to assert against.
49
+ if call.Arguments == nil || len(call.Arguments.Nodes) != 2 {
50
+ return
51
+ }
52
+ receiver, method, ok := promisePropertyAccessParts(call.Expression)
53
+ if !ok || method != "reduce" {
54
+ return
55
+ }
56
+ initial := stripParens(call.Arguments.Nodes[1])
57
+ if initial == nil {
58
+ return
59
+ }
60
+ // The initial value must carry an explicit type assertion that the
61
+ // rule can hoist into the call's type parameter list. Both the
62
+ // canonical `init as T` form and the legacy `<T>init` form qualify.
63
+ if initial.Kind != shimast.KindAsExpression && initial.Kind != shimast.KindTypeAssertionExpression {
64
+ return
65
+ }
66
+ if receiver == nil {
67
+ return
68
+ }
69
+ t := ctx.Checker.GetTypeAtLocation(receiver)
70
+ if t == nil {
71
+ return
72
+ }
73
+ if !preferReduceIsArrayOrTuple(ctx.Checker, t) {
74
+ return
75
+ }
76
+ ctx.Report(initial, preferReduceMessage)
77
+ }
78
+
79
+ const preferReduceMessage = "Pass the accumulator type to `reduce` as a type parameter — `arr.reduce<T>(cb, init)` — instead of asserting on the initial value."
80
+
81
+ // preferReduceIsArrayOrTuple reports whether t is provably an array or
82
+ // tuple. Mirrors `preferIncludesIsArrayOrString` but excludes strings
83
+ // (which have no `.reduce`). Generics, `any`, `unknown`, and `never`
84
+ // intentionally fail closed so the rule does not blow up on generic
85
+ // helpers whose receiver type leaks downward.
86
+ func preferReduceIsArrayOrTuple(checker *shimchecker.Checker, t *shimchecker.Type) bool {
87
+ if checker == nil || t == nil {
88
+ return false
89
+ }
90
+ flags := t.Flags()
91
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
92
+ return false
93
+ }
94
+ if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
95
+ for _, part := range t.Types() {
96
+ if part == nil {
97
+ continue
98
+ }
99
+ if !preferReduceIsArrayOrTuple(checker, part) {
100
+ return false
101
+ }
102
+ }
103
+ return true
104
+ }
105
+ if shimchecker.Checker_isArrayType(checker, t) {
106
+ return true
107
+ }
108
+ if shimchecker.IsTupleType(t) {
109
+ return true
110
+ }
111
+ return false
112
+ }
113
+
114
+ func init() {
115
+ Register(preferReduceTypeParameter{})
116
+ }