@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
@@ -11,7 +11,7 @@
11
11
  package linthost
12
12
 
13
13
  import (
14
- shimast "github.com/microsoft/typescript-go/shim/ast"
14
+ shimast "github.com/microsoft/typescript-go/shim/ast"
15
15
  )
16
16
 
17
17
  // noAwaitInLoop reports an `await` expression evaluated inside the body
@@ -28,30 +28,30 @@ type noAwaitInLoop struct{}
28
28
 
29
29
  func (noAwaitInLoop) Name() string { return "no-await-in-loop" }
30
30
  func (noAwaitInLoop) Visits() []shimast.Kind {
31
- return []shimast.Kind{shimast.KindAwaitExpression}
31
+ return []shimast.Kind{shimast.KindAwaitExpression}
32
32
  }
33
33
  func (noAwaitInLoop) Check(ctx *Context, node *shimast.Node) {
34
- for cur := node.Parent; cur != nil; cur = cur.Parent {
35
- if isFunctionLikeKind(cur) {
36
- return
37
- }
38
- switch cur.Kind {
39
- case shimast.KindForStatement,
40
- shimast.KindWhileStatement,
41
- shimast.KindDoStatement,
42
- shimast.KindForInStatement:
43
- ctx.Report(node, "Unexpected `await` inside a loop — iterations run sequentially; prefer `Promise.all` when independent.")
44
- return
45
- case shimast.KindForOfStatement:
46
- // `for await … of` loops are exempt by design — the await
47
- // is the iteration itself, not a sequential block.
48
- if isForAwaitOfStatement(ctx.File, cur) {
49
- return
50
- }
51
- ctx.Report(node, "Unexpected `await` inside a loop — iterations run sequentially; prefer `Promise.all` when independent.")
52
- return
53
- }
54
- }
34
+ for cur := node.Parent; cur != nil; cur = cur.Parent {
35
+ if isFunctionLikeKind(cur) {
36
+ return
37
+ }
38
+ switch cur.Kind {
39
+ case shimast.KindForStatement,
40
+ shimast.KindWhileStatement,
41
+ shimast.KindDoStatement,
42
+ shimast.KindForInStatement:
43
+ ctx.Report(node, "Unexpected `await` inside a loop — iterations run sequentially; prefer `Promise.all` when independent.")
44
+ return
45
+ case shimast.KindForOfStatement:
46
+ // `for await … of` loops are exempt by design — the await
47
+ // is the iteration itself, not a sequential block.
48
+ if isForAwaitOfStatement(ctx.File, cur) {
49
+ return
50
+ }
51
+ ctx.Report(node, "Unexpected `await` inside a loop — iterations run sequentially; prefer `Promise.all` when independent.")
52
+ return
53
+ }
54
+ }
55
55
  }
56
56
 
57
57
  // isForAwaitOfStatement reports whether the for-of statement at `node`
