@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,144 @@
1
+ // typescript/sort-type-constituents: union and intersection type
2
+ // constituents render the same set of values regardless of the order
3
+ // the author chose, so two authors writing the same type can disagree
4
+ // on the spelling. The rule pins one canonical ordering — primitives
5
+ // alphabetized first, then named / object types alphabetized, then
6
+ // `null` / `undefined` last — so reviewers don't have to argue about
7
+ // which spelling to land. typescript-eslint:
8
+ // https://typescript-eslint.io/rules/sort-type-constituents/
9
+ package linthost
10
+
11
+ import (
12
+ "sort"
13
+ "strings"
14
+
15
+ shimast "github.com/microsoft/typescript-go/shim/ast"
16
+ )
17
+
18
+ // sortTypeConstituents fires on `UnionType` and `IntersectionType` when
19
+ // the constituent order does not match the canonical ordering. The
20
+ // check is AST-only: ordering is decided by syntactic group (keyword
21
+ // primitive vs. named reference vs. nullish) and a within-group source
22
+ // sort, none of which need the Checker.
23
+ //
24
+ // The diagnostic anchors to the union / intersection node so the
25
+ // rendered location names the whole type, not just one constituent.
26
+ // One report per misordered type is enough — the autofixer would
27
+ // rewrite the entire list together anyway.
28
+ type sortTypeConstituents struct{}
29
+
30
+ func (sortTypeConstituents) Name() string {
31
+ return "typescript/sort-type-constituents"
32
+ }
33
+ func (sortTypeConstituents) Visits() []shimast.Kind {
34
+ return []shimast.Kind{
35
+ shimast.KindUnionType,
36
+ shimast.KindIntersectionType,
37
+ }
38
+ }
39
+ func (sortTypeConstituents) Check(ctx *Context, node *shimast.Node) {
40
+ types := unionOrIntersectionTypes(node)
41
+ if len(types) < 2 {
42
+ return
43
+ }
44
+ // Skip nested unions/intersections — the outermost shape is the one
45
+ // the user wrote, and reporting on every nesting level would
46
+ // double-fire on `(A | B) | C` shapes.
47
+ if node.Parent != nil &&
48
+ (node.Parent.Kind == shimast.KindUnionType || node.Parent.Kind == shimast.KindIntersectionType) {
49
+ return
50
+ }
51
+ entries := make([]sortTypeConstituentsEntry, len(types))
52
+ for i, t := range types {
53
+ entries[i] = sortTypeConstituentsEntry{
54
+ index: i,
55
+ group: sortTypeConstituentsClassify(t),
56
+ text: strings.TrimSpace(nodeText(ctx.File, t)),
57
+ }
58
+ }
59
+ sorted := make([]sortTypeConstituentsEntry, len(entries))
60
+ copy(sorted, entries)
61
+ sort.SliceStable(sorted, func(i, j int) bool {
62
+ if sorted[i].group != sorted[j].group {
63
+ return sorted[i].group < sorted[j].group
64
+ }
65
+ return sorted[i].text < sorted[j].text
66
+ })
67
+ for i := range entries {
68
+ if entries[i].index != sorted[i].index {
69
+ label := "union"
70
+ if node.Kind == shimast.KindIntersectionType {
71
+ label = "intersection"
72
+ }
73
+ ctx.Report(node, "Constituents of the "+label+" are not in the canonical order — primitives alphabetized first, named types alphabetized next, `null` / `undefined` last.")
74
+ return
75
+ }
76
+ }
77
+ }
78
+
79
+ // sortTypeConstituentsEntry is one constituent's sort key. `index`
80
+ // records the original position so the reorder check can compare the
81
+ // before/after sequences without losing identity.
82
+ type sortTypeConstituentsEntry struct {
83
+ index int
84
+ group int
85
+ text string
86
+ }
87
+
88
+ // sortTypeConstituentsClassify buckets a constituent into one of the
89
+ // canonical groups. Smaller numbers come first in the canonical order.
90
+ func sortTypeConstituentsClassify(node *shimast.Node) int {
91
+ if node == nil {
92
+ return sortTypeConstituentsGroupNamed
93
+ }
94
+ switch node.Kind {
95
+ case shimast.KindStringKeyword,
96
+ shimast.KindNumberKeyword,
97
+ shimast.KindBooleanKeyword,
98
+ shimast.KindBigIntKeyword,
99
+ shimast.KindSymbolKeyword,
100
+ shimast.KindAnyKeyword,
101
+ shimast.KindUnknownKeyword,
102
+ shimast.KindVoidKeyword,
103
+ shimast.KindNeverKeyword,
104
+ shimast.KindObjectKeyword:
105
+ return sortTypeConstituentsGroupPrimitive
106
+ case shimast.KindLiteralType:
107
+ // `null` and `undefined` parse as LiteralType / undefined
108
+ // keyword inside type position — surface them as the nullish
109
+ // group so the canonical order keeps them at the end.
110
+ if sortTypeConstituentsIsNullish(node) {
111
+ return sortTypeConstituentsGroupNullish
112
+ }
113
+ return sortTypeConstituentsGroupLiteral
114
+ case shimast.KindUndefinedKeyword, shimast.KindNullKeyword:
115
+ return sortTypeConstituentsGroupNullish
116
+ }
117
+ return sortTypeConstituentsGroupNamed
118
+ }
119
+
120
+ const (
121
+ sortTypeConstituentsGroupPrimitive = iota
122
+ sortTypeConstituentsGroupLiteral
123
+ sortTypeConstituentsGroupNamed
124
+ sortTypeConstituentsGroupNullish
125
+ )
126
+
127
+ // sortTypeConstituentsIsNullish reports whether a LiteralType node
128
+ // wraps the `null` keyword token. The `undefined` keyword in type
129
+ // position is a regular Identifier-shaped reference and is handled by
130
+ // the named group, not by this helper.
131
+ func sortTypeConstituentsIsNullish(node *shimast.Node) bool {
132
+ if node == nil || node.Kind != shimast.KindLiteralType {
133
+ return false
134
+ }
135
+ lit := node.AsLiteralTypeNode()
136
+ if lit == nil || lit.Literal == nil {
137
+ return false
138
+ }
139
+ return lit.Literal.Kind == shimast.KindNullKeyword
140
+ }
141
+
142
+ func init() {
143
+ Register(sortTypeConstituents{})
144
+ }
@@ -0,0 +1,157 @@
1
+ // strictBooleanExpressions fires when a non-boolean value is used in
2
+ // a boolean context — the test of an `if` / `while` / `do` / `for` /
3
+ // ternary, the operand of `!`, or either side of `&&` / `||`.
4
+ // JavaScript coerces every truthy / falsy shape silently:
5
+ //
6
+ // - numbers: `0`, `-0`, and `NaN` are falsy; every other number is
7
+ // truthy. `if (count)` therefore skips a legitimate zero.
8
+ // - strings: `""` is falsy; every other string is truthy.
9
+ // `if (name)` therefore skips a legitimate empty string.
10
+ // - nullable objects: `null` / `undefined` are falsy, the object is
11
+ // truthy. `if (obj)` collapses the present-vs-absent and
12
+ // present-but-empty cases together.
13
+ //
14
+ // The fix is always an explicit comparison naming the intent —
15
+ // `count !== 0`, `str.length > 0`, `obj != null`. typescript-eslint:
16
+ // https://typescript-eslint.io/rules/strict-boolean-expressions/
17
+ //
18
+ // Type-aware. Without a Checker the rule cannot tell a `boolean` apart
19
+ // from a `string`, so Context.Checker == nil short-circuits each Check
20
+ // to a no-op the way `no-for-in-array` and `no-misused-promises` do.
21
+ package linthost
22
+
23
+ import (
24
+ shimast "github.com/microsoft/typescript-go/shim/ast"
25
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
26
+ )
27
+
28
+ type strictBooleanExpressions struct{}
29
+
30
+ func (strictBooleanExpressions) Name() string { return "typescript/strict-boolean-expressions" }
31
+ func (strictBooleanExpressions) NeedsTypeChecker() bool {
32
+ return true
33
+ }
34
+ func (strictBooleanExpressions) Visits() []shimast.Kind {
35
+ return []shimast.Kind{
36
+ shimast.KindIfStatement,
37
+ shimast.KindWhileStatement,
38
+ shimast.KindDoStatement,
39
+ shimast.KindForStatement,
40
+ shimast.KindConditionalExpression,
41
+ shimast.KindPrefixUnaryExpression,
42
+ shimast.KindBinaryExpression,
43
+ }
44
+ }
45
+ func (strictBooleanExpressions) Check(ctx *Context, node *shimast.Node) {
46
+ if ctx.Checker == nil {
47
+ return
48
+ }
49
+ switch node.Kind {
50
+ case shimast.KindIfStatement:
51
+ if stmt := node.AsIfStatement(); stmt != nil {
52
+ strictBooleanExpressionsReport(ctx, stmt.Expression)
53
+ }
54
+ case shimast.KindWhileStatement:
55
+ if stmt := node.AsWhileStatement(); stmt != nil {
56
+ strictBooleanExpressionsReport(ctx, stmt.Expression)
57
+ }
58
+ case shimast.KindDoStatement:
59
+ if stmt := node.AsDoStatement(); stmt != nil {
60
+ strictBooleanExpressionsReport(ctx, stmt.Expression)
61
+ }
62
+ case shimast.KindForStatement:
63
+ if stmt := node.AsForStatement(); stmt != nil {
64
+ strictBooleanExpressionsReport(ctx, stmt.Condition)
65
+ }
66
+ case shimast.KindConditionalExpression:
67
+ if expr := node.AsConditionalExpression(); expr != nil {
68
+ strictBooleanExpressionsReport(ctx, expr.Condition)
69
+ }
70
+ case shimast.KindPrefixUnaryExpression:
71
+ expr := node.AsPrefixUnaryExpression()
72
+ if expr != nil && expr.Operator == shimast.KindExclamationToken {
73
+ strictBooleanExpressionsReport(ctx, expr.Operand)
74
+ }
75
+ case shimast.KindBinaryExpression:
76
+ bin := node.AsBinaryExpression()
77
+ if bin == nil || bin.OperatorToken == nil {
78
+ return
79
+ }
80
+ // Only `&&` / `||` test their left operand for truthiness.
81
+ // `??` short-circuits on nullish, not on falsy, so a non-boolean
82
+ // left operand is exactly the point of `??` and is not flagged.
83
+ switch bin.OperatorToken.Kind {
84
+ case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
85
+ strictBooleanExpressionsReport(ctx, bin.Left)
86
+ }
87
+ }
88
+ }
89
+
90
+ // strictBooleanExpressionsReport flags `expr` when its static type is
91
+ // not pure boolean-like. The recursion arm peels through `&&` / `||`
92
+ // chains so `if (a && b)` reports both `a` and `b`, mirroring the
93
+ // upstream rule. Parenthesized wrappers are skipped via stripParens
94
+ // so `if ((x))` resolves to `x`.
95
+ func strictBooleanExpressionsReport(ctx *Context, expr *shimast.Node) {
96
+ if expr == nil {
97
+ return
98
+ }
99
+ expr = stripParens(expr)
100
+ if expr == nil {
101
+ return
102
+ }
103
+ // Descend through `&&` / `||` — each conjunct/disjunct sits in
104
+ // boolean position too. The outer BinaryExpression visit only
105
+ // checks Left; the descent here finds Right as well.
106
+ if expr.Kind == shimast.KindBinaryExpression {
107
+ bin := expr.AsBinaryExpression()
108
+ if bin != nil && bin.OperatorToken != nil {
109
+ switch bin.OperatorToken.Kind {
110
+ case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken:
111
+ strictBooleanExpressionsReport(ctx, bin.Left)
112
+ strictBooleanExpressionsReport(ctx, bin.Right)
113
+ return
114
+ }
115
+ }
116
+ }
117
+ t := ctx.Checker.GetTypeAtLocation(expr)
118
+ if t == nil {
119
+ return
120
+ }
121
+ if strictBooleanExpressionsIsBoolean(t) {
122
+ return
123
+ }
124
+ ctx.Report(expr, "Unexpected non-boolean value in a boolean conditional position. Use an explicit comparison (`!== 0`, `.length > 0`, `!= null`) to name the intent.")
125
+ }
126
+
127
+ // strictBooleanExpressionsIsBoolean reports whether t is pure
128
+ // boolean-like. `any` / `unknown` / `never` are intentionally NOT
129
+ // considered boolean — they leak through generic helpers and would
130
+ // suppress the rule everywhere a value of unknown origin lands in a
131
+ // conditional. Union and intersection types must have every
132
+ // constituent boolean for the whole type to count.
133
+ func strictBooleanExpressionsIsBoolean(t *shimchecker.Type) bool {
134
+ if t == nil {
135
+ return false
136
+ }
137
+ flags := t.Flags()
138
+ if flags&(shimchecker.TypeFlagsAny|shimchecker.TypeFlagsUnknown|shimchecker.TypeFlagsNever) != 0 {
139
+ return false
140
+ }
141
+ if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
142
+ for _, part := range t.Types() {
143
+ if part == nil {
144
+ continue
145
+ }
146
+ if !strictBooleanExpressionsIsBoolean(part) {
147
+ return false
148
+ }
149
+ }
150
+ return true
151
+ }
152
+ return flags&shimchecker.TypeFlagsBooleanLike != 0
153
+ }
154
+
155
+ func init() {
156
+ Register(strictBooleanExpressions{})
157
+ }
@@ -0,0 +1,147 @@
1
+ // switchExhaustivenessCheck reports `switch (e)` statements where the
2
+ // discriminant is a union of literal types or an enum and at least one
3
+ // constituent has no matching `case` clause AND the switch carries no
4
+ // `default` clause. Either covering every member explicitly or adding a
5
+ // `default` arm makes the intent visible and forces the compiler to
6
+ // flag any future addition to the union/enum at every switch site.
7
+ // typescript-eslint strict-type-checked:
8
+ // https://typescript-eslint.io/rules/switch-exhaustiveness-check/
9
+ package linthost
10
+
11
+ import (
12
+ shimast "github.com/microsoft/typescript-go/shim/ast"
13
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
14
+ )
15
+
16
+ // switchExhaustivenessCheck is type-aware: the discriminant is resolved
17
+ // via the Checker, and uncovered members are computed by removing every
18
+ // case-clause expression's type from the union's constituent set. The
19
+ // rule only fires when the discriminant resolves to a union — plain
20
+ // `string` or `number` discriminants are open-ended and outside the
21
+ // rule's scope, matching typescript-eslint's behavior.
22
+ //
23
+ // Identity is established by `*Type` pointer comparison rather than
24
+ // literal value comparison: TypeScript canonicalizes string and number
25
+ // literal types (`stringLiteralTypes` / `numberLiteralTypes` maps inside
26
+ // the checker), so two references to `"a"` resolve to the same `*Type`
27
+ // instance. Enum literal types are likewise canonicalized per enum
28
+ // member, so `case E.A:` and the `E.A` constituent of the discriminant's
29
+ // union share their `*Type` pointer.
30
+ type switchExhaustivenessCheck struct{}
31
+
32
+ func (switchExhaustivenessCheck) Name() string { return "typescript/switch-exhaustiveness-check" }
33
+ func (switchExhaustivenessCheck) NeedsTypeChecker() bool {
34
+ return true
35
+ }
36
+ func (switchExhaustivenessCheck) Visits() []shimast.Kind {
37
+ return []shimast.Kind{shimast.KindSwitchStatement}
38
+ }
39
+ func (switchExhaustivenessCheck) Check(ctx *Context, node *shimast.Node) {
40
+ if ctx.Checker == nil {
41
+ return
42
+ }
43
+ sw := node.AsSwitchStatement()
44
+ if sw == nil || sw.Expression == nil || sw.CaseBlock == nil {
45
+ return
46
+ }
47
+ block := sw.CaseBlock.AsCaseBlock()
48
+ if block == nil || block.Clauses == nil {
49
+ return
50
+ }
51
+ // A `default` clause covers anything not enumerated above, so the
52
+ // rule has nothing to add. typescript-eslint also exits early in
53
+ // this case.
54
+ for _, clause := range block.Clauses.Nodes {
55
+ if clause != nil && clause.Kind == shimast.KindDefaultClause {
56
+ return
57
+ }
58
+ }
59
+ discriminantType := ctx.Checker.GetTypeAtLocation(sw.Expression)
60
+ if discriminantType == nil {
61
+ return
62
+ }
63
+ // Only consider discriminants whose static type is a finite union of
64
+ // literal-like constituents. Plain `string` / `number` / `unknown`
65
+ // are open-ended and never exhaustively coverable.
66
+ members := switchExhaustivenessCheckCollectMembers(discriminantType)
67
+ if len(members) == 0 {
68
+ return
69
+ }
70
+ covered := make(map[*shimchecker.Type]bool, len(members))
71
+ for _, clause := range block.Clauses.Nodes {
72
+ if clause == nil || clause.Kind != shimast.KindCaseClause {
73
+ continue
74
+ }
75
+ caseClause := clause.AsCaseOrDefaultClause()
76
+ if caseClause == nil || caseClause.Expression == nil {
77
+ continue
78
+ }
79
+ caseType := ctx.Checker.GetTypeAtLocation(caseClause.Expression)
80
+ if caseType == nil {
81
+ continue
82
+ }
83
+ covered[caseType] = true
84
+ }
85
+ missing := 0
86
+ for _, member := range members {
87
+ if !covered[member] {
88
+ missing++
89
+ }
90
+ }
91
+ if missing == 0 {
92
+ return
93
+ }
94
+ ctx.Report(node, "Switch is not exhaustive. Cases not matched: add a `case` for every union/enum member, or include a `default` clause.")
95
+ }
96
+
97
+ // switchExhaustivenessCheckCollectMembers returns the finite literal /
98
+ // enum-literal constituents of t when t is a discriminable union, and
99
+ // nil when t is open-ended (plain `string`, `number`, `any`, `unknown`,
100
+ // etc.). A union whose constituents are all literals or enum literals
101
+ // is treated as exhaustively coverable; any non-literal constituent
102
+ // (e.g. `string` mixed into `"a" | "b" | string`) widens the union and
103
+ // disqualifies the whole discriminant.
104
+ func switchExhaustivenessCheckCollectMembers(t *shimchecker.Type) []*shimchecker.Type {
105
+ if t == nil {
106
+ return nil
107
+ }
108
+ flags := t.Flags()
109
+ if flags&shimchecker.TypeFlagsUnion == 0 {
110
+ return nil
111
+ }
112
+ parts := t.Types()
113
+ if len(parts) == 0 {
114
+ return nil
115
+ }
116
+ members := make([]*shimchecker.Type, 0, len(parts))
117
+ for _, part := range parts {
118
+ if part == nil {
119
+ return nil
120
+ }
121
+ if !switchExhaustivenessCheckIsLiteralLike(part) {
122
+ return nil
123
+ }
124
+ members = append(members, part)
125
+ }
126
+ return members
127
+ }
128
+
129
+ // switchExhaustivenessCheckIsLiteralLike reports whether t is a
130
+ // constituent that participates in finite enumeration: a unit type
131
+ // (string/number/bigint/boolean literal), an enum literal, or one of
132
+ // the nullish singletons. The matching set mirrors typescript-eslint's
133
+ // `lib.isTypeFlagSet(constituent, TypeFlags.Literal | ...)` filter.
134
+ func switchExhaustivenessCheckIsLiteralLike(t *shimchecker.Type) bool {
135
+ flags := t.Flags()
136
+ if flags&shimchecker.TypeFlagsLiteral != 0 {
137
+ return true
138
+ }
139
+ if flags&(shimchecker.TypeFlagsUndefined|shimchecker.TypeFlagsNull|shimchecker.TypeFlagsVoid) != 0 {
140
+ return true
141
+ }
142
+ return false
143
+ }
144
+
145
+ func init() {
146
+ Register(switchExhaustivenessCheck{})
147
+ }
@@ -0,0 +1,126 @@
1
+ // unboundMethod reports a property access that names a class instance
2
+ // method but is used as a value instead of being immediately invoked.
3
+ // JavaScript methods are not bound to their receiver — `obj.method`,
4
+ // once extracted, loses the `this` binding the body relies on, so
5
+ // passing it as a callback (`setTimeout(obj.method, 0)`) or aliasing
6
+ // it (`const f = obj.method`) silently breaks at the first `this.x`
7
+ // dereference. typescript-eslint:
8
+ // https://typescript-eslint.io/rules/unbound-method/
9
+ //
10
+ // Type-aware. The Checker resolves the property's symbol; the rule
11
+ // fires when any of the symbol's declarations is a class
12
+ // MethodDeclaration. The conservative baseline skips:
13
+ //
14
+ // - the callee position of a call (`obj.method()` is fine);
15
+ // - the left-hand side of an assignment (`obj.method = fn`);
16
+ // - the operand of `typeof`, `delete`, `instanceof`, and `in`;
17
+ // - tagged-template tag positions;
18
+ // - static methods (the constructor that owns them is stably bound);
19
+ // - methods declared only as MethodSignature on an interface or
20
+ // type literal (those are structural — the runtime value may be a
21
+ // plain function property, and flagging them at every consumer
22
+ // produces too many false positives).
23
+ package linthost
24
+
25
+ import (
26
+ shimast "github.com/microsoft/typescript-go/shim/ast"
27
+ )
28
+
29
+ type unboundMethod struct{}
30
+
31
+ func (unboundMethod) Name() string { return "typescript/unbound-method" }
32
+ func (unboundMethod) NeedsTypeChecker() bool {
33
+ return true
34
+ }
35
+ func (unboundMethod) Visits() []shimast.Kind {
36
+ return []shimast.Kind{shimast.KindPropertyAccessExpression}
37
+ }
38
+ func (unboundMethod) Check(ctx *Context, node *shimast.Node) {
39
+ if ctx.Checker == nil {
40
+ return
41
+ }
42
+ access := node.AsPropertyAccessExpression()
43
+ if access == nil || access.Name() == nil {
44
+ return
45
+ }
46
+ if unboundMethodSafePosition(node) {
47
+ return
48
+ }
49
+ symbol := ctx.Checker.GetSymbolAtLocation(access.Name())
50
+ if symbol == nil {
51
+ return
52
+ }
53
+ if !unboundMethodSymbolIsClassMethod(symbol) {
54
+ return
55
+ }
56
+ ctx.Report(node, "Avoid referencing an unbound method which may cause unintentional scoping of `this`.")
57
+ }
58
+
59
+ // unboundMethodSafePosition reports whether the property access sits in
60
+ // a syntactic position that already discharges the unbound-method risk.
61
+ // The list mirrors typescript-eslint's safe-position whitelist: an
62
+ // immediately-invoked call, an assignment target, a typeof / delete
63
+ // operand, an instanceof / in operand, and a tagged-template tag are
64
+ // all positions where the method reference is consumed in place rather
65
+ // than carried away as a free function value.
66
+ func unboundMethodSafePosition(node *shimast.Node) bool {
67
+ parent := node.Parent
68
+ if parent == nil {
69
+ return false
70
+ }
71
+ switch parent.Kind {
72
+ case shimast.KindCallExpression:
73
+ call := parent.AsCallExpression()
74
+ if call != nil && call.Expression == node {
75
+ return true
76
+ }
77
+ case shimast.KindTaggedTemplateExpression:
78
+ return true
79
+ case shimast.KindBinaryExpression:
80
+ bin := parent.AsBinaryExpression()
81
+ if bin == nil || bin.OperatorToken == nil {
82
+ return false
83
+ }
84
+ switch bin.OperatorToken.Kind {
85
+ case shimast.KindEqualsToken,
86
+ shimast.KindInstanceOfKeyword,
87
+ shimast.KindInKeyword:
88
+ return true
89
+ }
90
+ case shimast.KindTypeOfExpression, shimast.KindDeleteExpression:
91
+ return true
92
+ }
93
+ return false
94
+ }
95
+
96
+ // unboundMethodSymbolIsClassMethod reports whether symbol denotes a
97
+ // non-static class instance method. The rule ignores plain method
98
+ // signatures on interfaces and type literals because those are
99
+ // structural — the runtime value may be a regular function rather
100
+ // than a bound class member, and flagging them at every consumer
101
+ // would produce a high false-positive volume. Static methods slip
102
+ // past this check because they are accessed through the class
103
+ // constructor itself, which is bound for the lifetime of the
104
+ // program.
105
+ func unboundMethodSymbolIsClassMethod(symbol *shimast.Symbol) bool {
106
+ if symbol == nil {
107
+ return false
108
+ }
109
+ for _, decl := range symbol.Declarations {
110
+ if decl == nil {
111
+ continue
112
+ }
113
+ if decl.Kind != shimast.KindMethodDeclaration {
114
+ continue
115
+ }
116
+ if hasModifier(decl, shimast.KindStaticKeyword) {
117
+ continue
118
+ }
119
+ return true
120
+ }
121
+ return false
122
+ }
123
+
124
+ func init() {
125
+ Register(unboundMethod{})
126
+ }