@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
@@ -1,257 +1,257 @@
1
1
  package linthost
2
2
 
3
3
  import (
4
- "strings"
4
+ "strings"
5
5
 
6
- shimast "github.com/microsoft/typescript-go/shim/ast"
6
+ shimast "github.com/microsoft/typescript-go/shim/ast"
7
7
  )
8
8
 
9
9
  const reactRulePrefix = "react/"
10
10
 
11
11
  type reactRule struct {
12
- name string
12
+ name string
13
13
  }
14
14
 
15
15
  func (r reactRule) Name() string { return reactRulePrefix + r.name }
16
16
  func (r reactRule) Visits() []shimast.Kind {
17
- switch r.name {
18
- case "no-find-dom-node", "no-is-mounted":
19
- return []shimast.Kind{shimast.KindCallExpression}
20
- case "no-direct-mutation-state":
21
- return []shimast.Kind{shimast.KindBinaryExpression}
22
- case "no-unescaped-entities":
23
- return []shimast.Kind{shimast.KindJsxText}
24
- case "jsx-no-useless-fragment":
25
- return []shimast.Kind{shimast.KindJsxFragment, shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
26
- }
27
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
17
+ switch r.name {
18
+ case "no-find-dom-node", "no-is-mounted":
19
+ return []shimast.Kind{shimast.KindCallExpression}
20
+ case "no-direct-mutation-state":
21
+ return []shimast.Kind{shimast.KindBinaryExpression}
22
+ case "no-unescaped-entities":
23
+ return []shimast.Kind{shimast.KindJsxText}
24
+ case "jsx-no-useless-fragment":
25
+ return []shimast.Kind{shimast.KindJsxFragment, shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
26
+ }
27
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
28
28
  }
29
29
 
30
30
  func (r reactRule) Check(ctx *Context, node *shimast.Node) {
31
- switch r.name {
32
- case "jsx-key":
33
- checkReactJSXKey(ctx, node)
34
- case "jsx-no-duplicate-props":
35
- checkReactJSXNoDuplicateProps(ctx, node)
36
- case "no-array-index-key":
37
- checkReactNoArrayIndexKey(ctx, node)
38
- case "no-children-prop":
39
- checkReactNoChildrenProp(ctx, node)
40
- case "no-danger":
41
- checkReactNoDanger(ctx, node)
42
- case "no-danger-with-children":
43
- checkReactNoDangerWithChildren(ctx, node)
44
- case "no-direct-mutation-state":
45
- checkReactNoDirectMutationState(ctx, node)
46
- case "no-find-dom-node":
47
- checkReactNoFindDOMNode(ctx, node)
48
- case "no-is-mounted":
49
- checkReactNoIsMounted(ctx, node)
50
- case "no-string-refs":
51
- checkReactNoStringRefs(ctx, node)
52
- case "no-unescaped-entities":
53
- checkReactNoUnescapedEntities(ctx, node)
54
- case "button-has-type":
55
- checkReactButtonHasType(ctx, node)
56
- case "iframe-missing-sandbox":
57
- checkReactIframeMissingSandbox(ctx, node)
58
- case "jsx-no-script-url":
59
- checkReactJSXNoScriptURL(ctx, node)
60
- case "jsx-no-target-blank":
61
- checkReactJSXNoTargetBlank(ctx, node)
62
- case "jsx-no-useless-fragment":
63
- checkReactJSXNoUselessFragment(ctx, node)
64
- case "style-prop-object":
65
- checkReactStylePropObject(ctx, node)
66
- case "void-dom-elements-no-children":
67
- checkReactVoidDOMElementsNoChildren(ctx, node)
68
- }
31
+ switch r.name {
32
+ case "jsx-key":
33
+ checkReactJSXKey(ctx, node)
34
+ case "jsx-no-duplicate-props":
35
+ checkReactJSXNoDuplicateProps(ctx, node)
36
+ case "no-array-index-key":
37
+ checkReactNoArrayIndexKey(ctx, node)
38
+ case "no-children-prop":
39
+ checkReactNoChildrenProp(ctx, node)
40
+ case "no-danger":
41
+ checkReactNoDanger(ctx, node)
42
+ case "no-danger-with-children":
43
+ checkReactNoDangerWithChildren(ctx, node)
44
+ case "no-direct-mutation-state":
45
+ checkReactNoDirectMutationState(ctx, node)
46
+ case "no-find-dom-node":
47
+ checkReactNoFindDOMNode(ctx, node)
48
+ case "no-is-mounted":
49
+ checkReactNoIsMounted(ctx, node)
50
+ case "no-string-refs":
51
+ checkReactNoStringRefs(ctx, node)
52
+ case "no-unescaped-entities":
53
+ checkReactNoUnescapedEntities(ctx, node)
54
+ case "button-has-type":
55
+ checkReactButtonHasType(ctx, node)
56
+ case "iframe-missing-sandbox":
57
+ checkReactIframeMissingSandbox(ctx, node)
58
+ case "jsx-no-script-url":
59
+ checkReactJSXNoScriptURL(ctx, node)
60
+ case "jsx-no-target-blank":
61
+ checkReactJSXNoTargetBlank(ctx, node)
62
+ case "jsx-no-useless-fragment":
63
+ checkReactJSXNoUselessFragment(ctx, node)
64
+ case "style-prop-object":
65
+ checkReactStylePropObject(ctx, node)
66
+ case "void-dom-elements-no-children":
67
+ checkReactVoidDOMElementsNoChildren(ctx, node)
68
+ }
69
69
  }
70
70
 
71
71
  func checkReactJSXKey(ctx *Context, node *shimast.Node) {
72
- info := reactJSXElementFromNode(node)
73
- if info.opening == nil || reactJSXHasAttr(info.attrs, "key") {
74
- return
75
- }
76
- if reactJSXNeedsKey(node) {
77
- ctx.Report(info.opening, "Missing key prop for element in array or iterator.")
78
- }
72
+ info := reactJSXElementFromNode(node)
73
+ if info.opening == nil || reactJSXHasAttr(info.attrs, "key") {
74
+ return
75
+ }
76
+ if reactJSXNeedsKey(node) {
77
+ ctx.Report(info.opening, "Missing key prop for element in array or iterator.")
78
+ }
79
79
  }
80
80
 
81
81
  func checkReactJSXNoDuplicateProps(ctx *Context, node *shimast.Node) {
82
- info := reactJSXElementFromNode(node)
83
- seen := map[string]*shimast.Node{}
84
- for _, attr := range info.attrs {
85
- name := strings.ToLower(attr.name)
86
- if name == "" {
87
- continue
88
- }
89
- if prev := seen[name]; prev != nil {
90
- ctx.Report(attr.node, "No duplicate props allowed.")
91
- continue
92
- }
93
- seen[name] = attr.node
94
- }
82
+ info := reactJSXElementFromNode(node)
83
+ seen := map[string]*shimast.Node{}
84
+ for _, attr := range info.attrs {
85
+ name := strings.ToLower(attr.name)
86
+ if name == "" {
87
+ continue
88
+ }
89
+ if prev := seen[name]; prev != nil {
90
+ ctx.Report(attr.node, "No duplicate props allowed.")
91
+ continue
92
+ }
93
+ seen[name] = attr.node
94
+ }
95
95
  }
96
96
 
97
97
  func checkReactNoArrayIndexKey(ctx *Context, node *shimast.Node) {
98
- info := reactJSXElementFromNode(node)
99
- attr, ok := reactFindJSXAttr(info.attrs, "key")
100
- if !ok {
101
- return
102
- }
103
- name := reactJSXAttrExpressionIdentifier(attr)
104
- if name != "" && reactJSXNeedsKey(node) && reactJSXKeyUsesMapIndex(node, name) {
105
- ctx.Report(attr.node, "Do not use array index as key.")
106
- }
98
+ info := reactJSXElementFromNode(node)
99
+ attr, ok := reactFindJSXAttr(info.attrs, "key")
100
+ if !ok {
101
+ return
102
+ }
103
+ name := reactJSXAttrExpressionIdentifier(attr)
104
+ if name != "" && reactJSXNeedsKey(node) && reactJSXKeyUsesMapIndex(node, name) {
105
+ ctx.Report(attr.node, "Do not use array index as key.")
106
+ }
107
107
  }
108
108
 
109
109
  func checkReactNoChildrenProp(ctx *Context, node *shimast.Node) {
110
- info := reactJSXElementFromNode(node)
111
- if attr, ok := reactFindJSXAttr(info.attrs, "children"); ok {
112
- ctx.Report(attr.node, "Do not pass children as a prop.")
113
- }
110
+ info := reactJSXElementFromNode(node)
111
+ if attr, ok := reactFindJSXAttr(info.attrs, "children"); ok {
112
+ ctx.Report(attr.node, "Do not pass children as a prop.")
113
+ }
114
114
  }
115
115
 
116
116
  func checkReactNoDanger(ctx *Context, node *shimast.Node) {
117
- info := reactJSXElementFromNode(node)
118
- if attr, ok := reactFindJSXAttr(info.attrs, "dangerouslySetInnerHTML"); ok {
119
- ctx.Report(attr.node, "Do not use dangerouslySetInnerHTML.")
120
- }
117
+ info := reactJSXElementFromNode(node)
118
+ if attr, ok := reactFindJSXAttr(info.attrs, "dangerouslySetInnerHTML"); ok {
119
+ ctx.Report(attr.node, "Do not use dangerouslySetInnerHTML.")
120
+ }
121
121
  }
122
122
 
123
123
  func checkReactNoDangerWithChildren(ctx *Context, node *shimast.Node) {
124
- info := reactJSXElementFromNode(node)
125
- attr, ok := reactFindJSXAttr(info.attrs, "dangerouslySetInnerHTML")
126
- if ok && (reactJSXHasContent(info.children) || reactJSXHasAttr(info.attrs, "children")) {
127
- ctx.Report(attr.node, "Do not use dangerouslySetInnerHTML with children.")
128
- }
124
+ info := reactJSXElementFromNode(node)
125
+ attr, ok := reactFindJSXAttr(info.attrs, "dangerouslySetInnerHTML")
126
+ if ok && (reactJSXHasContent(info.children) || reactJSXHasAttr(info.attrs, "children")) {
127
+ ctx.Report(attr.node, "Do not use dangerouslySetInnerHTML with children.")
128
+ }
129
129
  }
130
130
 
131
131
  func checkReactNoDirectMutationState(ctx *Context, node *shimast.Node) {
132
- expr := node.AsBinaryExpression()
133
- if expr == nil || expr.OperatorToken == nil || !isAssignmentOperator(expr.OperatorToken.Kind) {
134
- return
135
- }
136
- if reactIsThisStateAccess(expr.Left) && !reactIsConstructorThisStateInitialization(node) {
137
- ctx.Report(expr.Left, "Do not mutate this.state directly.")
138
- }
132
+ expr := node.AsBinaryExpression()
133
+ if expr == nil || expr.OperatorToken == nil || !isAssignmentOperator(expr.OperatorToken.Kind) {
134
+ return
135
+ }
136
+ if reactIsThisStateAccess(expr.Left) && !reactIsConstructorThisStateInitialization(node) {
137
+ ctx.Report(expr.Left, "Do not mutate this.state directly.")
138
+ }
139
139
  }
140
140
 
141
141
  func checkReactNoFindDOMNode(ctx *Context, node *shimast.Node) {
142
- call := node.AsCallExpression()
143
- if call == nil {
144
- return
145
- }
146
- if callCalleeName(call) == "findDOMNode" || reactIsNamedPropertyCall(call, "findDOMNode") {
147
- ctx.Report(node, "Do not use findDOMNode.")
148
- }
142
+ call := node.AsCallExpression()
143
+ if call == nil {
144
+ return
145
+ }
146
+ if callCalleeName(call) == "findDOMNode" || reactIsNamedPropertyCall(call, "findDOMNode") {
147
+ ctx.Report(node, "Do not use findDOMNode.")
148
+ }
149
149
  }
150
150
 
151
151
  func checkReactNoIsMounted(ctx *Context, node *shimast.Node) {
152
- call := node.AsCallExpression()
153
- if call == nil {
154
- return
155
- }
156
- if callCalleeName(call) == "isMounted" || reactIsNamedPropertyCall(call, "isMounted") {
157
- ctx.Report(node, "Do not use isMounted.")
158
- }
152
+ call := node.AsCallExpression()
153
+ if call == nil {
154
+ return
155
+ }
156
+ if callCalleeName(call) == "isMounted" || reactIsNamedPropertyCall(call, "isMounted") {
157
+ ctx.Report(node, "Do not use isMounted.")
158
+ }
159
159
  }
160
160
 
161
161
  func checkReactNoStringRefs(ctx *Context, node *shimast.Node) {
162
- info := reactJSXElementFromNode(node)
163
- attr, ok := reactFindJSXAttr(info.attrs, "ref")
164
- if ok && attr.known && attr.value != "" {
165
- ctx.Report(attr.node, "String refs are deprecated.")
166
- }
162
+ info := reactJSXElementFromNode(node)
163
+ attr, ok := reactFindJSXAttr(info.attrs, "ref")
164
+ if ok && attr.known && attr.value != "" {
165
+ ctx.Report(attr.node, "String refs are deprecated.")
166
+ }
167
167
  }
168
168
 
169
169
  func checkReactNoUnescapedEntities(ctx *Context, node *shimast.Node) {
170
- text := nodeText(ctx.File, node)
171
- if strings.TrimSpace(text) == "" {
172
- return
173
- }
174
- for _, ch := range text {
175
- switch ch {
176
- case '>', '"', '\'', '}':
177
- ctx.Report(node, "Unescaped HTML entity in JSX text.")
178
- return
179
- }
180
- }
170
+ text := nodeText(ctx.File, node)
171
+ if strings.TrimSpace(text) == "" {
172
+ return
173
+ }
174
+ for _, ch := range text {
175
+ switch ch {
176
+ case '>', '"', '\'', '}':
177
+ ctx.Report(node, "Unescaped HTML entity in JSX text.")
178
+ return
179
+ }
180
+ }
181
181
  }
182
182
 
183
183
  func checkReactButtonHasType(ctx *Context, node *shimast.Node) {
184
- info := reactJSXElementFromNode(node)
185
- if info.tag != "button" {
186
- return
187
- }
188
- attr, ok := reactFindJSXAttr(info.attrs, "type")
189
- if !ok {
190
- ctx.Report(info.opening, "button elements must have an explicit type.")
191
- return
192
- }
193
- if !attr.known {
194
- return
195
- }
196
- switch strings.ToLower(strings.TrimSpace(attr.value)) {
197
- case "button", "submit", "reset":
198
- return
199
- }
200
- ctx.Report(attr.node, "button type must be button, submit, or reset.")
184
+ info := reactJSXElementFromNode(node)
185
+ if info.tag != "button" {
186
+ return
187
+ }
188
+ attr, ok := reactFindJSXAttr(info.attrs, "type")
189
+ if !ok {
190
+ ctx.Report(info.opening, "button elements must have an explicit type.")
191
+ return
192
+ }
193
+ if !attr.known {
194
+ return
195
+ }
196
+ switch strings.ToLower(strings.TrimSpace(attr.value)) {
197
+ case "button", "submit", "reset":
198
+ return
199
+ }
200
+ ctx.Report(attr.node, "button type must be button, submit, or reset.")
201
201
  }
202
202
 
203
203
  func checkReactIframeMissingSandbox(ctx *Context, node *shimast.Node) {
204
- info := reactJSXElementFromNode(node)
205
- if info.tag == "iframe" && !reactJSXHasAttr(info.attrs, "sandbox") {
206
- ctx.Report(info.opening, "iframe elements must include a sandbox attribute.")
207
- }
204
+ info := reactJSXElementFromNode(node)
205
+ if info.tag == "iframe" && !reactJSXHasAttr(info.attrs, "sandbox") {
206
+ ctx.Report(info.opening, "iframe elements must include a sandbox attribute.")
207
+ }
208
208
  }
209
209
 
210
210
  func checkReactJSXNoScriptURL(ctx *Context, node *shimast.Node) {
211
- info := reactJSXElementFromNode(node)
212
- for _, name := range []string{"href", "src", "action", "formAction"} {
213
- attr, ok := reactFindJSXAttr(info.attrs, name)
214
- if ok && attr.known && strings.HasPrefix(strings.ToLower(strings.TrimSpace(attr.value)), "javascript:") {
215
- ctx.Report(attr.node, "Do not use javascript: URLs in JSX props.")
216
- }
217
- }
211
+ info := reactJSXElementFromNode(node)
212
+ for _, name := range []string{"href", "src", "action", "formAction"} {
213
+ attr, ok := reactFindJSXAttr(info.attrs, name)
214
+ if ok && attr.known && strings.HasPrefix(strings.ToLower(strings.TrimSpace(attr.value)), "javascript:") {
215
+ ctx.Report(attr.node, "Do not use javascript: URLs in JSX props.")
216
+ }
217
+ }
218
218
  }
219
219
 
220
220
  func checkReactJSXNoTargetBlank(ctx *Context, node *shimast.Node) {
221
- info := reactJSXElementFromNode(node)
222
- if info.opening == nil {
223
- return
224
- }
225
- target, ok := reactFindJSXAttr(info.attrs, "target")
226
- if !ok || !target.known {
227
- return
228
- }
229
- if strings.TrimSpace(target.value) != "_blank" {
230
- return
231
- }
232
- rel, ok := reactFindJSXAttr(info.attrs, "rel")
233
- if ok && rel.known && strings.Contains(rel.value, "noreferrer") {
234
- return
235
- }
236
- ctx.Report(info.opening, "JSX elements with `target=\"_blank\"` must include `rel=\"noreferrer\"` (or `noopener noreferrer`).")
221
+ info := reactJSXElementFromNode(node)
222
+ if info.opening == nil {
223
+ return
224
+ }
225
+ target, ok := reactFindJSXAttr(info.attrs, "target")
226
+ if !ok || !target.known {
227
+ return
228
+ }
229
+ if strings.TrimSpace(target.value) != "_blank" {
230
+ return
231
+ }
232
+ rel, ok := reactFindJSXAttr(info.attrs, "rel")
233
+ if ok && rel.known && strings.Contains(rel.value, "noreferrer") {
234
+ return
235
+ }
236
+ ctx.Report(info.opening, "JSX elements with `target=\"_blank\"` must include `rel=\"noreferrer\"` (or `noopener noreferrer`).")
237
237
  }
238
238
 
239
239
  func checkReactJSXNoUselessFragment(ctx *Context, node *shimast.Node) {
240
- children, ok := reactUselessFragmentChildren(node)
241
- if !ok {
242
- return
243
- }
244
- meaningful := reactMeaningfulJSXChildren(children)
245
- if len(meaningful) == 0 {
246
- ctx.Report(node, "Fragment wraps a single element — return the child directly.")
247
- return
248
- }
249
- if len(meaningful) == 1 {
250
- switch meaningful[0].Kind {
251
- case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement, shimast.KindJsxFragment:
252
- ctx.Report(node, "Fragment wraps a single element — return the child directly.")
253
- }
254
- }
240
+ children, ok := reactUselessFragmentChildren(node)
241
+ if !ok {
242
+ return
243
+ }
244
+ meaningful := reactMeaningfulJSXChildren(children)
245
+ if len(meaningful) == 0 {
246
+ ctx.Report(node, "Fragment wraps a single element — return the child directly.")
247
+ return
248
+ }
249
+ if len(meaningful) == 1 {
250
+ switch meaningful[0].Kind {
251
+ case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement, shimast.KindJsxFragment:
252
+ ctx.Report(node, "Fragment wraps a single element — return the child directly.")
253
+ }
254
+ }
255
255
  }
256
256
 
257
257
  // reactUselessFragmentChildren returns the child list of a fragment-like node
@@ -261,513 +261,513 @@ func checkReactJSXNoUselessFragment(ctx *Context, node *shimast.Node) {
261
261
  // JsxSelfClosingElement is included so an empty `<Fragment />` is still
262
262
  // considered a useless wrapper.
263
263
  func reactUselessFragmentChildren(node *shimast.Node) (*shimast.NodeList, bool) {
264
- if node == nil {
265
- return nil, false
266
- }
267
- switch node.Kind {
268
- case shimast.KindJsxFragment:
269
- frag := node.AsJsxFragment()
270
- if frag == nil {
271
- return nil, false
272
- }
273
- return frag.Children, true
274
- case shimast.KindJsxElement:
275
- el := node.AsJsxElement()
276
- if el == nil || el.OpeningElement == nil {
277
- return nil, false
278
- }
279
- if !reactIsFragmentTagName(el.OpeningElement.TagName()) {
280
- return nil, false
281
- }
282
- return el.Children, true
283
- case shimast.KindJsxSelfClosingElement:
284
- el := node.AsJsxSelfClosingElement()
285
- if el == nil {
286
- return nil, false
287
- }
288
- if !reactIsFragmentTagName(el.TagName) {
289
- return nil, false
290
- }
291
- return nil, true
292
- }
293
- return nil, false
264
+ if node == nil {
265
+ return nil, false
266
+ }
267
+ switch node.Kind {
268
+ case shimast.KindJsxFragment:
269
+ frag := node.AsJsxFragment()
270
+ if frag == nil {
271
+ return nil, false
272
+ }
273
+ return frag.Children, true
274
+ case shimast.KindJsxElement:
275
+ el := node.AsJsxElement()
276
+ if el == nil || el.OpeningElement == nil {
277
+ return nil, false
278
+ }
279
+ if !reactIsFragmentTagName(el.OpeningElement.TagName()) {
280
+ return nil, false
281
+ }
282
+ return el.Children, true
283
+ case shimast.KindJsxSelfClosingElement:
284
+ el := node.AsJsxSelfClosingElement()
285
+ if el == nil {
286
+ return nil, false
287
+ }
288
+ if !reactIsFragmentTagName(el.TagName) {
289
+ return nil, false
290
+ }
291
+ return nil, true
292
+ }
293
+ return nil, false
294
294
  }
295
295
 
296
296
  // reactIsFragmentTagName reports whether a JSX tag-name node refers to React's
297
297
  // fragment component — either the bare `Fragment` identifier or the
298
298
  // `React.Fragment` qualified form.
299
299
  func reactIsFragmentTagName(node *shimast.Node) bool {
300
- if node == nil {
301
- return false
302
- }
303
- if identifierText(node) == "Fragment" {
304
- return true
305
- }
306
- if node.Kind == shimast.KindPropertyAccessExpression {
307
- access := node.AsPropertyAccessExpression()
308
- if access == nil {
309
- return false
310
- }
311
- if identifierText(access.Expression) == "React" && identifierText(access.Name()) == "Fragment" {
312
- return true
313
- }
314
- }
315
- return false
300
+ if node == nil {
301
+ return false
302
+ }
303
+ if identifierText(node) == "Fragment" {
304
+ return true
305
+ }
306
+ if node.Kind == shimast.KindPropertyAccessExpression {
307
+ access := node.AsPropertyAccessExpression()
308
+ if access == nil {
309
+ return false
310
+ }
311
+ if identifierText(access.Expression) == "React" && identifierText(access.Name()) == "Fragment" {
312
+ return true
313
+ }
314
+ }
315
+ return false
316
316
  }
317
317
 
318
318
  // reactMeaningfulJSXChildren returns the JSX children that contribute rendered
319
319
  // output. Whitespace-only JsxText and empty JsxExpression nodes are skipped so
320
320
  // the caller sees only nodes that could replace the fragment.
321
321
  func reactMeaningfulJSXChildren(children *shimast.NodeList) []*shimast.Node {
322
- if children == nil {
323
- return nil
324
- }
325
- out := make([]*shimast.Node, 0, len(children.Nodes))
326
- for _, child := range children.Nodes {
327
- if child == nil {
328
- continue
329
- }
330
- if child.Kind == shimast.KindJsxText {
331
- if strings.TrimSpace(nodeText(nilSafeSourceFile(child), child)) == "" {
332
- continue
333
- }
334
- out = append(out, child)
335
- continue
336
- }
337
- if child.Kind == shimast.KindJsxExpression {
338
- expr := child.AsJsxExpression()
339
- if expr == nil || expr.Expression == nil {
340
- continue
341
- }
342
- }
343
- out = append(out, child)
344
- }
345
- return out
322
+ if children == nil {
323
+ return nil
324
+ }
325
+ out := make([]*shimast.Node, 0, len(children.Nodes))
326
+ for _, child := range children.Nodes {
327
+ if child == nil {
328
+ continue
329
+ }
330
+ if child.Kind == shimast.KindJsxText {
331
+ if strings.TrimSpace(nodeText(nilSafeSourceFile(child), child)) == "" {
332
+ continue
333
+ }
334
+ out = append(out, child)
335
+ continue
336
+ }
337
+ if child.Kind == shimast.KindJsxExpression {
338
+ expr := child.AsJsxExpression()
339
+ if expr == nil || expr.Expression == nil {
340
+ continue
341
+ }
342
+ }
343
+ out = append(out, child)
344
+ }
345
+ return out
346
346
  }
347
347
 
348
348
  func checkReactStylePropObject(ctx *Context, node *shimast.Node) {
349
- info := reactJSXElementFromNode(node)
350
- attr, ok := reactFindJSXAttr(info.attrs, "style")
351
- if !ok || !attr.known {
352
- return
353
- }
354
- if attr.value != "" {
355
- ctx.Report(attr.node, "Style prop value must be an object.")
356
- }
349
+ info := reactJSXElementFromNode(node)
350
+ attr, ok := reactFindJSXAttr(info.attrs, "style")
351
+ if !ok || !attr.known {
352
+ return
353
+ }
354
+ if attr.value != "" {
355
+ ctx.Report(attr.node, "Style prop value must be an object.")
356
+ }
357
357
  }
358
358
 
359
359
  func checkReactVoidDOMElementsNoChildren(ctx *Context, node *shimast.Node) {
360
- info := reactJSXElementFromNode(node)
361
- if !reactVoidDOMElement(info.tag) {
362
- return
363
- }
364
- if reactJSXHasContent(info.children) || reactJSXHasAttr(info.attrs, "children", "dangerouslySetInnerHTML") {
365
- ctx.Report(info.opening, "Void DOM elements must not receive children.")
366
- }
360
+ info := reactJSXElementFromNode(node)
361
+ if !reactVoidDOMElement(info.tag) {
362
+ return
363
+ }
364
+ if reactJSXHasContent(info.children) || reactJSXHasAttr(info.attrs, "children", "dangerouslySetInnerHTML") {
365
+ ctx.Report(info.opening, "Void DOM elements must not receive children.")
366
+ }
367
367
  }
368
368
 
369
369
  type reactJSXAttr struct {
370
- node *shimast.Node
371
- name string
372
- value string
373
- known bool
374
- boolean bool
370
+ node *shimast.Node
371
+ name string
372
+ value string
373
+ known bool
374
+ boolean bool
375
375
  }
376
376
 
377
377
  type reactJSXElementInfo struct {
378
- opening *shimast.Node
379
- tag string
380
- attrs []reactJSXAttr
381
- children *shimast.NodeList
378
+ opening *shimast.Node
379
+ tag string
380
+ attrs []reactJSXAttr
381
+ children *shimast.NodeList
382
382
  }
383
383
 
384
384
  func reactJSXElementFromNode(node *shimast.Node) reactJSXElementInfo {
385
- info := reactJSXElementInfo{}
386
- if node == nil {
387
- return info
388
- }
389
- switch node.Kind {
390
- case shimast.KindJsxElement:
391
- el := node.AsJsxElement()
392
- if el == nil || el.OpeningElement == nil {
393
- return info
394
- }
395
- info.opening = el.OpeningElement.AsNode()
396
- info.tag = reactJSXTagName(el.OpeningElement.TagName())
397
- info.attrs = reactJSXAttrs(el.OpeningElement.Attributes())
398
- info.children = el.Children
399
- case shimast.KindJsxSelfClosingElement:
400
- el := node.AsJsxSelfClosingElement()
401
- if el == nil {
402
- return info
403
- }
404
- info.opening = node
405
- info.tag = reactJSXTagName(el.TagName)
406
- info.attrs = reactJSXAttrs(el.Attributes)
407
- }
408
- return info
385
+ info := reactJSXElementInfo{}
386
+ if node == nil {
387
+ return info
388
+ }
389
+ switch node.Kind {
390
+ case shimast.KindJsxElement:
391
+ el := node.AsJsxElement()
392
+ if el == nil || el.OpeningElement == nil {
393
+ return info
394
+ }
395
+ info.opening = el.OpeningElement.AsNode()
396
+ info.tag = reactJSXTagName(el.OpeningElement.TagName())
397
+ info.attrs = reactJSXAttrs(el.OpeningElement.Attributes())
398
+ info.children = el.Children
399
+ case shimast.KindJsxSelfClosingElement:
400
+ el := node.AsJsxSelfClosingElement()
401
+ if el == nil {
402
+ return info
403
+ }
404
+ info.opening = node
405
+ info.tag = reactJSXTagName(el.TagName)
406
+ info.attrs = reactJSXAttrs(el.Attributes)
407
+ }
408
+ return info
409
409
  }
410
410
 
411
411
  func reactJSXTagName(node *shimast.Node) string {
412
- if node == nil {
413
- return ""
414
- }
415
- if name := identifierText(node); name != "" {
416
- return name
417
- }
418
- return ""
412
+ if node == nil {
413
+ return ""
414
+ }
415
+ if name := identifierText(node); name != "" {
416
+ return name
417
+ }
418
+ return ""
419
419
  }
420
420
 
421
421
  func reactJSXAttrs(node *shimast.Node) []reactJSXAttr {
422
- if node == nil {
423
- return nil
424
- }
425
- attrs := node.AsJsxAttributes()
426
- if attrs == nil || attrs.Properties == nil {
427
- return nil
428
- }
429
- out := make([]reactJSXAttr, 0, len(attrs.Properties.Nodes))
430
- for _, prop := range attrs.Properties.Nodes {
431
- attr := prop.AsJsxAttribute()
432
- if attr == nil || attr.Name() == nil {
433
- continue
434
- }
435
- name := reactJSXAttrName(attr.Name())
436
- if name == "" {
437
- continue
438
- }
439
- out = append(out, reactJSXAttr{
440
- node: prop,
441
- name: name,
442
- value: reactJSXAttrValue(attr.Initializer),
443
- known: reactJSXAttrValueKnown(attr.Initializer),
444
- boolean: attr.Initializer == nil,
445
- })
446
- }
447
- return out
422
+ if node == nil {
423
+ return nil
424
+ }
425
+ attrs := node.AsJsxAttributes()
426
+ if attrs == nil || attrs.Properties == nil {
427
+ return nil
428
+ }
429
+ out := make([]reactJSXAttr, 0, len(attrs.Properties.Nodes))
430
+ for _, prop := range attrs.Properties.Nodes {
431
+ attr := prop.AsJsxAttribute()
432
+ if attr == nil || attr.Name() == nil {
433
+ continue
434
+ }
435
+ name := reactJSXAttrName(attr.Name())
436
+ if name == "" {
437
+ continue
438
+ }
439
+ out = append(out, reactJSXAttr{
440
+ node: prop,
441
+ name: name,
442
+ value: reactJSXAttrValue(attr.Initializer),
443
+ known: reactJSXAttrValueKnown(attr.Initializer),
444
+ boolean: attr.Initializer == nil,
445
+ })
446
+ }
447
+ return out
448
448
  }
449
449
 
450
450
  func reactJSXAttrName(node *shimast.Node) string {
451
- if node == nil {
452
- return ""
453
- }
454
- if name := identifierText(node); name != "" {
455
- return name
456
- }
457
- if node.Kind == shimast.KindJsxNamespacedName {
458
- ns := node.AsJsxNamespacedName()
459
- if ns != nil {
460
- left := identifierText(ns.Namespace)
461
- right := identifierText(ns.Name())
462
- if left != "" && right != "" {
463
- return left + ":" + right
464
- }
465
- }
466
- }
467
- return ""
451
+ if node == nil {
452
+ return ""
453
+ }
454
+ if name := identifierText(node); name != "" {
455
+ return name
456
+ }
457
+ if node.Kind == shimast.KindJsxNamespacedName {
458
+ ns := node.AsJsxNamespacedName()
459
+ if ns != nil {
460
+ left := identifierText(ns.Namespace)
461
+ right := identifierText(ns.Name())
462
+ if left != "" && right != "" {
463
+ return left + ":" + right
464
+ }
465
+ }
466
+ }
467
+ return ""
468
468
  }
469
469
 
470
470
  func reactFindJSXAttr(attrs []reactJSXAttr, name string) (reactJSXAttr, bool) {
471
- for _, attr := range attrs {
472
- if attr.name == name {
473
- return attr, true
474
- }
475
- }
476
- return reactJSXAttr{}, false
471
+ for _, attr := range attrs {
472
+ if attr.name == name {
473
+ return attr, true
474
+ }
475
+ }
476
+ return reactJSXAttr{}, false
477
477
  }
478
478
 
479
479
  func reactJSXHasAttr(attrs []reactJSXAttr, names ...string) bool {
480
- for _, name := range names {
481
- if _, ok := reactFindJSXAttr(attrs, name); ok {
482
- return true
483
- }
484
- }
485
- return false
480
+ for _, name := range names {
481
+ if _, ok := reactFindJSXAttr(attrs, name); ok {
482
+ return true
483
+ }
484
+ }
485
+ return false
486
486
  }
487
487
 
488
488
  func reactJSXAttrValue(node *shimast.Node) string {
489
- if node == nil {
490
- return "true"
491
- }
492
- if text := stringLiteralText(node); text != "" || node.Kind == shimast.KindStringLiteral || node.Kind == shimast.KindNoSubstitutionTemplateLiteral {
493
- return text
494
- }
495
- if node.Kind == shimast.KindJsxExpression {
496
- expr := node.AsJsxExpression()
497
- if expr == nil || expr.Expression == nil {
498
- return ""
499
- }
500
- if text := stringLiteralText(expr.Expression); text != "" || expr.Expression.Kind == shimast.KindStringLiteral || expr.Expression.Kind == shimast.KindNoSubstitutionTemplateLiteral {
501
- return text
502
- }
503
- }
504
- return ""
489
+ if node == nil {
490
+ return "true"
491
+ }
492
+ if text := stringLiteralText(node); text != "" || node.Kind == shimast.KindStringLiteral || node.Kind == shimast.KindNoSubstitutionTemplateLiteral {
493
+ return text
494
+ }
495
+ if node.Kind == shimast.KindJsxExpression {
496
+ expr := node.AsJsxExpression()
497
+ if expr == nil || expr.Expression == nil {
498
+ return ""
499
+ }
500
+ if text := stringLiteralText(expr.Expression); text != "" || expr.Expression.Kind == shimast.KindStringLiteral || expr.Expression.Kind == shimast.KindNoSubstitutionTemplateLiteral {
501
+ return text
502
+ }
503
+ }
504
+ return ""
505
505
  }
506
506
 
507
507
  func reactJSXAttrValueKnown(node *shimast.Node) bool {
508
- if node == nil {
509
- return true
510
- }
511
- switch node.Kind {
512
- case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
513
- return true
514
- case shimast.KindJsxExpression:
515
- expr := node.AsJsxExpression()
516
- if expr == nil || expr.Expression == nil {
517
- return true
518
- }
519
- switch expr.Expression.Kind {
520
- case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
521
- return true
522
- }
523
- }
524
- return false
508
+ if node == nil {
509
+ return true
510
+ }
511
+ switch node.Kind {
512
+ case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
513
+ return true
514
+ case shimast.KindJsxExpression:
515
+ expr := node.AsJsxExpression()
516
+ if expr == nil || expr.Expression == nil {
517
+ return true
518
+ }
519
+ switch expr.Expression.Kind {
520
+ case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
521
+ return true
522
+ }
523
+ }
524
+ return false
525
525
  }
526
526
 
527
527
  func reactJSXAttrExpressionIdentifier(attr reactJSXAttr) string {
528
- if attr.node == nil {
529
- return ""
530
- }
531
- jsxAttr := attr.node.AsJsxAttribute()
532
- if jsxAttr == nil || jsxAttr.Initializer == nil || jsxAttr.Initializer.Kind != shimast.KindJsxExpression {
533
- return ""
534
- }
535
- expr := jsxAttr.Initializer.AsJsxExpression()
536
- if expr == nil || expr.Expression == nil {
537
- return ""
538
- }
539
- return identifierText(stripParens(expr.Expression))
528
+ if attr.node == nil {
529
+ return ""
530
+ }
531
+ jsxAttr := attr.node.AsJsxAttribute()
532
+ if jsxAttr == nil || jsxAttr.Initializer == nil || jsxAttr.Initializer.Kind != shimast.KindJsxExpression {
533
+ return ""
534
+ }
535
+ expr := jsxAttr.Initializer.AsJsxExpression()
536
+ if expr == nil || expr.Expression == nil {
537
+ return ""
538
+ }
539
+ return identifierText(stripParens(expr.Expression))
540
540
  }
541
541
 
542
542
  func reactJSXHasContent(children *shimast.NodeList) bool {
543
- if children == nil {
544
- return false
545
- }
546
- for _, child := range children.Nodes {
547
- if child == nil {
548
- continue
549
- }
550
- if child.Kind == shimast.KindJsxText {
551
- if strings.TrimSpace(nodeText(nilSafeSourceFile(child), child)) != "" {
552
- return true
553
- }
554
- continue
555
- }
556
- if child.Kind == shimast.KindJsxExpression {
557
- expr := child.AsJsxExpression()
558
- if expr == nil || expr.Expression == nil {
559
- continue
560
- }
561
- }
562
- return true
563
- }
564
- return false
543
+ if children == nil {
544
+ return false
545
+ }
546
+ for _, child := range children.Nodes {
547
+ if child == nil {
548
+ continue
549
+ }
550
+ if child.Kind == shimast.KindJsxText {
551
+ if strings.TrimSpace(nodeText(nilSafeSourceFile(child), child)) != "" {
552
+ return true
553
+ }
554
+ continue
555
+ }
556
+ if child.Kind == shimast.KindJsxExpression {
557
+ expr := child.AsJsxExpression()
558
+ if expr == nil || expr.Expression == nil {
559
+ continue
560
+ }
561
+ }
562
+ return true
563
+ }
564
+ return false
565
565
  }
566
566
 
567
567
  func nilSafeSourceFile(node *shimast.Node) *shimast.SourceFile {
568
- for cur := node; cur != nil; cur = cur.Parent {
569
- if cur.Kind == shimast.KindSourceFile {
570
- return cur.AsSourceFile()
571
- }
572
- }
573
- return nil
568
+ for cur := node; cur != nil; cur = cur.Parent {
569
+ if cur.Kind == shimast.KindSourceFile {
570
+ return cur.AsSourceFile()
571
+ }
572
+ }
573
+ return nil
574
574
  }
575
575
 
576
576
  func reactJSXNeedsKey(node *shimast.Node) bool {
577
- if reactInsideArrayLiteral(node) {
578
- return true
579
- }
580
- return reactIsMapCallbackReturn(node)
577
+ if reactInsideArrayLiteral(node) {
578
+ return true
579
+ }
580
+ return reactIsMapCallbackReturn(node)
581
581
  }
582
582
 
583
583
  func reactInsideArrayLiteral(node *shimast.Node) bool {
584
- for cur := node.Parent; cur != nil; cur = cur.Parent {
585
- switch cur.Kind {
586
- case shimast.KindArrayLiteralExpression:
587
- return true
588
- case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement:
589
- return false
590
- }
591
- if isFunctionLikeKind(cur) {
592
- return false
593
- }
594
- }
595
- return false
584
+ for cur := node.Parent; cur != nil; cur = cur.Parent {
585
+ switch cur.Kind {
586
+ case shimast.KindArrayLiteralExpression:
587
+ return true
588
+ case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement:
589
+ return false
590
+ }
591
+ if isFunctionLikeKind(cur) {
592
+ return false
593
+ }
594
+ }
595
+ return false
596
596
  }
597
597
 
598
598
  func reactIsMapCallbackReturn(node *shimast.Node) bool {
599
- fn := reactNearestFunctionLike(node)
600
- if fn == nil || !reactIsMapCallback(fn) {
601
- return false
602
- }
603
- body := fn.Body()
604
- if reactJSXIsReturnedExpression(node, body) {
605
- return true
606
- }
607
- for cur := node.Parent; cur != nil && cur != fn; cur = cur.Parent {
608
- if cur.Kind == shimast.KindReturnStatement {
609
- ret := cur.AsReturnStatement()
610
- return ret != nil && reactJSXIsReturnedExpression(node, ret.Expression)
611
- }
612
- }
613
- return false
599
+ fn := reactNearestFunctionLike(node)
600
+ if fn == nil || !reactIsMapCallback(fn) {
601
+ return false
602
+ }
603
+ body := fn.Body()
604
+ if reactJSXIsReturnedExpression(node, body) {
605
+ return true
606
+ }
607
+ for cur := node.Parent; cur != nil && cur != fn; cur = cur.Parent {
608
+ if cur.Kind == shimast.KindReturnStatement {
609
+ ret := cur.AsReturnStatement()
610
+ return ret != nil && reactJSXIsReturnedExpression(node, ret.Expression)
611
+ }
612
+ }
613
+ return false
614
614
  }
615
615
 
616
616
  func reactJSXIsReturnedExpression(node, expr *shimast.Node) bool {
617
- target := stripParens(expr)
618
- if target == nil {
619
- return false
620
- }
621
- for cur := node; cur != nil; cur = cur.Parent {
622
- if cur != node && (cur.Kind == shimast.KindJsxElement || cur.Kind == shimast.KindJsxSelfClosingElement) {
623
- return false
624
- }
625
- if stripParens(cur) == target {
626
- return true
627
- }
628
- if cur != node {
629
- switch cur.Kind {
630
- case shimast.KindParenthesizedExpression, shimast.KindConditionalExpression, shimast.KindBinaryExpression:
631
- default:
632
- return false
633
- }
634
- }
635
- }
636
- return false
617
+ target := stripParens(expr)
618
+ if target == nil {
619
+ return false
620
+ }
621
+ for cur := node; cur != nil; cur = cur.Parent {
622
+ if cur != node && (cur.Kind == shimast.KindJsxElement || cur.Kind == shimast.KindJsxSelfClosingElement) {
623
+ return false
624
+ }
625
+ if stripParens(cur) == target {
626
+ return true
627
+ }
628
+ if cur != node {
629
+ switch cur.Kind {
630
+ case shimast.KindParenthesizedExpression, shimast.KindConditionalExpression, shimast.KindBinaryExpression:
631
+ default:
632
+ return false
633
+ }
634
+ }
635
+ }
636
+ return false
637
637
  }
638
638
 
639
639
  func reactIsMapCallback(fn *shimast.Node) bool {
640
- if fn == nil || fn.Parent == nil || fn.Parent.Kind != shimast.KindCallExpression {
641
- return false
642
- }
643
- call := fn.Parent.AsCallExpression()
644
- if call == nil || call.Arguments == nil {
645
- return false
646
- }
647
- found := false
648
- for _, arg := range call.Arguments.Nodes {
649
- if stripParens(arg) == fn {
650
- found = true
651
- break
652
- }
653
- }
654
- if !found {
655
- return false
656
- }
657
- _, method, ok := reactPropertyAccessParts(call.Expression)
658
- return ok && method == "map"
640
+ if fn == nil || fn.Parent == nil || fn.Parent.Kind != shimast.KindCallExpression {
641
+ return false
642
+ }
643
+ call := fn.Parent.AsCallExpression()
644
+ if call == nil || call.Arguments == nil {
645
+ return false
646
+ }
647
+ found := false
648
+ for _, arg := range call.Arguments.Nodes {
649
+ if stripParens(arg) == fn {
650
+ found = true
651
+ break
652
+ }
653
+ }
654
+ if !found {
655
+ return false
656
+ }
657
+ _, method, ok := reactPropertyAccessParts(call.Expression)
658
+ return ok && method == "map"
659
659
  }
660
660
 
661
661
  func reactJSXKeyUsesMapIndex(node *shimast.Node, name string) bool {
662
- fn := reactNearestFunctionLike(node)
663
- if fn == nil || !reactIsMapCallback(fn) {
664
- return false
665
- }
666
- params := fn.Parameters()
667
- if len(params) < 2 {
668
- return false
669
- }
670
- param := params[1].AsParameterDeclaration()
671
- return param != nil && identifierText(param.Name()) == name
662
+ fn := reactNearestFunctionLike(node)
663
+ if fn == nil || !reactIsMapCallback(fn) {
664
+ return false
665
+ }
666
+ params := fn.Parameters()
667
+ if len(params) < 2 {
668
+ return false
669
+ }
670
+ param := params[1].AsParameterDeclaration()
671
+ return param != nil && identifierText(param.Name()) == name
672
672
  }
673
673
 
674
674
  func reactPropertyAccessParts(node *shimast.Node) (*shimast.Node, string, bool) {
675
- node = stripParens(node)
676
- if node == nil || node.Kind != shimast.KindPropertyAccessExpression {
677
- return nil, "", false
678
- }
679
- access := node.AsPropertyAccessExpression()
680
- if access == nil {
681
- return nil, "", false
682
- }
683
- name := identifierText(access.Name())
684
- return access.Expression, name, name != ""
675
+ node = stripParens(node)
676
+ if node == nil || node.Kind != shimast.KindPropertyAccessExpression {
677
+ return nil, "", false
678
+ }
679
+ access := node.AsPropertyAccessExpression()
680
+ if access == nil {
681
+ return nil, "", false
682
+ }
683
+ name := identifierText(access.Name())
684
+ return access.Expression, name, name != ""
685
685
  }
686
686
 
687
687
  func reactIsNamedPropertyCall(call *shimast.CallExpression, name string) bool {
688
- if call == nil {
689
- return false
690
- }
691
- _, prop, ok := reactPropertyAccessParts(call.Expression)
692
- return ok && prop == name
688
+ if call == nil {
689
+ return false
690
+ }
691
+ _, prop, ok := reactPropertyAccessParts(call.Expression)
692
+ return ok && prop == name
693
693
  }
694
694
 
695
695
  func reactIsThisStateAccess(node *shimast.Node) bool {
696
- for cur := stripParens(node); cur != nil; {
697
- obj, prop, ok := reactPropertyAccessParts(cur)
698
- if !ok {
699
- return false
700
- }
701
- if prop == "state" && obj != nil && obj.Kind == shimast.KindThisKeyword {
702
- return true
703
- }
704
- cur = obj
705
- }
706
- return false
696
+ for cur := stripParens(node); cur != nil; {
697
+ obj, prop, ok := reactPropertyAccessParts(cur)
698
+ if !ok {
699
+ return false
700
+ }
701
+ if prop == "state" && obj != nil && obj.Kind == shimast.KindThisKeyword {
702
+ return true
703
+ }
704
+ cur = obj
705
+ }
706
+ return false
707
707
  }
708
708
 
709
709
  func reactIsConstructorThisStateInitialization(node *shimast.Node) bool {
710
- if !reactIsExactThisStateAssignment(node) {
711
- return false
712
- }
713
- for cur := node.Parent; cur != nil; cur = cur.Parent {
714
- if cur.Kind == shimast.KindConstructor {
715
- return true
716
- }
717
- if isFunctionLikeKind(cur) && cur.Kind != shimast.KindConstructor {
718
- return false
719
- }
720
- }
721
- return false
710
+ if !reactIsExactThisStateAssignment(node) {
711
+ return false
712
+ }
713
+ for cur := node.Parent; cur != nil; cur = cur.Parent {
714
+ if cur.Kind == shimast.KindConstructor {
715
+ return true
716
+ }
717
+ if isFunctionLikeKind(cur) && cur.Kind != shimast.KindConstructor {
718
+ return false
719
+ }
720
+ }
721
+ return false
722
722
  }
723
723
 
724
724
  func reactIsExactThisStateAssignment(node *shimast.Node) bool {
725
- expr := node.AsBinaryExpression()
726
- if expr == nil || expr.Left == nil {
727
- return false
728
- }
729
- obj, prop, ok := reactPropertyAccessParts(expr.Left)
730
- return ok && prop == "state" && obj != nil && obj.Kind == shimast.KindThisKeyword
725
+ expr := node.AsBinaryExpression()
726
+ if expr == nil || expr.Left == nil {
727
+ return false
728
+ }
729
+ obj, prop, ok := reactPropertyAccessParts(expr.Left)
730
+ return ok && prop == "state" && obj != nil && obj.Kind == shimast.KindThisKeyword
731
731
  }
732
732
 
733
733
  func reactVoidDOMElement(tag string) bool {
734
- switch tag {
735
- case "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr":
736
- return true
737
- }
738
- return false
734
+ switch tag {
735
+ case "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr":
736
+ return true
737
+ }
738
+ return false
739
739
  }
740
740
 
741
741
  func reactNearestFunctionLike(node *shimast.Node) *shimast.Node {
742
- for cur := node.Parent; cur != nil; cur = cur.Parent {
743
- if isFunctionLikeKind(cur) {
744
- return cur
745
- }
746
- }
747
- return nil
742
+ for cur := node.Parent; cur != nil; cur = cur.Parent {
743
+ if isFunctionLikeKind(cur) {
744
+ return cur
745
+ }
746
+ }
747
+ return nil
748
748
  }
749
749
 
750
750
  func init() {
751
- for _, name := range []string{
752
- "button-has-type",
753
- "iframe-missing-sandbox",
754
- "jsx-key",
755
- "jsx-no-duplicate-props",
756
- "jsx-no-script-url",
757
- "jsx-no-target-blank",
758
- "jsx-no-useless-fragment",
759
- "no-array-index-key",
760
- "no-children-prop",
761
- "no-danger",
762
- "no-danger-with-children",
763
- "no-direct-mutation-state",
764
- "no-find-dom-node",
765
- "no-is-mounted",
766
- "no-string-refs",
767
- "no-unescaped-entities",
768
- "style-prop-object",
769
- "void-dom-elements-no-children",
770
- } {
771
- Register(reactRule{name: name})
772
- }
751
+ for _, name := range []string{
752
+ "button-has-type",
753
+ "iframe-missing-sandbox",
754
+ "jsx-key",
755
+ "jsx-no-duplicate-props",
756
+ "jsx-no-script-url",
757
+ "jsx-no-target-blank",
758
+ "jsx-no-useless-fragment",
759
+ "no-array-index-key",
760
+ "no-children-prop",
761
+ "no-danger",
762
+ "no-danger-with-children",
763
+ "no-direct-mutation-state",
764
+ "no-find-dom-node",
765
+ "no-is-mounted",
766
+ "no-string-refs",
767
+ "no-unescaped-entities",
768
+ "style-prop-object",
769
+ "void-dom-elements-no-children",
770
+ } {
771
+ Register(reactRule{name: name})
772
+ }
773
773
  }