@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,584 +1,584 @@
1
1
  package linthost
2
2
 
3
3
  import (
4
- "strconv"
5
- "strings"
4
+ "strconv"
5
+ "strings"
6
6
 
7
- shimast "github.com/microsoft/typescript-go/shim/ast"
7
+ shimast "github.com/microsoft/typescript-go/shim/ast"
8
8
  )
9
9
 
10
10
  type jsxAttr struct {
11
- node *shimast.Node
12
- value string
13
- known bool
14
- boolean bool
11
+ node *shimast.Node
12
+ value string
13
+ known bool
14
+ boolean bool
15
15
  }
16
16
 
17
17
  type jsxElementInfo struct {
18
- opening *shimast.Node
19
- tag string
20
- attrs map[string]jsxAttr
21
- children *shimast.NodeList
18
+ opening *shimast.Node
19
+ tag string
20
+ attrs map[string]jsxAttr
21
+ children *shimast.NodeList
22
22
  }
23
23
 
24
24
  func jsxElementFromNode(node *shimast.Node) jsxElementInfo {
25
- info := jsxElementInfo{attrs: map[string]jsxAttr{}}
26
- if node == nil {
27
- return info
28
- }
29
- switch node.Kind {
30
- case shimast.KindJsxElement:
31
- el := node.AsJsxElement()
32
- if el == nil || el.OpeningElement == nil {
33
- return info
34
- }
35
- info.opening = el.OpeningElement.AsNode()
36
- info.tag = jsxTagName(el.OpeningElement.TagName())
37
- info.attrs = jsxAttrs(el.OpeningElement.Attributes())
38
- info.children = el.Children
39
- case shimast.KindJsxSelfClosingElement:
40
- el := node.AsJsxSelfClosingElement()
41
- if el == nil {
42
- return info
43
- }
44
- info.opening = node
45
- info.tag = jsxTagName(el.TagName)
46
- info.attrs = jsxAttrs(el.Attributes)
47
- case shimast.KindJsxOpeningElement:
48
- el := node.AsJsxOpeningElement()
49
- if el == nil {
50
- return info
51
- }
52
- info.opening = node
53
- info.tag = jsxTagName(el.TagName)
54
- info.attrs = jsxAttrs(el.Attributes)
55
- }
56
- return info
25
+ info := jsxElementInfo{attrs: map[string]jsxAttr{}}
26
+ if node == nil {
27
+ return info
28
+ }
29
+ switch node.Kind {
30
+ case shimast.KindJsxElement:
31
+ el := node.AsJsxElement()
32
+ if el == nil || el.OpeningElement == nil {
33
+ return info
34
+ }
35
+ info.opening = el.OpeningElement.AsNode()
36
+ info.tag = jsxTagName(el.OpeningElement.TagName())
37
+ info.attrs = jsxAttrs(el.OpeningElement.Attributes())
38
+ info.children = el.Children
39
+ case shimast.KindJsxSelfClosingElement:
40
+ el := node.AsJsxSelfClosingElement()
41
+ if el == nil {
42
+ return info
43
+ }
44
+ info.opening = node
45
+ info.tag = jsxTagName(el.TagName)
46
+ info.attrs = jsxAttrs(el.Attributes)
47
+ case shimast.KindJsxOpeningElement:
48
+ el := node.AsJsxOpeningElement()
49
+ if el == nil {
50
+ return info
51
+ }
52
+ info.opening = node
53
+ info.tag = jsxTagName(el.TagName)
54
+ info.attrs = jsxAttrs(el.Attributes)
55
+ }
56
+ return info
57
57
  }
58
58
 
59
59
  func jsxTagName(node *shimast.Node) string {
60
- if node == nil {
61
- return ""
62
- }
63
- if name := identifierText(node); name != "" {
64
- return name
65
- }
66
- return ""
60
+ if node == nil {
61
+ return ""
62
+ }
63
+ if name := identifierText(node); name != "" {
64
+ return name
65
+ }
66
+ return ""
67
67
  }
68
68
 
69
69
  func jsxAttrs(node *shimast.Node) map[string]jsxAttr {
70
- out := map[string]jsxAttr{}
71
- if node == nil {
72
- return out
73
- }
74
- attrs := node.AsJsxAttributes()
75
- if attrs == nil || attrs.Properties == nil {
76
- return out
77
- }
78
- for _, prop := range attrs.Properties.Nodes {
79
- attr := prop.AsJsxAttribute()
80
- if attr == nil || attr.Name() == nil {
81
- continue
82
- }
83
- name := jsxAttrName(attr.Name())
84
- if name == "" {
85
- continue
86
- }
87
- out[name] = jsxAttr{
88
- node: prop,
89
- value: jsxAttrValue(attr.Initializer),
90
- known: jsxAttrValueKnown(attr.Initializer),
91
- boolean: attr.Initializer == nil,
92
- }
93
- }
94
- return out
70
+ out := map[string]jsxAttr{}
71
+ if node == nil {
72
+ return out
73
+ }
74
+ attrs := node.AsJsxAttributes()
75
+ if attrs == nil || attrs.Properties == nil {
76
+ return out
77
+ }
78
+ for _, prop := range attrs.Properties.Nodes {
79
+ attr := prop.AsJsxAttribute()
80
+ if attr == nil || attr.Name() == nil {
81
+ continue
82
+ }
83
+ name := jsxAttrName(attr.Name())
84
+ if name == "" {
85
+ continue
86
+ }
87
+ out[name] = jsxAttr{
88
+ node: prop,
89
+ value: jsxAttrValue(attr.Initializer),
90
+ known: jsxAttrValueKnown(attr.Initializer),
91
+ boolean: attr.Initializer == nil,
92
+ }
93
+ }
94
+ return out
95
95
  }
96
96
 
97
97
  func jsxAttrName(node *shimast.Node) string {
98
- if node == nil {
99
- return ""
100
- }
101
- if name := identifierText(node); name != "" {
102
- return name
103
- }
104
- if node.Kind == shimast.KindJsxNamespacedName {
105
- ns := node.AsJsxNamespacedName()
106
- if ns != nil {
107
- left := identifierText(ns.Namespace)
108
- right := identifierText(ns.Name())
109
- if left != "" && right != "" {
110
- return left + ":" + right
111
- }
112
- }
113
- }
114
- return ""
98
+ if node == nil {
99
+ return ""
100
+ }
101
+ if name := identifierText(node); name != "" {
102
+ return name
103
+ }
104
+ if node.Kind == shimast.KindJsxNamespacedName {
105
+ ns := node.AsJsxNamespacedName()
106
+ if ns != nil {
107
+ left := identifierText(ns.Namespace)
108
+ right := identifierText(ns.Name())
109
+ if left != "" && right != "" {
110
+ return left + ":" + right
111
+ }
112
+ }
113
+ }
114
+ return ""
115
115
  }
116
116
 
117
117
  func jsxAttrValue(node *shimast.Node) string {
118
- if node == nil {
119
- return "true"
120
- }
121
- if text := stringLiteralText(node); text != "" || node.Kind == shimast.KindStringLiteral || node.Kind == shimast.KindNoSubstitutionTemplateLiteral {
122
- return text
123
- }
124
- if node.Kind == shimast.KindJsxExpression {
125
- expr := node.AsJsxExpression()
126
- if expr == nil || expr.Expression == nil {
127
- return ""
128
- }
129
- if text := stringLiteralText(expr.Expression); text != "" || expr.Expression.Kind == shimast.KindStringLiteral || expr.Expression.Kind == shimast.KindNoSubstitutionTemplateLiteral {
130
- return text
131
- }
132
- if value, ok := isLiteralBoolean(expr.Expression); ok {
133
- if value {
134
- return "true"
135
- }
136
- return "false"
137
- }
138
- if expr.Expression.Kind == shimast.KindNumericLiteral {
139
- return numericLiteralText(expr.Expression)
140
- }
141
- }
142
- return ""
118
+ if node == nil {
119
+ return "true"
120
+ }
121
+ if text := stringLiteralText(node); text != "" || node.Kind == shimast.KindStringLiteral || node.Kind == shimast.KindNoSubstitutionTemplateLiteral {
122
+ return text
123
+ }
124
+ if node.Kind == shimast.KindJsxExpression {
125
+ expr := node.AsJsxExpression()
126
+ if expr == nil || expr.Expression == nil {
127
+ return ""
128
+ }
129
+ if text := stringLiteralText(expr.Expression); text != "" || expr.Expression.Kind == shimast.KindStringLiteral || expr.Expression.Kind == shimast.KindNoSubstitutionTemplateLiteral {
130
+ return text
131
+ }
132
+ if value, ok := isLiteralBoolean(expr.Expression); ok {
133
+ if value {
134
+ return "true"
135
+ }
136
+ return "false"
137
+ }
138
+ if expr.Expression.Kind == shimast.KindNumericLiteral {
139
+ return numericLiteralText(expr.Expression)
140
+ }
141
+ }
142
+ return ""
143
143
  }
144
144
 
145
145
  func jsxAttrValueKnown(node *shimast.Node) bool {
146
- if node == nil {
147
- return true
148
- }
149
- switch node.Kind {
150
- case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
151
- return true
152
- case shimast.KindJsxExpression:
153
- expr := node.AsJsxExpression()
154
- if expr == nil || expr.Expression == nil {
155
- return true
156
- }
157
- switch expr.Expression.Kind {
158
- case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral, shimast.KindTrueKeyword, shimast.KindFalseKeyword, shimast.KindNumericLiteral:
159
- return true
160
- }
161
- }
162
- return false
146
+ if node == nil {
147
+ return true
148
+ }
149
+ switch node.Kind {
150
+ case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
151
+ return true
152
+ case shimast.KindJsxExpression:
153
+ expr := node.AsJsxExpression()
154
+ if expr == nil || expr.Expression == nil {
155
+ return true
156
+ }
157
+ switch expr.Expression.Kind {
158
+ case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral, shimast.KindTrueKeyword, shimast.KindFalseKeyword, shimast.KindNumericLiteral:
159
+ return true
160
+ }
161
+ }
162
+ return false
163
163
  }
164
164
 
165
165
  func jsxHasAttr(attrs map[string]jsxAttr, names ...string) bool {
166
- for _, name := range names {
167
- if _, ok := attrs[name]; ok {
168
- return true
169
- }
170
- }
171
- return false
166
+ for _, name := range names {
167
+ if _, ok := attrs[name]; ok {
168
+ return true
169
+ }
170
+ }
171
+ return false
172
172
  }
173
173
 
174
174
  func jsxKnownAttr(attrs map[string]jsxAttr, name string) (jsxAttr, bool) {
175
- attr, ok := attrs[name]
176
- if !ok || !attr.known {
177
- return jsxAttr{}, false
178
- }
179
- return attr, true
175
+ attr, ok := attrs[name]
176
+ if !ok || !attr.known {
177
+ return jsxAttr{}, false
178
+ }
179
+ return attr, true
180
180
  }
181
181
 
182
182
  func jsxBoolAttr(attrs map[string]jsxAttr, name string) (bool, bool) {
183
- attr, ok := jsxKnownAttr(attrs, name)
184
- if !ok {
185
- return false, false
186
- }
187
- if attr.boolean {
188
- return true, true
189
- }
190
- switch strings.ToLower(strings.TrimSpace(attr.value)) {
191
- case "true":
192
- return true, true
193
- case "false":
194
- return false, true
195
- }
196
- return false, false
183
+ attr, ok := jsxKnownAttr(attrs, name)
184
+ if !ok {
185
+ return false, false
186
+ }
187
+ if attr.boolean {
188
+ return true, true
189
+ }
190
+ switch strings.ToLower(strings.TrimSpace(attr.value)) {
191
+ case "true":
192
+ return true, true
193
+ case "false":
194
+ return false, true
195
+ }
196
+ return false, false
197
197
  }
198
198
 
199
199
  func jsxNumericAttr(attrs map[string]jsxAttr, names ...string) (int, bool) {
200
- for _, name := range names {
201
- attr, ok := jsxKnownAttr(attrs, name)
202
- if !ok || strings.TrimSpace(attr.value) == "" {
203
- continue
204
- }
205
- value, err := strconv.Atoi(strings.TrimSpace(attr.value))
206
- if err == nil {
207
- return value, true
208
- }
209
- }
210
- return 0, false
200
+ for _, name := range names {
201
+ attr, ok := jsxKnownAttr(attrs, name)
202
+ if !ok || strings.TrimSpace(attr.value) == "" {
203
+ continue
204
+ }
205
+ value, err := strconv.Atoi(strings.TrimSpace(attr.value))
206
+ if err == nil {
207
+ return value, true
208
+ }
209
+ }
210
+ return 0, false
211
211
  }