@@ -61,28 +61,28 @@ func (noAwaitInLoop) Check(ctx *Context, node *shimast.Node) {
61
61
  // in the small window before the opening parenthesis. The width 24
62
62
  // covers any reasonable spacing/comment-free header.
63
63
  func isForAwaitOfStatement(file *shimast.SourceFile, node *shimast.Node) bool {
64
- if file == nil || node == nil {
65
- return false
66
- }
67
- forPos := keywordStart(file, node, "for")
68
- if forPos < 0 {
69
- return false
70
- }
71
- src := file.Text()
72
- limit := forPos + 24
73
- if limit > len(src) {
74
- limit = len(src)
75
- }
76
- if node.End() < limit {
77
- limit = node.End()
78
- }
79
- for i := forPos + 3; i < limit; i++ {
80
- if src[i] == '(' {
81
- limit = i
82
- break
83
- }
84
- }
85
- return findKeyword(file, forPos+3, limit, "await") >= 0
64
+ if file == nil || node == nil {
65
+ return false
66
+ }
67
+ forPos := keywordStart(file, node, "for")
68
+ if forPos < 0 {
69
+ return false
70
+ }
71
+ src := file.Text()
72
+ limit := forPos + 24
73
+ if limit > len(src) {
74
+ limit = len(src)
75
+ }
76
+ if node.End() < limit {
77
+ limit = node.End()
78
+ }
79
+ for i := forPos + 3; i < limit; i++ {
80
+ if src[i] == '(' {
81
+ limit = i
82
+ break
83
+ }
84
+ }
85
+ return findKeyword(file, forPos+3, limit, "await") >= 0
86
86
  }
87
87
 
88
88
  // noDupeClassMembers reports two declarations of the same member on a
@@ -98,52 +98,52 @@ type noDupeClassMembers struct{}
98
98
 
99
99
  func (noDupeClassMembers) Name() string { return "no-dupe-class-members" }
100
100
  func (noDupeClassMembers) Visits() []shimast.Kind {
101
- return []shimast.Kind{shimast.KindClassDeclaration, shimast.KindClassExpression}
101
+ return []shimast.Kind{shimast.KindClassDeclaration, shimast.KindClassExpression}
102
102
  }
103
103
  func (noDupeClassMembers) Check(ctx *Context, node *shimast.Node) {
104
- members := classMembers(node)
105
- if len(members) == 0 {
106
- return
107
- }
108
- type slot struct {
109
- name string
110
- static bool
111
- kind string
112
- }
113
- seen := map[slot]*shimast.Node{}
114
- for _, member := range members {
115
- if member == nil {
116
- continue
117
- }
118
- name, kind, ok := classMemberSlot(member)
119
- if !ok {
120
- continue
121
- }
122
- key := slot{name: name, static: hasModifier(member, shimast.KindStaticKeyword), kind: kind}
123
- if prior, exists := seen[key]; exists {
124
- _ = prior
125
- ctx.Report(member, "Duplicate class member `"+name+"`.")
126
- continue
127
- }
128
- seen[key] = member
129
- }
104
+ members := classMembers(node)
105
+ if len(members) == 0 {
106
+ return
107
+ }
108
+ type slot struct {
109
+ name string
110
+ static bool
111
+ kind string
112
+ }
113
+ seen := map[slot]*shimast.Node{}
114
+ for _, member := range members {
115
+ if member == nil {
116
+ continue
117
+ }
118
+ name, kind, ok := classMemberSlot(member)
119
+ if !ok {
120
+ continue
121
+ }
122
+ key := slot{name: name, static: hasModifier(member, shimast.KindStaticKeyword), kind: kind}
123
+ if prior, exists := seen[key]; exists {
124
+ _ = prior
125
+ ctx.Report(member, "Duplicate class member `"+name+"`.")
126
+ continue
127
+ }
128
+ seen[key] = member
129
+ }
130
130
  }
131
131
 
132
132
  // classMembers returns the member list of a class declaration or
133
133
  // expression. Returns nil for any other kind so the helper is safe to
134
134
  // call from a multi-visit rule.
135
135
  func classMembers(node *shimast.Node) []*shimast.Node {
136
- switch node.Kind {
137
- case shimast.KindClassDeclaration:
138
- if decl := node.AsClassDeclaration(); decl != nil && decl.Members != nil {
139
- return decl.Members.Nodes
140
- }
141
- case shimast.KindClassExpression:
142
- if expr := node.AsClassExpression(); expr != nil && expr.Members != nil {
143
- return expr.Members.Nodes
144
- }
145
- }
146
- return nil
136
+ switch node.Kind {
137
+ case shimast.KindClassDeclaration:
138
+ if decl := node.AsClassDeclaration(); decl != nil && decl.Members != nil {
139
+ return decl.Members.Nodes
140
+ }
141
+ case shimast.KindClassExpression:
142
+ if expr := node.AsClassExpression(); expr != nil && expr.Members != nil {
143
+ return expr.Members.Nodes
144
+ }
145
+ }
146
+ return nil
147
147
  }
148
148
 
149
149
  // classMemberSlot extracts the (name, kind) identity for a class
@@ -152,30 +152,30 @@ func classMembers(node *shimast.Node) []*shimast.Node {
152
152
  // getter/setter pairs from regular method/property declarations so a
153
153
  // getter+setter on the same name does not trip the dupe check.
154
154
  func classMemberSlot(member *shimast.Node) (string, string, bool) {
155
- if member == nil {
156
- return "", "", false
157
- }
158
- switch member.Kind {
159
- case shimast.KindMethodDeclaration,
160
- shimast.KindPropertyDeclaration,
161
- shimast.KindGetAccessor,
162
- shimast.KindSetAccessor:
163
- name := classMemberName(member)
164
- if name == "" {
165
- return "", "", false
166
- }
167
- var kind string
168
- switch member.Kind {
169
- case shimast.KindGetAccessor:
170
- kind = "get"
171
- case shimast.KindSetAccessor:
172
- kind = "set"
173
- default:
174
- kind = "data"
175
- }
176
- return name, kind, true
177
- }
178
- return "", "", false
155
+ if member == nil {
156
+ return "", "", false
157
+ }
158
+ switch member.Kind {
159
+ case shimast.KindMethodDeclaration,
160
+ shimast.KindPropertyDeclaration,
161
+ shimast.KindGetAccessor,
162
+ shimast.KindSetAccessor:
163
+ name := classMemberName(member)
164
+ if name == "" {
165
+ return "", "", false
166
+ }
167
+ var kind string
168
+ switch member.Kind {
169
+ case shimast.KindGetAccessor:
170
+ kind = "get"
171
+ case shimast.KindSetAccessor:
172
+ kind = "set"
173
+ default:
174
+ kind = "data"
175
+ }
176
+ return name, kind, true
177
+ }
178
+ return "", "", false
179
179
  }
180
180
 
181
181
  // classMemberName returns the textual name of a class member identifier
@@ -183,19 +183,19 @@ func classMemberSlot(member *shimast.Node) (string, string, bool) {
183
183
  // the caller can skip them — the rule cannot prove equivalence of two
184
184
  // computed expressions statically.
185
185
  func classMemberName(member *shimast.Node) string {
186
- name := member.Name()
187
- if name == nil {
188
- return ""
189
- }
190
- switch name.Kind {
191
- case shimast.KindIdentifier, shimast.KindPrivateIdentifier:
192
- return identifierText(name)
193
- case shimast.KindStringLiteral:
194
- return stringLiteralText(name)
195
- case shimast.KindNumericLiteral:
196
- return numericLiteralText(name)
197
- }
198
- return ""
186
+ name := member.Name()
187
+ if name == nil {
188
+ return ""
189
+ }
190
+ switch name.Kind {
191
+ case shimast.KindIdentifier, shimast.KindPrivateIdentifier:
192
+ return identifierText(name)
193
+ case shimast.KindStringLiteral:
194
+ return stringLiteralText(name)
195
+ case shimast.KindNumericLiteral:
196
+ return numericLiteralText(name)
197
+ }
198
+ return ""
199
199
  }
200
200
 
201
201
  // noThisBeforeSuper reports a derived constructor that references
@@ -213,114 +213,114 @@ type noThisBeforeSuper struct{}
213
213
 
214
214
  func (noThisBeforeSuper) Name() string { return "no-this-before-super" }
215
215
  func (noThisBeforeSuper) Visits() []shimast.Kind {
216
- return []shimast.Kind{shimast.KindConstructor}
216
+ return []shimast.Kind{shimast.KindConstructor}
217
217
  }
218
218
  func (noThisBeforeSuper) Check(ctx *Context, node *shimast.Node) {
219
- parent := node.Parent
220
- if parent == nil || !classExtendsAnother(parent) {
221
- return
222
- }
223
- ctor := node.AsConstructorDeclaration()
224
- if ctor == nil || ctor.Body == nil {
225
- return
226
- }
227
- var superCallPos = -1
228
- walkConstructorBody(ctor.Body, func(child *shimast.Node) {
229
- if child == nil || superCallPos >= 0 {
230
- return
231
- }
232
- if child.Kind == shimast.KindCallExpression {
233
- call := child.AsCallExpression()
234
- if call != nil && call.Expression != nil && call.Expression.Kind == shimast.KindSuperKeyword {
235
- superCallPos = child.Pos()
236
- }
237
- }
238
- })
239
- walkConstructorBody(ctor.Body, func(child *shimast.Node) {
240
- if child == nil {
241
- return
242
- }
243
- // Skip the call to super() itself.
244
- if child.Kind == shimast.KindCallExpression {
245
- call := child.AsCallExpression()
246
- if call != nil && call.Expression != nil && call.Expression.Kind == shimast.KindSuperKeyword {
247
- return
248
- }
249
- }
250
- switch child.Kind {
251
- case shimast.KindThisKeyword:
252
- if superCallPos < 0 || child.Pos() < superCallPos {
253
- ctx.Report(child, "`this` referenced before `super()` call in a derived constructor.")
254
- }
255
- case shimast.KindPropertyAccessExpression:
256
- access := child.AsPropertyAccessExpression()
257
- if access != nil && access.Expression != nil && access.Expression.Kind == shimast.KindSuperKeyword {
258
- if superCallPos < 0 || child.Pos() < superCallPos {
259
- ctx.Report(child, "`super.` access before `super()` call in a derived constructor.")
260
- }
261
- }
262
- }
263
- })
219
+ parent := node.Parent
220
+ if parent == nil || !classExtendsAnother(parent) {
221
+ return
222
+ }
223
+ ctor := node.AsConstructorDeclaration()
224
+ if ctor == nil || ctor.Body == nil {
225
+ return
226
+ }
227
+ var superCallPos = -1
228
+ walkConstructorBody(ctor.Body, func(child *shimast.Node) {
229
+ if child == nil || superCallPos >= 0 {
230
+ return
231
+ }
232
+ if child.Kind == shimast.KindCallExpression {
233
+ call := child.AsCallExpression()
234
+ if call != nil && call.Expression != nil && call.Expression.Kind == shimast.KindSuperKeyword {
235
+ superCallPos = child.Pos()
236
+ }
237
+ }
238
+ })
239
+ walkConstructorBody(ctor.Body, func(child *shimast.Node) {
240
+ if child == nil {
241
+ return
242
+ }
243
+ // Skip the call to super() itself.
244
+ if child.Kind == shimast.KindCallExpression {
245
+ call := child.AsCallExpression()
246
+ if call != nil && call.Expression != nil && call.Expression.Kind == shimast.KindSuperKeyword {
247
+ return
248
+ }
249
+ }
250
+ switch child.Kind {
251
+ case shimast.KindThisKeyword:
252
+ if superCallPos < 0 || child.Pos() < superCallPos {
253
+ ctx.Report(child, "`this` referenced before `super()` call in a derived constructor.")
254
+ }
255
+ case shimast.KindPropertyAccessExpression:
256
+ access := child.AsPropertyAccessExpression()
257
+ if access != nil && access.Expression != nil && access.Expression.Kind == shimast.KindSuperKeyword {
258
+ if superCallPos < 0 || child.Pos() < superCallPos {
259
+ ctx.Report(child, "`super.` access before `super()` call in a derived constructor.")
260
+ }
261
+ }
262
+ }
263
+ })
264
264
  }
265
265
 
266
266
  // classExtendsAnother reports whether the class declaration/expression
267
267
  // has a non-empty `extends` heritage clause. Base classes (no extends)
268
268
  // are skipped — `this` is legal before any super call there.
269
269
  func classExtendsAnother(class *shimast.Node) bool {
270
- var clauses []*shimast.Node
271
- switch class.Kind {
272
- case shimast.KindClassDeclaration:
273
- decl := class.AsClassDeclaration()
274
- if decl == nil || decl.HeritageClauses == nil {
275
- return false
276
- }
277
- clauses = decl.HeritageClauses.Nodes
278
- case shimast.KindClassExpression:
279
- expr := class.AsClassExpression()
280
- if expr == nil || expr.HeritageClauses == nil {
281
- return false
282
- }
283
- clauses = expr.HeritageClauses.Nodes
284
- default:
285
- return false
286
- }
287
- for _, clause := range clauses {
288
- if clause == nil {
289
- continue
290
- }
291
- hc := clause.AsHeritageClause()
292
- if hc == nil || hc.Token != shimast.KindExtendsKeyword {
293
- continue
294
- }
295
- if hc.Types != nil && len(hc.Types.Nodes) > 0 {
296
- return true
297
- }
298
- }
299
- return false
270
+ var clauses []*shimast.Node
271
+ switch class.Kind {
272
+ case shimast.KindClassDeclaration:
273
+ decl := class.AsClassDeclaration()
274
+ if decl == nil || decl.HeritageClauses == nil {
275
+ return false
276
+ }
277
+ clauses = decl.HeritageClauses.Nodes
278
+ case shimast.KindClassExpression:
279
+ expr := class.AsClassExpression()
280
+ if expr == nil || expr.HeritageClauses == nil {
281
+ return false
282
+ }
283
+ clauses = expr.HeritageClauses.Nodes
284
+ default:
285
+ return false
286
+ }
287
+ for _, clause := range clauses {
288
+ if clause == nil {
289
+ continue
290
+ }
291
+ hc := clause.AsHeritageClause()
292
+ if hc == nil || hc.Token != shimast.KindExtendsKeyword {
293
+ continue
294
+ }
295
+ if hc.Types != nil && len(hc.Types.Nodes) > 0 {
296
+ return true
297
+ }
298
+ }
299
+ return false
300
300
  }
301
301
 
302
302
  // walkConstructorBody walks every descendant of body, skipping into
303
303
  // nested function-like scopes so a `this` inside an inner arrow does
304
304
  // not get attributed to the surrounding constructor.
305
305
  func walkConstructorBody(body *shimast.Node, visit func(*shimast.Node)) {
306
- if body == nil {
307
- return
308
- }
309
- var walk func(*shimast.Node)
310
- walk = func(n *shimast.Node) {
311
- if n == nil {
312
- return
313
- }
314
- if n != body && isFunctionLikeKind(n) {
315
- return
316
- }
317
- visit(n)
318
- n.ForEachChild(func(child *shimast.Node) bool {
319
- walk(child)
320
- return false
321
- })
322
- }
323
- walk(body)
306
+ if body == nil {
307
+ return
308
+ }
309
+ var walk func(*shimast.Node)
310
+ walk = func(n *shimast.Node) {
311
+ if n == nil {
312
+ return
313
+ }
314
+ if n != body && isFunctionLikeKind(n) {
315
+ return
316
+ }
317
+ visit(n)
318
+ n.ForEachChild(func(child *shimast.Node) bool {
319
+ walk(child)
320
+ return false
321
+ })
322
+ }
323
+ walk(body)
324
324
  }
325
325
 
326
326
  // preferObjectSpread reports `Object.assign({}, …)` calls that should
@@ -338,43 +338,43 @@ type preferObjectSpread struct{}
338
338
 
339
339
  func (preferObjectSpread) Name() string { return "prefer-object-spread" }
340
340
  func (preferObjectSpread) Visits() []shimast.Kind {
341
- return []shimast.Kind{shimast.KindCallExpression}
341
+ return []shimast.Kind{shimast.KindCallExpression}
342
342
  }
343
343
  func (preferObjectSpread) Check(ctx *Context, node *shimast.Node) {
344
- call := node.AsCallExpression()
345
- if call == nil || call.Expression == nil || call.Arguments == nil {
346
- return
347
- }
348
- obj, method, ok := promisePropertyAccessParts(call.Expression)
349
- if !ok || method != "assign" {
350
- return
351
- }
352
- if identifierText(obj) != "Object" {
353
- return
354
- }
355
- if len(call.Arguments.Nodes) < 2 {
356
- return
357
- }
358
- first := stripParens(call.Arguments.Nodes[0])
359
- if first == nil || first.Kind != shimast.KindObjectLiteralExpression {
360
- return
361
- }
362
- if objectLiteralIsEmpty(first) {
363
- ctx.Report(node, "Prefer object spread `{ ...a, ...b }` over `Object.assign({}, a, b)`.")
364
- }
344
+ call := node.AsCallExpression()
345
+ if call == nil || call.Expression == nil || call.Arguments == nil {
346
+ return
347
+ }
348
+ obj, method, ok := promisePropertyAccessParts(call.Expression)
349
+ if !ok || method != "assign" {
350
+ return
351
+ }
352
+ if identifierText(obj) != "Object" {
353
+ return
354
+ }
355
+ if len(call.Arguments.Nodes) < 2 {
356
+ return
357
+ }
358
+ first := stripParens(call.Arguments.Nodes[0])
359
+ if first == nil || first.Kind != shimast.KindObjectLiteralExpression {
360
+ return
361
+ }
362
+ if objectLiteralIsEmpty(first) {
363
+ ctx.Report(node, "Prefer object spread `{ ...a, ...b }` over `Object.assign({}, a, b)`.")
364
+ }
365
365
  }
366
366
 
367
367
  // objectLiteralIsEmpty reports whether node is the literal `{}` (no
368
368
  // properties, no shorthand assignments, no spreads).
369
369
  func objectLiteralIsEmpty(node *shimast.Node) bool {
370
- if node == nil || node.Kind != shimast.KindObjectLiteralExpression {
371
- return false
372
- }
373
- lit := node.AsObjectLiteralExpression()
374
- if lit == nil || lit.Properties == nil {
375
- return true
376
- }
377
- return len(lit.Properties.Nodes) == 0
370
+ if node == nil || node.Kind != shimast.KindObjectLiteralExpression {
371
+ return false
372
+ }
373
+ lit := node.AsObjectLiteralExpression()
374
+ if lit == nil || lit.Properties == nil {
375
+ return true
376
+ }
377
+ return len(lit.Properties.Nodes) == 0
378
378
  }
379
379
 
380
380
  // noDuplicateImports reports two import declarations that resolve to
@@ -391,29 +391,29 @@ type noDuplicateImports struct{}
391
391
 
392
392
  func (noDuplicateImports) Name() string { return "no-duplicate-imports" }
393
393
  func (noDuplicateImports) Visits() []shimast.Kind {
394
- return []shimast.Kind{shimast.KindSourceFile}
394
+ return []shimast.Kind{shimast.KindSourceFile}
395
395
  }
396
396
  func (noDuplicateImports) Check(ctx *Context, node *shimast.Node) {
397
- seen := map[string]bool{}
398
- node.ForEachChild(func(child *shimast.Node) bool {
399
- if child == nil || child.Kind != shimast.KindImportDeclaration {
400
- return false
401
- }
402
- decl := child.AsImportDeclaration()
403
- if decl == nil || decl.ModuleSpecifier == nil {
404
- return false
405
- }
406
- spec := stringLiteralText(decl.ModuleSpecifier)
407
- if spec == "" {
408
- return false
409
- }
410
- if seen[spec] {
411
- ctx.Report(child, "Module `"+spec+"` is already imported above; consolidate the imports.")
412
- return false
413
- }
414
- seen[spec] = true
415
- return false
416
- })
397
+ seen := map[string]bool{}
398
+ node.ForEachChild(func(child *shimast.Node) bool {
399
+ if child == nil || child.Kind != shimast.KindImportDeclaration {
400
+ return false
401
+ }
402
+ decl := child.AsImportDeclaration()
403
+ if decl == nil || decl.ModuleSpecifier == nil {
404
+ return false
405
+ }
406
+ spec := stringLiteralText(decl.ModuleSpecifier)
407
+ if spec == "" {
408
+ return false
409
+ }
410
+ if seen[spec] {
411
+ ctx.Report(child, "Module `"+spec+"` is already imported above; consolidate the imports.")
412
+ return false
413
+ }
414
+ seen[spec] = true
415
+ return false
416
+ })
417
417
  }
418
418
 
419
419
  // getterReturn reports a `get` accessor whose body completes without
@@ -425,16 +425,16 @@ type getterReturn struct{}
425
425
 
426
426
  func (getterReturn) Name() string { return "getter-return" }
427
427
  func (getterReturn) Visits() []shimast.Kind {
428
- return []shimast.Kind{shimast.KindGetAccessor}
428
+ return []shimast.Kind{shimast.KindGetAccessor}
429
429
  }
430
430
  func (getterReturn) Check(ctx *Context, node *shimast.Node) {
431
- accessor := node.AsGetAccessorDeclaration()
432
- if accessor == nil || accessor.Body == nil {
433
- return
434
- }
435
- if !getterBodyAlwaysReturns(accessor.Body) {
436
- ctx.Report(node, "Getter must return a value.")
437
- }
431
+ accessor := node.AsGetAccessorDeclaration()
432
+ if accessor == nil || accessor.Body == nil {
433
+ return
434
+ }
435
+ if !getterBodyAlwaysReturns(accessor.Body) {
436
+ ctx.Report(node, "Getter must return a value.")
437
+ }
438
438
  }
439
439
 
440
440
  // getterBodyAlwaysReturns walks a `get` accessor body and reports
@@ -442,44 +442,44 @@ func (getterReturn) Check(ctx *Context, node *shimast.Node) {
442
442
  // shallow approximation — sufficient for the common case where the
443
443
  // getter's body is a sequence of statements ending in `return X`.
444
444
  func getterBodyAlwaysReturns(body *shimast.Node) bool {
445
- if body == nil || body.Kind != shimast.KindBlock {
446
- return false
447
- }
448
- statements := body.Statements()
449
- if len(statements) == 0 {
450
- return false
451
- }
452
- last := statements[len(statements)-1]
453
- return statementReturnsValue(last)
445
+ if body == nil || body.Kind != shimast.KindBlock {
446
+ return false
447
+ }
448
+ statements := body.Statements()
449
+ if len(statements) == 0 {
450
+ return false
451
+ }
452
+ last := statements[len(statements)-1]
453
+ return statementReturnsValue(last)
454
454
  }
455
455
 
456
456
  // statementReturnsValue checks if a statement is a value-returning
457
457
  // `return X;`, a `throw`, a block that ends in one of those, or a
458
458
  // conditional whose every branch returns a value.
459
459
  func statementReturnsValue(stmt *shimast.Node) bool {
460
- if stmt == nil {
461
- return false
462
- }
463
- switch stmt.Kind {
464
- case shimast.KindReturnStatement:
465
- ret := stmt.AsReturnStatement()
466
- return ret != nil && ret.Expression != nil
467
- case shimast.KindThrowStatement:
468
- return true
469
- case shimast.KindBlock:
470
- stmts := stmt.Statements()
471
- if len(stmts) == 0 {
472
- return false
473
- }
474
- return statementReturnsValue(stmts[len(stmts)-1])
475
- case shimast.KindIfStatement:
476
- ifStmt := stmt.AsIfStatement()
477
- if ifStmt == nil || ifStmt.ThenStatement == nil || ifStmt.ElseStatement == nil {
478
- return false
479
- }
480
- return statementReturnsValue(ifStmt.ThenStatement) && statementReturnsValue(ifStmt.ElseStatement)
481
- }
482
- return false
460
+ if stmt == nil {
461
+ return false
462
+ }
463
+ switch stmt.Kind {
464
+ case shimast.KindReturnStatement:
465
+ ret := stmt.AsReturnStatement()
466
+ return ret != nil && ret.Expression != nil
467
+ case shimast.KindThrowStatement:
468
+ return true
469
+ case shimast.KindBlock:
470
+ stmts := stmt.Statements()
471
+ if len(stmts) == 0 {
472
+ return false
473
+ }
474
+ return statementReturnsValue(stmts[len(stmts)-1])
475
+ case shimast.KindIfStatement:
476
+ ifStmt := stmt.AsIfStatement()
477
+ if ifStmt == nil || ifStmt.ThenStatement == nil || ifStmt.ElseStatement == nil {
478
+ return false
479
+ }
480
+ return statementReturnsValue(ifStmt.ThenStatement) && statementReturnsValue(ifStmt.ElseStatement)
481
+ }
482
+ return false
483
483
  }
484
484
 
485
485
  // noNewSymbol reports `new Symbol(...)`. `Symbol` is a function but not
@@ -492,16 +492,16 @@ type noNewSymbol struct{}
492
492
 
493
493
  func (noNewSymbol) Name() string { return "no-new-symbol" }
494
494
  func (noNewSymbol) Visits() []shimast.Kind {
495
- return []shimast.Kind{shimast.KindNewExpression}
495
+ return []shimast.Kind{shimast.KindNewExpression}
496
496
  }
497
497
  func (noNewSymbol) Check(ctx *Context, node *shimast.Node) {
498
- ne := node.AsNewExpression()
499
- if ne == nil {
500
- return
501
- }
502
- if identifierText(ne.Expression) == "Symbol" {
503
- ctx.Report(node, "`Symbol` cannot be called with `new`.")
504
- }
498
+ ne := node.AsNewExpression()
499
+ if ne == nil {
500
+ return
501
+ }
502
+ if identifierText(ne.Expression) == "Symbol" {
503
+ ctx.Report(node, "`Symbol` cannot be called with `new`.")
504
+ }
505
505
  }
506
506
 
507
507
  // noConstructorReturn reports a constructor body that contains a
@@ -514,22 +514,22 @@ type noConstructorReturn struct{}
514
514
 
515
515
  func (noConstructorReturn) Name() string { return "no-constructor-return" }
516
516
  func (noConstructorReturn) Visits() []shimast.Kind {
517
- return []shimast.Kind{shimast.KindConstructor}
517
+ return []shimast.Kind{shimast.KindConstructor}
518
518
  }
519
519
  func (noConstructorReturn) Check(ctx *Context, node *shimast.Node) {
520
- ctor := node.AsConstructorDeclaration()
521
- if ctor == nil || ctor.Body == nil {
522
- return
523
- }
524
- walkConstructorBody(ctor.Body, func(child *shimast.Node) {
525
- if child == nil || child.Kind != shimast.KindReturnStatement {
526
- return
527
- }
528
- ret := child.AsReturnStatement()
529
- if ret != nil && ret.Expression != nil {
530
- ctx.Report(child, "Class constructors should not return a value.")
531
- }
532
- })
520
+ ctor := node.AsConstructorDeclaration()
521
+ if ctor == nil || ctor.Body == nil {
522
+ return
523
+ }
524
+ walkConstructorBody(ctor.Body, func(child *shimast.Node) {
525
+ if child == nil || child.Kind != shimast.KindReturnStatement {
526
+ return
527
+ }
528
+ ret := child.AsReturnStatement()
529
+ if ret != nil && ret.Expression != nil {
530
+ ctx.Report(child, "Class constructors should not return a value.")
531
+ }
532
+ })
533
533
  }
534
534
 
535
535
  // noUnsafeOptionalChaining reports member access or call expressions
@@ -543,47 +543,47 @@ type noUnsafeOptionalChaining struct{}
543
543
 
544
544
  func (noUnsafeOptionalChaining) Name() string { return "no-unsafe-optional-chaining" }
545
545
  func (noUnsafeOptionalChaining) Visits() []shimast.Kind {
546
- return []shimast.Kind{
547
- shimast.KindPropertyAccessExpression,
548
- shimast.KindElementAccessExpression,
549
- shimast.KindCallExpression,
550
- }
546
+ return []shimast.Kind{
547
+ shimast.KindPropertyAccessExpression,
548
+ shimast.KindElementAccessExpression,
549
+ shimast.KindCallExpression,
550
+ }
551
551
  }
552
552
  func (noUnsafeOptionalChaining) Check(ctx *Context, node *shimast.Node) {
553
- var receiver *shimast.Node
554
- switch node.Kind {
555
- case shimast.KindPropertyAccessExpression:
556
- access := node.AsPropertyAccessExpression()
557
- if access == nil {
558
- return
559
- }
560
- // If this access is itself optional, the chain continues — safe.
561
- if access.QuestionDotToken != nil {
562
- return
563
- }
564
- receiver = access.Expression
565
- case shimast.KindElementAccessExpression:
566
- access := node.AsElementAccessExpression()
567
- if access == nil {
568
- return
569
- }
570
- if access.QuestionDotToken != nil {
571
- return
572
- }
573
- receiver = access.Expression
574
- case shimast.KindCallExpression:
575
- call := node.AsCallExpression()
576
- if call == nil {
577
- return
578
- }
579
- if call.QuestionDotToken != nil {
580
- return
581
- }
582
- receiver = call.Expression
583
- }
584
- if receiverEndsWithOptionalChain(receiver) {
585
- ctx.Report(node, "Unsafe access after an optional chain — continue the chain with `?.` or check for nullish above.")
586
- }
553
+ var receiver *shimast.Node
554
+ switch node.Kind {
555
+ case shimast.KindPropertyAccessExpression:
556
+ access := node.AsPropertyAccessExpression()
557
+ if access == nil {
558
+ return
559
+ }
560
+ // If this access is itself optional, the chain continues — safe.
561
+ if access.QuestionDotToken != nil {
562
+ return
563
+ }
564
+ receiver = access.Expression
565
+ case shimast.KindElementAccessExpression:
566
+ access := node.AsElementAccessExpression()
567
+ if access == nil {
568
+ return
569
+ }
570
+ if access.QuestionDotToken != nil {
571
+ return
572
+ }
573
+ receiver = access.Expression
574
+ case shimast.KindCallExpression:
575
+ call := node.AsCallExpression()
576
+ if call == nil {
577
+ return
578
+ }
579
+ if call.QuestionDotToken != nil {
580
+ return
581
+ }
582
+ receiver = call.Expression
583
+ }
584
+ if receiverEndsWithOptionalChain(receiver) {
585
+ ctx.Report(node, "Unsafe access after an optional chain — continue the chain with `?.` or check for nullish above.")
586
+ }
587
587
  }
588
588
 
589
589
  // receiverEndsWithOptionalChain reports whether the receiver expression
@@ -594,27 +594,27 @@ func (noUnsafeOptionalChaining) Check(ctx *Context, node *shimast.Node) {
594
594
  // at runtime the chain still resolves to undefined when the optional
595
595
  // link short-circuits, so we look through `NonNullExpression` too.
596
596
  func receiverEndsWithOptionalChain(node *shimast.Node) bool {
597
- node = stripParens(node)
598
- if node == nil {
599
- return false
600
- }
601
- if node.Kind == shimast.KindNonNullExpression {
602
- if nn := node.AsNonNullExpression(); nn != nil {
603
- return receiverEndsWithOptionalChain(nn.Expression)
604
- }
605
- }
606
- switch node.Kind {
607
- case shimast.KindPropertyAccessExpression:
608
- access := node.AsPropertyAccessExpression()
609
- return access != nil && access.QuestionDotToken != nil
610
- case shimast.KindElementAccessExpression:
611
- access := node.AsElementAccessExpression()
612
- return access != nil && access.QuestionDotToken != nil
613
- case shimast.KindCallExpression:
614
- call := node.AsCallExpression()
615
- return call != nil && call.QuestionDotToken != nil
616
- }
617
- return false
597
+ node = stripParens(node)
598
+ if node == nil {
599
+ return false
600
+ }
601
+ if node.Kind == shimast.KindNonNullExpression {
602
+ if nn := node.AsNonNullExpression(); nn != nil {
603
+ return receiverEndsWithOptionalChain(nn.Expression)
604
+ }
605
+ }
606
+ switch node.Kind {
607
+ case shimast.KindPropertyAccessExpression:
608
+ access := node.AsPropertyAccessExpression()
609
+ return access != nil && access.QuestionDotToken != nil
610
+ case shimast.KindElementAccessExpression:
611
+ access := node.AsElementAccessExpression()
612
+ return access != nil && access.QuestionDotToken != nil
613
+ case shimast.KindCallExpression:
614
+ call := node.AsCallExpression()
615
+ return call != nil && call.QuestionDotToken != nil
616
+ }
617
+ return false
618
618
  }
619
619
 
620
620
  // preferObjectHasOwn reports calls of the form
@@ -628,30 +628,30 @@ type preferObjectHasOwn struct{}
628
628
 
629
629
  func (preferObjectHasOwn) Name() string { return "prefer-object-has-own" }
630
630
  func (preferObjectHasOwn) Visits() []shimast.Kind {
631
- return []shimast.Kind{shimast.KindCallExpression}
631
+ return []shimast.Kind{shimast.KindCallExpression}
632
632
  }
633
633
  func (preferObjectHasOwn) Check(ctx *Context, node *shimast.Node) {
634
- call := node.AsCallExpression()
635
- if call == nil || call.Expression == nil {
636
- return
637
- }
638
- // Pattern: Object.prototype.hasOwnProperty.call(obj, key)
639
- outer, method, ok := promisePropertyAccessParts(call.Expression)
640
- if !ok || method != "call" {
641
- return
642
- }
643
- inner, name, ok := promisePropertyAccessParts(outer)
644
- if !ok || name != "hasOwnProperty" {
645
- return
646
- }
647
- base, prop, ok := promisePropertyAccessParts(inner)
648
- if !ok || prop != "prototype" {
649
- return
650
- }
651
- if identifierText(base) != "Object" {
652
- return
653
- }
654
- ctx.Report(node, "Prefer `Object.hasOwn(obj, key)` over `Object.prototype.hasOwnProperty.call(obj, key)`.")
634
+ call := node.AsCallExpression()
635
+ if call == nil || call.Expression == nil {
636
+ return
637
+ }
638
+ // Pattern: Object.prototype.hasOwnProperty.call(obj, key)
639
+ outer, method, ok := promisePropertyAccessParts(call.Expression)
640
+ if !ok || method != "call" {
641
+ return
642
+ }
643
+ inner, name, ok := promisePropertyAccessParts(outer)
644
+ if !ok || name != "hasOwnProperty" {
645
+ return
646
+ }
647
+ base, prop, ok := promisePropertyAccessParts(inner)
648
+ if !ok || prop != "prototype" {
649
+ return
650
+ }
651
+ if identifierText(base) != "Object" {
652
+ return
653
+ }
654
+ ctx.Report(node, "Prefer `Object.hasOwn(obj, key)` over `Object.prototype.hasOwnProperty.call(obj, key)`.")
655
655
  }
656
656
 
657
657
  // noImplicitCoercion reports the most common implicit coercion idioms:
@@ -664,76 +664,76 @@ type noImplicitCoercion struct{}
664
664
 
665
665
  func (noImplicitCoercion) Name() string { return "no-implicit-coercion" }
666
666
  func (noImplicitCoercion) Visits() []shimast.Kind {
667
- return []shimast.Kind{
668
- shimast.KindPrefixUnaryExpression,
669
- shimast.KindBinaryExpression,
670
- }
667
+ return []shimast.Kind{
668
+ shimast.KindPrefixUnaryExpression,
669
+ shimast.KindBinaryExpression,
670
+ }
671
671
  }
672
672
  func (noImplicitCoercion) Check(ctx *Context, node *shimast.Node) {
673
- switch node.Kind {
674
- case shimast.KindPrefixUnaryExpression:
675
- prefix := node.AsPrefixUnaryExpression()
676
- if prefix == nil || prefix.Operand == nil {
677
- return
678
- }
679
- switch prefix.Operator {
680
- case shimast.KindExclamationToken:
681
- // `!!x` → Boolean(x). The inner expression must be another `!`.
682
- inner := stripParens(prefix.Operand)
683
- if inner == nil || inner.Kind != shimast.KindPrefixUnaryExpression {
684
- return
685
- }
686
- innerPrefix := inner.AsPrefixUnaryExpression()
687
- if innerPrefix != nil && innerPrefix.Operator == shimast.KindExclamationToken {
688
- ctx.Report(node, "Prefer `Boolean(x)` over `!!x` for explicit boolean coercion.")
689
- }
690
- case shimast.KindPlusToken:
691
- // `+x` where x is not a numeric literal → Number(x). Skip
692
- // numeric literals because `+0` / `+1` are the canonical form
693
- // for explicit positive numbers.
694
- operand := stripParens(prefix.Operand)
695
- if operand == nil || operand.Kind == shimast.KindNumericLiteral {
696
- return
697
- }
698
- ctx.Report(node, "Prefer `Number(x)` over `+x` for explicit number coercion.")
699
- }
700
- case shimast.KindBinaryExpression:
701
- bin := node.AsBinaryExpression()
702
- if bin == nil || bin.OperatorToken == nil || bin.OperatorToken.Kind != shimast.KindPlusToken {
703
- return
704
- }
705
- // `"" + x` or `x + ""` → String(x).
706
- left := stripParens(bin.Left)
707
- right := stripParens(bin.Right)
708
- if isEmptyStringLiteral(left) && right != nil && !isEmptyStringLiteral(right) {
709
- ctx.Report(node, "Prefer `String(x)` over `\"\" + x` for explicit string coercion.")
710
- return
711
- }
712
- if isEmptyStringLiteral(right) && left != nil && !isEmptyStringLiteral(left) {
713
- ctx.Report(node, "Prefer `String(x)` over `x + \"\"` for explicit string coercion.")
714
- }
715
- }
673
+ switch node.Kind {
674
+ case shimast.KindPrefixUnaryExpression:
675
+ prefix := node.AsPrefixUnaryExpression()
676
+ if prefix == nil || prefix.Operand == nil {
677
+ return
678
+ }
679
+ switch prefix.Operator {
680
+ case shimast.KindExclamationToken:
681
+ // `!!x` → Boolean(x). The inner expression must be another `!`.
682
+ inner := stripParens(prefix.Operand)
683
+ if inner == nil || inner.Kind != shimast.KindPrefixUnaryExpression {
684
+ return
685
+ }
686
+ innerPrefix := inner.AsPrefixUnaryExpression()
687
+ if innerPrefix != nil && innerPrefix.Operator == shimast.KindExclamationToken {
688
+ ctx.Report(node, "Prefer `Boolean(x)` over `!!x` for explicit boolean coercion.")
689
+ }
690
+ case shimast.KindPlusToken:
691
+ // `+x` where x is not a numeric literal → Number(x). Skip
692
+ // numeric literals because `+0` / `+1` are the canonical form
693
+ // for explicit positive numbers.
694
+ operand := stripParens(prefix.Operand)
695
+ if operand == nil || operand.Kind == shimast.KindNumericLiteral {
696
+ return
697
+ }
698
+ ctx.Report(node, "Prefer `Number(x)` over `+x` for explicit number coercion.")
699
+ }
700
+ case shimast.KindBinaryExpression:
701
+ bin := node.AsBinaryExpression()
702
+ if bin == nil || bin.OperatorToken == nil || bin.OperatorToken.Kind != shimast.KindPlusToken {
703
+ return
704
+ }
705
+ // `"" + x` or `x + ""` → String(x).
706
+ left := stripParens(bin.Left)
707
+ right := stripParens(bin.Right)
708
+ if isEmptyStringLiteral(left) && right != nil && !isEmptyStringLiteral(right) {
709
+ ctx.Report(node, "Prefer `String(x)` over `\"\" + x` for explicit string coercion.")
710
+ return
711
+ }
712
+ if isEmptyStringLiteral(right) && left != nil && !isEmptyStringLiteral(left) {
713
+ ctx.Report(node, "Prefer `String(x)` over `x + \"\"` for explicit string coercion.")
714
+ }
715
+ }
716
716
  }
717
717
 
718
718
  // isEmptyStringLiteral reports whether node is the literal `""` or
719
- // `''` (an empty-string string literal).
719
+ // `”` (an empty-string string literal).
720
720
  func isEmptyStringLiteral(node *shimast.Node) bool {
721
- if node == nil || node.Kind != shimast.KindStringLiteral {
722
- return false
723
- }
724
- return stringLiteralText(node) == ""
721
+ if node == nil || node.Kind != shimast.KindStringLiteral {
722
+ return false
723
+ }
724
+ return stringLiteralText(node) == ""
725
725
  }
726
726
 
727
727
  func init() {
728
- Register(noAwaitInLoop{})
729
- Register(noConstructorReturn{})
730
- Register(noDupeClassMembers{})
731
- Register(noDuplicateImports{})
732
- Register(noImplicitCoercion{})
733
- Register(noNewSymbol{})
734
- Register(noThisBeforeSuper{})
735
- Register(noUnsafeOptionalChaining{})
736
- Register(getterReturn{})
737
- Register(preferObjectHasOwn{})
738
- Register(preferObjectSpread{})
728
+ Register(noAwaitInLoop{})
729
+ Register(noConstructorReturn{})
730
+ Register(noDupeClassMembers{})
731
+ Register(noDuplicateImports{})
732
+ Register(noImplicitCoercion{})
733
+ Register(noNewSymbol{})
734
+ Register(noThisBeforeSuper{})
735
+ Register(noUnsafeOptionalChaining{})
736
+ Register(getterReturn{})
737
+ Register(preferObjectHasOwn{})
738
+ Register(preferObjectSpread{})
739
739
  }