@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
@@ -28,7 +28,7 @@ import (
28
28
  // indented, corrupt output. To prevent that, every printer reports a
29
29
  // `covered` boolean alongside its Doc: `true` means the whole printed
30
30
  // subtree is reflow-safe (no multi-line verbatim node), `false` means a
31
- // multi-line verbatim node is buried inside. The format/print-width
31
+ // multi-line verbatim node is buried inside. The formatPrintWidth
32
32
  // rule abstains entirely when `covered` is false, so `ttsc format`
33
33
  // either reflows correctly or leaves the bytes untouched — it never
34
34
  // emits the half-reflowed shape. Single-line verbatim is always safe:
@@ -59,7 +59,7 @@ func NewPrintContext(file *shimast.SourceFile, opts PrintOptions) *PrintContext
59
59
  // boolean: `true` when the whole printed subtree is reflow-safe,
60
60
  // `false` when a multi-line verbatim node is buried inside it.
61
61
  //
62
- // The format/print-width rule consults `covered` to decide whether to
62
+ // The formatPrintWidth rule consults `covered` to decide whether to
63
63
  // emit an edit at all — see the coverage-signal note at the top of this
64
64
  // file. A `false` reading is a hard abstain, not a soft hint.
65
65
  func PrintNode(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
@@ -118,6 +118,9 @@ func dispatchNode(ctx *PrintContext, node *shimast.Node) (Doc, bool, bool) {
118
118
  case shimast.KindReturnStatement:
119
119
  doc, covered := printReturnStatement(ctx, node)
120
120
  return doc, covered, true
121
+ case shimast.KindConditionalExpression:
122
+ doc, covered := printConditionalExpression(ctx, node)
123
+ return doc, covered, true
121
124
  }
122
125
  return Doc{}, false, false
123
126
  }
@@ -68,11 +68,11 @@ import "strings"
68
68
  //
69
69
  // - "all" (default) every multi-line list gets one.
70
70
  // - "es5" arrays, objects, named imports / exports get one;
71
- // call arguments, parameter lists, and type-level
72
- // lists do not — those positions accepted trailing
73
- // commas only in ES2017+, so es5 mode skips them
74
- // to match Prettier and avoid oscillating against
75
- // the formatter on every cascade pass.
71
+ // call arguments, parameter lists, and type-level
72
+ // lists do not — those positions accepted trailing
73
+ // commas only in ES2017+, so es5 mode skips them
74
+ // to match Prettier and avoid oscillating against
75
+ // the formatter on every cascade pass.
76
76
  // - "none" no list gets one.
77
77
  //
78
78
  // An empty string is treated as "all", which keeps `DefaultPrintOptions()`
@@ -46,12 +46,16 @@ func printCallExpression(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
46
46
  }
47
47
  if call.TypeArguments != nil {
48
48
  // Verbatim range covering `<A, B>` punctuation and members.
49
- parts = append(parts, verbatimRange(ctx.Source, callTypeArgsStart(ctx, call), callTypeArgsEnd(ctx, call)))
49
+ parts = append(parts, verbatimRange(ctx.Source, typeArgsStart(ctx.Source, call.TypeArguments), typeArgsEnd(ctx.Source, call.TypeArguments)))
50
50
  }
51
51
  if hasNilEntry(call.Arguments) {
52
52
  return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
53
53
  }
54
- argDoc, argCovered := printArgList(ctx, call.Arguments)
54
+ // Prettier never appends a trailing comma inside a dynamic
55
+ // `import(...)`, so the printer's reflow must agree with
56
+ // format/trailing-comma's same exception (see isDynamicImportCall).
57
+ addComma := ctx.allowsCallArgumentTrailingComma() && !isDynamicImportCall(call)
58
+ argDoc, argCovered := printArgList(ctx, call.Arguments, addComma)
55
59
  parts = append(parts, argDoc)
56
60
  return Concat(parts...), covered && argCovered
57
61
  }
