@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,372 @@
1
+ package linthost
2
+
3
+ import (
4
+ shimast "github.com/microsoft/typescript-go/shim/ast"
5
+ shimscanner "github.com/microsoft/typescript-go/shim/scanner"
6
+ )
7
+
8
+ // formatIndent normalizes the leading indentation of each statement's
9
+ // first line to `depth * tabWidth` columns (or `depth` tabs under
10
+ // useTabs), mirroring Prettier's block indentation.
11
+ //
12
+ // The rule shares `format/statement-split`'s file-level walk: it
13
+ // registers for KindSourceFile and visits every statement in every
14
+ // statement list (SourceFile body, Block, ModuleBlock, case/default
15
+ // clause) at its nesting depth.
16
+ //
17
+ // Per-statement decision:
18
+ //
19
+ // 1. Find the statement's first non-trivia byte and the start of its
20
+ // physical line.
21
+ // 2. Abstain unless the statement is the first non-whitespace token on
22
+ // that line. A statement sharing a line with a previous statement is
23
+ // `format/statement-split`'s surface; keeping the two rules disjoint
24
+ // means their edits never overlap on one cascade pass.
25
+ // 3. Compare the leading-whitespace run `[lineStart, firstNonWS)` to the
26
+ // desired indent. When they differ, replace the run with the indent.
27
+ //
28
+ // The rule only ever touches a statement's own starting line. Interior
29
+ // and continuation lines belong to `format/print-width`, which owns
30
+ // reflow indentation; rewriting them here would fight that rule.
31
+ //
32
+ // Idempotent: a correctly-indented statement compares equal in step 3
33
+ // and emits nothing.
34
+ type formatIndent struct{}
35
+
36
+ func (formatIndent) Name() string { return "format/indent" }
37
+ func (formatIndent) IsFormat() bool { return true }
38
+ func (formatIndent) Visits() []shimast.Kind {
39
+ return []shimast.Kind{shimast.KindSourceFile}
40
+ }
41
+
42
+ func (formatIndent) Check(ctx *Context, node *shimast.Node) {
43
+ if ctx == nil || ctx.File == nil {
44
+ return
45
+ }
46
+ layout := loadFormatLayout(ctx)
47
+ src := ctx.File.Text()
48
+ var edits []TextEdit
49
+ forEachStatementInList(ctx.File, func(stmt *shimast.Node, depth int) {
50
+ // A statement whose indentation is owned by format/print-width's
51
+ // expression reflow (it sits inside a call/new/array/object that the
52
+ // printer lays out) must not be re-indented here: the printer hangs a
53
+ // callback body under its call-argument column, which is deeper than
54
+ // this rule's block-nesting depth, and reindenting it would oscillate
55
+ // against the printer pass forever (the cascade never converges).
56
+ if indentCededToReflow(stmt) {
57
+ return
58
+ }
59
+ start := shimscanner.SkipTrivia(src, stmt.Pos())
60
+ if start < 0 || start > len(src) {
61
+ return
62
+ }
63
+ lineStart := lineStartOffset(src, start)
64
+ // Only the leading run may be whitespace for this to be the first
65
+ // token on its line. A non-whitespace byte in `[lineStart, start)`
66
+ // means a previous statement shares the line, defer to
67
+ // `format/statement-split`.
68
+ for i := lineStart; i < start; i++ {
69
+ if src[i] != ' ' && src[i] != '\t' {
70
+ return
71
+ }
72
+ }
73
+ want := layout.indent(depth)
74
+ if src[lineStart:start] == want {
75
+ return
76
+ }
77
+ // Cede everything inside a chained-arrow body (`a => b => { … }`).
78
+ // Prettier indents such a body one extra level for the chain
79
+ // continuation, so the body block AND every statement nested below it
80
+ // sit one level deeper than the column-0 depth model computes;
81
+ // reindenting any of them to depth*tabWidth de-indents correct source.
82
+ // This is detected structurally (an ancestor block whose owning arrow is
83
+ // itself another arrow's body), so a mangled input cannot fool it,
84
+ // unlike a class method body, a switch case body, a single-head arrow,
85
+ // or a multi-line-condition `if` body, all of which the depth model
86
+ // places correctly.
87
+ if cededByChainedArrowAncestor(stmt) {
88
+ return
89
+ }
90
+ edits = append(edits, TextEdit{Pos: lineStart, End: start, Text: want})
91
+ })
92
+ // Second pass: align the block-closing `}` lines and the header lines
93
+ // (class / interface / type-literal member declarations and
94
+ // `case`/`default` labels) that are neither statements nor closing
95
+ // braces. Both surfaces are visited by a single ForEachChild descent
96
+ // (forEachIndentFrame) that tracks depth once and fires a brace callback
97
+ // and a header callback at the right nodes/depths; the two callbacks
98
+ // never target the same node, so this is exactly the two former
99
+ // descents fused.
100
+ //
101
+ // Closing brace: a `}` is not a statement, so the statement walk never
102
+ // touches it; without this a mangled (flat) block body gets its
103
+ // statements re-indented while the closing braces stay at their wrong
104
+ // column, and the cascade "converges" on that malformed result (exit 0
105
+ // on broken output). The brace aligns to the block OWNER's depth, one
106
+ // level shallower than the block's own statements, under the same cede /
107
+ // wrapped-head guards as the opening pass, so an expression-nested or
108
+ // wrapped-head block's `}` is left to the printer / its head.
109
+ //
110
+ // Header: the statement walk never visits a member declaration or a
111
+ // clause label (neither is a statement), so without this a flattened
112
+ // class body or switch leaves member headers and case labels at column 0
113
+ // while their bodies are re-indented, a malformed result the cascade
114
+ // reports as success.
115
+ forEachIndentFrame(
116
+ ctx.File,
117
+ func(block *shimast.Node, ownerDepth int) {
118
+ closeBrace := blockCloseBracePos(src, block)
119
+ if closeBrace < 0 {
120
+ return
121
+ }
122
+ lineStart := lineStartOffset(src, closeBrace)
123
+ // The `}` must be the first non-whitespace byte on its line; a brace
124
+ // sharing a line with content (`} else {`, `{ x }`) is not this
125
+ // rule's to move.
126
+ for i := lineStart; i < closeBrace; i++ {
127
+ if src[i] != ' ' && src[i] != '\t' {
128
+ return
129
+ }
130
+ }
131
+ // indentCededToReflow walks block.Parent upward, the same ancestor
132
+ // chain a body statement would, so a callback / expression-nested
133
+ // block's `}` cedes in lockstep with its body (print-width owns it).
134
+ if indentCededToReflow(block) {
135
+ return
136
+ }
137
+ // Chained-arrow body: cede the `}` in lockstep with its body
138
+ // statements. A chained-arrow body's own brace, and any brace nested
139
+ // inside it, sit one extra level deep for the chain continuation, so
140
+ // leave them be.
141
+ if cededByChainedArrowAncestor(block) {
142
+ return
143
+ }
144
+ want := layout.indent(ownerDepth)
145
+ if src[lineStart:closeBrace] == want {
146
+ return
147
+ }
148
+ edits = append(edits, TextEdit{Pos: lineStart, End: closeBrace, Text: want})
149
+ },
150
+ func(header *shimast.Node, depth int) {
151
+ pos := shimscanner.SkipTrivia(src, header.Pos())
152
+ if pos < 0 || pos > len(src) {
153
+ return
154
+ }
155
+ lineStart := lineStartOffset(src, pos)
156
+ for i := lineStart; i < pos; i++ {
157
+ if src[i] != ' ' && src[i] != '\t' {
158
+ return
159
+ }
160
+ }
161
+ if indentCededToReflow(header) || cededByChainedArrowAncestor(header) {
162
+ return
163
+ }
164
+ want := layout.indent(depth)
165
+ if src[lineStart:pos] == want {
166
+ return
167
+ }
168
+ edits = append(edits, TextEdit{Pos: lineStart, End: pos, Text: want})
169
+ },
170
+ )
171
+ if len(edits) == 0 {
172
+ return
173
+ }
174
+ ctx.ReportRangeFix(
175
+ edits[0].Pos,
176
+ edits[0].End,
177
+ "Statement indentation must match its nesting depth.",
178
+ edits...,
179
+ )
180
+ }
181
+
182
+ // indentCededToReflow reports whether `stmt` lives inside an expression
183
+ // whose layout column format/indent cannot compute from block-nesting
184
+ // depth alone, a call/new argument, an array/object element, a
185
+ // conditional branch, or a parenthesized expression. format/indent's
186
+ // depth counts only Block/clause/declaration nesting, so a statement
187
+ // hung under such an expression (a callback body, a `new (class {…})()`
188
+ // method, a `cond ? () => {…} : …` arm) sits at a deeper column than its
189
+ // block depth, and reindenting it to depth*tabWidth both corrupts
190
+ // correct source and ping-pongs against format/print-width every cascade
191
+ // pass (the cascade never converges).
192
+ //
193
+ // Walking outward from the statement, an enclosing expression of those
194
+ // kinds means the indentation is owned by the printer (when print-width
195
+ // is active) or by the already-correct source (when it is off), so
196
+ // format/indent cedes. Reaching the source file or a module block first
197
+ // means the statement is in ordinary block/declaration position,
198
+ // format/indent owns it and indents to its nesting depth.
199
+ func indentCededToReflow(stmt *shimast.Node) bool {
200
+ for n := stmt.Parent; n != nil; n = n.Parent {
201
+ switch n.Kind {
202
+ case shimast.KindCallExpression,
203
+ shimast.KindNewExpression,
204
+ shimast.KindArrayLiteralExpression,
205
+ shimast.KindObjectLiteralExpression,
206
+ shimast.KindConditionalExpression,
207
+ shimast.KindParenthesizedExpression:
208
+ return true
209
+ case shimast.KindSourceFile,
210
+ shimast.KindModuleBlock:
211
+ return false
212
+ }
213
+ }
214
+ return false
215
+ }
216
+
217
+ // cededByChainedArrowAncestor reports whether `node` sits inside the body of
218
+ // a chained arrow (`a => b => { … }`). Prettier indents a chained arrow's
219
+ // body one extra level for the chain continuation, so the body block AND
220
+ // every statement / brace nested below it sit one level deeper than the
221
+ // column-0 depth model computes; format/indent must cede all of them or it
222
+ // de-indents correct source. Walking ancestor blocks (not just the nearest)
223
+ // catches a statement deep inside the body, e.g. an `if` body two levels
224
+ // down. Purely structural (AST kinds), so a mangled input cannot fool it,
225
+ // and it does NOT match a class method body, a switch case body, a
226
+ // single-head arrow body, or a multi-line-condition `if` body, those the
227
+ // depth model places correctly.
228
+ //
229
+ // `node` may be a statement (statement pass) or a Block (closing-brace
230
+ // pass). The walk starts at `node` itself so a Block argument's own
231
+ // chained-arrow-body-ness is tested (its `}` must cede too), then climbs
232
+ // ancestors for a statement nested deeper inside the body.
233
+ func cededByChainedArrowAncestor(node *shimast.Node) bool {
234
+ for n := node; n != nil; n = n.Parent {
235
+ if n.Kind == shimast.KindSourceFile {
236
+ return false
237
+ }
238
+ if n.Kind == shimast.KindBlock {
239
+ arrow := n.Parent
240
+ if arrow != nil && arrow.Kind == shimast.KindArrowFunction &&
241
+ arrow.Parent != nil && arrow.Parent.Kind == shimast.KindArrowFunction {
242
+ return true
243
+ }
244
+ }
245
+ }
246
+ return false
247
+ }
248
+
249
+ // forEachIndentFrame walks the file's AST once and fires two callbacks at
250
+ // the nodes/depths the former forEachBlockClose and forEachIndentHeader
251
+ // descents fired, fused into a single ForEachChild descent that tracks
252
+ // depth once. The two former walks computed an identical childDepth for
253
+ // every child kind and only differed in which callback they fired on which
254
+ // node (the brace surface and the header surface never overlap on one
255
+ // node), so one descent firing both is exactly the two passes combined.
256
+ //
257
+ // - brace(owner, ownerDepth): fired for every Block / ModuleBlock /
258
+ // CaseBlock / class / interface / type-literal owner with the depth
259
+ // its closing `}` aligns to (one level shallower than the owner's own
260
+ // statements). A case-body Block fires at depth-1 so its `}` aligns
261
+ // with the `case` label one level up. It mirrors walkStatementLists's
262
+ // depth model so all indent passes agree.
263
+ // - header(node, depth): fired for every class/interface/type-literal
264
+ // member declaration and every case/default label with the depth its
265
+ // header line should align to. A class/interface/type-literal body is
266
+ // a +1 frame and its member headers sit at that body depth; a switch's
267
+ // CaseBlock is a +1 frame and each case/default label sits at that
268
+ // CaseBlock depth (its body statements nest one deeper, handled by the
269
+ // statement pass).
270
+ func forEachIndentFrame(
271
+ file *shimast.SourceFile,
272
+ brace func(block *shimast.Node, ownerDepth int),
273
+ header func(node *shimast.Node, depth int),
274
+ ) {
275
+ if file == nil {
276
+ return
277
+ }
278
+ walkIndentFrames(file.AsNode(), 0, brace, header)
279
+ }
280
+
281
+ func walkIndentFrames(
282
+ node *shimast.Node,
283
+ depth int,
284
+ brace func(block *shimast.Node, ownerDepth int),
285
+ header func(node *shimast.Node, depth int),
286
+ ) {
287
+ if node == nil {
288
+ return
289
+ }
290
+ node.ForEachChild(func(child *shimast.Node) bool {
291
+ if child == nil {
292
+ return false
293
+ }
294
+ childDepth := depth
295
+ switch child.Kind {
296
+ case shimast.KindBlock, shimast.KindModuleBlock:
297
+ isCaseBody := child.Kind == shimast.KindBlock && child.Parent != nil &&
298
+ (child.Parent.Kind == shimast.KindCaseClause ||
299
+ child.Parent.Kind == shimast.KindDefaultClause)
300
+ if isCaseBody {
301
+ // A case-body block (`case X: { … }`) adds no extra level for its
302
+ // statements (they stay at the clause body depth, this `depth`), but
303
+ // its own closing `}` aligns with the `case` label one level up.
304
+ brace(child, depth-1)
305
+ childDepth = depth
306
+ } else {
307
+ // The block's `}` aligns to the owner depth (this `depth`); its
308
+ // statements nest one deeper.
309
+ brace(child, depth)
310
+ childDepth = depth + 1
311
+ }
312
+ case shimast.KindCaseClause, shimast.KindDefaultClause:
313
+ // The label (`case X:` / `default:`) sits at the current (CaseBlock)
314
+ // depth; its body statements nest one deeper.
315
+ header(child, depth)
316
+ childDepth = depth + 1
317
+ case shimast.KindCaseBlock,
318
+ shimast.KindClassDeclaration,
319
+ shimast.KindClassExpression,
320
+ shimast.KindInterfaceDeclaration,
321
+ shimast.KindTypeLiteral:
322
+ // These carry a real closing `}` that is not a Block node: a switch's
323
+ // `}` (CaseBlock), a class/interface/type-literal body `}`. Align it to
324
+ // the depth the owner sits at (this `depth`); the members/clauses nest
325
+ // one deeper.
326
+ brace(child, depth)
327
+ childDepth = depth + 1
328
+ case shimast.KindObjectLiteralExpression:
329
+ // Object-literal braces live in expression position (assignments,
330
+ // arguments); their layout is the printer's / source's, so leave the
331
+ // `}` alone and only descend one level for any nested statement lists.
332
+ childDepth = depth + 1
333
+ case shimast.KindMethodDeclaration,
334
+ shimast.KindPropertyDeclaration,
335
+ shimast.KindGetAccessor,
336
+ shimast.KindSetAccessor,
337
+ shimast.KindConstructor,
338
+ shimast.KindMethodSignature,
339
+ shimast.KindPropertySignature,
340
+ shimast.KindIndexSignature:
341
+ // A class/interface/type-literal member: its header line sits at the
342
+ // current body depth (the enclosing frame already bumped it).
343
+ header(child, depth)
344
+ }
345
+ walkIndentFrames(child, childDepth, brace, header)
346
+ return false
347
+ })
348
+ }
349
+
350
+ // blockCloseBracePos returns the byte offset of a block's closing `}`.
351
+ // A block's End() points just past the `}`, so the brace is the last
352
+ // non-whitespace byte before End(); returns -1 if it is not a `}`.
353
+ func blockCloseBracePos(src string, block *shimast.Node) int {
354
+ end := block.End()
355
+ if end <= 0 || end > len(src) {
356
+ return -1
357
+ }
358
+ for i := end - 1; i >= 0; i-- {
359
+ c := src[i]
360
+ if c == '}' {
361
+ return i
362
+ }
363
+ if c != ' ' && c != '\t' && c != '\n' && c != '\r' {
364
+ return -1
365
+ }
366
+ }
367
+ return -1
368
+ }
369
+
370
+ func init() {
371
+ Register(formatIndent{})
372
+ }
@@ -5,7 +5,7 @@ import (
5
5
  shimscanner "github.com/microsoft/typescript-go/shim/scanner"
6
6
  )
