@ttsc/lint 0.14.0-dev.20260529.2 → 0.14.0

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 (380) hide show
  1. package/README.md +21 -23
  2. package/lib/defaultFormat.d.ts +10 -6
  3. package/lib/defaultFormat.js +10 -6
  4. package/lib/defaultFormat.js.map +1 -1
  5. package/lib/structures/ITtscLintConfig.d.ts +5 -5
  6. package/lib/structures/TtscLintRuleSetting.d.ts +19 -19
  7. package/lib/structures/{ITtscLintFormat.d.ts → format/ITtscLintFormat.d.ts} +45 -70
  8. package/lib/structures/format/ITtscLintFormat.js.map +1 -0
  9. package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +15 -0
  10. package/lib/structures/format/ITtscLintFormatJsDoc.js +3 -0
  11. package/lib/structures/format/ITtscLintFormatJsDoc.js.map +1 -0
  12. package/lib/structures/format/ITtscLintFormatSortImports.d.ts +54 -0
  13. package/lib/structures/format/ITtscLintFormatSortImports.js +3 -0
  14. package/lib/structures/format/ITtscLintFormatSortImports.js.map +1 -0
  15. package/lib/structures/format/index.d.ts +3 -0
  16. package/lib/structures/format/index.js +20 -0
  17. package/lib/structures/format/index.js.map +1 -0
  18. package/lib/structures/index.d.ts +1 -1
  19. package/lib/structures/index.js +1 -1
  20. package/lib/structures/index.js.map +1 -1
  21. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +18 -27
  22. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +4 -5
  23. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -1
  24. package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +29 -33
  25. package/lib/structures/rules/ITtscLintContributorRules.d.ts +6 -7
  26. package/lib/structures/rules/ITtscLintCoreRules.d.ts +380 -408
  27. package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +5 -5
  28. package/lib/structures/rules/ITtscLintCypressRuleOptions.js +2 -2
  29. package/lib/structures/rules/ITtscLintCypressRules.d.ts +34 -38
  30. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +21 -24
  31. package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +2 -2
  32. package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +51 -56
  33. package/lib/structures/rules/ITtscLintJestRules.d.ts +63 -74
  34. package/lib/structures/rules/ITtscLintJsdocRules.d.ts +47 -54
  35. package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +94 -102
  36. package/lib/structures/rules/ITtscLintNextjsRules.d.ts +50 -55
  37. package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +104 -122
  38. package/lib/structures/rules/ITtscLintPromiseRules.d.ts +62 -71
  39. package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +4 -4
  40. package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +17 -19
  41. package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +8 -10
  42. package/lib/structures/rules/ITtscLintReactRuleOptions.js +1 -2
  43. package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -1
  44. package/lib/structures/rules/ITtscLintReactRules.d.ts +91 -104
  45. package/lib/structures/rules/ITtscLintRegexpRules.d.ts +46 -54
  46. package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +7 -8
  47. package/lib/structures/rules/ITtscLintSecurityRules.d.ts +45 -52
  48. package/lib/structures/rules/ITtscLintSolidRules.d.ts +53 -56
  49. package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +3 -4
  50. package/lib/structures/rules/ITtscLintStorybookRules.d.ts +60 -69
  51. package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +31 -37
  52. package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +2 -3
  53. package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +102 -119
  54. package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +460 -518
  55. package/lib/structures/rules/ITtscLintVitestRules.d.ts +43 -51
  56. package/linthost/config.go +89 -72
  57. package/linthost/config_format.go +265 -99
  58. package/linthost/directives.go +5 -1
  59. package/linthost/display_width.go +72 -0
  60. package/linthost/fix.go +26 -1
  61. package/linthost/format.go +222 -25
  62. package/linthost/format_editor_settings.go +262 -0
  63. package/linthost/lsp.go +8 -4
  64. package/linthost/print_dispatch.go +3 -0
  65. package/linthost/print_doc.go +13 -0
  66. package/linthost/print_engine.go +68 -11
  67. package/linthost/print_nodes_array.go +108 -5
  68. package/linthost/print_nodes_call.go +515 -74
  69. package/linthost/print_nodes_function.go +25 -0
  70. package/linthost/print_nodes_imports.go +47 -14
  71. package/linthost/print_nodes_list.go +191 -8
  72. package/linthost/print_nodes_object.go +12 -6
  73. package/linthost/print_nodes_ternary.go +106 -0
  74. package/linthost/rules_boundaries.go +400 -400
  75. package/linthost/rules_camelcase.go +81 -81
  76. package/linthost/rules_complexity.go +52 -51
  77. package/linthost/rules_consistent_return.go +81 -81
  78. package/linthost/rules_core_extra.go +472 -472
  79. package/linthost/rules_curly.go +43 -43
  80. package/linthost/rules_default_case.go +15 -15
  81. package/linthost/rules_default_case_last.go +22 -22
  82. package/linthost/rules_format_arrow_parens.go +167 -0
  83. package/linthost/rules_format_bracket_spacing.go +117 -0
  84. package/linthost/rules_format_clause_join.go +172 -0
  85. package/linthost/rules_format_declaration_header.go +664 -0
  86. package/linthost/rules_format_indent.go +616 -0
  87. package/linthost/rules_format_jsdoc.go +4 -4
  88. package/linthost/rules_format_orphan_semi.go +106 -0
  89. package/linthost/rules_format_parameter_properties.go +175 -0
  90. package/linthost/rules_format_print_width.go +185 -69
  91. package/linthost/rules_format_quote_props.go +169 -0
  92. package/linthost/rules_format_quotes.go +75 -29
  93. package/linthost/rules_format_semi.go +185 -10
  94. package/linthost/rules_format_sort_imports.go +456 -121
  95. package/linthost/rules_format_statement_split.go +368 -0
  96. package/linthost/rules_format_ternary_nullish_parens.go +77 -0
  97. package/linthost/rules_format_trailing_comma.go +21 -2
  98. package/linthost/rules_format_whitespace.go +336 -0
  99. package/linthost/rules_functional.go +688 -688
  100. package/linthost/rules_gap.go +146 -11
  101. package/linthost/rules_grouped_accessor_pairs.go +60 -60
  102. package/linthost/rules_guard_for_in.go +122 -122
  103. package/linthost/rules_id_length.go +44 -44
  104. package/linthost/rules_imports.go +11 -3
  105. package/linthost/rules_init_declarations.go +25 -25
  106. package/linthost/rules_jsx_a11y.go +844 -844
  107. package/linthost/rules_max_classes_per_file.go +24 -24
  108. package/linthost/rules_max_depth.go +43 -43
  109. package/linthost/rules_max_lines.go +53 -53
  110. package/linthost/rules_max_lines_per_function.go +28 -28
  111. package/linthost/rules_max_nested_callbacks.go +26 -26
  112. package/linthost/rules_max_params.go +20 -20
  113. package/linthost/rules_max_statements.go +29 -29
  114. package/linthost/rules_nextjs.go +5 -5
  115. package/linthost/rules_no_else_return.go +38 -38
  116. package/linthost/rules_no_empty_named_blocks.go +45 -45
  117. package/linthost/rules_no_import_assign.go +96 -96
  118. package/linthost/rules_no_invalid_this.go +19 -19
  119. package/linthost/rules_no_loop_func.go +43 -43
  120. package/linthost/rules_no_magic_numbers.go +60 -60
  121. package/linthost/rules_no_mixed_operators.go +44 -44
  122. package/linthost/rules_no_param_reassign.go +64 -64
  123. package/linthost/rules_no_restricted_imports.go +45 -45
  124. package/linthost/rules_no_restricted_syntax.go +17 -17
  125. package/linthost/rules_no_shadow.go +112 -112
  126. package/linthost/rules_no_unreachable.go +36 -36
  127. package/linthost/rules_no_useless_assignment.go +79 -79
  128. package/linthost/rules_no_useless_constructor.go +167 -167
  129. package/linthost/rules_no_useless_return.go +28 -28
  130. package/linthost/rules_prefer_arrow_callback.go +74 -74
  131. package/linthost/rules_prefer_destructuring.go +61 -61
  132. package/linthost/rules_prefer_named_capture_group.go +87 -87
  133. package/linthost/rules_prefer_rest_params.go +61 -61
  134. package/linthost/rules_promise.go +800 -800
  135. package/linthost/rules_react.go +600 -600
  136. package/linthost/rules_react_extras.go +162 -162
  137. package/linthost/rules_react_hooks.go +2 -2
  138. package/linthost/rules_react_perf.go +231 -231
  139. package/linthost/rules_regexp.go +293 -293
  140. package/linthost/rules_security.go +613 -613
  141. package/linthost/rules_sort_imports.go +37 -37
  142. package/linthost/rules_sort_keys.go +88 -88
  143. package/linthost/rules_suggestions.go +13 -0
  144. package/linthost/rules_ts.go +2 -2
  145. package/linthost/rules_ts_async.go +247 -247
  146. package/linthost/rules_ts_class_literal_property_style.go +64 -64
  147. package/linthost/rules_ts_consistent_type_exports.go +209 -209
  148. package/linthost/rules_ts_explicit_function_return_type.go +35 -35
  149. package/linthost/rules_ts_extra.go +6 -2
  150. package/linthost/rules_ts_no_base_to_string.go +140 -140
  151. package/linthost/rules_ts_no_confusing_void.go +28 -28
  152. package/linthost/rules_ts_no_deprecated.go +110 -110
  153. package/linthost/rules_ts_no_for_in_array.go +45 -45
  154. package/linthost/rules_ts_no_magic_numbers.go +67 -67
  155. package/linthost/rules_ts_no_meaningless_void_operator.go +44 -44
  156. package/linthost/rules_ts_no_misused_spread.go +64 -64
  157. package/linthost/rules_ts_no_redundant_type_constituents.go +72 -72
  158. package/linthost/rules_ts_no_restricted_types.go +28 -28
  159. package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +87 -87
  160. package/linthost/rules_ts_no_unnecessary_condition.go +184 -184
  161. package/linthost/rules_ts_no_unnecessary_qualifier.go +72 -72
  162. package/linthost/rules_ts_no_unnecessary_template_expression.go +120 -120
  163. package/linthost/rules_ts_no_unnecessary_type_arguments.go +171 -171
  164. package/linthost/rules_ts_no_unnecessary_type_assertion.go +90 -90
  165. package/linthost/rules_ts_no_unsafe_argument.go +50 -50
  166. package/linthost/rules_ts_no_unsafe_assignment.go +60 -60
  167. package/linthost/rules_ts_no_unsafe_call.go +40 -40
  168. package/linthost/rules_ts_no_unsafe_enum_comparison.go +147 -147
  169. package/linthost/rules_ts_no_unsafe_member_access.go +29 -29
  170. package/linthost/rules_ts_no_unsafe_return.go +64 -64
  171. package/linthost/rules_ts_no_unsafe_unary_minus.go +42 -42
  172. package/linthost/rules_ts_no_useless_constructor.go +20 -20
  173. package/linthost/rules_ts_non_nullable_type_assertion_style.go +60 -60
  174. package/linthost/rules_ts_parameter_properties.go +10 -10
  175. package/linthost/rules_ts_prefer_find.go +116 -116
  176. package/linthost/rules_ts_prefer_includes.go +173 -173
  177. package/linthost/rules_ts_prefer_nullish_coalescing.go +54 -54
  178. package/linthost/rules_ts_prefer_optional_chain.go +156 -156
  179. package/linthost/rules_ts_prefer_promise_reject_errors.go +104 -104
  180. package/linthost/rules_ts_prefer_readonly.go +31 -31
  181. package/linthost/rules_ts_prefer_reduce_type_parameter.go +74 -74
  182. package/linthost/rules_ts_prefer_regexp_exec.go +69 -69
  183. package/linthost/rules_ts_prefer_return_this_type.go +79 -79
  184. package/linthost/rules_ts_prefer_string_starts_ends_with.go +237 -237
  185. package/linthost/rules_ts_promise_function_async.go +41 -41
  186. package/linthost/rules_ts_related_getter_setter_pairs.go +61 -61
  187. package/linthost/rules_ts_require_array_sort_compare.go +58 -58
  188. package/linthost/rules_ts_restrict_plus_operands.go +82 -82
  189. package/linthost/rules_ts_restrict_template_expressions.go +50 -50
  190. package/linthost/rules_ts_simple.go +249 -249
  191. package/linthost/rules_ts_sort_type_constituents.go +88 -88
  192. package/linthost/rules_ts_strict_boolean_expressions.go +103 -103
  193. package/linthost/rules_ts_switch_exhaustiveness_check.go +90 -90
  194. package/linthost/rules_ts_unbound_method.go +65 -65
  195. package/linthost/rules_tsdoc.go +88 -88
  196. package/linthost/rules_unicorn_better_regex.go +1 -1
  197. package/linthost/rules_unicorn_catch_error_name.go +19 -19
  198. package/linthost/rules_unicorn_consistent_assert.go +20 -20
  199. package/linthost/rules_unicorn_consistent_date_clone.go +27 -27
  200. package/linthost/rules_unicorn_consistent_destructuring.go +3 -3
  201. package/linthost/rules_unicorn_consistent_empty_array_spread.go +34 -34
  202. package/linthost/rules_unicorn_consistent_existence_index_check.go +42 -42
  203. package/linthost/rules_unicorn_consistent_function_scoping.go +3 -3
  204. package/linthost/rules_unicorn_consistent_template_literal_escape.go +3 -3
  205. package/linthost/rules_unicorn_custom_error_definition.go +92 -92
  206. package/linthost/rules_unicorn_empty_brace_spaces.go +47 -47
  207. package/linthost/rules_unicorn_error_message.go +34 -34
  208. package/linthost/rules_unicorn_escape_case.go +14 -14
  209. package/linthost/rules_unicorn_expiring_todo_comments.go +36 -36
  210. package/linthost/rules_unicorn_explicit_length_check.go +51 -51
  211. package/linthost/rules_unicorn_filename_case.go +1 -1
  212. package/linthost/rules_unicorn_import_style.go +1 -1
  213. package/linthost/rules_unicorn_isolated_functions.go +2 -2
  214. package/linthost/rules_unicorn_new_for_builtins.go +49 -49
  215. package/linthost/rules_unicorn_no_abusive_eslint_disable.go +31 -31
  216. package/linthost/rules_unicorn_no_accessor_recursion.go +69 -69
  217. package/linthost/rules_unicorn_no_anonymous_default_export.go +40 -40
  218. package/linthost/rules_unicorn_no_array_callback_reference.go +33 -33
  219. package/linthost/rules_unicorn_no_array_for_each.go +14 -14
  220. package/linthost/rules_unicorn_no_array_method_this_argument.go +29 -29
  221. package/linthost/rules_unicorn_no_array_reduce.go +15 -15
  222. package/linthost/rules_unicorn_no_array_reverse.go +17 -17
  223. package/linthost/rules_unicorn_no_array_sort.go +17 -17
  224. package/linthost/rules_unicorn_no_await_expression_member.go +12 -12
  225. package/linthost/rules_unicorn_no_await_in_promise_methods.go +38 -38
  226. package/linthost/rules_unicorn_no_console_spaces.go +30 -30
  227. package/linthost/rules_unicorn_no_document_cookie.go +13 -13
  228. package/linthost/rules_unicorn_no_empty_file.go +16 -16
  229. package/linthost/rules_unicorn_no_for_loop.go +58 -58
  230. package/linthost/rules_unicorn_no_hex_escape.go +11 -11
  231. package/linthost/rules_unicorn_no_immediate_mutation.go +55 -55
  232. package/linthost/rules_unicorn_no_instanceof_builtins.go +34 -34
  233. package/linthost/rules_unicorn_no_invalid_fetch_options.go +52 -52
  234. package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +25 -25
  235. package/linthost/rules_unicorn_no_keyword_prefix.go +56 -56
  236. package/linthost/rules_unicorn_no_lonely_if.go +21 -21
  237. package/linthost/rules_unicorn_no_magic_array_flat_depth.go +22 -22
  238. package/linthost/rules_unicorn_no_named_default.go +25 -25
  239. package/linthost/rules_unicorn_no_negated_condition.go +54 -54
  240. package/linthost/rules_unicorn_no_negation_in_equality_check.go +23 -23
  241. package/linthost/rules_unicorn_no_nested_ternary.go +15 -15
  242. package/linthost/rules_unicorn_no_new_array.go +5 -5
  243. package/linthost/rules_unicorn_no_new_buffer.go +5 -5
  244. package/linthost/rules_unicorn_no_null.go +2 -2
  245. package/linthost/rules_unicorn_no_object_as_default_parameter.go +19 -19
  246. package/linthost/rules_unicorn_no_process_exit.go +17 -17
  247. package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +29 -29
  248. package/linthost/rules_unicorn_no_static_only_class.go +27 -27
  249. package/linthost/rules_unicorn_no_thenable.go +47 -47
  250. package/linthost/rules_unicorn_no_this_assignment.go +10 -10
  251. package/linthost/rules_unicorn_no_typeof_undefined.go +31 -31
  252. package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +23 -23
  253. package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +37 -37
  254. package/linthost/rules_unicorn_no_unnecessary_await.go +24 -24
  255. package/linthost/rules_unicorn_no_unnecessary_slice_end.go +22 -22
  256. package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +67 -67
  257. package/linthost/rules_unicorn_no_unreadable_iife.go +22 -22
  258. package/linthost/rules_unicorn_no_useless_collection_argument.go +34 -34
  259. package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +18 -18
  260. package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +49 -49
  261. package/linthost/rules_unicorn_no_useless_iterator_to_array.go +41 -41
  262. package/linthost/rules_unicorn_no_useless_length_check.go +82 -82
  263. package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +42 -42
  264. package/linthost/rules_unicorn_no_useless_spread.go +38 -38
  265. package/linthost/rules_unicorn_no_useless_switch_case.go +29 -29
  266. package/linthost/rules_unicorn_no_useless_undefined.go +25 -25
  267. package/linthost/rules_unicorn_no_zero_fractions.go +17 -17
  268. package/linthost/rules_unicorn_number_literal_case.go +33 -33
  269. package/linthost/rules_unicorn_numeric_separators_style.go +36 -36
  270. package/linthost/rules_unicorn_prefer_add_event_listener.go +30 -30
  271. package/linthost/rules_unicorn_prefer_array_find.go +27 -27
  272. package/linthost/rules_unicorn_prefer_array_flat.go +25 -25
  273. package/linthost/rules_unicorn_prefer_array_flat_map.go +37 -37
  274. package/linthost/rules_unicorn_prefer_array_index_of.go +108 -108
  275. package/linthost/rules_unicorn_prefer_array_some.go +43 -43
  276. package/linthost/rules_unicorn_prefer_at.go +42 -42
  277. package/linthost/rules_unicorn_prefer_bigint_literals.go +42 -42
  278. package/linthost/rules_unicorn_prefer_blob_reading_methods.go +15 -15
  279. package/linthost/rules_unicorn_prefer_class_fields.go +57 -57
  280. package/linthost/rules_unicorn_prefer_classlist_toggle.go +76 -76
  281. package/linthost/rules_unicorn_prefer_code_point.go +21 -21
  282. package/linthost/rules_unicorn_prefer_date_now.go +47 -47
  283. package/linthost/rules_unicorn_prefer_default_parameters.go +96 -96
  284. package/linthost/rules_unicorn_prefer_dom_node_append.go +14 -14
  285. package/linthost/rules_unicorn_prefer_dom_node_dataset.go +27 -27
  286. package/linthost/rules_unicorn_prefer_dom_node_remove.go +17 -17
  287. package/linthost/rules_unicorn_prefer_dom_node_text_content.go +11 -11
  288. package/linthost/rules_unicorn_prefer_event_target.go +10 -10
  289. package/linthost/rules_unicorn_prefer_export_from.go +99 -99
  290. package/linthost/rules_unicorn_prefer_global_this.go +91 -91
  291. package/linthost/rules_unicorn_prefer_import_meta_properties.go +38 -38
  292. package/linthost/rules_unicorn_prefer_includes.go +108 -108
  293. package/linthost/rules_unicorn_prefer_json_parse_buffer.go +37 -37
  294. package/linthost/rules_unicorn_prefer_keyboard_event_key.go +10 -10
  295. package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +20 -20
  296. package/linthost/rules_unicorn_prefer_math_min_max.go +33 -33
  297. package/linthost/rules_unicorn_prefer_math_trunc.go +32 -32
  298. package/linthost/rules_unicorn_prefer_modern_dom_apis.go +18 -18
  299. package/linthost/rules_unicorn_prefer_modern_math_apis.go +38 -38
  300. package/linthost/rules_unicorn_prefer_module.go +22 -22
  301. package/linthost/rules_unicorn_prefer_native_coercion_functions.go +73 -73
  302. package/linthost/rules_unicorn_prefer_negative_index.go +46 -46
  303. package/linthost/rules_unicorn_prefer_node_protocol.go +90 -90
  304. package/linthost/rules_unicorn_prefer_number_properties.go +57 -57
  305. package/linthost/rules_unicorn_prefer_object_from_entries.go +26 -26
  306. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +24 -24
  307. package/linthost/rules_unicorn_prefer_prototype_methods.go +25 -25
  308. package/linthost/rules_unicorn_prefer_query_selector.go +25 -25
  309. package/linthost/rules_unicorn_prefer_reflect_apply.go +10 -10
  310. package/linthost/rules_unicorn_prefer_regexp_test_rule.go +47 -47
  311. package/linthost/rules_unicorn_prefer_response_static_json.go +26 -26
  312. package/linthost/rules_unicorn_prefer_set_has.go +16 -16
  313. package/linthost/rules_unicorn_prefer_set_size.go +22 -22
  314. package/linthost/rules_unicorn_prefer_simple_condition_first.go +3 -3
  315. package/linthost/rules_unicorn_prefer_single_call.go +59 -59
  316. package/linthost/rules_unicorn_prefer_spread.go +24 -24
  317. package/linthost/rules_unicorn_prefer_string_raw.go +12 -12
  318. package/linthost/rules_unicorn_prefer_string_replace_all.go +46 -46
  319. package/linthost/rules_unicorn_prefer_string_slice.go +17 -17
  320. package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +104 -104
  321. package/linthost/rules_unicorn_prefer_string_trim_start_end.go +21 -21
  322. package/linthost/rules_unicorn_prefer_structured_clone.go +36 -36
  323. package/linthost/rules_unicorn_prefer_switch.go +65 -65
  324. package/linthost/rules_unicorn_prefer_ternary.go +35 -35
  325. package/linthost/rules_unicorn_prefer_top_level_await.go +34 -34
  326. package/linthost/rules_unicorn_prefer_type_error.go +84 -84
  327. package/linthost/rules_unicorn_prevent_abbreviations.go +68 -68
  328. package/linthost/rules_unicorn_relative_url_style.go +19 -19
  329. package/linthost/rules_unicorn_require_array_join_separator.go +18 -18
  330. package/linthost/rules_unicorn_require_module_attributes.go +25 -25
  331. package/linthost/rules_unicorn_require_module_specifiers.go +28 -28
  332. package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +18 -18
  333. package/linthost/rules_unicorn_require_post_message_target_origin.go +18 -18
  334. package/linthost/rules_unicorn_string_content.go +1 -1
  335. package/linthost/rules_unicorn_switch_case_braces.go +16 -16
  336. package/linthost/rules_unicorn_switch_case_break_position.go +3 -3
  337. package/linthost/rules_unicorn_template_indent.go +1 -1
  338. package/linthost/rules_unicorn_text_encoding_identifier_case.go +36 -36
  339. package/linthost/rules_unicorn_throw_new_error.go +30 -30
  340. package/linthost/rules_var.go +273 -3
  341. package/package.json +3 -3
  342. package/src/defaultFormat.ts +11 -7
  343. package/src/structures/ITtscLintConfig.ts +5 -5
  344. package/src/structures/TtscLintRuleSetting.ts +19 -19
  345. package/src/structures/{ITtscLintFormat.ts → format/ITtscLintFormat.ts} +48 -75
  346. package/src/structures/format/ITtscLintFormatJsDoc.ts +16 -0
  347. package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
  348. package/src/structures/format/index.ts +3 -0
  349. package/src/structures/index.ts +1 -1
  350. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +20 -31
  351. package/src/structures/rules/ITtscLintBoundariesRules.ts +32 -36
  352. package/src/structures/rules/ITtscLintContributorRules.ts +6 -7
  353. package/src/structures/rules/ITtscLintCoreRules.ts +380 -408
  354. package/src/structures/rules/ITtscLintCypressRuleOptions.ts +5 -5
  355. package/src/structures/rules/ITtscLintCypressRules.ts +34 -38
  356. package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +28 -41
  357. package/src/structures/rules/ITtscLintFunctionalRules.ts +51 -56
  358. package/src/structures/rules/ITtscLintJestRules.ts +63 -74
  359. package/src/structures/rules/ITtscLintJsdocRules.ts +47 -54
  360. package/src/structures/rules/ITtscLintJsxA11yRules.ts +94 -102
  361. package/src/structures/rules/ITtscLintNextjsRules.ts +50 -55
  362. package/src/structures/rules/ITtscLintPlaywrightRules.ts +104 -122
  363. package/src/structures/rules/ITtscLintPromiseRules.ts +62 -71
  364. package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +4 -4
  365. package/src/structures/rules/ITtscLintReactPerfRules.ts +17 -19
  366. package/src/structures/rules/ITtscLintReactRuleOptions.ts +8 -10
  367. package/src/structures/rules/ITtscLintReactRules.ts +91 -104
  368. package/src/structures/rules/ITtscLintRegexpRules.ts +46 -54
  369. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +7 -8
  370. package/src/structures/rules/ITtscLintSecurityRules.ts +45 -52
  371. package/src/structures/rules/ITtscLintSolidRules.ts +53 -56
  372. package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +3 -4
  373. package/src/structures/rules/ITtscLintStorybookRules.ts +60 -69
  374. package/src/structures/rules/ITtscLintTanstackQueryRules.ts +31 -37
  375. package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +2 -3
  376. package/src/structures/rules/ITtscLintTestingLibraryRules.ts +102 -119
  377. package/src/structures/rules/ITtscLintTypeScriptRules.ts +460 -518
  378. package/src/structures/rules/ITtscLintVitestRules.ts +43 -51
  379. package/lib/structures/ITtscLintFormat.js.map +0 -1
  380. /package/lib/structures/{ITtscLintFormat.js → format/ITtscLintFormat.js} +0 -0