212
212
 
213
213
  func jsxHasAccessibleLabel(info jsxElementInfo) bool {
214
- if attr, ok := jsxKnownAttr(info.attrs, "aria-label"); ok && strings.TrimSpace(attr.value) != "" {
215
- return true
216
- }
217
- if attr, ok := jsxKnownAttr(info.attrs, "aria-labelledby"); ok && strings.TrimSpace(attr.value) != "" {
218
- return true
219
- }
220
- if attr, ok := jsxKnownAttr(info.attrs, "alt"); ok && strings.TrimSpace(attr.value) != "" {
221
- return true
222
- }
223
- if attr, ok := jsxKnownAttr(info.attrs, "title"); ok && strings.TrimSpace(attr.value) != "" {
224
- return true
225
- }
226
- return jsxChildrenHaveAccessibleContent(info.children)
214
+ if attr, ok := jsxKnownAttr(info.attrs, "aria-label"); ok && strings.TrimSpace(attr.value) != "" {
215
+ return true
216
+ }
217
+ if attr, ok := jsxKnownAttr(info.attrs, "aria-labelledby"); ok && strings.TrimSpace(attr.value) != "" {
218
+ return true
219
+ }
220
+ if attr, ok := jsxKnownAttr(info.attrs, "alt"); ok && strings.TrimSpace(attr.value) != "" {
221
+ return true
222
+ }
223
+ if attr, ok := jsxKnownAttr(info.attrs, "title"); ok && strings.TrimSpace(attr.value) != "" {
224
+ return true
225
+ }
226
+ return jsxChildrenHaveAccessibleContent(info.children)
227
227
  }
228
228
 
229
229
  func jsxChildrenHaveAccessibleContent(children *shimast.NodeList) bool {
230
- if children == nil {
231
- return false
232
- }
233
- for _, child := range children.Nodes {
234
- if child == nil {
235
- continue
236
- }
237
- switch child.Kind {
238
- case shimast.KindJsxText:
239
- text := child.AsJsxText()
240
- if text != nil && !text.ContainsOnlyTriviaWhiteSpaces && strings.TrimSpace(text.Text) != "" {
241
- return true
242
- }
243
- case shimast.KindJsxExpression:
244
- expr := child.AsJsxExpression()
245
- if expr != nil && expr.Expression != nil {
246
- if text := stringLiteralText(expr.Expression); strings.TrimSpace(text) != "" {
247
- return true
248
- }
249
- if expr.Expression.Kind != shimast.KindNullKeyword && identifierText(expr.Expression) != "undefined" {
250
- return true
251
- }
252
- }
253
- case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement:
254
- nested := jsxElementFromNode(child)
255
- if jsxHasAccessibleLabel(nested) {
256
- return true
257
- }
258
- }
259
- }
260
- return false
230
+ if children == nil {
231
+ return false
232
+ }
233
+ for _, child := range children.Nodes {
234
+ if child == nil {
235
+ continue
236
+ }
237
+ switch child.Kind {
238
+ case shimast.KindJsxText:
239
+ text := child.AsJsxText()
240
+ if text != nil && !text.ContainsOnlyTriviaWhiteSpaces && strings.TrimSpace(text.Text) != "" {
241
+ return true
242
+ }
243
+ case shimast.KindJsxExpression:
244
+ expr := child.AsJsxExpression()
245
+ if expr != nil && expr.Expression != nil {
246
+ if text := stringLiteralText(expr.Expression); strings.TrimSpace(text) != "" {
247
+ return true
248
+ }
249
+ if expr.Expression.Kind != shimast.KindNullKeyword && identifierText(expr.Expression) != "undefined" {
250
+ return true
251
+ }
252
+ }
253
+ case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement:
254
+ nested := jsxElementFromNode(child)
255
+ if jsxHasAccessibleLabel(nested) {
256
+ return true
257
+ }
258
+ }
259
+ }
260
+ return false
261
261
  }
262
262
 
263
263
  func jsxHasDescendantControl(children *shimast.NodeList) bool {
264
- if children == nil {
265
- return false
266
- }
267
- for _, child := range children.Nodes {
268
- if child == nil {
269
- continue
270
- }
271
- switch child.Kind {
272
- case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement:
273
- info := jsxElementFromNode(child)
274
- if jsxIsFormControl(info) {
275
- return true
276
- }
277
- if jsxHasDescendantControl(info.children) {
278
- return true
279
- }
280
- }
281
- }
282
- return false
264
+ if children == nil {
265
+ return false
266
+ }
267
+ for _, child := range children.Nodes {
268
+ if child == nil {
269
+ continue
270
+ }
271
+ switch child.Kind {
272
+ case shimast.KindJsxElement, shimast.KindJsxSelfClosingElement:
273
+ info := jsxElementFromNode(child)
274
+ if jsxIsFormControl(info) {
275
+ return true
276
+ }
277
+ if jsxHasDescendantControl(info.children) {
278
+ return true
279
+ }
280
+ }
281
+ }
282
+ return false
283
283
  }
284
284
 
285
285
  func jsxHasTrackCaption(children *shimast.NodeList) bool {
286
- if children == nil {
287
- return false
288
- }
289
- for _, child := range children.Nodes {
290
- info := jsxElementFromNode(child)
291
- if info.tag != "track" {
292
- continue
293
- }
294
- attr, ok := jsxKnownAttr(info.attrs, "kind")
295
- if !ok {
296
- return true
297
- }
298
- kind := strings.ToLower(strings.TrimSpace(attr.value))
299
- if kind == "captions" || kind == "subtitles" {
300
- return true
301
- }
302
- }
303
- return false
286
+ if children == nil {
287
+ return false
288
+ }
289
+ for _, child := range children.Nodes {
290
+ info := jsxElementFromNode(child)
291
+ if info.tag != "track" {
292
+ continue
293
+ }
294
+ attr, ok := jsxKnownAttr(info.attrs, "kind")
295
+ if !ok {
296
+ return true
297
+ }
298
+ kind := strings.ToLower(strings.TrimSpace(attr.value))
299
+ if kind == "captions" || kind == "subtitles" {
300
+ return true
301
+ }
302
+ }
303
+ return false
304
304
  }
305
305
 
306
306
  func jsxIsFormControl(info jsxElementInfo) bool {
307
- switch info.tag {
308
- case "button", "select", "textarea":
309
- return true
310
- case "input":
311
- if attr, ok := jsxKnownAttr(info.attrs, "type"); ok && strings.EqualFold(attr.value, "hidden") {
312
- return false
313
- }
314
- return true
315
- }
316
- return false
307
+ switch info.tag {
308
+ case "button", "select", "textarea":
309
+ return true
310
+ case "input":
311
+ if attr, ok := jsxKnownAttr(info.attrs, "type"); ok && strings.EqualFold(attr.value, "hidden") {
312
+ return false
313
+ }
314
+ return true
315
+ }
316
+ return false
317
317
  }
318
318
 
319
319
  func jsxIsHidden(info jsxElementInfo) bool {
320
- if value, ok := jsxBoolAttr(info.attrs, "aria-hidden"); ok && value {
321
- return true
322
- }
323
- _, hidden := info.attrs["hidden"]
324
- return hidden
320
+ if value, ok := jsxBoolAttr(info.attrs, "aria-hidden"); ok && value {
321
+ return true
322
+ }
323
+ _, hidden := info.attrs["hidden"]
324
+ return hidden
325
325
  }
326
326
 
327
327
  func jsxHasKeyboardHandler(attrs map[string]jsxAttr) bool {
328
- return jsxHasAttr(attrs, "onKeyDown", "onKeyUp", "onKeyPress", "onkeydown", "onkeyup", "onkeypress")
328
+ return jsxHasAttr(attrs, "onKeyDown", "onKeyUp", "onKeyPress", "onkeydown", "onkeyup", "onkeypress")
329
329
  }
330
330
 
331
331
  func jsxHasMouseOrKeyboardInteraction(attrs map[string]jsxAttr) bool {
332
- return jsxHasAttr(
333
- attrs,
334
- "onClick", "onclick",
335
- "onMouseDown", "onmousedown",
336
- "onMouseUp", "onmouseup",
337
- "onKeyDown", "onkeydown",
338
- "onKeyUp", "onkeyup",
339
- "onKeyPress", "onkeypress",
340
- )
332
+ return jsxHasAttr(
333
+ attrs,
334
+ "onClick", "onclick",
335
+ "onMouseDown", "onmousedown",
336
+ "onMouseUp", "onmouseup",
337
+ "onKeyDown", "onkeydown",
338
+ "onKeyUp", "onkeyup",
339
+ "onKeyPress", "onkeypress",
340
+ )
341
341
  }
342
342
 
343
343
  func jsxRole(attrs map[string]jsxAttr) (string, bool) {
344
- attr, ok := jsxKnownAttr(attrs, "role")
345
- if !ok {
346
- return "", false
347
- }
348
- for _, token := range strings.Fields(strings.ToLower(attr.value)) {
349
- if token != "" {
350
- return token, true
351
- }
352
- }
353
- return "", true
344
+ attr, ok := jsxKnownAttr(attrs, "role")
345
+ if !ok {
346
+ return "", false
347
+ }
348
+ for _, token := range strings.Fields(strings.ToLower(attr.value)) {
349
+ if token != "" {
350
+ return token, true
351
+ }
352
+ }
353
+ return "", true
354
354
  }
355
355
 
356
356
  func jsxImplicitRole(info jsxElementInfo) string {
357
- switch info.tag {
358
- case "a", "area":
359
- if jsxHasAttr(info.attrs, "href") {
360
- return "link"
361
- }
362
- case "article":
363
- return "article"
364
- case "button":
365
- return "button"
366
- case "img":
367
- return "img"
368
- case "input":
369
- if attr, ok := jsxKnownAttr(info.attrs, "type"); ok {
370
- switch strings.ToLower(attr.value) {
371
- case "button", "submit", "reset":
372
- return "button"
373
- case "checkbox":
374
- return "checkbox"
375
- case "radio":
376
- return "radio"
377
- case "range":
378
- return "slider"
379
- case "email", "password", "search", "tel", "text", "url":
380
- return "textbox"
381
- }
382
- }
383
- return "textbox"
384
- case "select":
385
- return "combobox"
386
- case "textarea":
387
- return "textbox"
388
- case "nav":
389
- return "navigation"
390
- case "main":
391
- return "main"
392
- case "ul", "ol":
393
- return "list"
394
- case "li":
395
- return "listitem"
396
- case "table":
397
- return "table"
398
- case "tr":
399
- return "row"
400
- case "td":
401
- return "cell"
402
- case "th":
403
- return "columnheader"
404
- case "h1", "h2", "h3", "h4", "h5", "h6":
405
- return "heading"
406
- }
407
- return ""
357
+ switch info.tag {
358
+ case "a", "area":
359
+ if jsxHasAttr(info.attrs, "href") {
360
+ return "link"
361
+ }
362
+ case "article":
363
+ return "article"
364
+ case "button":
365
+ return "button"
366
+ case "img":
367
+ return "img"
368
+ case "input":
369
+ if attr, ok := jsxKnownAttr(info.attrs, "type"); ok {
370
+ switch strings.ToLower(attr.value) {
371
+ case "button", "submit", "reset":
372
+ return "button"
373
+ case "checkbox":
374
+ return "checkbox"
375
+ case "radio":
376
+ return "radio"
377
+ case "range":
378
+ return "slider"
379
+ case "email", "password", "search", "tel", "text", "url":
380
+ return "textbox"
381
+ }
382
+ }
383
+ return "textbox"
384
+ case "select":
385
+ return "combobox"
386
+ case "textarea":
387
+ return "textbox"
388
+ case "nav":
389
+ return "navigation"
390
+ case "main":
391
+ return "main"
392
+ case "ul", "ol":
393
+ return "list"
394
+ case "li":
395
+ return "listitem"
396
+ case "table":
397
+ return "table"
398
+ case "tr":
399
+ return "row"
400
+ case "td":
401
+ return "cell"
402
+ case "th":
403
+ return "columnheader"
404
+ case "h1", "h2", "h3", "h4", "h5", "h6":
405
+ return "heading"
406
+ }
407
+ return ""
408
408
  }
409
409
 