@@ -77,13 +81,13 @@ func printNewExpression(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
77
81
  covered = covered && !nodeSpansMultipleLines(ctx, ne.Expression)
78
82
  }
79
83
  if ne.TypeArguments != nil {
80
- parts = append(parts, verbatimRange(ctx.Source, newTypeArgsStart(ctx, ne), newTypeArgsEnd(ctx, ne)))
84
+ parts = append(parts, verbatimRange(ctx.Source, typeArgsStart(ctx.Source, ne.TypeArguments), typeArgsEnd(ctx.Source, ne.TypeArguments)))
81
85
  }
82
86
  if ne.Arguments != nil {
83
87
  if hasNilEntry(ne.Arguments) {
84
88
  return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
85
89
  }
86
- argDoc, argCovered := printArgList(ctx, ne.Arguments)
90
+ argDoc, argCovered := printArgList(ctx, ne.Arguments, ctx.allowsCallArgumentTrailingComma())
87
91
  parts = append(parts, argDoc)
88
92
  covered = covered && argCovered
89
93
  }
@@ -116,7 +120,14 @@ func hasNilEntry(list *shimast.NodeList) bool {
116
120
  // layout, so the parens stay attached and the preceding arguments are
117
121
  // not exploded onto their own lines. This is the Prettier behavior for
118
122
  // `foo(x, () => { … })`.
119
- func printArgList(ctx *PrintContext, list *shimast.NodeList) (Doc, bool) {
123
+ // `addComma` is supplied by the caller (which honors `format.trailingComma`
124
+ // and the dynamic-import exception) rather than read here, so call and new
125
+ // expressions can diverge on the comma without printArgList knowing the
126
+ // callee. Call / new argument lists accepted trailing commas only in
127
+ // ES2017+, so Prettier's "es5" and "none" modes pass false; otherwise the
128
+ // printer would oscillate against format/trailing-comma on every cascade
129
+ // pass (rxjs hit this on ajax.ts and several operators / testing helpers).
130
+ func printArgList(ctx *PrintContext, list *shimast.NodeList, addComma bool) (Doc, bool) {
120
131
  if list == nil {
121
132
  return Text("()"), true
122
133
  }
@@ -127,24 +138,65 @@ func printArgList(ctx *PrintContext, list *shimast.NodeList) (Doc, bool) {
127
138
  covered = covered && childCovered
128
139
  items = append(items, doc)
129
140
  }
130
- // AddComma honors `format.trailingComma`: call / new argument lists
131
- // accepted trailing commas only in ES2017+, so Prettier's "es5" and
132
- // "none" modes skip them here. Hardcoding `true` would oscillate
133
- // against Prettier on every cascade pass on any project configured
134
- // with "es5" (rxjs hit this on ajax.ts and several operators / testing
135
- // helpers — the rule said "no comma needed" while the printer added
136
- // one back on its own reflow).
141
+ // Last-argument hugging wins when both predicates match; first-arg
142
+ // hugging only applies to the two-argument `callback, simpleArg` shape.
143
+ // Decline last-arg hugging when a leading argument forces the call
144
+ // multi-line on its own, so Prettier explodes the whole call rather than
145
+ // hugging the last argument. Two leading shapes trigger that: a function
146
+ // or arrow expression (`useMemo(() => x, [deps])`, even with an inline
147
+ // expression body Prettier never hugs after it), and any argument whose
148
+ // doc carries hard breaks (a block-bodied callback). A leading object or
149
+ // array that merely fits flat does NOT decline — Prettier still hugs the
150
+ // last argument there (`doConfigure({ … }, () => { … })`).
151
+ hugLast := shouldHugLastArgument(list.Nodes) &&
152
+ !anyLeadingArgIsFunctionLike(list.Nodes) &&
153
+ !anyLeadingItemBreaks(items)
137
154
  shape := listShape{
138
155
  OpenTok: "(",
139
156
  CloseTok: ")",
140
157
  Items: items,
141
158
  Space: false,
142
- AddComma: ctx.allowsCallArgumentTrailingComma(),
143
- HugLast: shouldHugLastArgument(list.Nodes),
159
+ AddComma: addComma,
160
+ HugLast: hugLast,
161
+ HugFirst: !hugLast && shouldHugFirstArgument(list.Nodes),
144
162
  }
145
163
  return printList(ctx, shape), covered
146
164
  }
147
165
 
166
+ // anyLeadingArgIsFunctionLike reports whether any argument before the last
167
+ // is a function or arrow expression. Prettier declines last-argument
168
+ // hugging when a non-last argument is itself a function/arrow, regardless
169
+ // of its body, so `useMemo(() => compute(), [deps])` explodes rather than
170
+ // hugging the trailing array. This complements anyLeadingItemBreaks, which
171
+ // only catches leads with hard line breaks (a block body) and so misses an
172
+ // expression-bodied arrow.
173
+ func anyLeadingArgIsFunctionLike(args []*shimast.Node) bool {
174
+ for i := 0; i+1 < len(args); i++ {
175
+ if args[i] == nil {
176
+ continue
177
+ }
178
+ switch args[i].Kind {
179
+ case shimast.KindArrowFunction, shimast.KindFunctionExpression:
180
+ return true
181
+ }
182
+ }
183
+ return false
184
+ }
185
+
186
+ // anyLeadingItemBreaks reports whether any item before the last carries a
187
+ // hard line break — it cannot render flat. Such an item (a block-bodied
188
+ // callback) forces the call multi-line on its own, so last-argument
189
+ // hugging must decline and let the whole list explode, matching Prettier's
190
+ // willBreak gate on the non-last arguments.
191
+ func anyLeadingItemBreaks(items []Doc) bool {
192
+ for i := 0; i+1 < len(items); i++ {
193
+ if _, ok := flatten(items[i]); !ok {
194
+ return true
195
+ }
196
+ }
197
+ return false
198
+ }
199
+
148
200
  // shouldHugLastArgument reports whether the final entry of `args` is a
149
201
  // shape Prettier keeps hugging the closing paren: an object or array
150
202
  // literal, a function expression, or an arrow function whose body is a
@@ -195,6 +247,74 @@ func shouldHugLastArgument(args []*shimast.Node) bool {
195
247
  return false
196
248
  }
197
249
 
250
+ // shouldHugFirstArgument reports whether a call's argument list takes
251
+ // Prettier's "first-argument hugging" shape: exactly two arguments where
252
+ // the first is a block-bodied callback and the second is a short, simple
253
+ // value. `foo(() => { … }, target)` keeps the callback attached to the
254
+ // open paren and flows `, target)` after its closing brace, instead of
255
+ // exploding both arguments onto their own lines.
256
+ //
257
+ // Mirrors Prettier's shouldGroupFirstArg: it declines when the second
258
+ // argument is itself a function, arrow, conditional, or any expandable
259
+ // shape, so `both(() => {}, () => {})` falls through to the exploded
260
+ // list rather than hugging.
261
+ func shouldHugFirstArgument(args []*shimast.Node) bool {
262
+ if len(args) != 2 {
263
+ return false
264
+ }
265
+ first, second := args[0], args[1]
266
+ if first == nil || second == nil {
267
+ return false
268
+ }
269
+ return isFirstArgHuggableCallback(first) && isSimpleTrailingArg(second)
270
+ }
271
+
272
+ // isFirstArgHuggableCallback reports whether `node` is the callback shape
273
+ // Prettier hugs in the first-argument position: a function expression or
274
+ // an arrow with a block body. An expression-bodied arrow is excluded
275
+ // because it carries no internal break point.
276
+ func isFirstArgHuggableCallback(node *shimast.Node) bool {
277
+ switch node.Kind {
278
+ case shimast.KindFunctionExpression:
279
+ return true
280
+ case shimast.KindArrowFunction:
281
+ arrow := node.AsArrowFunction()
282
+ return arrow != nil && arrow.Body != nil && arrow.Body.Kind == shimast.KindBlock
283
+ }
284
+ return false
285
+ }
286
+
287
+ // isSimpleTrailingArg reports whether `node` is a value that may trail a
288
+ // hugged first-argument callback. Prettier hugs the leading callback when
289
+ // the trailing argument is an identifier, member access, literal, `this`,
290
+ // or an array literal — most notably the `useEffect(() => { … }, [deps])`
291
+ // idiom. An object literal, function, arrow, or conditional is excluded so
292
+ // first-argument hugging declines and the whole list explodes.
293
+ //
294
+ // A call expression is deliberately NOT included: the conditional-group
295
+ // fit check only measures an option's first line, so a hugged-first option
296
+ // whose trailing call overflows the closing line (`}, deeplyNested(…))`)
297
+ // would still be selected, where Prettier explodes. The array case shares
298
+ // that limitation in principle, but dependency arrays are short in
299
+ // practice, the same way the identifier/member cases already are.
300
+ func isSimpleTrailingArg(node *shimast.Node) bool {
301
+ switch node.Kind {
302
+ case shimast.KindIdentifier,
303
+ shimast.KindStringLiteral,
304
+ shimast.KindNumericLiteral,
305
+ shimast.KindBigIntLiteral,
306
+ shimast.KindTrueKeyword,
307
+ shimast.KindFalseKeyword,
308
+ shimast.KindNullKeyword,
309
+ shimast.KindThisKeyword,
310
+ shimast.KindPropertyAccessExpression,
311
+ shimast.KindElementAccessExpression,
312
+ shimast.KindArrayLiteralExpression:
313
+ return true
314
+ }
315
+ return false
316
+ }
317
+
198
318
  // forceBreakFirstGroup returns `doc` with the first Group found in a
199
319
  // left-to-right walk of its subtree forced broken, and reports whether
200
320
  // one was found. printListHuggingLast uses it to commit a hugged
@@ -225,72 +345,34 @@ func forceBreakFirstGroup(doc Doc) (Doc, bool) {
225
345
 
226
346
  // Type-argument byte-range helpers. The shim's NodeList.End() points
227
347
  // past the last argument; the surrounding `<` and `>` are not part of
228
- // the list's range, so we have to scan around it.
348
+ // the list's range, so we have to scan around it. Call and new
349
+ // expressions share these — only the field holding the list differs.
229
350
 
230
- // callTypeArgsStart returns the byte offset of the `<` that opens the
231
- // type-argument list of a CallExpression. Returns -1 when absent.
232
- func callTypeArgsStart(ctx *PrintContext, call *shimast.CallExpression) int {
233
- if call.TypeArguments == nil || len(call.TypeArguments.Nodes) == 0 {
234
- return -1
235
- }
236
- first := call.TypeArguments.Nodes[0]
237
- if first == nil {
351
+ // typeArgsStart returns the byte offset of the `<` that opens a
352
+ // type-argument list. Returns -1 when absent.
353
+ func typeArgsStart(src string, list *shimast.NodeList) int {
354
+ if list == nil || len(list.Nodes) == 0 || list.Nodes[0] == nil {
238
355
  return -1
239
356
  }
240
357
  // `<` is the byte immediately before the first type argument
241
358
  // (modulo whitespace).
242
- pos := first.Pos()
243
- for i := pos - 1; i >= 0; i-- {
244
- if ctx.Source[i] == '<' {
359
+ for i := list.Nodes[0].Pos() - 1; i >= 0; i-- {
360
+ if src[i] == '<' {
245
361
  return i
246
362
  }
247
363
  }
248
364
  return -1
249
365
  }
250
366
 
251
- // callTypeArgsEnd returns the byte offset one past the closing `>` of a
252
- // CallExpression's type-argument list. Returns -1 when absent.
253
- func callTypeArgsEnd(ctx *PrintContext, call *shimast.CallExpression) int {
254
- if call.TypeArguments == nil {
255
- return -1
256
- }
257
- end := call.TypeArguments.End()
258
- for i := end; i < len(ctx.Source); i++ {
259
- if ctx.Source[i] == '>' {
260
- return i + 1
261
- }
262
- }
263
- return end
264
- }
265
-
266
- // newTypeArgsStart returns the byte offset of the `<` that opens the
267
- // type-argument list of a NewExpression. Returns -1 when absent.
268
- func newTypeArgsStart(ctx *PrintContext, ne *shimast.NewExpression) int {
269
- if ne.TypeArguments == nil || len(ne.TypeArguments.Nodes) == 0 {
270
- return -1
271
- }
272
- first := ne.TypeArguments.Nodes[0]
273
- if first == nil {
274
- return -1
275
- }
276
- pos := first.Pos()
277
- for i := pos - 1; i >= 0; i-- {
278
- if ctx.Source[i] == '<' {
279
- return i
280
- }
281
- }
282
- return -1
283
- }
284
-
285
- // newTypeArgsEnd returns the byte offset one past the closing `>` of a
286
- // NewExpression's type-argument list. Returns -1 when absent.
287
- func newTypeArgsEnd(ctx *PrintContext, ne *shimast.NewExpression) int {
288
- if ne.TypeArguments == nil {
367
+ // typeArgsEnd returns the byte offset one past the closing `>` of a
368
+ // type-argument list. Returns -1 when the list is absent.
369
+ func typeArgsEnd(src string, list *shimast.NodeList) int {
370
+ if list == nil {
289
371
  return -1
290
372
  }
291
- end := ne.TypeArguments.End()
292
- for i := end; i < len(ctx.Source); i++ {
293
- if ctx.Source[i] == '>' {
373
+ end := list.End()
374
+ for i := end; i < len(src); i++ {
375
+ if src[i] == '>' {
294
376
  return i + 1
295
377
  }
296
378
  }
@@ -25,7 +25,7 @@ import (
25
25
  // the newlines live, so the body is dispatched through PrintNode and
26
26
  // re-indented by the Doc engine. Each printer ANDs the body's `covered`
27
27
  // flag into its own result: a body the dispatcher cannot fully control
28
- // taints the whole subtree and the format/print-width rule abstains.
28
+ // taints the whole subtree and the formatPrintWidth rule abstains.
29
29
  //
30
30
  // The expression- and return-statement printers carry the same
31
31
  // discipline one level deeper: a callback body whose statements are
@@ -180,6 +180,16 @@ func printBlock(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
180
180
  bodyParts := make([]Doc, 0, len(items)*2)
181
181
  for i, item := range items {
182
182
  if i > 0 {
183
+ // A lone leading-semicolon ASI guard stays glued to the statement
184
+ // it protects (`;(expr)`): when the previous statement is an empty
185
+ // `;` sitting directly against this one in the source, emit no line
186
+ // break, so the reflow agrees with format/orphan-semi instead of
187
+ // ping-ponging it back onto two lines every cascade pass.
188
+ if stmts[i-1].Kind == shimast.KindEmptyStatement &&
189
+ !rangeHasNewline(ctx.Source, stmts[i-1].End(), shimscanner.SkipTrivia(ctx.Source, stmts[i].Pos())) {
190
+ bodyParts = append(bodyParts, item)
191
+ continue
192
+ }
183
193
  if blankLineBetweenStatements(ctx.Source, stmts[i-1].End(), stmts[i].Pos()) {
184
194
  bodyParts = append(bodyParts, Literalline())
185
195
  }
@@ -196,6 +206,21 @@ func printBlock(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
196
206
  return doc, covered
197
207
  }
198
208
 
209
+ // rangeHasNewline reports whether src[start:end) contains a newline. Used
210
+ // to detect whether a leading-semicolon guard sits on the same line as
211
+ // the statement it protects.
212
+ func rangeHasNewline(src string, start, end int) bool {
213
+ if start < 0 || end > len(src) || end <= start {
214
+ return false
215
+ }
216
+ for i := start; i < end; i++ {
217
+ if src[i] == '\n' {
218
+ return true
219
+ }
220
+ }
221
+ return false
222
+ }
223
+
199
224
  // blankLineBetweenStatements reports whether the source gap between the
200
225
  // end of one block statement and the start of the next contains a blank
201
226
  // line — two or more newlines. printBlock uses it to keep a single
@@ -224,7 +249,7 @@ func blankLineBetweenStatements(src string, prevEnd, nextPos int) bool {
224
249
  // printer joins statements with bare Hardlines that have no slot for
225
250
  // inter-statement trivia, so a stray comment would be dropped by a
226
251
  // reflow. Detecting it lets printBlock report the block uncovered and
227
- // the format/print-width rule abstain.
252
+ // the formatPrintWidth rule abstain.
228
253
  //
229
254
  // The scan mirrors rules_format_print_width.go::hasNonChildComments:
230
255
  // comment-shaped bytes inside a complete statement token range (string
@@ -35,6 +35,12 @@ type listShape struct {
35
35
  // multi-line callback body does not force every preceding argument
36
36
  // onto its own line.
37
37
  HugLast bool
38
+ // HugFirst keeps the FIRST item attached to the open paren and flows
39
+ // the remaining simple items after it, the mirror of HugLast. The
40
+ // call-argument printer sets it for the two-argument
41
+ // `callback, simpleArg` shape Prettier hugs (`foo(() => { … }, x)`).
42
+ // HugLast and HugFirst are mutually exclusive.
43
+ HugFirst bool
38
44
  // ForceBreak commits the list to its broken, one-item-per-line shape
39
45
  // even when it would fit flat. The object-literal printer sets it to
40
46
  // mirror Prettier's objectWrap:"preserve" — an object the source
@@ -50,19 +56,22 @@ func printList(ctx *PrintContext, shape listShape) Doc {
50
56
  return Text(shape.OpenTok + shape.CloseTok)
51
57
  }
52
58
  plain := printListPlain(ctx, shape)
53
- if !shape.HugLast {
59
+ if !shape.HugLast && !shape.HugFirst {
54
60
  return plain
55
61
  }
56
- // A HugLast list offers the engine up to three shapes, in preference
62
+ // A hugging list offers the engine up to three shapes, in preference
57
63
  // order:
58
64
  // 1. allFlat — every item on one line, chosen when it fits;
59
- // 2. hugged — leading items inline, the final callback or object
60
- // committed to its multi-line shape, chosen when its opening
61
- // line fits but the all-flat form does not;
65
+ // 2. hugged — the callback (last for HugLast, first for HugFirst)
66
+ // committed to its multi-line shape with the other items inline,
67
+ // chosen when its opening line fits but the all-flat form does not;
62
68
  // 3. plain — every item exploded onto its own indented line.
63
69
  // The all-flat option is dropped when the list cannot render flat
64
70
  // (a block-bodied callback argument carries hard line breaks).
65
71
  hugged := printListHuggingLast(ctx, shape)
72
+ if shape.HugFirst {
73
+ hugged = printListHuggingFirst(ctx, shape)
74
+ }
66
75
  if allFlat, ok := flatten(plain); ok {
67
76
  return ConditionalGroup(allFlat, hugged, plain)
68
77
  }
@@ -143,3 +152,29 @@ func printListHuggingLast(ctx *PrintContext, shape listShape) Doc {
143
152
  parts = append(parts, last, Text(shape.CloseTok))
144
153
  return Concat(parts...)
145
154
  }
155
+
156
+ // printListHuggingFirst renders the "first-argument hugging" shape
157
+ // Prettier uses for `foo(() => { … }, target)`: the first item stays
158
+ // attached to the open paren and the remaining simple items flow inline
159
+ // after it, so a multi-line callback body does not explode the trailing
160
+ // arguments onto their own lines.
161
+ //
162
+ // hugged: OPEN OPEN-of-first … CLOSE-of-first, b, c CLOSE
163
+ //
164
+ // Like printListHuggingLast it returns a plain Concat (the callback's own
165
+ // printer owns its body's break) and forces the hugged item's first Group
166
+ // broken when the item has no hard line breaks of its own, so the hugged
167
+ // option stays distinct from the all-flat option.
168
+ func printListHuggingFirst(ctx *PrintContext, shape listShape) Doc {
169
+ first := shape.Items[0]
170
+ rest := shape.Items[1:]
171
+ if _, flat := flatten(first); flat {
172
+ first, _ = forceBreakFirstGroup(first)
173
+ }
174
+ parts := []Doc{Text(shape.OpenTok), first}
175
+ for _, item := range rest {
176
+ parts = append(parts, Text(", "), item)
177
+ }
178
+ parts = append(parts, Text(shape.CloseTok))
179
+ return Concat(parts...)
180
+ }
@@ -74,7 +74,7 @@ func printObjectLiteral(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
74
74
  //
75
75
  // Prettier's objectWrap:"preserve" default keeps such an object
76
76
  // expanded even when it would fit flat, treating the author's line
77
- // break as intentional structure. format/print-width mirrors that:
77
+ // break as intentional structure. formatPrintWidth mirrors that:
78
78
  // without it a deliberately multi-line object that happens to fit
79
79
  // would be silently collapsed onto one line, which Prettier never
80
80
  // does.
@@ -0,0 +1,86 @@
1
+ package linthost
2
+
3
+ import (
4
+ shimast "github.com/microsoft/typescript-go/shim/ast"
5
+ )
6
+
7
+ // printConditionalExpression renders a (possibly chained) ternary with
8
+ // Prettier 3's "indent nested ternaries" staircase. A conditional whose
9
+ // consequent or alternate is itself a conditional is printed inline
10
+ // under the same break group, but its arms indent one extra level:
11
+ //
12
+ // aaaaaaaaaa
13
+ // ? bbbbbbbbbb
14
+ // : cccccccccc
15
+ // ? dddddddddd
16
+ // : eeeeeeeeee
17
+ //
18
+ // The whole chain shares one fit-or-break decision (a single outer
19
+ // Group), matching Prettier: either the entire chain fits flat
20
+ // (`a ? b : c ? d : e`) or every rung breaks onto its own line. Nesting
21
+ // is expressed by recursing the chain builder without wrapping the
22
+ // nested conditional in its own Group, so the Doc engine's Indent stack
23
+ // accumulates `tabWidth` columns per level.
24
+ //
25
+ // The second return value is the coverage flag (see PrintNode): the AND
26
+ // of the test and both branches, so a multi-line verbatim node anywhere
27
+ // in the chain makes formatPrintWidth abstain rather than emit a
28
+ // half-reflowed shape.
29
+ func printConditionalExpression(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
30
+ body, covered := buildConditionalChain(ctx, node)
31
+ if body.IsNil() {
32
+ return verbatim(ctx, node), !nodeSpansMultipleLines(ctx, node)
33
+ }
34
+ return Group(body), covered
35
+ }
36
+
37
+ // buildConditionalChain returns the chain body for `node` WITHOUT a
38
+ // surrounding Group, so a nested conditional recursed from here shares
39
+ // the caller's group and its arms indent one level deeper. The top-level
40
+ // printConditionalExpression wraps the outermost body in the single
41
+ // Group that owns the break decision.
42
+ func buildConditionalChain(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
43
+ cond := node.AsConditionalExpression()
44
+ if cond == nil || cond.Condition == nil || cond.WhenTrue == nil || cond.WhenFalse == nil {
45
+ return Doc{}, true
46
+ }
47
+ testDoc, c1 := PrintNode(ctx, cond.Condition)
48
+ consDoc, c2 := ternaryArm(ctx, cond.WhenTrue)
49
+ altDoc, c3 := ternaryArm(ctx, cond.WhenFalse)
50
+ doc := Concat(
51
+ testDoc,
52
+ Indent(ctx.indentUnit(),
53
+ Line(), Text("? "), consDoc,
54
+ Line(), Text(": "), altDoc,
55
+ ),
56
+ )
57
+ return doc, c1 && c2 && c3
58
+ }
59
+
60
+ // ternaryArm prints a ternary consequent/alternate. A nested conditional
61
+ // continues the chain inline (no new Group) so the staircase
62
+ // accumulates; every other arm prints through the normal dispatcher (an
63
+ // arm that is a `??` expression is already parenthesized in valid
64
+ // source, so it round-trips its parens via the ParenthesizedExpression
65
+ // printer).
66
+ //
67
+ // A non-conditional arm is wrapped in Align so that, when it breaks
68
+ // internally, its continuation hangs under the arm expression's own
69
+ // column (one level past the `? `/`: ` marker) rather than under the
70
+ // chain's rung indent. Prettier hangs a broken call/object arm there:
71
+ //
72
+ // cond
73
+ // ? foo(
74
+ // arg, // arm-column + one level, not rung + one level
75
+ // )
76
+ // : bar
77
+ //
78
+ // Align is a no-op for an arm that stays flat, and a nested conditional
79
+ // is deliberately NOT aligned — it keeps the Indent-based staircase.
80
+ func ternaryArm(ctx *PrintContext, node *shimast.Node) (Doc, bool) {
81
+ if node != nil && node.Kind == shimast.KindConditionalExpression {
82
+ return buildConditionalChain(ctx, node)
83
+ }
84
+ doc, covered := PrintNode(ctx, node)
85
+ return Align(doc), covered
86
+ }
@@ -0,0 +1,14 @@
1
+ package linthost
2
+
3
+ import "strings"
4
+
5
+ // normalizeBuiltinRuleName strips the optional `eslint/` namespace prefix
6
+ // so users may write either the bare rule id or the explicit `eslint/<id>`
7
+ // form. `@ttsc/lint` deliberately rejects the legacy `@typescript-eslint/`
8
+ // and `typescript-eslint/` prefixes — TypeScript-only rules live under
9
+ // the canonical `typescript/<id>` namespace.
10
+ func normalizeBuiltinRuleName(name string) string {
11
+ name = strings.TrimSpace(name)
12
+ name = strings.TrimPrefix(name, "eslint/")
13
+ return name
14
+ }
@@ -2,7 +2,7 @@ package linthost
2
2
 
3
3
  import shimast "github.com/microsoft/typescript-go/shim/ast"
4
4
 
5
- // no-sparse-arrays: `[1, , 2]` — the implied undefined slot is almost
5
+ // noSparseArrays: `[1, , 2]` — the implied undefined slot is almost
6
6
  // always a typo.
7
7
  // https://eslint.org/docs/latest/rules/no-sparse-arrays
8
8
  type noSparseArrays struct{}
@@ -24,7 +24,7 @@ func (noSparseArrays) Check(ctx *Context, node *shimast.Node) {
24
24
  }
25
25
  }
26
26
 
27
- // no-array-constructor: forbid `new Array(0)` / `Array(1, 2, 3)` (use
27
+ // noArrayConstructor: forbid `new Array(0)` / `Array(1, 2, 3)` (use
28
28
  // array literals). The single-argument form is intentionally excluded from
29
29
  // the ban: `Array(n)` is commonly used to pre-allocate a sparse array by
30
30
  // length, and banning it would generate noise on existing idiomatic code.