erblint-github 0.0.9 → 0.1.2
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.
- 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
|