@@ -2,60 +2,54 @@ import type { TtscLintRuleSetting } from "../TtscLintRuleSetting";
2
2
  /**
3
3
  * Vitest test source rules from `@vitest/eslint-plugin`.
4
4
  *
5
- * Vitest reuses much of Jest's testing surface but ships its own
6
- * runner and configuration. These rules mirror the ergonomic subset
7
- * of `eslint-plugin-jest` adapted for Vitest semantics — focused
8
- * tests, identical titles, conditional logic, valid `expect` shape.
5
+ * Vitest reuses much of Jest's testing surface but ships its own runner and
6
+ * configuration. These rules mirror the ergonomic subset of
7
+ * `eslint-plugin-jest` adapted for Vitest semantics — focused tests, identical
8
+ * titles, conditional logic, valid `expect` shape.
9
9
  *
10
10
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest
11
11
  */
12
12
  export interface ITtscLintVitestRules {
13
13
  /**
14
- * Require every Vitest test body to contain at least one
15
- * `expect(...)` call. A test with no assertions still passes,
16
- * giving a false-positive signal.
14
+ * Require every Vitest test body to contain at least one `expect(...)` call.
15
+ * A test with no assertions still passes, giving a false-positive signal.
17
16
  *
18
17
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/expect-expect.md
19
18
  */
20
19
  "vitest/expect-expect"?: TtscLintRuleSetting;
21
20
  /**
22
- * Reject `expect(...)` calls under `if`/`try`/`catch` or other
23
- * conditional branches in Vitest tests.
21
+ * Reject `expect(...)` calls under `if`/`try`/`catch` or other conditional
22
+ * branches in Vitest tests.
24
23
  *
25
- * A branch that never runs turns the assertion into a silent no-op
26
- * rather than a failure.
24
+ * A branch that never runs turns the assertion into a silent no-op rather
25
+ * than a failure.
27
26
  *
28
27
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-conditional-expect.md
29
28
  */
30
29
  "vitest/no-conditional-expect"?: TtscLintRuleSetting;
31
30
  /**
32
- * Reject `test(...)`/`it(...)` declarations inside loops or `if`
33
- * branches.
31
+ * Reject `test(...)`/`it(...)` declarations inside loops or `if` branches.
34
32
  *
35
- * Vitest collects tests at module load, so a conditional
36
- * declaration produces a different suite shape than the file
37
- * appears to describe.
33
+ * Vitest collects tests at module load, so a conditional declaration produces
34
+ * a different suite shape than the file appears to describe.
38
35
  *
39
36
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-conditional-tests.md
40
37
  */
41
38
  "vitest/no-conditional-tests"?: TtscLintRuleSetting;
42
39
  /**
43
- * Reject `test.skip`, `it.skip`, `describe.skip`, and `.todo`
44
- * variants.
40
+ * Reject `test.skip`, `it.skip`, `describe.skip`, and `.todo` variants.
45
41
  *
46
- * Disabled tests rot in place and quietly drop coverage for the
47
- * feature they were meant to pin.
42
+ * Disabled tests rot in place and quietly drop coverage for the feature they
43
+ * were meant to pin.
48
44
  *
49
45
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-disabled-tests.md
50
46
  */
51
47
  "vitest/no-disabled-tests"?: TtscLintRuleSetting;
52
48
  /**
53
- * Reject `done` callback parameters in Vitest tests and
54
- * lifecycle hooks.
49
+ * Reject `done` callback parameters in Vitest tests and lifecycle hooks.
55
50
  *
56
- * The callback style predates async/await and makes failure
57
- * propagation easy to miss; return a Promise or mark the body
58
- * `async` instead.
51
+ * The callback style predates async/await and makes failure propagation easy
52
+ * to miss; return a Promise or mark the body `async` instead.
59
53
  *
60
54
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-done-callback.md
61
55
  */
@@ -63,18 +57,18 @@ export interface ITtscLintVitestRules {
63
57
  /**
64
58
  * Reject `test.only`, `it.only`, and `describe.only`.
65
59
  *
66
- * A focused suite silently skips the rest of the file, so a stray
67
- * `.only` left from debugging hides every other test in CI.
60
+ * A focused suite silently skips the rest of the file, so a stray `.only`
61
+ * left from debugging hides every other test in CI.
68
62
  *
69
63
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-focused-tests.md
70
64
  */
71
65
  "vitest/no-focused-tests"?: TtscLintRuleSetting;
72
66
  /**
73
- * Reject duplicate Vitest test or `describe` titles within the
74
- * same suite scope.
67
+ * Reject duplicate Vitest test or `describe` titles within the same suite
68
+ * scope.
75
69
  *
76
- * The runner cannot disambiguate two siblings with identical names
77
- * in its error output or filter flags.
70
+ * The runner cannot disambiguate two siblings with identical names in its
71
+ * error output or filter flags.
78
72
  *
79
73
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-identical-title.md
80
74
  */
@@ -82,28 +76,28 @@ export interface ITtscLintVitestRules {
82
76
  /**
83
77
  * Reject `expect(...)` calls outside Vitest tests and hooks.
84
78
  *
85
- * Top-level assertions execute at module load before any test
86
- * starts, so failures never attach to a named case.
79
+ * Top-level assertions execute at module load before any test starts, so
80
+ * failures never attach to a named case.
87
81
  *
88
82
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-standalone-expect.md
89
83
  */
90
84
  "vitest/no-standalone-expect"?: TtscLintRuleSetting;
91
85
  /**
92
- * Reject `return` statements that return non-Promise values from
93
- * a Vitest test callback.
86
+ * Reject `return` statements that return non-Promise values from a Vitest
87
+ * test callback.
94
88
  *
95
- * The runner ignores the value and following code is dead, which
96
- * usually masks a missing `await` or stray early-exit.
89
+ * The runner ignores the value and following code is dead, which usually
90
+ * masks a missing `await` or stray early-exit.
97
91
  *
98
92
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/no-test-return-statement.md
99
93
  */
100
94
  "vitest/no-test-return-statement"?: TtscLintRuleSetting;
101
95
  /**
102
- * Prefer `expect(value).toHaveLength(n)` over asserting on
103
- * `value.length` with `toBe`.
96
+ * Prefer `expect(value).toHaveLength(n)` over asserting on `value.length`
97
+ * with `toBe`.
104
98
  *
105
- * The dedicated matcher reports the actual length on failure
106
- * instead of a bare number mismatch.
99
+ * The dedicated matcher reports the actual length on failure instead of a
100
+ * bare number mismatch.
107
101
  *
108
102
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/prefer-to-have-length.md
109
103
  */
@@ -111,20 +105,18 @@ export interface ITtscLintVitestRules {
111
105
  /**
112
106
  * Validate the shape of Vitest `describe` callbacks.
113
107
  *
114
- * The callback must be synchronous and take no arguments — the
115
- * runner ignores returned Promises and `done`-style parameters at
116
- * the describe level.
108
+ * The callback must be synchronous and take no arguments — the runner ignores
109
+ * returned Promises and `done`-style parameters at the describe level.
117
110
  *
118
111
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/valid-describe-callback.md
119
112
  */
120
113
  "vitest/valid-describe-callback"?: TtscLintRuleSetting;
121
114
  /**
122
- * Validate `expect(...)` arity and matcher chaining: exactly one
123
- * argument, terminated by a matcher call, and async matchers
124
- * properly awaited.
115
+ * Validate `expect(...)` arity and matcher chaining: exactly one argument,
116
+ * terminated by a matcher call, and async matchers properly awaited.
125
117
  *
126
- * Malformed expects either throw at runtime or pass without
127
- * asserting anything.
118
+ * Malformed expects either throw at runtime or pass without asserting
119
+ * anything.
128
120
  *
129
121
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/valid-expect.md
130
122
  */
@@ -132,8 +124,8 @@ export interface ITtscLintVitestRules {
132
124
  /**
133
125
  * Require non-empty static Vitest test and `describe` titles.
134
126
  *
135
- * Empty or dynamically-built titles produce unreadable failure
136
- * output and break filter-by-name flags.
127
+ * Empty or dynamically-built titles produce unreadable failure output and
128
+ * break filter-by-name flags.
137
129
  *
138
130
  * @reference https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/valid-title.md
139
131
  */
@@ -140,7 +140,7 @@ func (c RuleConfig) EnabledRuleConfig() RuleConfig {
140
140
  out := RuleConfig{}
141
141
  for name, sev := range c {
142
142
  if sev != SeverityOff {
143
- out[normalizeExternalRuleName(name)] = sev
143
+ out[normalizeBuiltinRuleName(name)] = sev
144
144
  }
145
145
  }
146
146
  return out
@@ -157,7 +157,7 @@ func normalizeRuleConfigKeys(c RuleConfig) RuleConfig {
157
157
  }
158
158
  out := RuleConfig{}
159
159
  for name, sev := range c {
160
- out[normalizeExternalRuleName(name)] = sev
160
+ out[normalizeBuiltinRuleName(name)] = sev
161
161
  }
162
162
  return out
163
163
  }
@@ -196,7 +196,7 @@ func (r InlineRuleResolver) RuleOptions(name string) json.RawMessage {
196
196
  if raw := r.Options[name]; len(raw) > 0 {
197
197
  return raw
198
198
  }
199
- canonical := normalizeExternalRuleName(name)
199
+ canonical := normalizeBuiltinRuleName(name)
200
200
  if raw := r.Options[canonical]; len(raw) > 0 {
201
201
  return raw
202
202
  }
@@ -231,7 +231,7 @@ func (s *ConfigStore) RuleOptions(name string) json.RawMessage {
231
231
  if raw := s.options[name]; len(raw) > 0 {
232
232
  return raw
233
233
  }
234
- canonical := normalizeExternalRuleName(name)
234
+ canonical := normalizeBuiltinRuleName(name)
235
235
  if raw := s.options[canonical]; len(raw) > 0 {
236
236
  return raw
237
237
  }
@@ -270,7 +270,7 @@ func (s *ConfigStore) ResolveRules(fileName string) ResolvedRuleConfig {
270
270
  continue
271
271
  }
272
272
  for name, sev := range entry.Rules {
273
- out[normalizeExternalRuleName(name)] = sev
273
+ out[normalizeBuiltinRuleName(name)] = sev
274
274
  }
275
275
  }
276
276
  return ResolvedRuleConfig{Rules: out}
@@ -291,7 +291,7 @@ func (s *ConfigStore) ActiveRuleNames() []string {
291
291
  }
292
292
  for name, sev := range entry.Rules {
293
293
  if sev != SeverityOff {
294
- active[normalizeExternalRuleName(name)] = sev
294
+ active[normalizeBuiltinRuleName(name)] = sev
295
295
  }
296
296
  }
297
297
  }
@@ -314,7 +314,7 @@ func (s *ConfigStore) EnabledRuleConfig() RuleConfig {
314
314
  if sev == SeverityOff {
315
315
  continue
316
316
  }
317
- canonical := normalizeExternalRuleName(name)
317
+ canonical := normalizeBuiltinRuleName(name)
318
318
  if out[canonical] != SeverityError {
319
319
  out[canonical] = sev
320
320
  }
@@ -336,7 +336,7 @@ func (s *ConfigStore) Flatten() RuleConfig {
336
336
  continue
337
337
  }
338
338
  for name, sev := range entry.Rules {
339
- out[normalizeExternalRuleName(name)] = sev
339
+ out[normalizeBuiltinRuleName(name)] = sev
340
340
  }
341
341
  }
342
342
  return out
@@ -570,9 +570,10 @@ func collectConfigObject(store *ConfigStore, raw any, baseDir, path string, chai
570
570
  formatValue, hasFormat := obj["format"]
571
571
  if hasRules || hasFormat {
572
572
  // Expand the format block (if any) into a rules-shaped map, then
573
- // overlay any explicit `rules` entries. `rules`-wins semantics: a
574
- // `rules` entry that names a `format/*` rule fully replaces the
575
- // entry expanded from the `format` block.
573
+ // overlay the user's explicit `rules` entries. Formatter settings live
574
+ // exclusively in the `format` block: any `format/*` key in `rules` is
575
+ // dropped below (never activates, never overrides the format block), so
576
+ // the overlay only ever layers lint-rule severities on top.
576
577
  var formatRulesRaw map[string]any
577
578
  if hasFormat {
578
579
  formatMap, ok := formatValue.(map[string]any)
@@ -591,7 +592,18 @@ func collectConfigObject(store *ConfigStore, raw any, baseDir, path string, chai
591
592
  if !ok {
592
593
  return fmt.Errorf("@ttsc/lint: %s.rules must be a rule severity map, got %T", path, rulesValue)
593
594
  }
595
+ // `format/*` rules are configured exclusively through the `format`
596
+ // block; they are never valid keys in `rules`. Silently drop any that
597
+ // appear, the same way an unknown rule name is ignored (see
598
+ // parseExternalRuleMapInto): a config must not carry a formatter
599
+ // setting in two places, and a stray `format/*` here is simply not the
600
+ // formatting surface, so it has no effect rather than erroring.
594
601
  rulesMap = typedMap
602
+ for key := range rulesMap {
603
+ if isFormatRuleName(key) {
604
+ delete(rulesMap, key)
605
+ }
606
+ }
595
607
  }
596
608
  merged := mergeRuleMaps(formatRulesRaw, rulesMap)
597
609
  if len(merged) > 0 {
@@ -646,7 +658,7 @@ func collectExternalRuleMapWithOptions(out RuleConfig, opts RuleOptionsMap, raw
646
658
  if err != nil {
647
659
  return fmt.Errorf("@ttsc/lint: rule %q: %w", name, err)
648
660
  }
649
- canonical := normalizeExternalRuleName(name)
661
+ canonical := normalizeBuiltinRuleName(name)
650
662
  out[canonical] = sev
651
663
  if opts != nil && len(ruleOpts) > 0 {
652
664
  opts[canonical] = ruleOpts
@@ -675,12 +687,6 @@ func rejectUnknownConfigKeys(value map[string]any, path string) error {
675
687
  return nil
676
688
  }
677
689
 
678
- // normalizeExternalRuleName strips standard TypeScript-ESLint namespaces while
679
- // preserving @ttsc/lint's canonical kebab/slash rule IDs.
680
- func normalizeExternalRuleName(name string) string {
681
- return normalizeBuiltinRuleName(name)
682
- }
683
-
684
690
  // parsePatternList coerces a raw config value to a string slice for use as a
685
691
  // `files` or `ignores` pattern list. Accepts a bare string (single-pattern
686
692
  // shorthand) or a string array. Empty patterns are rejected eagerly.
@@ -767,7 +773,7 @@ func LoadConfigResolver(entry *PluginEntry, cwd, tsconfigPath string) (RuleResol
767
773
  return nil, err
768
774
  }
769
775
  if discovered == "" {
770
- return nil, fmt.Errorf("@ttsc/lint: no lint.config.* or ttsc-lint.config.* file found (searched upward from %s); create one or set \"configFile\" on the tsconfig plugin entry", cwd)
776
+ return nil, fmt.Errorf("%w (searched upward from %s); create one or set \"configFile\" on the tsconfig plugin entry", errNoLintConfigFile, cwd)
771
777
  }
772
778
  return loadConfigResolver(discovered)
773
779
  }
@@ -1053,13 +1059,66 @@ func loadJSONConfigFile(location string) (any, error) {
1053
1059
  return out, nil
1054
1060
  }
1055
1061
 
1062
+ // serializableConfigKeys is the single source of truth for the ITtscLintConfig
1063
+ // keys that survive the JSON round trip from a config-loader subprocess back to
1064
+ // the Go sidecar. Both the .js/.cjs/.mjs loader (loadScriptConfigFile) and the
1065
+ // .ts/.cts/.mts loader (typeScriptConfigLoaderSource) splice this list into the
1066
+ // `toSerializableConfig` key whitelist of their generated scripts, so the set
1067
+ // of copied keys is defined here once rather than duplicated per loader.
1068
+ var serializableConfigKeys = []string{"files", "ignores", "extends", "plugins", "rules", "format"}
1069
+
1070
+ // serializableConfigKeysLiteral renders serializableConfigKeys as a
1071
+ // JS/TS array literal (e.g. `"files", "ignores", ...`) for splicing into the
1072
+ // generated loader scripts' `toSerializableConfig` whitelist.
1073
+ func serializableConfigKeysLiteral() string {
1074
+ quoted := make([]string, len(serializableConfigKeys))
1075
+ for i, key := range serializableConfigKeys {
1076
+ quoted[i] = fmt.Sprintf("%q", key)
1077
+ }
1078
+ return strings.Join(quoted, ", ")
1079
+ }
1080
+
1081
+ // runConfigLoaderCommand runs a prepared config-loader subprocess (`cmd`),
1082
+ // then turns its result into a parsed config object. It owns the shared tail
1083
+ // of both subprocess-backed loaders: capturing stdout, distinguishing a
1084
+ // timeout from a process error (extracting the subprocess stderr when present),
1085
+ // JSON-parsing the output, and rejecting a non-object result. `ctx` is the
1086
+ // timeout context the caller bound `cmd` to; `location` is the config file path
1087
+ // for error messages; `label` is the human-readable subject (e.g. "config
1088
+ // file" or "TypeScript config file") spliced into the load/parse error
1089
+ // prefixes so each loader keeps its own wording.
1090
+ func runConfigLoaderCommand(ctx context.Context, cmd *exec.Cmd, location, label string) (any, error) {
1091
+ output, err := cmd.Output()
1092
+ if err != nil {
1093
+ if ctx.Err() == context.DeadlineExceeded {
1094
+ return nil, fmt.Errorf("@ttsc/lint: load %s %s: timed out after %s", label, location, configLoaderTimeout)
1095
+ }
1096
+ stderr := ""
1097
+ if exit, ok := err.(*exec.ExitError); ok {
1098
+ stderr = strings.TrimSpace(string(exit.Stderr))
1099
+ }
1100
+ if stderr != "" {
1101
+ return nil, fmt.Errorf("@ttsc/lint: load %s %s: %s", label, location, stderr)
1102
+ }
1103
+ return nil, fmt.Errorf("@ttsc/lint: load %s %s: %w", label, location, err)
1104
+ }
1105
+ var out any
1106
+ if err := json.Unmarshal(output, &out); err != nil {
1107
+ return nil, fmt.Errorf("@ttsc/lint: parse %s %s output: %w", label, location, err)
1108
+ }
1109
+ if !isConfigObject(out) {
1110
+ return nil, fmt.Errorf("@ttsc/lint: config file %s must export an ITtscLintConfig object", location)
1111
+ }
1112
+ return out, nil
1113
+ }
1114
+
1056
1115
  // loadScriptConfigFile evaluates a .js/.cjs/.mjs config file by running a
1057
1116
  // Node subprocess that dynamic-imports the file, resolves the exported config
1058
1117
  // through the same 8-hop default/config unwrap used by the TS loader, and
1059
1118
  // serializes the result as JSON to stdout. The subprocess has a
1060
1119
  // configLoaderTimeout deadline to prevent user code from hanging indefinitely.
1061
1120
  func loadScriptConfigFile(location string) (any, error) {
1062
- const script = `
1121
+ script := fmt.Sprintf(`
1063
1122
  const { pathToFileURL } = require("node:url");
1064
1123
 
1065
1124
  (async () => {
@@ -1067,8 +1126,8 @@ const { pathToFileURL } = require("node:url");
1067
1126
  let current = mod;
1068
1127
  let allowNamedConfig = true;
1069
1128
  // Match the 8-hop walk used by the TypeScript loader at
1070
- // ` + "`" + `typeScriptConfigLoaderSource` + "`" + ` so doubly-wrapped CJS/ESM
1071
- // interop (e.g. ` + "`" + `{default:{default:config}}` + "`" + `) is resolved
1129
+ // `+"`"+`typeScriptConfigLoaderSource`+"`"+` so doubly-wrapped CJS/ESM
1130
+ // interop (e.g. `+"`"+`{default:{default:config}}`+"`"+`) is resolved
1072
1131
  // consistently across .js/.cjs/.mjs and .ts/.cts/.mts loaders.
1073
1132
  for (let i = 0; i < 8; i++) {
1074
1133
  if (current !== null && typeof current === "object" && Object.prototype.hasOwnProperty.call(current, "default")) {
@@ -1096,17 +1155,17 @@ const { pathToFileURL } = require("node:url");
1096
1155
  // toSerializableConfig copies every ITtscLintConfig key onto a plain object so
1097
1156
  // it survives the JSON round trip to the Go sidecar. Every key is copied
1098
1157
  // verbatim — files, ignores, extends, plugins, rules, AND format — so a config
1099
- // whose only key is ` + "`" + `format` + "`" + ` is not silently dropped.
1158
+ // whose only key is `+"`"+`format`+"`"+` is not silently dropped.
1100
1159
  function toSerializableConfig(value) {
1101
1160
  const out = {};
1102
- for (const key of ["files", "ignores", "extends", "plugins", "rules", "format"]) {
1161
+ for (const key of [%s]) {
1103
1162
  if (Object.prototype.hasOwnProperty.call(value, key)) {
1104
1163
  out[key] = value[key];
1105
1164
  }
1106
1165
  }
1107
1166
  return out;
1108
1167
  }
1109
- `
1168
+ `, serializableConfigKeysLiteral())
1110
1169
  node := os.Getenv("TTSC_NODE_BINARY")
1111
1170
  if node == "" {
1112
1171
  node = "node"
@@ -1114,28 +1173,7 @@ function toSerializableConfig(value) {
1114
1173
  ctx, cancel := context.WithTimeout(context.Background(), configLoaderTimeout)
1115
1174
  defer cancel()
1116
1175
  cmd := exec.CommandContext(ctx, node, "-e", script, location)
1117
- output, err := cmd.Output()
1118
- if err != nil {
1119
- if ctx.Err() == context.DeadlineExceeded {
1120
- return nil, fmt.Errorf("@ttsc/lint: load config file %s: timed out after %s", location, configLoaderTimeout)
1121
- }
1122
- stderr := ""
1123
- if exit, ok := err.(*exec.ExitError); ok {
1124
- stderr = strings.TrimSpace(string(exit.Stderr))
1125
- }
1126
- if stderr != "" {
1127
- return nil, fmt.Errorf("@ttsc/lint: load config file %s: %s", location, stderr)
1128
- }
1129
- return nil, fmt.Errorf("@ttsc/lint: load config file %s: %w", location, err)
1130
- }
1131
- var out any
1132
- if err := json.Unmarshal(output, &out); err != nil {
1133
- return nil, fmt.Errorf("@ttsc/lint: parse config file %s output: %w", location, err)
1134
- }
1135
- if !isConfigObject(out) {
1136
- return nil, fmt.Errorf("@ttsc/lint: config file %s must export an ITtscLintConfig object", location)
1137
- }
1138
- return out, nil
1176
+ return runConfigLoaderCommand(ctx, cmd, location, "config file")
1139
1177
  }
1140
1178
 
1141
1179
  // loadTypeScriptConfigFile evaluates a .ts/.cts/.mts config file by writing
@@ -1194,28 +1232,7 @@ func loadTypeScriptConfigFile(location string) (any, error) {
1194
1232
  defer cancel()
1195
1233
  cmd := ttsxCommandContext(ctx, args...)
1196
1234
  cmd.Env = nodeConfigLoaderEnv(location)
1197
- output, err := cmd.Output()
1198
- if err != nil {
1199
- if ctx.Err() == context.DeadlineExceeded {
1200
- return nil, fmt.Errorf("@ttsc/lint: load TypeScript config file %s: timed out after %s", location, configLoaderTimeout)
1201
- }
1202
- stderr := ""
1203
- if exit, ok := err.(*exec.ExitError); ok {
1204
- stderr = strings.TrimSpace(string(exit.Stderr))
1205
- }
1206
- if stderr != "" {
1207
- return nil, fmt.Errorf("@ttsc/lint: load TypeScript config file %s: %s", location, stderr)
1208
- }
1209
- return nil, fmt.Errorf("@ttsc/lint: load TypeScript config file %s: %w", location, err)
1210
- }
1211
- var out any
1212
- if err := json.Unmarshal(output, &out); err != nil {
1213
- return nil, fmt.Errorf("@ttsc/lint: parse TypeScript config file %s output: %w", location, err)
1214
- }
1215
- if !isConfigObject(out) {
1216
- return nil, fmt.Errorf("@ttsc/lint: config file %s must export an ITtscLintConfig object", location)
1217
- }
1218
- return out, nil
1235
+ return runConfigLoaderCommand(ctx, cmd, location, "TypeScript config file")
1219
1236
  }
1220
1237
 
1221
1238
  // isConfigObject reports whether `value` is a top-level config object. A lint
@@ -1303,14 +1320,14 @@ function hasOwn(value: Record<string, unknown>, key: string): boolean {
1303
1320
  // whose only key is "format" is not silently dropped.
1304
1321
  function toSerializableConfig(value: Record<string, unknown>): Record<string, unknown> {
1305
1322
  const out: Record<string, unknown> = {};
1306
- for (const key of ["files", "ignores", "extends", "plugins", "rules", "format"]) {
1323
+ for (const key of [%s]) {
1307
1324
  if (hasOwn(value, key)) {
1308
1325
  out[key] = value[key];
1309
1326
  }
1310
1327
  }
1311
1328
  return out;
1312
1329
  }
1313
- `, importLiteral)
1330
+ `, importLiteral, serializableConfigKeysLiteral())
1314
1331
  }
1315
1332
 
1316
1333
  // typeScriptConfigLoaderTsconfig generates the JSON content of the ephemeral
@@ -1731,7 +1748,7 @@ func (c RuleConfig) Severity(name string) Severity {
1731
1748
  if sev, ok := c[name]; ok {
1732
1749
  return sev
1733
1750
  }
1734
- canonical := normalizeExternalRuleName(name)
1751
+ canonical := normalizeBuiltinRuleName(name)
1735
1752
  if sev, ok := c[canonical]; ok {
1736
1753
  return sev
1737
1754
  }