410
410
  func jsxIsInteractive(info jsxElementInfo) bool {
411
- if role, ok := jsxRole(info.attrs); ok && jsxInteractiveRoles[role] {
412
- return true
413
- }
414
- switch jsxImplicitRole(info) {
415
- case "button", "checkbox", "combobox", "link", "radio", "slider", "textbox":
416
- return true
417
- }
418
- return false
411
+ if role, ok := jsxRole(info.attrs); ok && jsxInteractiveRoles[role] {
412
+ return true
413
+ }
414
+ switch jsxImplicitRole(info) {
415
+ case "button", "checkbox", "combobox", "link", "radio", "slider", "textbox":
416
+ return true
417
+ }
418
+ return false
419
419
  }
420
420
 
421
421
  func jsxIsFocusable(info jsxElementInfo) bool {
422
- if disabled, ok := jsxBoolAttr(info.attrs, "disabled"); ok && disabled {
423
- return false
424
- }
425
- if value, ok := jsxNumericAttr(info.attrs, "tabIndex", "tabindex"); ok && value >= 0 {
426
- return true
427
- }
428
- switch info.tag {
429
- case "button", "input", "select", "textarea":
430
- return true
431
- case "a", "area":
432
- return jsxHasAttr(info.attrs, "href")
433
- }
434
- return false
422
+ if disabled, ok := jsxBoolAttr(info.attrs, "disabled"); ok && disabled {
423
+ return false
424
+ }
425
+ if value, ok := jsxNumericAttr(info.attrs, "tabIndex", "tabindex"); ok && value >= 0 {
426
+ return true
427
+ }
428
+ switch info.tag {
429
+ case "button", "input", "select", "textarea":
430
+ return true
431
+ case "a", "area":
432
+ return jsxHasAttr(info.attrs, "href")
433
+ }
434
+ return false
435
435
  }
436
436
 
437
437
  func jsxIsNonInteractiveElement(tag string) bool {
438
- switch tag {
439
- case "article", "aside", "div", "footer", "header", "li", "main", "nav", "ol", "p", "section", "ul",
440
- "h1", "h2", "h3", "h4", "h5", "h6":
441
- return true
442
- }
443
- return false
438
+ switch tag {
439
+ case "article", "aside", "div", "footer", "header", "li", "main", "nav", "ol", "p", "section", "ul",
440
+ "h1", "h2", "h3", "h4", "h5", "h6":
441
+ return true
442
+ }
443
+ return false
444
444
  }
445
445
 
446
446
  var jsxA11yRoles = map[string]bool{
447
- "alert": true, "alertdialog": true, "application": true, "article": true, "banner": true,
448
- "button": true, "cell": true, "checkbox": true, "columnheader": true, "combobox": true,
449
- "complementary": true, "contentinfo": true, "definition": true, "dialog": true, "directory": true,
450
- "document": true, "feed": true, "figure": true, "form": true, "grid": true, "gridcell": true,
451
- "group": true, "heading": true, "img": true, "link": true, "list": true, "listbox": true,
452
- "listitem": true, "log": true, "main": true, "marquee": true, "math": true, "menu": true,
453
- "menubar": true, "menuitem": true, "menuitemcheckbox": true, "menuitemradio": true,
454
- "meter": true, "navigation": true, "none": true, "note": true, "option": true, "presentation": true,
455
- "progressbar": true, "radio": true, "radiogroup": true, "region": true, "row": true,
456
- "rowgroup": true, "rowheader": true, "scrollbar": true, "search": true, "searchbox": true,
457
- "separator": true, "slider": true, "spinbutton": true, "status": true, "switch": true,
458
- "tab": true, "table": true, "tablist": true, "tabpanel": true, "term": true, "textbox": true,
459
- "timer": true, "toolbar": true, "tooltip": true, "tree": true, "treegrid": true, "treeitem": true,
447
+ "alert": true, "alertdialog": true, "application": true, "article": true, "banner": true,
448
+ "button": true, "cell": true, "checkbox": true, "columnheader": true, "combobox": true,
449
+ "complementary": true, "contentinfo": true, "definition": true, "dialog": true, "directory": true,
450
+ "document": true, "feed": true, "figure": true, "form": true, "grid": true, "gridcell": true,
451
+ "group": true, "heading": true, "img": true, "link": true, "list": true, "listbox": true,
452
+ "listitem": true, "log": true, "main": true, "marquee": true, "math": true, "menu": true,
453
+ "menubar": true, "menuitem": true, "menuitemcheckbox": true, "menuitemradio": true,
454
+ "meter": true, "navigation": true, "none": true, "note": true, "option": true, "presentation": true,
455
+ "progressbar": true, "radio": true, "radiogroup": true, "region": true, "row": true,
456
+ "rowgroup": true, "rowheader": true, "scrollbar": true, "search": true, "searchbox": true,
457
+ "separator": true, "slider": true, "spinbutton": true, "status": true, "switch": true,
458
+ "tab": true, "table": true, "tablist": true, "tabpanel": true, "term": true, "textbox": true,
459
+ "timer": true, "toolbar": true, "tooltip": true, "tree": true, "treegrid": true, "treeitem": true,
460
460
  }
461
461
 
462
462
  var jsxInteractiveRoles = map[string]bool{
463
- "button": true, "checkbox": true, "combobox": true, "gridcell": true, "link": true,
464
- "listbox": true, "menuitem": true, "menuitemcheckbox": true, "menuitemradio": true,
465
- "option": true, "radio": true, "scrollbar": true, "searchbox": true, "slider": true,
466
- "spinbutton": true, "switch": true, "tab": true, "textbox": true, "treeitem": true,
463
+ "button": true, "checkbox": true, "combobox": true, "gridcell": true, "link": true,
464
+ "listbox": true, "menuitem": true, "menuitemcheckbox": true, "menuitemradio": true,
465
+ "option": true, "radio": true, "scrollbar": true, "searchbox": true, "slider": true,
466
+ "spinbutton": true, "switch": true, "tab": true, "textbox": true, "treeitem": true,
467
467
  }
468
468
 
469
469
  var jsxNonInteractiveRoles = map[string]bool{
470
- "article": true, "complementary": true, "contentinfo": true, "definition": true,
471
- "document": true, "feed": true, "figure": true, "group": true, "heading": true,
472
- "img": true, "list": true, "listitem": true, "main": true, "navigation": true,
473
- "none": true, "note": true, "presentation": true, "region": true, "row": true,
474
- "rowgroup": true, "separator": true, "table": true, "term": true, "toolbar": true,
470
+ "article": true, "complementary": true, "contentinfo": true, "definition": true,
471
+ "document": true, "feed": true, "figure": true, "group": true, "heading": true,
472
+ "img": true, "list": true, "listitem": true, "main": true, "navigation": true,
473
+ "none": true, "note": true, "presentation": true, "region": true, "row": true,
474
+ "rowgroup": true, "separator": true, "table": true, "term": true, "toolbar": true,
475
475
  }
476
476
 
477
477
  var jsxAriaProps = map[string]bool{
478
- "aria-activedescendant": true, "aria-atomic": true, "aria-autocomplete": true, "aria-braillelabel": true,
479
- "aria-brailleroledescription": true, "aria-busy": true, "aria-checked": true, "aria-colcount": true,
480
- "aria-colindex": true, "aria-colindextext": true, "aria-colspan": true, "aria-controls": true,
481
- "aria-current": true, "aria-describedby": true, "aria-description": true, "aria-details": true,
482
- "aria-disabled": true, "aria-dropeffect": true, "aria-errormessage": true, "aria-expanded": true,
483
- "aria-flowto": true, "aria-grabbed": true, "aria-haspopup": true, "aria-hidden": true,
484
- "aria-invalid": true, "aria-keyshortcuts": true, "aria-label": true, "aria-labelledby": true,
485
- "aria-level": true, "aria-live": true, "aria-modal": true, "aria-multiline": true,
486
- "aria-multiselectable": true, "aria-orientation": true, "aria-owns": true, "aria-placeholder": true,
487
- "aria-posinset": true, "aria-pressed": true, "aria-readonly": true, "aria-relevant": true,
488
- "aria-required": true, "aria-roledescription": true, "aria-rowcount": true, "aria-rowindex": true,
489
- "aria-rowindextext": true, "aria-rowspan": true, "aria-selected": true, "aria-setsize": true,
490
- "aria-sort": true, "aria-valuemax": true, "aria-valuemin": true, "aria-valuenow": true,
491
- "aria-valuetext": true,
478
+ "aria-activedescendant": true, "aria-atomic": true, "aria-autocomplete": true, "aria-braillelabel": true,
479
+ "aria-brailleroledescription": true, "aria-busy": true, "aria-checked": true, "aria-colcount": true,
480
+ "aria-colindex": true, "aria-colindextext": true, "aria-colspan": true, "aria-controls": true,
481
+ "aria-current": true, "aria-describedby": true, "aria-description": true, "aria-details": true,
482
+ "aria-disabled": true, "aria-dropeffect": true, "aria-errormessage": true, "aria-expanded": true,
483
+ "aria-flowto": true, "aria-grabbed": true, "aria-haspopup": true, "aria-hidden": true,
484
+ "aria-invalid": true, "aria-keyshortcuts": true, "aria-label": true, "aria-labelledby": true,
485
+ "aria-level": true, "aria-live": true, "aria-modal": true, "aria-multiline": true,
486
+ "aria-multiselectable": true, "aria-orientation": true, "aria-owns": true, "aria-placeholder": true,
487
+ "aria-posinset": true, "aria-pressed": true, "aria-readonly": true, "aria-relevant": true,
488
+ "aria-required": true, "aria-roledescription": true, "aria-rowcount": true, "aria-rowindex": true,
489
+ "aria-rowindextext": true, "aria-rowspan": true, "aria-selected": true, "aria-setsize": true,
490
+ "aria-sort": true, "aria-valuemax": true, "aria-valuemin": true, "aria-valuenow": true,
491
+ "aria-valuetext": true,
492
492
  }
493
493
 
494
494
  var jsxGlobalAriaProps = map[string]bool{
495
- "aria-atomic": true, "aria-busy": true, "aria-controls": true, "aria-current": true,
496
- "aria-describedby": true, "aria-description": true, "aria-details": true, "aria-disabled": true,
497
- "aria-dropeffect": true, "aria-errormessage": true, "aria-flowto": true, "aria-grabbed": true,
498
- "aria-haspopup": true, "aria-hidden": true, "aria-invalid": true, "aria-keyshortcuts": true,
499
- "aria-label": true, "aria-labelledby": true, "aria-live": true, "aria-owns": true,
500
- "aria-relevant": true, "aria-roledescription": true,
495
+ "aria-atomic": true, "aria-busy": true, "aria-controls": true, "aria-current": true,
496
+ "aria-describedby": true, "aria-description": true, "aria-details": true, "aria-disabled": true,
497
+ "aria-dropeffect": true, "aria-errormessage": true, "aria-flowto": true, "aria-grabbed": true,
498
+ "aria-haspopup": true, "aria-hidden": true, "aria-invalid": true, "aria-keyshortcuts": true,
499
+ "aria-label": true, "aria-labelledby": true, "aria-live": true, "aria-owns": true,
500
+ "aria-relevant": true, "aria-roledescription": true,
501
501
  }
502
502
 
503
503
  var jsxRoleRequiredProps = map[string][]string{
504
- "checkbox": {"aria-checked"},
505
- "combobox": {"aria-controls", "aria-expanded"},
506
- "heading": {"aria-level"},
507
- "menuitemcheckbox": {"aria-checked"},
508
- "menuitemradio": {"aria-checked"},
509
- "option": {"aria-selected"},
510
- "radio": {"aria-checked"},
511
- "scrollbar": {"aria-controls", "aria-valuenow"},
512
- "slider": {"aria-valuenow"},
513
- "spinbutton": {"aria-valuenow"},
514
- "switch": {"aria-checked"},
504
+ "checkbox": {"aria-checked"},
505
+ "combobox": {"aria-controls", "aria-expanded"},
506
+ "heading": {"aria-level"},
507
+ "menuitemcheckbox": {"aria-checked"},
508
+ "menuitemradio": {"aria-checked"},
509
+ "option": {"aria-selected"},
510
+ "radio": {"aria-checked"},
511
+ "scrollbar": {"aria-controls", "aria-valuenow"},
512
+ "slider": {"aria-valuenow"},
513
+ "spinbutton": {"aria-valuenow"},
514
+ "switch": {"aria-checked"},
515
515
  }
516
516
 
