@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,595 @@
1
+ package linthost
2
+
3
+ import (
4
+ "strings"
5
+
6
+ shimast "github.com/microsoft/typescript-go/shim/ast"
7
+ shimscanner "github.com/microsoft/typescript-go/shim/scanner"
8
+ )
9
+
10
+ // formatDeclarationHeader reflows the header of a class or interface
11
+ // declaration, its type-parameter list and `extends`/`implements`
12
+ // clauses up to the opening `{`, to match Prettier 3. The member body
13
+ // is never touched (members keep reflowing independently via
14
+ // format/print-width), so the rule edits only the byte range
15
+ // `[header start, '{']` and can never overlap a member edit.
16
+ //
17
+ // It reconstructs the header canonically and emits an edit only when the
18
+ // result differs from the source, so it both fixes a Prettier-2-style
19
+ // broken header and leaves an already-correct one alone (idempotent).
20
+ //
21
+ // Verified Prettier 3 shapes (printWidth W, the header overflows):
22
+ //
23
+ // - Single heritage type, no type parameters -> kept inline (Prettier
24
+ // never breaks a lone `extends X<Y>`), so the rule abstains.
25
+ // - One clause with multiple types -> break before the keyword and keep
26
+ // the types inline; explode them one-per-line only when that inline
27
+ // line still overflows:
28
+ // interface B
29
+ // extends First, Second {
30
+ // - Multiple clauses -> break before each keyword, types inline:
31
+ // class C
32
+ // extends Base
33
+ // implements First, Second
34
+ // {
35
+ // - Opening brace placement -> Prettier moves `{` onto its own line only
36
+ // for a class with a non-empty body; an interface and any empty body
37
+ // keep it glued to the last header line (so `… implements X {}`).
38
+ // - Type-parameter list overflow -> explode the `<...>` list (trailing
39
+ // comma, `>` at the base indent), heritage inline after `>`:
40
+ // interface D<
41
+ // TKey extends string,
42
+ // > extends Base<TKey> {
43
+ // A single parameter whose `extends C = D` overflows breaks after `=`.
44
+ //
45
+ // Any combination the rule has not verified (e.g. type parameters AND a
46
+ // breaking heritage clause at once), a header carrying comments, or a
47
+ // type/parameter that is itself multi-line makes the rule ABSTAIN, so it
48
+ // never emits a header it cannot reproduce exactly.
49
+ type formatDeclarationHeader struct{}
50
+
51
+ type formatDeclarationHeaderOptions struct {
52
+ PrintWidth *int `json:"printWidth"`
53
+ TabWidth *int `json:"tabWidth"`
54
+ UseTabs *bool `json:"useTabs"`
55
+ EndOfLine *string `json:"endOfLine"`
56
+ }
57
+
58
+ func (formatDeclarationHeader) Name() string { return "format/declaration-header" }
59
+ func (formatDeclarationHeader) IsFormat() bool { return true }
60
+
61
+ func (formatDeclarationHeader) Visits() []shimast.Kind {
62
+ return []shimast.Kind{
63
+ shimast.KindClassDeclaration,
64
+ shimast.KindInterfaceDeclaration,
65
+ }
66
+ }
67
+
68
+ func (formatDeclarationHeader) Check(ctx *Context, node *shimast.Node) {
69
+ if ctx == nil || ctx.File == nil || node == nil {
70
+ return
71
+ }
72
+ typeParams, heritage, name := declarationHeaderParts(node)
73
+ if name == nil {
74
+ return
75
+ }
76
+ hasTypeParams := typeParams != nil && len(typeParams.Nodes) > 0
77
+ hasHeritage := heritage != nil && len(heritage.Nodes) > 0
78
+ if !hasTypeParams && !hasHeritage {
79
+ return // nothing in the header to reflow
80
+ }
81
+
82
+ src := ctx.File.Text()
83
+ nameEnd := name.End()
84
+ if nameEnd <= 0 || nameEnd > len(src) {
85
+ return
86
+ }
87
+
88
+ // The header line starts at the first non-whitespace byte of the line
89
+ // holding the declaration name; decorators and modifiers on that line
90
+ // are carried verbatim in the prefix.
91
+ headerStart := lineFirstNonSpace(src, name.Pos())
92
+ if headerStart < 0 {
93
+ return
94
+ }
95
+
96
+ // Locate the `{` that opens the body, scanning from the end of the
97
+ // last header element so a `{` inside a type-parameter default does
98
+ // not fool the search.
99
+ scanFrom := nameEnd
100
+ if hasTypeParams {
101
+ // A type-parameter NodeList ends at the last parameter, before the
102
+ // closing `>`. Advance past that `>` so the body-brace search does
103
+ // not stop on it (the heritage case is already past it via
104
+ // heritage.End()).
105
+ scanFrom = maxInt(scanFrom, typeParams.End())
106
+ if gt := findCloseTokenAfter(src, typeParams.End(), '>'); gt >= 0 {
107
+ scanFrom = maxInt(scanFrom, gt+1)
108
+ }
109
+ }
110
+ if hasHeritage {
111
+ scanFrom = maxInt(scanFrom, heritage.End())
112
+ }
113
+ bracePos := findCloseTokenAfter(src, scanFrom, '{')
114
+ if bracePos < 0 {
115
+ return
116
+ }
117
+
118
+ // Everything from the end of the verbatim prefix (the name) to the
119
+ // brace is discarded and rebuilt element by element, so a comment
120
+ // anywhere in that span would be lost, including one between the name
121
+ // and `extends`, or between `extends` and its first type. Scan the whole
122
+ // [nameEnd, brace) region and abstain on any comment.
123
+ if containsComment(src[nameEnd:bracePos]) {
124
+ return
125
+ }
126
+
127
+ layout := loadDeclarationHeaderLayout(ctx)
128
+ // The prefix is the modifiers + keyword + name, which live between the
129
+ // header line's first token and the name's end. Type parameters and
130
+ // heritage are rebuilt separately, so anything after the name (incl.
131
+ // newlines an already-broken header introduced) is not part of it.
132
+ prefix := strings.TrimRight(src[headerStart:nameEnd], " \t")
133
+ if strings.ContainsRune(prefix, '\n') {
134
+ return // modifiers split across lines: abstain
135
+ }
136
+
137
+ // Gather verbatim element texts; abstain if any spans multiple lines.
138
+ paramTexts, ok := nodeListTexts(src, typeParams)
139
+ if !ok {
140
+ return
141
+ }
142
+ clauses, ok := heritageClauseInfos(src, heritage)
143
+ if !ok {
144
+ return
145
+ }
146
+
147
+ base := src[lineStartOffset(src, headerStart):headerStart]
148
+ startCol := visualWidth(base, layout.tabWidth)
149
+ flat := prefix + flatTypeParams(paramTexts) + flatHeritage(clauses) + " {"
150
+ region := src[headerStart : bracePos+1]
151
+
152
+ // An empty body renders its closing `}` on the same line (`… {}`), so the
153
+ // flat form is one column wider than the rebuilt region (which ends at the
154
+ // `{`). Charge that column when deciding whether the header fits, or the
155
+ // fit check is off by one against Prettier at the width boundary.
156
+ isClass := node.Kind == shimast.KindClassDeclaration
157
+ emptyBody := headerBodyIsEmpty(src, bracePos)
158
+ flatExtra := 0
159
+ if emptyBody {
160
+ flatExtra = 1
161
+ }
162
+
163
+ var target string
164
+ if startCol+visualWidth(flat, layout.tabWidth)+flatExtra <= layout.printWidth {
165
+ target = flat
166
+ } else if t, ok2 := singleGenericHeritageHeader(src, base, prefix, typeParams, heritage, layout); ok2 {
167
+ // A lone heritage clause whose single generic type has two or more type
168
+ // arguments breaks the argument list, not the clause (`extends Omit<\n …\n>`).
169
+ target = t
170
+ } else {
171
+ // Prettier drops the opening brace onto its own line only for a class
172
+ // with a non-empty body; an interface (any body) and an empty body
173
+ // keep `{` glued to the last header line (so an empty body reads
174
+ // `… {}`). isClass && !emptyBody captures that.
175
+ brace := headerBrace(isClass, emptyBody, base)
176
+ target, ok = brokenDeclarationHeader(src, base, prefix, typeParams, paramTexts, clauses, layout, brace)
177
+ if !ok {
178
+ return // unverified combination: abstain
179
+ }
180
+ }
181
+ if target == region {
182
+ return
183
+ }
184
+ ctx.ReportRangeFix(
185
+ headerStart,
186
+ bracePos+1,
187
+ "Reflow class/interface header to match Prettier.",
188
+ TextEdit{Pos: headerStart, End: bracePos + 1, Text: target},
189
+ )
190
+ }
191
+
192
+ // declarationHeaderLayout bundles the resolved width/indent settings.
193
+ type declarationHeaderLayout struct {
194
+ printWidth int
195
+ tabWidth int
196
+ oneLevel string
197
+ }
198
+
199
+ func (l declarationHeaderLayout) indent(base string, depth int) string {
200
+ return base + strings.Repeat(l.oneLevel, depth)
201
+ }
202
+
203
+ func loadDeclarationHeaderLayout(ctx *Context) declarationHeaderLayout {
204
+ var opts formatDeclarationHeaderOptions
205
+ _ = ctx.DecodeOptions(&opts)
206
+ l := declarationHeaderLayout{printWidth: 80, tabWidth: 2, oneLevel: " "}
207
+ if opts.PrintWidth != nil && *opts.PrintWidth > 0 {
208
+ l.printWidth = *opts.PrintWidth
209
+ }
210
+ if opts.TabWidth != nil && *opts.TabWidth > 0 {
211
+ l.tabWidth = *opts.TabWidth
212
+ }
213
+ if opts.UseTabs != nil && *opts.UseTabs {
214
+ l.oneLevel = "\t"
215
+ } else if opts.TabWidth != nil && *opts.TabWidth > 0 {
216
+ l.oneLevel = strings.Repeat(" ", *opts.TabWidth)
217
+ }
218
+ return l
219
+ }
220
+
221
+ // heritageClauseText pairs a clause keyword with its type texts.
222
+ type heritageClauseText struct {
223
+ keyword string
224
+ types []string
225
+ }
226
+
227
+ // declarationHeaderParts returns the type-parameter list, heritage clause
228
+ // list, and name node for a class or interface declaration.
229
+ func declarationHeaderParts(node *shimast.Node) (*shimast.NodeList, *shimast.NodeList, *shimast.Node) {
230
+ switch node.Kind {
231
+ case shimast.KindClassDeclaration:
232
+ d := node.AsClassDeclaration()
233
+ if d == nil {
234
+ return nil, nil, nil
235
+ }
236
+ return d.TypeParameters, d.HeritageClauses, node.Name()
237
+ case shimast.KindInterfaceDeclaration:
238
+ d := node.AsInterfaceDeclaration()
239
+ if d == nil {
240
+ return nil, nil, nil
241
+ }
242
+ return d.TypeParameters, d.HeritageClauses, node.Name()
243
+ }
244
+ return nil, nil, nil
245
+ }
246
+
247
+ // nodeListTexts returns the trimmed verbatim source of each node in the
248
+ // list. ok is false if any node spans multiple lines, so the caller
249
+ // abstains rather than collapsing a multi-line element.
250
+ func nodeListTexts(src string, list *shimast.NodeList) ([]string, bool) {
251
+ if list == nil {
252
+ return nil, true
253
+ }
254
+ out := make([]string, 0, len(list.Nodes))
255
+ for _, n := range list.Nodes {
256
+ if n == nil {
257
+ return nil, false
258
+ }
259
+ s := shimscanner.SkipTrivia(src, n.Pos())
260
+ e := n.End()
261
+ if s < 0 || e < s || e > len(src) {
262
+ return nil, false
263
+ }
264
+ text := strings.TrimRight(src[s:e], " \t")
265
+ if strings.ContainsRune(text, '\n') {
266
+ return nil, false
267
+ }
268
+ out = append(out, text)
269
+ }
270
+ return out, true
271
+ }
272
+
273
+ // heritageClauseInfos extracts keyword + type texts for each heritage
274
+ // clause. ok is false on any multi-line type, so the caller abstains.
275
+ func heritageClauseInfos(src string, list *shimast.NodeList) ([]heritageClauseText, bool) {
276
+ if list == nil {
277
+ return nil, true
278
+ }
279
+ out := make([]heritageClauseText, 0, len(list.Nodes))
280
+ for _, clauseNode := range list.Nodes {
281
+ if clauseNode == nil {
282
+ return nil, false
283
+ }
284
+ clause := clauseNode.AsHeritageClause()
285
+ if clause == nil || clause.Types == nil {
286
+ return nil, false
287
+ }
288
+ keyword := "implements"
289
+ if clause.Token == shimast.KindExtendsKeyword {
290
+ keyword = "extends"
291
+ }
292
+ types, ok := nodeListTexts(src, clause.Types)
293
+ if !ok || len(types) == 0 {
294
+ return nil, false
295
+ }
296
+ out = append(out, heritageClauseText{keyword: keyword, types: types})
297
+ }
298
+ return out, true
299
+ }
300
+
301
+ func flatTypeParams(params []string) string {
302
+ if len(params) == 0 {
303
+ return ""
304
+ }
305
+ return "<" + strings.Join(params, ", ") + ">"
306
+ }
307
+
308
+ func flatHeritage(clauses []heritageClauseText) string {
309
+ var b strings.Builder
310
+ for _, c := range clauses {
311
+ b.WriteString(" ")
312
+ b.WriteString(c.keyword)
313
+ b.WriteString(" ")
314
+ b.WriteString(strings.Join(c.types, ", "))
315
+ }
316
+ return b.String()
317
+ }
318
+
319
+ // brokenDeclarationHeader builds the multi-line header for the verified
320
+ // strategies, or returns ok=false for an unverified combination. `base`
321
+ // is the declaration line's leading indent; continuation lines indent
322
+ // from it while the first line keeps its existing indent (the edit
323
+ // starts at the line's first non-space byte).
324
+ func brokenDeclarationHeader(
325
+ src string,
326
+ base string,
327
+ prefix string,
328
+ typeParams *shimast.NodeList,
329
+ paramTexts []string,
330
+ clauses []heritageClauseText,
331
+ layout declarationHeaderLayout,
332
+ brace string,
333
+ ) (string, bool) {
334
+ hasTypeParams := len(paramTexts) > 0
335
+ switch {
336
+ case len(clauses) >= 2:
337
+ if hasTypeParams {
338
+ return "", false
339
+ }
340
+ return multiClauseHeader(prefix, clauses, layout, base, brace), true
341
+ case len(clauses) == 1 && len(clauses[0].types) >= 2:
342
+ if hasTypeParams {
343
+ return "", false
344
+ }
345
+ return multiTypeHeader(prefix, clauses[0], layout, base, brace), true
346
+ case hasTypeParams:
347
+ if len(clauses) == 1 && len(clauses[0].types) >= 2 {
348
+ return "", false
349
+ }
350
+ return typeParamExplodeHeader(src, base, prefix, typeParams, clauses, layout), true
351
+ }
352
+ return "", false
353
+ }
354
+
355
+ // multiClauseHeader: break before each keyword, types inline per clause.
356
+ // Only a class carries multiple clauses (`extends` + `implements`), so
357
+ // `brace` is the class brace placement decided by the caller.
358
+ func multiClauseHeader(prefix string, clauses []heritageClauseText, layout declarationHeaderLayout, base, brace string) string {
359
+ var b strings.Builder
360
+ b.WriteString(prefix)
361
+ for _, c := range clauses {
362
+ b.WriteString("\n")
363
+ b.WriteString(layout.indent(base, 1))
364
+ b.WriteString(c.keyword)
365
+ b.WriteString(" ")
366
+ b.WriteString(strings.Join(c.types, ", "))
367
+ }
368
+ b.WriteString(brace)
369
+ return b.String()
370
+ }
371
+
372
+ // multiTypeHeader renders a single heritage clause with two or more types.
373
+ // Prettier breaks before the keyword and first tries to keep the types
374
+ // inline on that continuation line (`extends A, B, C`); it only explodes
375
+ // them one-per-line when the inline line itself still overflows. `brace`
376
+ // carries the caller's brace placement; when glued it shares the final
377
+ // line, so it is charged against the width budget for the tier decision.
378
+ func multiTypeHeader(prefix string, clause heritageClauseText, layout declarationHeaderLayout, base, brace string) string {
379
+ indent1 := layout.indent(base, 1)
380
+ inline := indent1 + clause.keyword + " " + strings.Join(clause.types, ", ")
381
+ inlineWidth := visualWidth(inline, layout.tabWidth)
382
+ if !strings.HasPrefix(brace, "\n") {
383
+ inlineWidth += visualWidth(brace, layout.tabWidth)
384
+ }
385
+ if inlineWidth <= layout.printWidth {
386
+ return prefix + "\n" + inline + brace
387
+ }
388
+
389
+ var b strings.Builder
390
+ b.WriteString(prefix)
391
+ b.WriteString("\n")
392
+ b.WriteString(indent1)
393
+ b.WriteString(clause.keyword)
394
+ for i, t := range clause.types {
395
+ b.WriteString("\n")
396
+ b.WriteString(layout.indent(base, 2))
397
+ b.WriteString(t)
398
+ if i < len(clause.types)-1 {
399
+ b.WriteString(",")
400
+ } else {
401
+ b.WriteString(brace)
402
+ }
403
+ }
404
+ return b.String()
405
+ }
406
+
407
+ // singleGenericHeritageHeader handles the Prettier-3 shape for a lone
408
+ // heritage clause whose single type is generic with two or more type
409
+ // arguments: instead of breaking before the keyword, Prettier keeps
410
+ // `<keyword> <TypeName><` on the first line and breaks the type-argument
411
+ // list one per line, with `>` back at the declaration's base indent and
412
+ // the brace glued:
413
+ //
414
+ // export class C implements Serializer<
415
+ // any,
416
+ // KafkaRequest | Promise<KafkaRequest>
417
+ // > {
418
+ //
419
+ // The list takes no trailing comma (Prettier omits it for heritage type
420
+ // arguments) and the brace stays glued even for a class with a non-empty
421
+ // body. Returns ok=false for any shape it has not verified, type
422
+ // parameters present, more than one clause or type, a non-generic type, a
423
+ // single type argument (Prettier leaves `extends Base<OneArg>` inline even
424
+ // when it overflows), or a multi-line argument, so the caller falls back
425
+ // to the clause-breaking strategies or abstains.
426
+ //
427
+ // On a second pass the rewritten type spans multiple lines, so
428
+ // heritageClauseInfos abstains before this point and the broken form is a
429
+ // stable fixed point.
430
+ func singleGenericHeritageHeader(src, base, prefix string, typeParams, heritage *shimast.NodeList, layout declarationHeaderLayout) (string, bool) {
431
+ if typeParams != nil && len(typeParams.Nodes) > 0 {
432
+ return "", false
433
+ }
434
+ if heritage == nil || len(heritage.Nodes) != 1 || heritage.Nodes[0] == nil {
435
+ return "", false
436
+ }
437
+ clause := heritage.Nodes[0].AsHeritageClause()
438
+ if clause == nil || clause.Types == nil || len(clause.Types.Nodes) != 1 {
439
+ return "", false
440
+ }
441
+ typeNode := clause.Types.Nodes[0]
442
+ if typeNode == nil {
443
+ return "", false
444
+ }
445
+ ewta := typeNode.AsExpressionWithTypeArguments()
446
+ if ewta == nil || ewta.TypeArguments == nil || len(ewta.TypeArguments.Nodes) < 2 {
447
+ return "", false
448
+ }
449
+ nameStart := shimscanner.SkipTrivia(src, typeNode.Pos())
450
+ ltPos := typeArgsStart(src, ewta.TypeArguments)
451
+ if nameStart < 0 || ltPos <= nameStart {
452
+ return "", false
453
+ }
454
+ typeName := strings.TrimRight(src[nameStart:ltPos], " \t")
455
+ if strings.ContainsRune(typeName, '\n') {
456
+ return "", false
457
+ }
458
+ args, ok := nodeListTexts(src, ewta.TypeArguments)
459
+ if !ok {
460
+ return "", false
461
+ }
462
+ keyword := "implements"
463
+ if clause.Token == shimast.KindExtendsKeyword {
464
+ keyword = "extends"
465
+ }
466
+
467
+ var b strings.Builder
468
+ b.WriteString(prefix)
469
+ b.WriteString(" ")
470
+ b.WriteString(keyword)
471
+ b.WriteString(" ")
472
+ b.WriteString(typeName)
473
+ b.WriteString("<\n")
474
+ for i, a := range args {
475
+ b.WriteString(layout.indent(base, 1))
476
+ b.WriteString(a)
477
+ if i < len(args)-1 {
478
+ b.WriteString(",")
479
+ }
480
+ b.WriteString("\n")
481
+ }
482
+ b.WriteString(base)
483
+ b.WriteString("> {")
484
+ return b.String(), true
485
+ }
486
+
487
+ // headerBrace returns the opening-brace fragment that closes a broken
488
+ // header. Prettier puts `{` on its own line only for a class with a
489
+ // non-empty body; an interface and any empty body keep it glued to the
490
+ // last header line.
491
+ func headerBrace(isClass, emptyBody bool, base string) string {
492
+ if isClass && !emptyBody {
493
+ return "\n" + base + "{"
494
+ }
495
+ return " {"
496
+ }
497
+
498
+ // headerBodyIsEmpty reports whether the body opened at bracePos holds no
499
+ // members, its first non-whitespace byte is the closing `}`. A body with
500
+ // a comment counts as non-empty (conservative: the comment keeps the
501
+ // brace where the source had it rather than forcing a glue).
502
+ func headerBodyIsEmpty(src string, bracePos int) bool {
503
+ for i := bracePos + 1; i < len(src); i++ {
504
+ switch src[i] {
505
+ case ' ', '\t', '\r', '\n':
506
+ continue
507
+ case '}':
508
+ return true
509
+ default:
510
+ return false
511
+ }
512
+ }
513
+ return false
514
+ }
515
+
516
+ // typeParamExplodeHeader: explode the `<...>` list, heritage inline after `>`.
517
+ func typeParamExplodeHeader(
518
+ src string,
519
+ base string,
520
+ prefix string,
521
+ typeParams *shimast.NodeList,
522
+ clauses []heritageClauseText,
523
+ layout declarationHeaderLayout,
524
+ ) string {
525
+ var b strings.Builder
526
+ b.WriteString(prefix)
527
+ b.WriteString("<\n")
528
+ paramIndent := layout.indent(base, 1)
529
+ for _, p := range typeParams.Nodes {
530
+ b.WriteString(renderExplodedTypeParam(src, p, layout, paramIndent))
531
+ b.WriteString(",\n")
532
+ }
533
+ b.WriteString(base)
534
+ b.WriteString(">")
535
+ b.WriteString(flatHeritage(clauses))
536
+ b.WriteString(" {")
537
+ return b.String()
538
+ }
539
+
540
+ // renderExplodedTypeParam renders one type parameter on its indented
541
+ // line, breaking after `=` when `name extends C = Default` overflows.
542
+ func renderExplodedTypeParam(src string, p *shimast.Node, layout declarationHeaderLayout, paramIndent string) string {
543
+ start := shimscanner.SkipTrivia(src, p.Pos())
544
+ end := p.End()
545
+ if start < 0 || end < start || end > len(src) {
546
+ return paramIndent
547
+ }
548
+ full := strings.TrimRight(src[start:end], " \t")
549
+ decl := p.AsTypeParameterDeclaration()
550
+ // Break after `=` only when the flat parameter line overflows and the
551
+ // parameter has a default; Prettier hangs the default one level deeper.
552
+ if decl != nil && decl.DefaultType != nil {
553
+ flatWidth := visualWidth(paramIndent, layout.tabWidth) + visualWidth(full, layout.tabWidth) + 1
554
+ if flatWidth > layout.printWidth {
555
+ defStart := shimscanner.SkipTrivia(src, decl.DefaultType.Pos())
556
+ // Guard the slice: defStart must sit strictly inside the parameter
557
+ // (between its name and end) for the head/default split to be sound.
558
+ if defStart > start && defStart < end {
559
+ head := strings.TrimRight(src[start:defStart], " \t") // ends in `=`
560
+ def := strings.TrimSpace(src[defStart:end])
561
+ if head != "" && def != "" {
562
+ return paramIndent + head + "\n" + paramIndent + layout.oneLevel + def
563
+ }
564
+ }
565
+ }
566
+ }
567
+ return paramIndent + full
568
+ }
569
+
570
+ // lineFirstNonSpace returns the offset of the first non-space, non-tab
571
+ // byte on the line containing `pos`.
572
+ func lineFirstNonSpace(src string, pos int) int {
573
+ ls := lineStartOffset(src, pos)
574
+ i := ls
575
+ for i < len(src) && (src[i] == ' ' || src[i] == '\t') {
576
+ i++
577
+ }
578
+ return i
579
+ }
580
+
581
+ // containsComment reports whether `s` holds a line or block comment.
582
+ func containsComment(s string) bool {
583
+ return strings.Contains(s, "//") || strings.Contains(s, "/*")
584
+ }
585
+
586
+ func maxInt(a, b int) int {
587
+ if a > b {
588
+ return a
589
+ }
590
+ return b
591
+ }
592
+
593
+ func init() {
594
+ Register(formatDeclarationHeader{})
595
+ }