7
7
 
8
- // format/jsdoc rewrites JSDoc blocks toward the prettier-plugin-jsdoc
8
+ // formatJsdoc rewrites JSDoc blocks toward the prettier-plugin-jsdoc
9
9
  // canonical shape. The MVP implementation handles tag-synonym
10
10
  // normalization; future passes will fold in tag sorting, @param column
11
11
  // alignment, and description wrapping under the same rule name so
@@ -19,7 +19,7 @@ import (
19
19
  // - @virtual → @abstract
20
20
  // - @func, @method → @function
21
21
  //
22
- // JSDoc tags only fire when the `@` is at the start of a JSDoc line —
22
+ // JSDoc tags only fire when the `@` is at the start of a JSDoc line,
23
23
  // preceded by `*`, whitespace, or a newline. Inline `@foo` references in
24
24
  // prose text are left alone. The rule scans source bytes directly inside
25
25
  // `/** ... */` blocks; it deliberately avoids relying on the JSDoc AST
@@ -65,7 +65,7 @@ func (formatJSDoc) Check(ctx *Context, node *shimast.Node) {
65
65
  }
66
66
  for k, v := range opts.TagSynonyms {
67
67
  // Reject empty canonicals or canonicals carrying non-identifier
68
- // bytes — the fixer would otherwise emit malformed JSDoc like
68
+ // bytes, the fixer would otherwise emit malformed JSDoc like
69
69
  // `@` or `@my tag`. Silently dropping the bad entry is the right
70
70
  // failure mode: the rule already runs on every file in a project
71
71
  // and a single typo'd entry should not poison every block.
@@ -82,7 +82,7 @@ func (formatJSDoc) Check(ctx *Context, node *shimast.Node) {
82
82
  // `sortTags` is reserved for a follow-up that pulls in the
83
83
  // prettier-plugin-jsdoc canonical order. The flag is parsed today so
84
84
  // the type surface freezes, but the implementation lands in a future
85
- // pass — projects that opt in get a no-op until then.
85
+ // pass, projects that opt in get a no-op until then.
86
86
  _ = opts.SortTags
87
87
  }
88
88
 
@@ -122,7 +122,7 @@ func findJSDocBlocks(src string) []jsdocBlock {
122
122
  if !(src[start] == '/' && src[start+1] == '*' && src[start+2] == '*') {
123
123
  continue
124
124
  }
125
- // Skip `/**/` — an empty doc block has no tags to rewrite.
125
+ // Skip `/**/`, an empty doc block has no tags to rewrite.
126
126
  if end-start == 4 && src[start+3] == '/' {
127
127
  continue
128
128
  }
@@ -0,0 +1,106 @@
1
+ package linthost
2
+
3
+ import (
4
+ shimast "github.com/microsoft/typescript-go/shim/ast"
5
+ shimscanner "github.com/microsoft/typescript-go/shim/scanner"
6
+ )
7
+
8
+ // formatOrphanSemi merges a lone leading-semicolon ASI guard onto the
9
+ // statement it protects, matching Prettier under semi:false:
10
+ //
11
+ // ;
12
+ // (expr).method()
13
+ //
14
+ // becomes `;(expr).method()`. Authors write the standalone `;` so ASI
15
+ // does not glue a `(`/`[`/`` ` ``-leading statement onto the previous
16
+ // line; Prettier keeps the guard but pulls it onto the guarded
17
+ // statement's line.
18
+ //
19
+ // Scope is deliberately narrow and safe: it acts only under semi:false
20
+ // (the guard is a no-semicolon idiom) and only when the next statement
21
+ // begins with an ASI-hazard token, so the `;` is genuinely required and
22
+ // the edit just deletes the whitespace gap. Every other empty statement
23
+ // (trailing `;`, a non-hazard successor, a comment in between, semi:true)
24
+ // is left alone, dropping a redundant `;` safely depends on the
25
+ // surrounding semicolon policy and is out of scope here. Idempotent:
26
+ // once merged the gap holds no newline, so the rule finds nothing to do.
27
+ type formatOrphanSemi struct{}
28
+
29
+ // formatOrphanSemiOptions carries the effective `semi` setting, mirrored
30
+ // from format.semi by the config layer. Defaults to true (semicolons),
31
+ // in which case the rule never acts.
32
+ type formatOrphanSemiOptions struct {
33
+ Semi *bool `json:"semi"`
34
+ }
35
+
36
+ func (formatOrphanSemi) Name() string { return "format/orphan-semi" }
37
+ func (formatOrphanSemi) IsFormat() bool { return true }
38
+
39
+ func (formatOrphanSemi) Visits() []shimast.Kind {
40
+ return []shimast.Kind{shimast.KindEmptyStatement}
41
+ }
42
+
43
+ func (formatOrphanSemi) Check(ctx *Context, node *shimast.Node) {
44
+ if ctx == nil || ctx.File == nil || node == nil {
45
+ return
46
+ }
47
+ var opts formatOrphanSemiOptions
48
+ _ = ctx.DecodeOptions(&opts)
49
+ // Only the semi:false guard idiom is in scope.
50
+ if opts.Semi == nil || *opts.Semi {
51
+ return
52
+ }
53
+
54
+ src := ctx.File.Text()
55
+ semiPos := shimscanner.SkipTrivia(src, node.Pos())
56
+ semiEnd := node.End()
57
+ if semiPos < 0 || semiEnd > len(src) || semiPos >= semiEnd || src[semiEnd-1] != ';' {
58
+ return
59
+ }
60
+ // The `;` must be the first token on its line, a true orphan guard,
61
+ // not a trailing empty statement after other code.
62
+ lineStart := lineStartOffset(src, semiPos)
63
+ for i := lineStart; i < semiPos; i++ {
64
+ if src[i] != ' ' && src[i] != '\t' {
65
+ return
66
+ }
67
+ }
68
+
69
+ // Find the next significant byte. A comment in the gap is left alone
70
+ // (the merge would have to reposition it).
71
+ i := semiEnd
72
+ for i < len(src) {
73
+ c := src[i]
74
+ if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
75
+ i++
76
+ continue
77
+ }
78
+ if c == '/' && i+1 < len(src) && (src[i+1] == '/' || src[i+1] == '*') {
79
+ return
80
+ }
81
+ break
82
+ }
83
+ if i >= len(src) {
84
+ return
85
+ }
86
+ // Merge only when the next statement begins with an ASI-hazard token,
87
+ // so the `;` is genuinely the guard Prettier keeps.
88
+ switch src[i] {
89
+ case '(', '[', '`':
90
+ default:
91
+ return
92
+ }
93
+ if i <= semiEnd {
94
+ return // already adjacent (idempotent no-op)
95
+ }
96
+ ctx.ReportRangeFix(
97
+ semiEnd,
98
+ i,
99
+ "Merge the leading-semicolon ASI guard onto its statement.",
100
+ TextEdit{Pos: semiEnd, End: i, Text: ""},
101
+ )
102
+ }
103
+
104
+ func init() {
105
+ Register(formatOrphanSemi{})
106
+ }