517
517
  var jsxRoleSupportedProps = map[string]map[string]bool{
518
- "button": {"aria-expanded": true, "aria-pressed": true},
519
- "checkbox": {"aria-checked": true, "aria-readonly": true},
520
- "combobox": {"aria-activedescendant": true, "aria-autocomplete": true, "aria-controls": true, "aria-expanded": true, "aria-readonly": true, "aria-required": true},
521
- "heading": {"aria-level": true},
522
- "img": {"aria-label": true, "aria-labelledby": true},
523
- "link": {"aria-expanded": true},
524
- "radio": {"aria-checked": true},
525
- "slider": {"aria-orientation": true, "aria-valuemax": true, "aria-valuemin": true, "aria-valuenow": true, "aria-valuetext": true},
526
- "spinbutton": {"aria-valuemax": true, "aria-valuemin": true, "aria-valuenow": true, "aria-valuetext": true},
527
- "switch": {"aria-checked": true},
528
- "tab": {"aria-controls": true, "aria-selected": true},
529
- "textbox": {"aria-activedescendant": true, "aria-autocomplete": true, "aria-multiline": true, "aria-placeholder": true, "aria-readonly": true, "aria-required": true},
518
+ "button": {"aria-expanded": true, "aria-pressed": true},
519
+ "checkbox": {"aria-checked": true, "aria-readonly": true},
520
+ "combobox": {"aria-activedescendant": true, "aria-autocomplete": true, "aria-controls": true, "aria-expanded": true, "aria-readonly": true, "aria-required": true},
521
+ "heading": {"aria-level": true},
522
+ "img": {"aria-label": true, "aria-labelledby": true},
523
+ "link": {"aria-expanded": true},
524
+ "radio": {"aria-checked": true},
525
+ "slider": {"aria-orientation": true, "aria-valuemax": true, "aria-valuemin": true, "aria-valuenow": true, "aria-valuetext": true},
526
+ "spinbutton": {"aria-valuemax": true, "aria-valuemin": true, "aria-valuenow": true, "aria-valuetext": true},
527
+ "switch": {"aria-checked": true},
528
+ "tab": {"aria-controls": true, "aria-selected": true},
529
+ "textbox": {"aria-activedescendant": true, "aria-autocomplete": true, "aria-multiline": true, "aria-placeholder": true, "aria-readonly": true, "aria-required": true},
530
530
  }
531
531
 
532
532
  var jsxRedundantRoles = map[string]string{
533
- "button": "button", "img": "img", "main": "main", "nav": "navigation", "ul": "list", "ol": "list",
534
- "li": "listitem", "table": "table", "tr": "row", "td": "cell",
533
+ "button": "button", "img": "img", "main": "main", "nav": "navigation", "ul": "list", "ol": "list",
534
+ "li": "listitem", "table": "table", "tr": "row", "td": "cell",
535
535
  }
536
536
 
537
537
  var jsxRolePreferredTag = map[string]string{
538
- "button": "button", "checkbox": "input", "heading": "h1-h6", "img": "img", "link": "a",
539
- "list": "ul or ol", "listitem": "li", "main": "main", "navigation": "nav", "radio": "input",
540
- "table": "table", "textbox": "input or textarea",
538
+ "button": "button", "checkbox": "input", "heading": "h1-h6", "img": "img", "link": "a",
539
+ "list": "ul or ol", "listitem": "li", "main": "main", "navigation": "nav", "radio": "input",
540
+ "table": "table", "textbox": "input or textarea",
541
541
  }
542
542
 
543
543
  var jsxAutocompleteTokens = map[string]bool{
544
- "on": true, "off": true, "name": true, "honorific-prefix": true, "given-name": true,
545
- "additional-name": true, "family-name": true, "honorific-suffix": true, "nickname": true,
546
- "email": true, "username": true, "new-password": true, "current-password": true,
547
- "one-time-code": true, "organization-title": true, "organization": true,
548
- "street-address": true, "address-line1": true, "address-line2": true, "address-line3": true,
549
- "address-level1": true, "address-level2": true, "address-level3": true, "address-level4": true,
550
- "country": true, "country-name": true, "postal-code": true, "cc-name": true,
551
- "cc-given-name": true, "cc-additional-name": true, "cc-family-name": true, "cc-number": true,
552
- "cc-exp": true, "cc-exp-month": true, "cc-exp-year": true, "cc-csc": true, "cc-type": true,
553
- "transaction-currency": true, "transaction-amount": true, "language": true, "bday": true,
554
- "bday-day": true, "bday-month": true, "bday-year": true, "sex": true, "tel": true,
555
- "tel-country-code": true, "tel-national": true, "tel-area-code": true, "tel-local": true,
556
- "tel-extension": true, "impp": true, "url": true, "photo": true,
544
+ "on": true, "off": true, "name": true, "honorific-prefix": true, "given-name": true,
545
+ "additional-name": true, "family-name": true, "honorific-suffix": true, "nickname": true,
546
+ "email": true, "username": true, "new-password": true, "current-password": true,
547
+ "one-time-code": true, "organization-title": true, "organization": true,
548
+ "street-address": true, "address-line1": true, "address-line2": true, "address-line3": true,
549
+ "address-level1": true, "address-level2": true, "address-level3": true, "address-level4": true,
550
+ "country": true, "country-name": true, "postal-code": true, "cc-name": true,
551
+ "cc-given-name": true, "cc-additional-name": true, "cc-family-name": true, "cc-number": true,
552
+ "cc-exp": true, "cc-exp-month": true, "cc-exp-year": true, "cc-csc": true, "cc-type": true,
553
+ "transaction-currency": true, "transaction-amount": true, "language": true, "bday": true,
554
+ "bday-day": true, "bday-month": true, "bday-year": true, "sex": true, "tel": true,
555
+ "tel-country-code": true, "tel-national": true, "tel-area-code": true, "tel-local": true,
556
+ "tel-extension": true, "impp": true, "url": true, "photo": true,
557
557
  }
558
558
 
559
559
  type jsxA11yAltText struct{}
560
560
 
561
561
  func (jsxA11yAltText) Name() string { return "jsx-a11y/alt-text" }
562
562
  func (jsxA11yAltText) Visits() []shimast.Kind {
563
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
563
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
564
564
  }
565
565
  func (jsxA11yAltText) Check(ctx *Context, node *shimast.Node) {
566
- info := jsxElementFromNode(node)
567
- switch info.tag {
568
- case "img", "area":
569
- if !jsxHasAttr(info.attrs, "alt", "aria-label", "aria-labelledby") {
570
- ctx.Report(info.opening, "Image-like elements must have alt text.")
571
- }
572
- case "input":
573
- attr, ok := jsxKnownAttr(info.attrs, "type")
574
- if ok && strings.EqualFold(attr.value, "image") && !jsxHasAttr(info.attrs, "alt", "aria-label", "aria-labelledby") {
575
- ctx.Report(info.opening, "Image input elements must have alt text.")
576
- }
577
- case "object":
578
- if !jsxHasAccessibleLabel(info) {
579
- ctx.Report(info.opening, "Object elements must have accessible text.")
580
- }
581
- }
566
+ info := jsxElementFromNode(node)
567
+ switch info.tag {
568
+ case "img", "area":
569
+ if !jsxHasAttr(info.attrs, "alt", "aria-label", "aria-labelledby") {
570
+ ctx.Report(info.opening, "Image-like elements must have alt text.")
571
+ }
572
+ case "input":
573
+ attr, ok := jsxKnownAttr(info.attrs, "type")
574
+ if ok && strings.EqualFold(attr.value, "image") && !jsxHasAttr(info.attrs, "alt", "aria-label", "aria-labelledby") {
575
+ ctx.Report(info.opening, "Image input elements must have alt text.")
576
+ }
577
+ case "object":
578
+ if !jsxHasAccessibleLabel(info) {
579
+ ctx.Report(info.opening, "Object elements must have accessible text.")
580
+ }
581
+ }
582
582
  }
583
583
 
584
584
  type jsxA11yAnchorHasContent struct{}
@@ -586,47 +586,47 @@ type jsxA11yAnchorHasContent struct{}
586
586
  func (jsxA11yAnchorHasContent) Name() string { return "jsx-a11y/anchor-has-content" }
587
587
  func (jsxA11yAnchorHasContent) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxElement} }
588
588
  func (jsxA11yAnchorHasContent) Check(ctx *Context, node *shimast.Node) {
589
- info := jsxElementFromNode(node)
590
- if info.tag == "a" && !jsxHasAccessibleLabel(info) {
591
- ctx.Report(info.opening, "Anchors must have accessible content.")
592
- }
589
+ info := jsxElementFromNode(node)
590
+ if info.tag == "a" && !jsxHasAccessibleLabel(info) {
591
+ ctx.Report(info.opening, "Anchors must have accessible content.")
592
+ }
593
593
  }
594
594
 
595
595
  type jsxA11yAnchorIsValid struct{}
596
596
 
597
597
  func (jsxA11yAnchorIsValid) Name() string { return "jsx-a11y/anchor-is-valid" }
598
598
  func (jsxA11yAnchorIsValid) Visits() []shimast.Kind {
599
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
599
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
600
600
  }
601
601
  func (jsxA11yAnchorIsValid) Check(ctx *Context, node *shimast.Node) {
602
- info := jsxElementFromNode(node)
603
- if info.tag != "a" {
604
- return
605
- }
606
- href, ok := jsxKnownAttr(info.attrs, "href")
607
- if !ok {
608
- ctx.Report(info.opening, "Anchor elements must have a valid href.")
609
- return
610
- }
611
- value := strings.TrimSpace(strings.ToLower(href.value))
612
- if value == "" || value == "#" || strings.HasPrefix(value, "javascript:") {
613
- ctx.Report(href.node, "Anchor href must be a valid navigation target.")
614
- }
602
+ info := jsxElementFromNode(node)
603
+ if info.tag != "a" {
604
+ return
605
+ }
606
+ href, ok := jsxKnownAttr(info.attrs, "href")
607
+ if !ok {
608
+ ctx.Report(info.opening, "Anchor elements must have a valid href.")
609
+ return
610
+ }
611
+ value := strings.TrimSpace(strings.ToLower(href.value))
612
+ if value == "" || value == "#" || strings.HasPrefix(value, "javascript:") {
613
+ ctx.Report(href.node, "Anchor href must be a valid navigation target.")
614
+ }
615
615
  }
616
616
 
617
617
  type jsxA11yAriaActivedescendantHasTabindex struct{}
618
618
 
619
619
  func (jsxA11yAriaActivedescendantHasTabindex) Name() string {
620
- return "jsx-a11y/aria-activedescendant-has-tabindex"
620
+ return "jsx-a11y/aria-activedescendant-has-tabindex"
621
621
  }
622
622
  func (jsxA11yAriaActivedescendantHasTabindex) Visits() []shimast.Kind {
623
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
623
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
624
624
  }
625
625
  func (jsxA11yAriaActivedescendantHasTabindex) Check(ctx *Context, node *shimast.Node) {
626
- info := jsxElementFromNode(node)
627
- if jsxHasAttr(info.attrs, "aria-activedescendant") && !jsxHasAttr(info.attrs, "tabIndex", "tabindex") {
628
- ctx.Report(info.opening, "Elements with aria-activedescendant must define tabIndex.")
629
- }
626
+ info := jsxElementFromNode(node)
627
+ if jsxHasAttr(info.attrs, "aria-activedescendant") && !jsxHasAttr(info.attrs, "tabIndex", "tabindex") {
628
+ ctx.Report(info.opening, "Elements with aria-activedescendant must define tabIndex.")
629
+ }
630
630
  }
631
631
 
632
632
  type jsxA11yAriaProps struct{}
@@ -634,14 +634,14 @@ type jsxA11yAriaProps struct{}
634
634
  func (jsxA11yAriaProps) Name() string { return "jsx-a11y/aria-props" }
635
635
  func (jsxA11yAriaProps) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxAttribute} }
636
636
  func (jsxA11yAriaProps) Check(ctx *Context, node *shimast.Node) {
637
- attr := node.AsJsxAttribute()
638
- if attr == nil || attr.Name() == nil {
639
- return
640
- }
641
- name := strings.ToLower(jsxAttrName(attr.Name()))
642
- if strings.HasPrefix(name, "aria-") && !jsxAriaProps[name] {
643
- ctx.Report(node, "Unknown ARIA property "+name+".")
644
- }
637
+ attr := node.AsJsxAttribute()
638
+ if attr == nil || attr.Name() == nil {
639
+ return
640
+ }
641
+ name := strings.ToLower(jsxAttrName(attr.Name()))
642
+ if strings.HasPrefix(name, "aria-") && !jsxAriaProps[name] {
643
+ ctx.Report(node, "Unknown ARIA property "+name+".")
644
+ }
645
645
  }
