erblint-github 0.0.9 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +53 -10
- data/lib/erblint-github/linters/github/accessibility/{avoid_both_disabled_and_aria_disabled.rb → avoid_both_disabled_and_aria_disabled_counter.rb} +16 -2
- data/lib/erblint-github/linters/github/accessibility/disabled_attribute_counter.rb +45 -0
- data/lib/erblint-github/linters/github/accessibility/{iframe_has_title.rb → iframe_has_title_counter.rb} +16 -2
- data/lib/erblint-github/linters/github/accessibility/{image_has_alt.rb → image_has_alt_counter.rb} +16 -2
- data/lib/erblint-github/linters/github/accessibility/landmark_has_label_counter.rb +75 -0
- data/lib/erblint-github/linters/github/accessibility/link_has_href_counter.rb +45 -0
- data/lib/erblint-github/linters/github/accessibility/nested_interactive_elements_counter.rb +55 -0
- data/lib/erblint-github/linters/github/accessibility/{no_positive_tab_index.rb → no_positive_tab_index_counter.rb} +16 -2
- data/lib/erblint-github/linters/github/accessibility/{no_redundant_image_alt.rb → no_redundant_image_alt_counter.rb} +16 -2
- data/lib/erblint-github/linters/github/accessibility/svg_has_accessible_text_counter.rb +60 -0
- metadata +13 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3e42bd7e46e4628deda31d1657890c3ccc9e683d85943f2540629d36962b114
|
4
|
+
data.tar.gz: '099d8957fbc44e9739296d60c6f4436d7cf96ad0731bf69aca6edd5663acf98f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e41f3c103e9b0c57cd9706706605d26e25aafdae1359d0d123d6dd05b32904a91e0609fcf42d0551bf871d904610c2e38b65e47b2cb10637424426714902394c
|
7
|
+
data.tar.gz: 6969aff49edec2d4f9d6768eb94d20c5ffc24b01495ea9ad68d134900a1351b7c7a5afcb5896c6b14da3212e36c1bf29c1a308c8fd5215a4bb055e9d303cdcc2
|
data/README.md
CHANGED
@@ -23,34 +23,77 @@ require "erblint-github/linters"
|
|
23
23
|
```yaml
|
24
24
|
---
|
25
25
|
linters:
|
26
|
-
GitHub::Accessibility::
|
26
|
+
GitHub::Accessibility::AvoidBothDisabledAndAriaDisabledCounter:
|
27
27
|
enabled: true
|
28
28
|
GitHub::Accessibility::AvoidGenericLinkTextCounter:
|
29
29
|
enabled: true
|
30
|
-
GitHub::Accessibility::
|
30
|
+
GitHub::Accessibility::DisabledAttributeCounter:
|
31
31
|
enabled: true
|
32
|
-
GitHub::Accessibility::
|
32
|
+
GitHub::Accessibility::IframeHasTitleCounter:
|
33
|
+
enabled: true
|
34
|
+
GitHub::Accessibility::ImageHasAltCounter:
|
35
|
+
enabled: true
|
36
|
+
GitHub::Accessibility::LandmarkHasLabelCounter:
|
37
|
+
enabled: true
|
38
|
+
GitHub::Accessibility::LinkHasHrefCounter:
|
39
|
+
enabled: true
|
40
|
+
GitHub::Accessibility::NestedInteractiveElementsCounter:
|
33
41
|
enabled: true
|
34
42
|
GitHub::Accessibility::NoAriaLabelMisuseCounter:
|
35
43
|
enabled: true
|
36
|
-
GitHub::Accessibility::
|
44
|
+
GitHub::Accessibility::NoPositiveTabIndexCounter:
|
37
45
|
enabled: true
|
38
|
-
GitHub::Accessibility::
|
46
|
+
GitHub::Accessibility::NoRedundantImageAltCounter:
|
39
47
|
enabled: true
|
40
48
|
GitHub::Accessibility::NoTitleAttributeCounter:
|
41
49
|
enabled: true
|
50
|
+
GitHub::Accessibility::SvgHasAccessibleTextCounter:
|
51
|
+
enabled: true
|
42
52
|
```
|
43
53
|
|
44
54
|
## Rules
|
45
55
|
|
46
|
-
- [GitHub::Accessibility::
|
56
|
+
- [GitHub::Accessibility::AvoidBothDisabledAndAriaDisabledCounter](./docs/rules/accessibility/avoid-both-disabled-and-aria-disabled-counter.md)
|
47
57
|
- [GitHub::Accessibility::AvoidGenericLinkTextCounter](./docs/rules/accessibility/avoid-generic-link-text-counter.md)
|
48
|
-
- [GitHub::Accessibility::
|
49
|
-
- [GitHub::Accessibility::
|
58
|
+
- [GitHub::Accessibility::DisabledAttributeCounter](./docs/rules/accessibility/disabled-attribute-counter.md)
|
59
|
+
- [GitHub::Accessibility::LandmarkHasLabelCounter](./docs/rules/accessibility/landmark-has-label-counter.md)
|
60
|
+
- [GitHub::Accessibility::LinkHasHrefCounter](./docs/rules/accessibility/link-has-href-counter.md)
|
61
|
+
- [GitHub::Accessibility::NestedInteractiveElementsCounter](./docs/rules/accessibility/nested-interactive-elements-counter.md)
|
62
|
+
- [GitHub::Accessibility::IframeHasTitleCounter](./docs/rules/accessibility/iframe-has-title-counter.md)
|
63
|
+
- [GitHub::Accessibility::ImageHasAltCounter](./docs/rules/accessibility/image-has-alt-counter.md)
|
50
64
|
- [GitHub::Accessibility::NoAriaLabelMisuseCounter](./docs/rules/accessibility/no-aria-label-misuse-counter.md)
|
51
|
-
- [GitHub::Accessibility::
|
52
|
-
- [GitHub::Accessibility::
|
65
|
+
- [GitHub::Accessibility::NoPositiveTabIndexCounter](./docs/rules/accessibility/no-positive-tab-index-counter.md)
|
66
|
+
- [GitHub::Accessibility::NoRedundantImageAltCounter](./docs/rules/accessibility/no-redundant-image-alt-counter.md)
|
53
67
|
- [GitHub::Accessibility::NoTitleAttributeCounter](./docs/rules/accessibility/no-title-attribute-counter.md)
|
68
|
+
- [GitHub::Accessibility::SvgHasAccessibleTextCounter](./docs/rules/accessibility/svg-has-accessible-text-counter.md)
|
69
|
+
|
70
|
+
## Disabling a rule (experimental)
|
71
|
+
|
72
|
+
_This is an experimental feature which should ideally be upstreamed to erblint_
|
73
|
+
|
74
|
+
`erblint` does not natively support rule disables. At GitHub, we've implemented these rules in a way to allow rules to be disabled at an offense-level via counters or disabled at a file-level because often times, we want to enable a rule but aren't able to address all offenses at once. We achieve this in one of two ways.
|
75
|
+
|
76
|
+
Rules that are marked as `Counter` can be disabled by adding a comment with the offense count that matches the number of offenses within the file like:
|
77
|
+
|
78
|
+
```.html.erb
|
79
|
+
<%# erblint:counter GitHub::Accessibility::LinkHasHrefCounter 1 %>
|
80
|
+
```
|
81
|
+
|
82
|
+
In this comment example, when a new `LinkHasHrefCounter` offense has been added, the counter will need to be bumped up to 2. More recent rules use a `Counter` format.
|
83
|
+
|
84
|
+
If you are enabling a rule for the first time and your codebase has a lot of offenses, you can use the `-a` command to automatically add these counter comments in the appropriate places.
|
85
|
+
|
86
|
+
```
|
87
|
+
bundle exec erblint app/views app/components -a
|
88
|
+
```
|
89
|
+
|
90
|
+
Rules that are not marked as `Counter` like `NoRedundantImageAlt` are considered to be legacy format. We are in the process of migrating these to counters. These rules can still be disabled at the file-level by adding this comment at the top of the file:
|
91
|
+
|
92
|
+
```.html.erb
|
93
|
+
<%# erblint:disable GitHub::Accessibility::NoRedundantImageAlt %>
|
94
|
+
```
|
95
|
+
|
96
|
+
However, unlike a counter, any subsequent offenses introduced to the file will not raise.
|
54
97
|
|
55
98
|
## Testing
|
56
99
|
|
@@ -6,7 +6,7 @@ module ERBLint
|
|
6
6
|
module Linters
|
7
7
|
module GitHub
|
8
8
|
module Accessibility
|
9
|
-
class
|
9
|
+
class AvoidBothDisabledAndAriaDisabledCounter < Linter
|
10
10
|
include ERBLint::Linters::CustomHelpers
|
11
11
|
include LinterRegistry
|
12
12
|
|
@@ -22,7 +22,21 @@ module ERBLint
|
|
22
22
|
generate_offense(self.class, processed_source, tag)
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
counter_correct?(processed_source)
|
26
|
+
end
|
27
|
+
|
28
|
+
def autocorrect(processed_source, offense)
|
29
|
+
return unless offense.context
|
30
|
+
|
31
|
+
lambda do |corrector|
|
32
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
33
|
+
# update the counter if exists
|
34
|
+
corrector.replace(offense.source_range, offense.context)
|
35
|
+
else
|
36
|
+
# add comment with counter if none
|
37
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
38
|
+
end
|
39
|
+
end
|
26
40
|
end
|
27
41
|
end
|
28
42
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../custom_helpers"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module GitHub
|
8
|
+
module Accessibility
|
9
|
+
class DisabledAttributeCounter < Linter
|
10
|
+
include ERBLint::Linters::CustomHelpers
|
11
|
+
include LinterRegistry
|
12
|
+
|
13
|
+
VALID_DISABLED_TAGS = %w[button input textarea option select fieldset optgroup task-lists].freeze
|
14
|
+
MESSAGE = "`disabled` is only valid on #{VALID_DISABLED_TAGS.join(', ')}."
|
15
|
+
|
16
|
+
def run(processed_source)
|
17
|
+
tags(processed_source).each do |tag|
|
18
|
+
next if tag.closing?
|
19
|
+
next if VALID_DISABLED_TAGS.include?(tag.name)
|
20
|
+
next if tag.attributes["disabled"].nil?
|
21
|
+
|
22
|
+
generate_offense(self.class, processed_source, tag)
|
23
|
+
end
|
24
|
+
|
25
|
+
counter_correct?(processed_source)
|
26
|
+
end
|
27
|
+
|
28
|
+
def autocorrect(processed_source, offense)
|
29
|
+
return unless offense.context
|
30
|
+
|
31
|
+
lambda do |corrector|
|
32
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
33
|
+
# update the counter if exists
|
34
|
+
corrector.replace(offense.source_range, offense.context)
|
35
|
+
else
|
36
|
+
# add comment with counter if none
|
37
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -6,7 +6,7 @@ module ERBLint
|
|
6
6
|
module Linters
|
7
7
|
module GitHub
|
8
8
|
module Accessibility
|
9
|
-
class
|
9
|
+
class IframeHasTitleCounter < Linter
|
10
10
|
include ERBLint::Linters::CustomHelpers
|
11
11
|
include LinterRegistry
|
12
12
|
|
@@ -23,7 +23,21 @@ module ERBLint
|
|
23
23
|
generate_offense(self.class, processed_source, tag) if title.empty? && !aria_hidden?(tag)
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
counter_correct?(processed_source)
|
27
|
+
end
|
28
|
+
|
29
|
+
def autocorrect(processed_source, offense)
|
30
|
+
return unless offense.context
|
31
|
+
|
32
|
+
lambda do |corrector|
|
33
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
34
|
+
# update the counter if exists
|
35
|
+
corrector.replace(offense.source_range, offense.context)
|
36
|
+
else
|
37
|
+
# add comment with counter if none
|
38
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
39
|
+
end
|
40
|
+
end
|
27
41
|
end
|
28
42
|
|
29
43
|
private
|
data/lib/erblint-github/linters/github/accessibility/{image_has_alt.rb → image_has_alt_counter.rb}
RENAMED
@@ -6,7 +6,7 @@ module ERBLint
|
|
6
6
|
module Linters
|
7
7
|
module GitHub
|
8
8
|
module Accessibility
|
9
|
-
class
|
9
|
+
class ImageHasAltCounter < Linter
|
10
10
|
include ERBLint::Linters::CustomHelpers
|
11
11
|
include LinterRegistry
|
12
12
|
|
@@ -22,7 +22,21 @@ module ERBLint
|
|
22
22
|
generate_offense(self.class, processed_source, tag) if alt.empty?
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
counter_correct?(processed_source)
|
26
|
+
end
|
27
|
+
|
28
|
+
def autocorrect(processed_source, offense)
|
29
|
+
return unless offense.context
|
30
|
+
|
31
|
+
lambda do |corrector|
|
32
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
33
|
+
# update the counter if exists
|
34
|
+
corrector.replace(offense.source_range, offense.context)
|
35
|
+
else
|
36
|
+
# add comment with counter if none
|
37
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
38
|
+
end
|
39
|
+
end
|
26
40
|
end
|
27
41
|
end
|
28
42
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../custom_helpers"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module GitHub
|
8
|
+
module Accessibility
|
9
|
+
class LandmarkHasLabelCounter < Linter
|
10
|
+
include ERBLint::Linters::CustomHelpers
|
11
|
+
include LinterRegistry
|
12
|
+
|
13
|
+
LANDMARK_ROLES = %w[complementary navigation region search].freeze
|
14
|
+
LANDMARK_TAGS = %w[aside nav section].freeze
|
15
|
+
MESSAGE = "Landmark elements should have an aria-label attribute, or aria-labelledby if a heading elements exists in the landmark."
|
16
|
+
ROLE_TAG_MAPPING = { "complementary" => "aside", "navigation" => "nav", "region" => "section" }.freeze
|
17
|
+
|
18
|
+
def get_additional_message(tag, roles)
|
19
|
+
role_matched = (roles & ROLE_TAG_MAPPING.keys).first
|
20
|
+
if role_matched
|
21
|
+
tag_matched = ROLE_TAG_MAPPING[role_matched]
|
22
|
+
|
23
|
+
if tag.name == tag_matched
|
24
|
+
"The <#{tag_matched}> element will automatically communicate a role of '#{role_matched}'. You can safely drop the role attribute."
|
25
|
+
else
|
26
|
+
replace_message = if tag.name == "div"
|
27
|
+
"If possible replace this tag with a <#{tag_matched}>."
|
28
|
+
else
|
29
|
+
"Wrapping this element in a <#{tag_matched}> and setting a label on it is reccomended."
|
30
|
+
end
|
31
|
+
|
32
|
+
"The <#{tag_matched}> element will automatically communicate a role of '#{role_matched}'. #{replace_message}"
|
33
|
+
end
|
34
|
+
elsif roles.include?("search") && tag.name != "form"
|
35
|
+
"The 'search' role works best when applied to a <form> element. If possible replace this tag with a <form>."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def run(processed_source)
|
40
|
+
tags(processed_source).each do |tag|
|
41
|
+
next if tag.closing?
|
42
|
+
|
43
|
+
possible_roles = possible_attribute_values(tag, "role")
|
44
|
+
next unless LANDMARK_TAGS.include?(tag.name) && (possible_roles & LANDMARK_ROLES).empty?
|
45
|
+
next if tag.attributes["aria-label"]&.value&.present? || tag.attributes["aria-labelledby"]&.value&.present?
|
46
|
+
|
47
|
+
message = get_additional_message(tag, possible_roles)
|
48
|
+
if message
|
49
|
+
generate_offense(self.class, processed_source, tag, "#{MESSAGE}\n#{message}")
|
50
|
+
else
|
51
|
+
generate_offense(self.class, processed_source, tag)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
counter_correct?(processed_source)
|
56
|
+
end
|
57
|
+
|
58
|
+
def autocorrect(processed_source, offense)
|
59
|
+
return unless offense.context
|
60
|
+
|
61
|
+
lambda do |corrector|
|
62
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
63
|
+
# update the counter if exists
|
64
|
+
corrector.replace(offense.source_range, offense.context)
|
65
|
+
else
|
66
|
+
# add comment with counter if none
|
67
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../custom_helpers"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module GitHub
|
8
|
+
module Accessibility
|
9
|
+
class LinkHasHrefCounter < Linter
|
10
|
+
include ERBLint::Linters::CustomHelpers
|
11
|
+
include LinterRegistry
|
12
|
+
|
13
|
+
MESSAGE = "Links should go somewhere, you probably want to use a `<button>` instead."
|
14
|
+
|
15
|
+
def run(processed_source)
|
16
|
+
tags(processed_source).each do |tag|
|
17
|
+
next if tag.name != "a"
|
18
|
+
next if tag.closing?
|
19
|
+
|
20
|
+
href = possible_attribute_values(tag, "href")
|
21
|
+
name = tag.attributes["name"]
|
22
|
+
generate_offense(self.class, processed_source, tag) if (!name && href.empty?) || href.include?("#")
|
23
|
+
end
|
24
|
+
|
25
|
+
counter_correct?(processed_source)
|
26
|
+
end
|
27
|
+
|
28
|
+
def autocorrect(processed_source, offense)
|
29
|
+
return unless offense.context
|
30
|
+
|
31
|
+
lambda do |corrector|
|
32
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
33
|
+
# update the counter if exists
|
34
|
+
corrector.replace(offense.source_range, offense.context)
|
35
|
+
else
|
36
|
+
# add comment with counter if none
|
37
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../custom_helpers"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module GitHub
|
8
|
+
module Accessibility
|
9
|
+
class NestedInteractiveElementsCounter < Linter
|
10
|
+
include ERBLint::Linters::CustomHelpers
|
11
|
+
include LinterRegistry
|
12
|
+
|
13
|
+
INTERACTIVE_ELEMENTS = %w[button summary input select textarea a].freeze
|
14
|
+
MESSAGE = "Nesting interactive elements produces invalid HTML, and ssistive technologies, such as screen readers, might ignore or respond unexpectedly to such nested controls."
|
15
|
+
|
16
|
+
def run(processed_source)
|
17
|
+
last_interactive_element = nil
|
18
|
+
tags(processed_source).each do |tag|
|
19
|
+
next unless INTERACTIVE_ELEMENTS.include?(tag.name)
|
20
|
+
|
21
|
+
last_interactive_element = nil if last_interactive_element && tag.name == last_interactive_element.name && tag.closing?
|
22
|
+
next if tag.closing?
|
23
|
+
|
24
|
+
if last_interactive_element
|
25
|
+
next if last_interactive_element.name == "summary" && tag.name == "a"
|
26
|
+
next if tag.name == "input" && tag.attributes["type"]&.value == "hidden"
|
27
|
+
|
28
|
+
message = "Found <#{tag.name}> nested inside of <#{last_interactive_element.name}>.\n" + MESSAGE
|
29
|
+
generate_offense(self.class, processed_source, tag, message)
|
30
|
+
end
|
31
|
+
|
32
|
+
last_interactive_element = tag unless tag&.name == "input"
|
33
|
+
end
|
34
|
+
|
35
|
+
counter_correct?(processed_source)
|
36
|
+
end
|
37
|
+
|
38
|
+
def autocorrect(processed_source, offense)
|
39
|
+
return unless offense.context
|
40
|
+
|
41
|
+
lambda do |corrector|
|
42
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
43
|
+
# update the counter if exists
|
44
|
+
corrector.replace(offense.source_range, offense.context)
|
45
|
+
else
|
46
|
+
# add comment with counter if none
|
47
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -6,7 +6,7 @@ module ERBLint
|
|
6
6
|
module Linters
|
7
7
|
module GitHub
|
8
8
|
module Accessibility
|
9
|
-
class
|
9
|
+
class NoPositiveTabIndexCounter < Linter
|
10
10
|
include ERBLint::Linters::CustomHelpers
|
11
11
|
include LinterRegistry
|
12
12
|
|
@@ -20,7 +20,21 @@ module ERBLint
|
|
20
20
|
generate_offense(self.class, processed_source, tag)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
counter_correct?(processed_source)
|
24
|
+
end
|
25
|
+
|
26
|
+
def autocorrect(processed_source, offense)
|
27
|
+
return unless offense.context
|
28
|
+
|
29
|
+
lambda do |corrector|
|
30
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
31
|
+
# update the counter if exists
|
32
|
+
corrector.replace(offense.source_range, offense.context)
|
33
|
+
else
|
34
|
+
# add comment with counter if none
|
35
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
36
|
+
end
|
37
|
+
end
|
24
38
|
end
|
25
39
|
end
|
26
40
|
end
|
@@ -6,7 +6,7 @@ module ERBLint
|
|
6
6
|
module Linters
|
7
7
|
module GitHub
|
8
8
|
module Accessibility
|
9
|
-
class
|
9
|
+
class NoRedundantImageAltCounter < Linter
|
10
10
|
include ERBLint::Linters::CustomHelpers
|
11
11
|
include LinterRegistry
|
12
12
|
|
@@ -24,7 +24,21 @@ module ERBLint
|
|
24
24
|
generate_offense(self.class, processed_source, tag) if (alt.downcase.split & REDUNDANT_ALT_WORDS).any?
|
25
25
|
end
|
26
26
|
|
27
|
-
|
27
|
+
counter_correct?(processed_source)
|
28
|
+
end
|
29
|
+
|
30
|
+
def autocorrect(processed_source, offense)
|
31
|
+
return unless offense.context
|
32
|
+
|
33
|
+
lambda do |corrector|
|
34
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
35
|
+
# update the counter if exists
|
36
|
+
corrector.replace(offense.source_range, offense.context)
|
37
|
+
else
|
38
|
+
# add comment with counter if none
|
39
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
40
|
+
end
|
41
|
+
end
|
28
42
|
end
|
29
43
|
end
|
30
44
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../custom_helpers"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module GitHub
|
8
|
+
module Accessibility
|
9
|
+
class SvgHasAccessibleTextCounter < Linter
|
10
|
+
include ERBLint::Linters::CustomHelpers
|
11
|
+
include LinterRegistry
|
12
|
+
|
13
|
+
MESSAGE = "`<svg>` must have accessible text. Set `aria-label`, or `aria-labelledby`, or nest a `<title>` element. However, if the `<svg>` is purely decorative, hide it with `aria-hidden='true'.\nFor more info, see https://css-tricks.com/accessible-svgs/."
|
14
|
+
|
15
|
+
def run(processed_source)
|
16
|
+
current_svg = nil
|
17
|
+
has_accessible_label = false
|
18
|
+
|
19
|
+
tags(processed_source).each do |tag|
|
20
|
+
# Checks whether tag is a <title> nested in an <svg>
|
21
|
+
has_accessible_label = true if current_svg && tag.name == "title" && !tag.closing?
|
22
|
+
|
23
|
+
next if tag.name != "svg"
|
24
|
+
|
25
|
+
if tag.closing?
|
26
|
+
generate_offense(self.class, processed_source, current_svg) unless has_accessible_label
|
27
|
+
current_svg = nil
|
28
|
+
elsif possible_attribute_values(tag, "aria-hidden").join == "true"
|
29
|
+
has_accessible_label = true
|
30
|
+
current_svg = tag
|
31
|
+
else
|
32
|
+
current_svg = tag
|
33
|
+
aria_label = possible_attribute_values(tag, "aria-label").join
|
34
|
+
aria_labelledby = possible_attribute_values(tag, "aria-labelledby").join
|
35
|
+
|
36
|
+
has_accessible_label = aria_label.present? || aria_labelledby.present?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
counter_correct?(processed_source)
|
41
|
+
end
|
42
|
+
|
43
|
+
def autocorrect(processed_source, offense)
|
44
|
+
return unless offense.context
|
45
|
+
|
46
|
+
lambda do |corrector|
|
47
|
+
if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
|
48
|
+
# update the counter if exists
|
49
|
+
corrector.replace(offense.source_range, offense.context)
|
50
|
+
else
|
51
|
+
# add comment with counter if none
|
52
|
+
corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erblint-github
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: erb_lint
|
@@ -105,14 +105,19 @@ files:
|
|
105
105
|
- README.md
|
106
106
|
- lib/erblint-github/linters.rb
|
107
107
|
- lib/erblint-github/linters/custom_helpers.rb
|
108
|
-
- lib/erblint-github/linters/github/accessibility/
|
108
|
+
- lib/erblint-github/linters/github/accessibility/avoid_both_disabled_and_aria_disabled_counter.rb
|
109
109
|
- lib/erblint-github/linters/github/accessibility/avoid_generic_link_text_counter.rb
|
110
|
-
- lib/erblint-github/linters/github/accessibility/
|
111
|
-
- lib/erblint-github/linters/github/accessibility/
|
110
|
+
- lib/erblint-github/linters/github/accessibility/disabled_attribute_counter.rb
|
111
|
+
- lib/erblint-github/linters/github/accessibility/iframe_has_title_counter.rb
|
112
|
+
- lib/erblint-github/linters/github/accessibility/image_has_alt_counter.rb
|
113
|
+
- lib/erblint-github/linters/github/accessibility/landmark_has_label_counter.rb
|
114
|
+
- lib/erblint-github/linters/github/accessibility/link_has_href_counter.rb
|
115
|
+
- lib/erblint-github/linters/github/accessibility/nested_interactive_elements_counter.rb
|
112
116
|
- lib/erblint-github/linters/github/accessibility/no_aria_label_misuse_counter.rb
|
113
|
-
- lib/erblint-github/linters/github/accessibility/
|
114
|
-
- lib/erblint-github/linters/github/accessibility/
|
117
|
+
- lib/erblint-github/linters/github/accessibility/no_positive_tab_index_counter.rb
|
118
|
+
- lib/erblint-github/linters/github/accessibility/no_redundant_image_alt_counter.rb
|
115
119
|
- lib/erblint-github/linters/github/accessibility/no_title_attribute_counter.rb
|
120
|
+
- lib/erblint-github/linters/github/accessibility/svg_has_accessible_text_counter.rb
|
116
121
|
- lib/tasks/docs.rake
|
117
122
|
- lib/tasks/tests.rake
|
118
123
|
homepage: https://github.com/github/erblint-github
|
@@ -135,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
140
|
- !ruby/object:Gem::Version
|
136
141
|
version: '0'
|
137
142
|
requirements: []
|
138
|
-
rubygems_version: 3.
|
143
|
+
rubygems_version: 3.3.10
|
139
144
|
signing_key:
|
140
145
|
specification_version: 4
|
141
146
|
summary: erblint GitHub
|