646
646
 
647
647
  type jsxA11yAriaProptypes struct{}
@@ -649,29 +649,29 @@ type jsxA11yAriaProptypes struct{}
649
649
  func (jsxA11yAriaProptypes) Name() string { return "jsx-a11y/aria-proptypes" }
650
650
  func (jsxA11yAriaProptypes) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxAttribute} }
651
651
  func (jsxA11yAriaProptypes) Check(ctx *Context, node *shimast.Node) {
652
- attr := node.AsJsxAttribute()
653
- if attr == nil || attr.Name() == nil {
654
- return
655
- }
656
- name := strings.ToLower(jsxAttrName(attr.Name()))
657
- value := strings.ToLower(strings.TrimSpace(jsxAttrValue(attr.Initializer)))
658
- if !jsxAttrValueKnown(attr.Initializer) || value == "" {
659
- return
660
- }
661
- switch name {
662
- case "aria-hidden", "aria-disabled", "aria-expanded", "aria-modal", "aria-multiline", "aria-multiselectable", "aria-readonly", "aria-required", "aria-selected":
663
- if value != "true" && value != "false" {
664
- ctx.Report(node, name+" must be true or false.")
665
- }
666
- case "aria-checked", "aria-pressed":
667
- if value != "true" && value != "false" && value != "mixed" {
668
- ctx.Report(node, name+" must be true, false, or mixed.")
669
- }
670
- case "aria-level", "aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-posinset", "aria-setsize", "aria-colcount", "aria-colindex", "aria-colspan", "aria-rowcount", "aria-rowindex", "aria-rowspan":
671
- if _, err := strconv.Atoi(value); err != nil {
672
- ctx.Report(node, name+" must be numeric.")
673
- }
674
- }
652
+ attr := node.AsJsxAttribute()
653
+ if attr == nil || attr.Name() == nil {
654
+ return
655
+ }
656
+ name := strings.ToLower(jsxAttrName(attr.Name()))
657
+ value := strings.ToLower(strings.TrimSpace(jsxAttrValue(attr.Initializer)))
658
+ if !jsxAttrValueKnown(attr.Initializer) || value == "" {
659
+ return
660
+ }
661
+ switch name {
662
+ case "aria-hidden", "aria-disabled", "aria-expanded", "aria-modal", "aria-multiline", "aria-multiselectable", "aria-readonly", "aria-required", "aria-selected":
663
+ if value != "true" && value != "false" {
664
+ ctx.Report(node, name+" must be true or false.")
665
+ }
666
+ case "aria-checked", "aria-pressed":
667
+ if value != "true" && value != "false" && value != "mixed" {
668
+ ctx.Report(node, name+" must be true, false, or mixed.")
669
+ }
670
+ case "aria-level", "aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-posinset", "aria-setsize", "aria-colcount", "aria-colindex", "aria-colspan", "aria-rowcount", "aria-rowindex", "aria-rowspan":
671
+ if _, err := strconv.Atoi(value); err != nil {
672
+ ctx.Report(node, name+" must be numeric.")
673
+ }
674
+ }
675
675
  }
676
676
 
677
677
  type jsxA11yAriaRole struct{}
@@ -679,189 +679,189 @@ type jsxA11yAriaRole struct{}
679
679
  func (jsxA11yAriaRole) Name() string { return "jsx-a11y/aria-role" }
680
680
  func (jsxA11yAriaRole) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxAttribute} }
681
681
  func (jsxA11yAriaRole) Check(ctx *Context, node *shimast.Node) {
682
- attr := node.AsJsxAttribute()
683
- if attr == nil || attr.Name() == nil || jsxAttrName(attr.Name()) != "role" || !jsxAttrValueKnown(attr.Initializer) {
684
- return
685
- }
686
- tokens := strings.Fields(strings.ToLower(jsxAttrValue(attr.Initializer)))
687
- if len(tokens) == 0 {
688
- ctx.Report(node, "Role must not be empty.")
689
- return
690
- }
691
- for _, token := range tokens {
692
- if jsxA11yRoles[token] {
693
- return
694
- }
695
- }
696
- ctx.Report(node, "Role must be a valid ARIA role.")
682
+ attr := node.AsJsxAttribute()
683
+ if attr == nil || attr.Name() == nil || jsxAttrName(attr.Name()) != "role" || !jsxAttrValueKnown(attr.Initializer) {
684
+ return
685
+ }
686
+ tokens := strings.Fields(strings.ToLower(jsxAttrValue(attr.Initializer)))
687
+ if len(tokens) == 0 {
688
+ ctx.Report(node, "Role must not be empty.")
689
+ return
690
+ }
691
+ for _, token := range tokens {
692
+ if jsxA11yRoles[token] {
693
+ return
694
+ }
695
+ }
696
+ ctx.Report(node, "Role must be a valid ARIA role.")
697
697
  }
698
698
 
699
699
  type jsxA11yAriaUnsupportedElements struct{}
700
700
 
701
701
  func (jsxA11yAriaUnsupportedElements) Name() string { return "jsx-a11y/aria-unsupported-elements" }
702
702
  func (jsxA11yAriaUnsupportedElements) Visits() []shimast.Kind {
703
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
703
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
704
704
  }
705
705
  func (jsxA11yAriaUnsupportedElements) Check(ctx *Context, node *shimast.Node) {
706
- info := jsxElementFromNode(node)
707
- switch info.tag {
708
- case "meta", "html", "script", "style":
709
- if jsxHasAttr(info.attrs, "role") {
710
- ctx.Report(info.opening, "This element does not support ARIA roles.")
711
- return
712
- }
713
- for name := range info.attrs {
714
- if strings.HasPrefix(strings.ToLower(name), "aria-") {
715
- ctx.Report(info.opening, "This element does not support ARIA attributes.")
716
- return
717
- }
718
- }
719
- }
706
+ info := jsxElementFromNode(node)
707
+ switch info.tag {
708
+ case "meta", "html", "script", "style":
709
+ if jsxHasAttr(info.attrs, "role") {
710
+ ctx.Report(info.opening, "This element does not support ARIA roles.")
711
+ return
712
+ }
713
+ for name := range info.attrs {
714
+ if strings.HasPrefix(strings.ToLower(name), "aria-") {
715
+ ctx.Report(info.opening, "This element does not support ARIA attributes.")
716
+ return
717
+ }
718
+ }
719
+ }
720
720
  }
721
721
 
722
722
  type jsxA11yAutocompleteValid struct{}
723
723
 
724
724
  func (jsxA11yAutocompleteValid) Name() string { return "jsx-a11y/autocomplete-valid" }
725
725
  func (jsxA11yAutocompleteValid) Visits() []shimast.Kind {
726
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
726
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
727
727
  }
728
728
  func (jsxA11yAutocompleteValid) Check(ctx *Context, node *shimast.Node) {
729
- info := jsxElementFromNode(node)
730
- attr, ok := jsxKnownAttr(info.attrs, "autoComplete")
731
- if !ok {
732
- attr, ok = jsxKnownAttr(info.attrs, "autocomplete")
733
- }
734
- if !ok || strings.TrimSpace(attr.value) == "" {
735
- return
736
- }
737
- for _, token := range strings.Fields(strings.ToLower(attr.value)) {
738
- if strings.HasPrefix(token, "section-") || token == "shipping" || token == "billing" || token == "home" || token == "work" || token == "mobile" || token == "fax" || token == "pager" {
739
- continue
740
- }
741
- if !jsxAutocompleteTokens[token] {
742
- ctx.Report(attr.node, "autocomplete contains an invalid token.")
743
- return
744
- }
745
- }
729
+ info := jsxElementFromNode(node)
730
+ attr, ok := jsxKnownAttr(info.attrs, "autoComplete")
731
+ if !ok {
732
+ attr, ok = jsxKnownAttr(info.attrs, "autocomplete")
733
+ }
734
+ if !ok || strings.TrimSpace(attr.value) == "" {
735
+ return
736
+ }
737
+ for _, token := range strings.Fields(strings.ToLower(attr.value)) {
738
+ if strings.HasPrefix(token, "section-") || token == "shipping" || token == "billing" || token == "home" || token == "work" || token == "mobile" || token == "fax" || token == "pager" {
739
+ continue
740
+ }
741
+ if !jsxAutocompleteTokens[token] {
742
+ ctx.Report(attr.node, "autocomplete contains an invalid token.")
743
+ return
744
+ }
745
+ }
746
746
  }
747
747
 
748
748
  type jsxA11yClickEventsHaveKeyEvents struct{}
749
749
 
750
750
  func (jsxA11yClickEventsHaveKeyEvents) Name() string { return "jsx-a11y/click-events-have-key-events" }
751
751
  func (jsxA11yClickEventsHaveKeyEvents) Visits() []shimast.Kind {
752
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
752
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
753
753
  }
754
754
  func (jsxA11yClickEventsHaveKeyEvents) Check(ctx *Context, node *shimast.Node) {
755
- info := jsxElementFromNode(node)
756
- if !jsxHasAttr(info.attrs, "onClick", "onclick") || jsxIsHidden(info) || jsxIsInteractive(info) || jsxHasKeyboardHandler(info.attrs) {
757
- return
758
- }
759
- ctx.Report(info.opening, "Clickable non-interactive elements must also handle keyboard events.")
755
+ info := jsxElementFromNode(node)
756
+ if !jsxHasAttr(info.attrs, "onClick", "onclick") || jsxIsHidden(info) || jsxIsInteractive(info) || jsxHasKeyboardHandler(info.attrs) {
757
+ return
758
+ }
759
+ ctx.Report(info.opening, "Clickable non-interactive elements must also handle keyboard events.")
760
760
  }
761
761
 
762
762
  type jsxA11yControlHasAssociatedLabel struct{}
763
763
 
764
764
  func (jsxA11yControlHasAssociatedLabel) Name() string { return "jsx-a11y/control-has-associated-label" }
765
765
  func (jsxA11yControlHasAssociatedLabel) Visits() []shimast.Kind {
766
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
766
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
767
767
  }
768
768
  func (jsxA11yControlHasAssociatedLabel) Check(ctx *Context, node *shimast.Node) {
769
- info := jsxElementFromNode(node)
770
- if (jsxIsFormControl(info) || jsxIsInteractive(info)) && !jsxHasAccessibleLabel(info) {
771
- ctx.Report(info.opening, "Interactive controls must have an accessible label.")
772
- }
769
+ info := jsxElementFromNode(node)
770
+ if (jsxIsFormControl(info) || jsxIsInteractive(info)) && !jsxHasAccessibleLabel(info) {
771
+ ctx.Report(info.opening, "Interactive controls must have an accessible label.")
772
+ }
773
773
  }
774
774
 
775
775
  type jsxA11yHeadingHasContent struct{}
776
776
 
777
777
  func (jsxA11yHeadingHasContent) Name() string { return "jsx-a11y/heading-has-content" }
778
778
  func (jsxA11yHeadingHasContent) Visits() []shimast.Kind {
779
- return []shimast.Kind{shimast.KindJsxElement}
779
+ return []shimast.Kind{shimast.KindJsxElement}
780
780
  }
781
781
  func (jsxA11yHeadingHasContent) Check(ctx *Context, node *shimast.Node) {
782
- info := jsxElementFromNode(node)
783
- switch info.tag {
784
- case "h1", "h2", "h3", "h4", "h5", "h6":
785
- if !jsxHasAccessibleLabel(info) {
786
- ctx.Report(info.opening, "Headings must have accessible content.")
787
- }
788
- }
782
+ info := jsxElementFromNode(node)
783
+ switch info.tag {
784
+ case "h1", "h2", "h3", "h4", "h5", "h6":
785
+ if !jsxHasAccessibleLabel(info) {
786
+ ctx.Report(info.opening, "Headings must have accessible content.")
787
+ }
788
+ }
789
789
  }
790
790
 
791
791
  type jsxA11yHtmlHasLang struct{}
792
792
 
793
793
  func (jsxA11yHtmlHasLang) Name() string { return "jsx-a11y/html-has-lang" }
794
794
  func (jsxA11yHtmlHasLang) Visits() []shimast.Kind {
795
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
795
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
796
796
  }
797
797
  func (jsxA11yHtmlHasLang) Check(ctx *Context, node *shimast.Node) {
798
- info := jsxElementFromNode(node)
799
- if info.tag == "html" && !jsxHasAttr(info.attrs, "lang") {
800
- ctx.Report(info.opening, "The html element must have a lang attribute.")
801
- }
798
+ info := jsxElementFromNode(node)
799
+ if info.tag == "html" && !jsxHasAttr(info.attrs, "lang") {
800
+ ctx.Report(info.opening, "The html element must have a lang attribute.")
801
+ }
802
802
  }
803
803
 
804
804
  type jsxA11yIframeHasTitle struct{}
805
805
 
806
806
  func (jsxA11yIframeHasTitle) Name() string { return "jsx-a11y/iframe-has-title" }
807
807
  func (jsxA11yIframeHasTitle) Visits() []shimast.Kind {
808
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
808
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
809
809
  }
810
810
  func (jsxA11yIframeHasTitle) Check(ctx *Context, node *shimast.Node) {
811
- info := jsxElementFromNode(node)
812
- if info.tag == "iframe" {
813
- attr, ok := jsxKnownAttr(info.attrs, "title")
814
- if !ok || strings.TrimSpace(attr.value) == "" {
815
- ctx.Report(info.opening, "Iframes must have a non-empty title.")
816
- }
817
- }
811
+ info := jsxElementFromNode(node)
812
+ if info.tag == "iframe" {
813
+ attr, ok := jsxKnownAttr(info.attrs, "title")
814
+ if !ok || strings.TrimSpace(attr.value) == "" {
815
+ ctx.Report(info.opening, "Iframes must have a non-empty title.")
816
+ }
817
+ }
818
818
  }
819
819
 
820
820
  type jsxA11yImgRedundantAlt struct{}
821
821
 
822
822
  func (jsxA11yImgRedundantAlt) Name() string { return "jsx-a11y/img-redundant-alt" }
823
823
  func (jsxA11yImgRedundantAlt) Visits() []shimast.Kind {
824
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
824
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
825
825
  }
826
826
  func (jsxA11yImgRedundantAlt) Check(ctx *Context, node *shimast.Node) {
827
- info := jsxElementFromNode(node)
828
- if info.tag != "img" {
829
- return
830
- }
831
- attr, ok := jsxKnownAttr(info.attrs, "alt")
832
- if !ok {
833
- return
834
- }
835
- value := strings.ToLower(attr.value)
836
- if strings.Contains(value, "image") || strings.Contains(value, "photo") || strings.Contains(value, "picture") {
837
- ctx.Report(attr.node, "Image alt text should not contain redundant words like image, photo, or picture.")
838
- }
827
+ info := jsxElementFromNode(node)
828
+ if info.tag != "img" {
829
+ return
830
+ }
831
+ attr, ok := jsxKnownAttr(info.attrs, "alt")
832
+ if !ok {
833
+ return
834
+ }
835
+ value := strings.ToLower(attr.value)
836
+ if strings.Contains(value, "image") || strings.Contains(value, "photo") || strings.Contains(value, "picture") {
837
+ ctx.Report(attr.node, "Image alt text should not contain redundant words like image, photo, or picture.")
838
+ }
839
839
  }
840
840
 
841
841
  type jsxA11yInteractiveSupportsFocus struct{}
842
842
 
843
843
  func (jsxA11yInteractiveSupportsFocus) Name() string { return "jsx-a11y/interactive-supports-focus" }
844
844
  func (jsxA11yInteractiveSupportsFocus) Visits() []shimast.Kind {
845
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
845
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
846
846
  }
847
847
  func (jsxA11yInteractiveSupportsFocus) Check(ctx *Context, node *shimast.Node) {
848
- info := jsxElementFromNode(node)
849
- if role, ok := jsxRole(info.attrs); ok && jsxInteractiveRoles[role] && !jsxIsFocusable(info) {
850
- ctx.Report(info.opening, "Elements with interactive roles must be focusable.")
851
- }
848
+ info := jsxElementFromNode(node)
849
+ if role, ok := jsxRole(info.attrs); ok && jsxInteractiveRoles[role] && !jsxIsFocusable(info) {
850
+ ctx.Report(info.opening, "Elements with interactive roles must be focusable.")
851
+ }
852
852
  }
853
853
 
854
854
  type jsxA11yLabelHasAssociatedControl struct{}
855
855
 
856
856
  func (jsxA11yLabelHasAssociatedControl) Name() string { return "jsx-a11y/label-has-associated-control" }
857
857
  func (jsxA11yLabelHasAssociatedControl) Visits() []shimast.Kind {
858
- return []shimast.Kind{shimast.KindJsxElement}
858
+ return []shimast.Kind{shimast.KindJsxElement}
859
859
  }
860
860
  func (jsxA11yLabelHasAssociatedControl) Check(ctx *Context, node *shimast.Node) {
861
- info := jsxElementFromNode(node)
862
- if info.tag == "label" && !jsxHasAttr(info.attrs, "htmlFor", "for") && !jsxHasDescendantControl(info.children) {
863
- ctx.Report(info.opening, "Labels must be associated with a control.")
864
- }
861
+ info := jsxElementFromNode(node)
862
+ if info.tag == "label" && !jsxHasAttr(info.attrs, "htmlFor", "for") && !jsxHasDescendantControl(info.children) {
863
+ ctx.Report(info.opening, "Labels must be associated with a control.")
864
+ }
865
865
  }
866
866
 
867
867
  type jsxA11yLabelHasFor struct{}
@@ -869,26 +869,26 @@ type jsxA11yLabelHasFor struct{}
869
869
  func (jsxA11yLabelHasFor) Name() string { return "jsx-a11y/label-has-for" }
870
870
  func (jsxA11yLabelHasFor) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxElement} }
871
871
  func (jsxA11yLabelHasFor) Check(ctx *Context, node *shimast.Node) {
872
- jsxA11yLabelHasAssociatedControl{}.Check(ctx, node)
872
+ jsxA11yLabelHasAssociatedControl{}.Check(ctx, node)
873
873
  }
874
874
 
875
875
  type jsxA11yLang struct{}
876
876
 
877
877
  func (jsxA11yLang) Name() string { return "jsx-a11y/lang" }
878
878
  func (jsxA11yLang) Visits() []shimast.Kind {
879
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
879
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
880
880
  }
881
881
  func (jsxA11yLang) Check(ctx *Context, node *shimast.Node) {
882
- info := jsxElementFromNode(node)
883
- attr, ok := jsxKnownAttr(info.attrs, "lang")
884
- if !ok {
885
- return
886
- }
887
- value := strings.TrimSpace(attr.value)
888
- parts := strings.Split(value, "-")
889
- if value == "" || len(parts[0]) < 2 || len(parts[0]) > 3 {
890
- ctx.Report(attr.node, "lang must be a valid BCP 47 language tag.")
891
- }
882
+ info := jsxElementFromNode(node)
883
+ attr, ok := jsxKnownAttr(info.attrs, "lang")
884
+ if !ok {
885
+ return
886
+ }
887
+ value := strings.TrimSpace(attr.value)
888
+ parts := strings.Split(value, "-")
889
+ if value == "" || len(parts[0]) < 2 || len(parts[0]) > 3 {
890
+ ctx.Report(attr.node, "lang must be a valid BCP 47 language tag.")
891
+ }
892
892
  }
893
893
 
894
894
  type jsxA11yMediaHasCaption struct{}
@@ -896,27 +896,27 @@ type jsxA11yMediaHasCaption struct{}
896
896
  func (jsxA11yMediaHasCaption) Name() string { return "jsx-a11y/media-has-caption" }
897
897
  func (jsxA11yMediaHasCaption) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxElement} }
898
898
  func (jsxA11yMediaHasCaption) Check(ctx *Context, node *shimast.Node) {
899
- info := jsxElementFromNode(node)
900
- if (info.tag == "audio" || info.tag == "video") && !jsxHasTrackCaption(info.children) {
901
- ctx.Report(info.opening, "Media elements must provide caption tracks.")
902
- }
899
+ info := jsxElementFromNode(node)
900
+ if (info.tag == "audio" || info.tag == "video") && !jsxHasTrackCaption(info.children) {
901
+ ctx.Report(info.opening, "Media elements must provide caption tracks.")
902
+ }
903
903
  }
904
904
 
905
905
  type jsxA11yMouseEventsHaveKeyEvents struct{}
906
906
 
907
907
  func (jsxA11yMouseEventsHaveKeyEvents) Name() string { return "jsx-a11y/mouse-events-have-key-events" }
908
908
  func (jsxA11yMouseEventsHaveKeyEvents) Visits() []shimast.Kind {
909
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
909
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
910
910
  }
911
911
  func (jsxA11yMouseEventsHaveKeyEvents) Check(ctx *Context, node *shimast.Node) {
912
- info := jsxElementFromNode(node)
913
- if jsxHasAttr(info.attrs, "onMouseOver", "onmouseover") && !jsxHasAttr(info.attrs, "onFocus", "onfocus") {
914
- ctx.Report(info.opening, "onMouseOver must be paired with onFocus.")
915
- return
916
- }
917
- if jsxHasAttr(info.attrs, "onMouseOut", "onmouseout") && !jsxHasAttr(info.attrs, "onBlur", "onblur") {
918
- ctx.Report(info.opening, "onMouseOut must be paired with onBlur.")
919
- }
912
+ info := jsxElementFromNode(node)
913
+ if jsxHasAttr(info.attrs, "onMouseOver", "onmouseover") && !jsxHasAttr(info.attrs, "onFocus", "onfocus") {
914
+ ctx.Report(info.opening, "onMouseOver must be paired with onFocus.")
915
+ return
916
+ }
917
+ if jsxHasAttr(info.attrs, "onMouseOut", "onmouseout") && !jsxHasAttr(info.attrs, "onBlur", "onblur") {
918
+ ctx.Report(info.opening, "onMouseOut must be paired with onBlur.")
919
+ }
920
920
  }
921
921
 
922
922
  type jsxA11yNoAccessKey struct{}
@@ -924,23 +924,23 @@ type jsxA11yNoAccessKey struct{}
924
924
  func (jsxA11yNoAccessKey) Name() string { return "jsx-a11y/no-access-key" }
925
925
  func (jsxA11yNoAccessKey) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxAttribute} }
926
926
  func (jsxA11yNoAccessKey) Check(ctx *Context, node *shimast.Node) {
927
- attr := node.AsJsxAttribute()
928
- if attr != nil && attr.Name() != nil && jsxAttrName(attr.Name()) == "accessKey" {
929
- ctx.Report(node, "Do not use accessKey.")
930
- }
927
+ attr := node.AsJsxAttribute()
928
+ if attr != nil && attr.Name() != nil && jsxAttrName(attr.Name()) == "accessKey" {
929
+ ctx.Report(node, "Do not use accessKey.")
930
+ }
931
931
  }
932
932
 
933
933
  type jsxA11yNoAriaHiddenOnFocusable struct{}
934
934
 
935
935
  func (jsxA11yNoAriaHiddenOnFocusable) Name() string { return "jsx-a11y/no-aria-hidden-on-focusable" }
936
936
  func (jsxA11yNoAriaHiddenOnFocusable) Visits() []shimast.Kind {
937
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
937
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
938
938
  }
939
939
  func (jsxA11yNoAriaHiddenOnFocusable) Check(ctx *Context, node *shimast.Node) {
940
- info := jsxElementFromNode(node)
941
- if hidden, ok := jsxBoolAttr(info.attrs, "aria-hidden"); ok && hidden && jsxIsFocusable(info) {
942
- ctx.Report(info.opening, "Focusable elements must not be aria-hidden.")
943
- }
940
+ info := jsxElementFromNode(node)
941
+ if hidden, ok := jsxBoolAttr(info.attrs, "aria-hidden"); ok && hidden && jsxIsFocusable(info) {
942
+ ctx.Report(info.opening, "Focusable elements must not be aria-hidden.")
943
+ }
944
944
  }
945
945
 
946
946
  type jsxA11yNoAutofocus struct{}
@@ -948,217 +948,217 @@ type jsxA11yNoAutofocus struct{}
948
948
  func (jsxA11yNoAutofocus) Name() string { return "jsx-a11y/no-autofocus" }
949
949
  func (jsxA11yNoAutofocus) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindJsxAttribute} }
950
950
  func (jsxA11yNoAutofocus) Check(ctx *Context, node *shimast.Node) {
951
- attr := node.AsJsxAttribute()
952
- if attr == nil || attr.Name() == nil {
953
- return
954
- }
955
- name := jsxAttrName(attr.Name())
956
- if name == "autoFocus" || name == "autofocus" {
957
- ctx.Report(node, "Do not use autoFocus.")
958
- }
951
+ attr := node.AsJsxAttribute()
952
+ if attr == nil || attr.Name() == nil {
953
+ return
954
+ }
955
+ name := jsxAttrName(attr.Name())
956
+ if name == "autoFocus" || name == "autofocus" {
957
+ ctx.Report(node, "Do not use autoFocus.")
958
+ }
959
959
  }
960
960
 
961
961
  type jsxA11yNoDistractingElements struct{}
962
962
 
963
963
  func (jsxA11yNoDistractingElements) Name() string { return "jsx-a11y/no-distracting-elements" }
964
964
  func (jsxA11yNoDistractingElements) Visits() []shimast.Kind {
965
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
965
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
966
966
  }
967
967
  func (jsxA11yNoDistractingElements) Check(ctx *Context, node *shimast.Node) {
968
- info := jsxElementFromNode(node)
969
- if info.tag == "blink" || info.tag == "marquee" {
970
- ctx.Report(info.opening, "Do not use distracting elements.")
971
- }
968
+ info := jsxElementFromNode(node)
969
+ if info.tag == "blink" || info.tag == "marquee" {
970
+ ctx.Report(info.opening, "Do not use distracting elements.")
971
+ }
972
972
  }
973
973
 
974
974
  type jsxA11yNoInteractiveElementToNoninteractiveRole struct{}
975
975
 
976
976
  func (jsxA11yNoInteractiveElementToNoninteractiveRole) Name() string {
977
- return "jsx-a11y/no-interactive-element-to-noninteractive-role"
977
+ return "jsx-a11y/no-interactive-element-to-noninteractive-role"
978
978
  }
979
979
  func (jsxA11yNoInteractiveElementToNoninteractiveRole) Visits() []shimast.Kind {
980
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
980
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
981
981
  }
982
982
  func (jsxA11yNoInteractiveElementToNoninteractiveRole) Check(ctx *Context, node *shimast.Node) {
983
- info := jsxElementFromNode(node)
984
- role, ok := jsxRole(info.attrs)
985
- if ok && jsxIsInteractive(info) && jsxNonInteractiveRoles[role] {
986
- ctx.Report(info.opening, "Interactive elements must not use non-interactive roles.")
987
- }
983
+ info := jsxElementFromNode(node)
984
+ role, ok := jsxRole(info.attrs)
985
+ if ok && jsxIsInteractive(info) && jsxNonInteractiveRoles[role] {
986
+ ctx.Report(info.opening, "Interactive elements must not use non-interactive roles.")
987
+ }
988
988
  }
989
989
 
990
990
  type jsxA11yNoNoninteractiveElementInteractions struct{}
991
991
 
992
992
  func (jsxA11yNoNoninteractiveElementInteractions) Name() string {
993
- return "jsx-a11y/no-noninteractive-element-interactions"
993
+ return "jsx-a11y/no-noninteractive-element-interactions"
994
994
  }
995
995
  func (jsxA11yNoNoninteractiveElementInteractions) Visits() []shimast.Kind {
996
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
996
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
997
997
  }
998
998
  func (jsxA11yNoNoninteractiveElementInteractions) Check(ctx *Context, node *shimast.Node) {
999
- info := jsxElementFromNode(node)
1000
- if jsxIsNonInteractiveElement(info.tag) && jsxHasMouseOrKeyboardInteraction(info.attrs) {
1001
- ctx.Report(info.opening, "Non-interactive elements must not have interaction handlers.")
1002
- }
999
+ info := jsxElementFromNode(node)
1000
+ if jsxIsNonInteractiveElement(info.tag) && jsxHasMouseOrKeyboardInteraction(info.attrs) {
1001
+ ctx.Report(info.opening, "Non-interactive elements must not have interaction handlers.")
1002
+ }
1003
1003
  }
1004
1004
 
1005
1005
  type jsxA11yNoNoninteractiveElementToInteractiveRole struct{}
1006
1006
 
1007
1007
  func (jsxA11yNoNoninteractiveElementToInteractiveRole) Name() string {
1008
- return "jsx-a11y/no-noninteractive-element-to-interactive-role"
1008
+ return "jsx-a11y/no-noninteractive-element-to-interactive-role"
1009
1009
  }
1010
1010
  func (jsxA11yNoNoninteractiveElementToInteractiveRole) Visits() []shimast.Kind {
1011
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1011
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1012
1012
  }
1013
1013
  func (jsxA11yNoNoninteractiveElementToInteractiveRole) Check(ctx *Context, node *shimast.Node) {
1014
- info := jsxElementFromNode(node)
1015
- role, ok := jsxRole(info.attrs)
1016
- if ok && jsxIsNonInteractiveElement(info.tag) && jsxInteractiveRoles[role] {
1017
- ctx.Report(info.opening, "Non-interactive elements must not use interactive roles.")
1018
- }
1014
+ info := jsxElementFromNode(node)
1015
+ role, ok := jsxRole(info.attrs)
1016
+ if ok && jsxIsNonInteractiveElement(info.tag) && jsxInteractiveRoles[role] {
1017
+ ctx.Report(info.opening, "Non-interactive elements must not use interactive roles.")
1018
+ }
1019
1019
  }
1020
1020
 
1021
1021
  type jsxA11yNoNoninteractiveTabindex struct{}
1022
1022
 
1023
1023
  func (jsxA11yNoNoninteractiveTabindex) Name() string { return "jsx-a11y/no-noninteractive-tabindex" }
1024
1024
  func (jsxA11yNoNoninteractiveTabindex) Visits() []shimast.Kind {
1025
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1025
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1026
1026
  }
1027
1027
  func (jsxA11yNoNoninteractiveTabindex) Check(ctx *Context, node *shimast.Node) {
1028
- info := jsxElementFromNode(node)
1029
- if _, ok := jsxNumericAttr(info.attrs, "tabIndex", "tabindex"); ok && !jsxIsInteractive(info) {
1030
- ctx.Report(info.opening, "Non-interactive elements must not be focusable with tabIndex.")
1031
- }
1028
+ info := jsxElementFromNode(node)
1029
+ if _, ok := jsxNumericAttr(info.attrs, "tabIndex", "tabindex"); ok && !jsxIsInteractive(info) {
1030
+ ctx.Report(info.opening, "Non-interactive elements must not be focusable with tabIndex.")
1031
+ }
1032
1032
  }
1033
1033
 
1034
1034
  type jsxA11yNoRedundantRoles struct{}
1035
1035
 
1036
1036
  func (jsxA11yNoRedundantRoles) Name() string { return "jsx-a11y/no-redundant-roles" }
1037
1037
  func (jsxA11yNoRedundantRoles) Visits() []shimast.Kind {
1038
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1038
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1039
1039
  }
1040
1040
  func (jsxA11yNoRedundantRoles) Check(ctx *Context, node *shimast.Node) {
1041
- info := jsxElementFromNode(node)
1042
- role, ok := jsxRole(info.attrs)
1043
- if !ok {
1044
- return
1045
- }
1046
- implicit := jsxImplicitRole(info)
1047
- if implicit == "" {
1048
- implicit = jsxRedundantRoles[info.tag]
1049
- }
1050
- if implicit == role {
1051
- ctx.Report(info.opening, "This role is redundant on the element.")
1052
- }
1041
+ info := jsxElementFromNode(node)
1042
+ role, ok := jsxRole(info.attrs)
1043
+ if !ok {
1044
+ return
1045
+ }
1046
+ implicit := jsxImplicitRole(info)
1047
+ if implicit == "" {
1048
+ implicit = jsxRedundantRoles[info.tag]
1049
+ }
1050
+ if implicit == role {
1051
+ ctx.Report(info.opening, "This role is redundant on the element.")
1052
+ }
1053
1053
  }
1054
1054
 
1055
1055
  type jsxA11yNoStaticElementInteractions struct{}
1056
1056
 
1057
1057
  func (jsxA11yNoStaticElementInteractions) Name() string {
1058
- return "jsx-a11y/no-static-element-interactions"
1058
+ return "jsx-a11y/no-static-element-interactions"
1059
1059
  }
1060
1060
  func (jsxA11yNoStaticElementInteractions) Visits() []shimast.Kind {
1061
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1061
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1062
1062
  }
1063
1063
  func (jsxA11yNoStaticElementInteractions) Check(ctx *Context, node *shimast.Node) {
1064
- info := jsxElementFromNode(node)
1065
- if info.tag == "" || jsxIsInteractive(info) || jsxIsNonInteractiveElement(info.tag) || jsxHasAttr(info.attrs, "role") || !jsxHasMouseOrKeyboardInteraction(info.attrs) {
1066
- return
1067
- }
1068
- ctx.Report(info.opening, "Static elements with interaction handlers must have an ARIA role.")
1064
+ info := jsxElementFromNode(node)
1065
+ if info.tag == "" || jsxIsInteractive(info) || jsxIsNonInteractiveElement(info.tag) || jsxHasAttr(info.attrs, "role") || !jsxHasMouseOrKeyboardInteraction(info.attrs) {
1066
+ return
1067
+ }
1068
+ ctx.Report(info.opening, "Static elements with interaction handlers must have an ARIA role.")
1069
1069
  }
1070
1070
 
1071
1071
  type jsxA11yPreferTagOverRole struct{}
1072
1072
 
1073
1073
  func (jsxA11yPreferTagOverRole) Name() string { return "jsx-a11y/prefer-tag-over-role" }
1074
1074
  func (jsxA11yPreferTagOverRole) Visits() []shimast.Kind {
1075
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1075
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1076
1076
  }
1077
1077
  func (jsxA11yPreferTagOverRole) Check(ctx *Context, node *shimast.Node) {
1078
- info := jsxElementFromNode(node)
1079
- if info.tag == "" || info.tag != "div" && info.tag != "span" {
1080
- return
1081
- }
1082
- role, ok := jsxRole(info.attrs)
1083
- if ok {
1084
- if tag, exists := jsxRolePreferredTag[role]; exists {
1085
- ctx.Report(info.opening, "Prefer the native "+tag+" element over role="+role+".")
1086
- }
1087
- }
1078
+ info := jsxElementFromNode(node)
1079
+ if info.tag == "" || info.tag != "div" && info.tag != "span" {
1080
+ return
1081
+ }
1082
+ role, ok := jsxRole(info.attrs)
1083
+ if ok {
1084
+ if tag, exists := jsxRolePreferredTag[role]; exists {
1085
+ ctx.Report(info.opening, "Prefer the native "+tag+" element over role="+role+".")
1086
+ }
1087
+ }
1088
1088
  }
1089
1089
 
1090
1090
  type jsxA11yRoleHasRequiredAriaProps struct{}
1091
1091
 
1092
1092
  func (jsxA11yRoleHasRequiredAriaProps) Name() string { return "jsx-a11y/role-has-required-aria-props" }
1093
1093
  func (jsxA11yRoleHasRequiredAriaProps) Visits() []shimast.Kind {
1094
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1094
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1095
1095
  }
1096
1096
  func (jsxA11yRoleHasRequiredAriaProps) Check(ctx *Context, node *shimast.Node) {
1097
- info := jsxElementFromNode(node)
1098
- role, ok := jsxRole(info.attrs)
1099
- if !ok {
1100
- return
1101
- }
1102
- for _, required := range jsxRoleRequiredProps[role] {
1103
- if !jsxHasAttr(info.attrs, required) {
1104
- ctx.Report(info.opening, "Role "+role+" requires "+required+".")
1105
- return
1106
- }
1107
- }
1097
+ info := jsxElementFromNode(node)
1098
+ role, ok := jsxRole(info.attrs)
1099
+ if !ok {
1100
+ return
1101
+ }
1102
+ for _, required := range jsxRoleRequiredProps[role] {
1103
+ if !jsxHasAttr(info.attrs, required) {
1104
+ ctx.Report(info.opening, "Role "+role+" requires "+required+".")
1105
+ return
1106
+ }
1107
+ }
1108
1108
  }
1109
1109
 
1110
1110
  type jsxA11yRoleSupportsAriaProps struct{}
1111
1111
 
1112
1112
  func (jsxA11yRoleSupportsAriaProps) Name() string { return "jsx-a11y/role-supports-aria-props" }
1113
1113
  func (jsxA11yRoleSupportsAriaProps) Visits() []shimast.Kind {
1114
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1114
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1115
1115
  }
1116
1116
  func (jsxA11yRoleSupportsAriaProps) Check(ctx *Context, node *shimast.Node) {
1117
- info := jsxElementFromNode(node)
1118
- role, ok := jsxRole(info.attrs)
1119
- if !ok {
1120
- return
1121
- }
1122
- if role == "" {
1123
- return
1124
- }
1125
- supported := jsxRoleSupportedProps[role]
1126
- for name, attr := range info.attrs {
1127
- lower := strings.ToLower(name)
1128
- if !strings.HasPrefix(lower, "aria-") || !jsxAriaProps[lower] || jsxGlobalAriaProps[lower] {
1129
- continue
1130
- }
1131
- if supported == nil || !supported[lower] {
1132
- ctx.Report(attr.node, "ARIA property "+lower+" is not supported by role "+role+".")
1133
- return
1134
- }
1135
- }
1117
+ info := jsxElementFromNode(node)
1118
+ role, ok := jsxRole(info.attrs)
1119
+ if !ok {
1120
+ return
1121
+ }
1122
+ if role == "" {
1123
+ return
1124
+ }
1125
+ supported := jsxRoleSupportedProps[role]
1126
+ for name, attr := range info.attrs {
1127
+ lower := strings.ToLower(name)
1128
+ if !strings.HasPrefix(lower, "aria-") || !jsxAriaProps[lower] || jsxGlobalAriaProps[lower] {
1129
+ continue
1130
+ }
1131
+ if supported == nil || !supported[lower] {
1132
+ ctx.Report(attr.node, "ARIA property "+lower+" is not supported by role "+role+".")
1133
+ return
1134
+ }
1135
+ }
1136
1136
  }
1137
1137
 
1138
1138
  type jsxA11yScope struct{}
1139
1139
 
1140
1140
  func (jsxA11yScope) Name() string { return "jsx-a11y/scope" }
1141
1141
  func (jsxA11yScope) Visits() []shimast.Kind {
1142
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1142
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1143
1143
  }
1144
1144
  func (jsxA11yScope) Check(ctx *Context, node *shimast.Node) {
1145
- info := jsxElementFromNode(node)
1146
- if jsxHasAttr(info.attrs, "scope") && info.tag != "th" {
1147
- ctx.Report(info.opening, "The scope attribute is only valid on th elements.")
1148
- }
1145
+ info := jsxElementFromNode(node)
1146
+ if jsxHasAttr(info.attrs, "scope") && info.tag != "th" {
1147
+ ctx.Report(info.opening, "The scope attribute is only valid on th elements.")
1148
+ }
1149
1149
  }
1150
1150
 
1151
1151
  type jsxA11yTabindexNoPositive struct{}
1152
1152
 
1153
1153
  func (jsxA11yTabindexNoPositive) Name() string { return "jsx-a11y/tabindex-no-positive" }
1154
1154
  func (jsxA11yTabindexNoPositive) Visits() []shimast.Kind {
1155
- return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1155
+ return []shimast.Kind{shimast.KindJsxElement, shimast.KindJsxSelfClosingElement}
1156
1156
  }
1157
1157
  func (jsxA11yTabindexNoPositive) Check(ctx *Context, node *shimast.Node) {
1158
- info := jsxElementFromNode(node)
1159
- if value, ok := jsxNumericAttr(info.attrs, "tabIndex", "tabindex"); ok && value > 0 {
1160
- ctx.Report(info.opening, "tabIndex must not be positive.")
1161
- }
1158
+ info := jsxElementFromNode(node)
1159
+ if value, ok := jsxNumericAttr(info.attrs, "tabIndex", "tabindex"); ok && value > 0 {
1160
+ ctx.Report(info.opening, "tabIndex must not be positive.")
1161
+ }
1162
1162
  }
1163
1163
 
1164
1164
  // jsxA11yAnchorAmbiguousText reports `<a>` elements whose visible text
@@ -1171,21 +1171,21 @@ type jsxA11yAnchorAmbiguousText struct{}
1171
1171
 
1172
1172
  func (jsxA11yAnchorAmbiguousText) Name() string { return "jsx-a11y/anchor-ambiguous-text" }
1173
1173
  func (jsxA11yAnchorAmbiguousText) Visits() []shimast.Kind {
1174
- return []shimast.Kind{shimast.KindJsxElement}
1174
+ return []shimast.Kind{shimast.KindJsxElement}
1175
1175
  }
1176
1176
  func (jsxA11yAnchorAmbiguousText) Check(ctx *Context, node *shimast.Node) {
1177
- info := jsxElementFromNode(node)
1178
- if info.tag != "a" {
1179
- return
1180
- }
1181
- text := strings.ToLower(strings.TrimSpace(jsxAnchorText(info.children)))
1182
- if text == "" {
1183
- return
1184
- }
1185
- switch text {
1186
- case "click here", "here", "link", "a link", "click", "more", "read more":
1187
- ctx.Report(info.opening, "Anchor text \""+text+"\" is too ambiguous out of context; describe the destination.")
1188
- }
1177
+ info := jsxElementFromNode(node)
1178
+ if info.tag != "a" {
1179
+ return
1180
+ }
1181
+ text := strings.ToLower(strings.TrimSpace(jsxAnchorText(info.children)))
1182
+ if text == "" {
1183
+ return
1184
+ }
1185
+ switch text {
1186
+ case "click here", "here", "link", "a link", "click", "more", "read more":
1187
+ ctx.Report(info.opening, "Anchor text \""+text+"\" is too ambiguous out of context; describe the destination.")
1188
+ }
1189
1189
  }
1190
1190
 
1191
1191
  // jsxAnchorText concatenates the visible text content of a JSX
@@ -1194,71 +1194,71 @@ func (jsxA11yAnchorAmbiguousText) Check(ctx *Context, node *shimast.Node) {
1194
1194
  // text; other expression shapes are skipped because their runtime value
1195
1195
  // is not known at lint time.
1196
1196
  func jsxAnchorText(children *shimast.NodeList) string {
1197
- if children == nil {
1198
- return ""
1199
- }
1200
- var b strings.Builder
1201
- for _, child := range children.Nodes {
1202
- if child == nil {
1203
- continue
1204
- }
1205
- switch child.Kind {
1206
- case shimast.KindJsxText:
1207
- t := child.AsJsxText()
1208
- if t != nil && !t.ContainsOnlyTriviaWhiteSpaces {
1209
- b.WriteString(t.Text)
1210
- }
1211
- case shimast.KindJsxExpression:
1212
- expr := child.AsJsxExpression()
1213
- if expr != nil && expr.Expression != nil {
1214
- if s := stringLiteralText(expr.Expression); s != "" {
1215
- b.WriteString(s)
1216
- }
1217
- }
1218
- case shimast.KindJsxElement:
1219
- inner := jsxElementFromNode(child)
1220
- b.WriteString(jsxAnchorText(inner.children))
1221
- }
1222
- }
1223
- return b.String()
1197
+ if children == nil {
1198
+ return ""
1199
+ }
1200
+ var b strings.Builder
1201
+ for _, child := range children.Nodes {
1202
+ if child == nil {
1203
+ continue
1204
+ }
1205
+ switch child.Kind {
1206
+ case shimast.KindJsxText:
1207
+ t := child.AsJsxText()
1208
+ if t != nil && !t.ContainsOnlyTriviaWhiteSpaces {
1209
+ b.WriteString(t.Text)
1210
+ }
1211
+ case shimast.KindJsxExpression:
1212
+ expr := child.AsJsxExpression()
1213
+ if expr != nil && expr.Expression != nil {
1214
+ if s := stringLiteralText(expr.Expression); s != "" {
1215
+ b.WriteString(s)
1216
+ }
1217
+ }
1218
+ case shimast.KindJsxElement:
1219
+ inner := jsxElementFromNode(child)
1220
+ b.WriteString(jsxAnchorText(inner.children))
1221
+ }
1222
+ }
1223
+ return b.String()
1224
1224
  }
1225
1225
 
1226
1226
  func init() {
1227
- Register(jsxA11yAltText{})
1228
- Register(jsxA11yAnchorAmbiguousText{})
1229
- Register(jsxA11yAnchorHasContent{})
1230
- Register(jsxA11yAnchorIsValid{})
1231
- Register(jsxA11yAriaActivedescendantHasTabindex{})
1232
- Register(jsxA11yAriaProps{})
1233
- Register(jsxA11yAriaProptypes{})
1234
- Register(jsxA11yAriaRole{})
1235
- Register(jsxA11yAriaUnsupportedElements{})
1236
- Register(jsxA11yAutocompleteValid{})
1237
- Register(jsxA11yClickEventsHaveKeyEvents{})
1238
- Register(jsxA11yControlHasAssociatedLabel{})
1239
- Register(jsxA11yHeadingHasContent{})
1240
- Register(jsxA11yHtmlHasLang{})
1241
- Register(jsxA11yIframeHasTitle{})
1242
- Register(jsxA11yImgRedundantAlt{})
1243
- Register(jsxA11yInteractiveSupportsFocus{})
1244
- Register(jsxA11yLabelHasAssociatedControl{})
1245
- Register(jsxA11yLabelHasFor{})
1246
- Register(jsxA11yLang{})
1247
- Register(jsxA11yMediaHasCaption{})
1248
- Register(jsxA11yMouseEventsHaveKeyEvents{})
1249
- Register(jsxA11yNoAccessKey{})
1250
- Register(jsxA11yNoAriaHiddenOnFocusable{})
1251
- Register(jsxA11yNoAutofocus{})
1252
- Register(jsxA11yNoDistractingElements{})
1253
- Register(jsxA11yNoInteractiveElementToNoninteractiveRole{})
1254
- Register(jsxA11yNoNoninteractiveElementInteractions{})
1255
- Register(jsxA11yNoNoninteractiveElementToInteractiveRole{})
1256
- Register(jsxA11yNoNoninteractiveTabindex{})
1257
- Register(jsxA11yNoRedundantRoles{})
1258
- Register(jsxA11yNoStaticElementInteractions{})
1259
- Register(jsxA11yPreferTagOverRole{})
1260
- Register(jsxA11yRoleHasRequiredAriaProps{})
1261
- Register(jsxA11yRoleSupportsAriaProps{})
1262
- Register(jsxA11yScope{})
1263
- Register(jsxA11yTabindexNoPositive{})
1227
+ Register(jsxA11yAltText{})
1228
+ Register(jsxA11yAnchorAmbiguousText{})
1229
+ Register(jsxA11yAnchorHasContent{})
1230
+ Register(jsxA11yAnchorIsValid{})
1231
+ Register(jsxA11yAriaActivedescendantHasTabindex{})
1232
+ Register(jsxA11yAriaProps{})
1233
+ Register(jsxA11yAriaProptypes{})
1234
+ Register(jsxA11yAriaRole{})
1235
+ Register(jsxA11yAriaUnsupportedElements{})
1236
+ Register(jsxA11yAutocompleteValid{})
1237
+ Register(jsxA11yClickEventsHaveKeyEvents{})
1238
+ Register(jsxA11yControlHasAssociatedLabel{})
1239
+ Register(jsxA11yHeadingHasContent{})
1240
+ Register(jsxA11yHtmlHasLang{})
1241
+ Register(jsxA11yIframeHasTitle{})
1242
+ Register(jsxA11yImgRedundantAlt{})
1243
+ Register(jsxA11yInteractiveSupportsFocus{})
1244
+ Register(jsxA11yLabelHasAssociatedControl{})
1245
+ Register(jsxA11yLabelHasFor{})
1246
+ Register(jsxA11yLang{})
1247
+ Register(jsxA11yMediaHasCaption{})
1248
+ Register(jsxA11yMouseEventsHaveKeyEvents{})
1249
+ Register(jsxA11yNoAccessKey{})
1250
+ Register(jsxA11yNoAriaHiddenOnFocusable{})
1251
+ Register(jsxA11yNoAutofocus{})
1252
+ Register(jsxA11yNoDistractingElements{})
1253
+ Register(jsxA11yNoInteractiveElementToNoninteractiveRole{})
1254
+ Register(jsxA11yNoNoninteractiveElementInteractions{})
1255
+ Register(jsxA11yNoNoninteractiveElementToInteractiveRole{})
1256
+ Register(jsxA11yNoNoninteractiveTabindex{})
1257
+ Register(jsxA11yNoRedundantRoles{})
1258
+ Register(jsxA11yNoStaticElementInteractions{})
1259
+ Register(jsxA11yPreferTagOverRole{})
1260
+ Register(jsxA11yRoleHasRequiredAriaProps{})
1261
+ Register(jsxA11yRoleSupportsAriaProps{})
1262
+ Register(jsxA11yScope{})
1263
+ Register(jsxA11yTabindexNoPositive{})
1264
1264
  }