erblint-github 0.0.6 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 310138254b0989437e8cf803d52cba66ad005d7cae43b8b6233e638a20e40868
4
- data.tar.gz: 654d731eb0c99317883327dd401726582d7df70995350d0006b365fe1b9670b6
3
+ metadata.gz: cfd39a72bcefe35b0231242045b4aca7cfdf6468b795d2703528655039b9e7be
4
+ data.tar.gz: 4331758cf201fe621f5510554766a6d300f46b43ef36d272e82f53d2ffaf420d
5
5
  SHA512:
6
- metadata.gz: ce1a90a1c2482b29b406787a1c530614718242de1b9fac828617c2f476db00578872bcddf52037bf8195c71beb8750916e853b5127f4de036aea5771a8edbe2b
7
- data.tar.gz: 2a1e8844fdae5d352a6798937629e4ae70bea7d3a16c00e1a6de363dcc805044164b55e5166d9ffaf6f288bbdb135c373c2f1b1b40d27ecb0705c2cb616a833c
6
+ metadata.gz: ea54a4d64005d7be039a3f9ed620447ca673db7113e821f303cce4c35da74835c6f124afa84f3b7e8eb35e2adb278394aef1f6326a10f73ebfb3a9a342c956a1
7
+ data.tar.gz: 942f3526203855f2a58c37f54b5d2775cc0de910a0adf057889dba2c4e60a1553276b640c7ba6c8fd6ed91d3b3af597ab86c0aa49e84f49ed47005feafcec59a
data/README.md CHANGED
@@ -25,6 +25,8 @@ require "erblint-github/linters"
25
25
  linters:
26
26
  GitHub::Accessibility::AvoidBothDisabledAndAriaDisabled:
27
27
  enabled: true
28
+ GitHub::Accessibility::AvoidGenericLinkTextCounter:
29
+ enabled: true
28
30
  GitHub::Accessibility::IframeHasTitle:
29
31
  enabled: true
30
32
  GitHub::Accessibility::ImageHasAlt:
@@ -56,3 +58,12 @@ linters:
56
58
  bundle install
57
59
  bundle exec rake
58
60
  ```
61
+
62
+ ## Recommended extension
63
+
64
+ If you use VS Code, we highly encourage [ERB Linter extension](https://marketplace.visualstudio.com/items?itemName=manuelpuyol.erb-linter) to see immediate feedback in your editor.
65
+
66
+ ## Note
67
+
68
+ This repo contains several accessibility-related linting rules to help surface accessibility issues that would otherwise go undetected until a later stage. Please note that due to the limitations of static code analysis,
69
+ these ERB accessibility checks are NOT enough for ensuring the accessibility of your app. This shouldn't be the only tool you use to catch accessibility issues and should be supplemented with other tools that can check the runtime browser DOM output, as well as processes like accessibility design reviews, manual audits, user testing, etc.
@@ -18,6 +18,8 @@ module ERBLint
18
18
  "Link",
19
19
  "Here"
20
20
  ].freeze
21
+ ARIA_LABEL_ATTRIBUTES = %w[aria-labelledby aria-label].freeze
22
+
21
23
  MESSAGE = "Avoid using generic link text such as #{BANNED_GENERIC_TEXT.join(', ')} which do not make sense in isolation."
22
24
 
23
25
  def run(processed_source)
@@ -25,6 +27,7 @@ module ERBLint
25
27
  next unless node.methods.include?(:type) && node.type == :text
26
28
 
27
29
  text = node.children.join.strip
30
+
28
31
  # Checks HTML tags
29
32
  if banned_text?(text)
30
33
  prev_node = processed_source.ast.children[index - 1]
@@ -36,8 +39,17 @@ module ERBLint
36
39
  prev_node_tag = BetterHtml::Tree::Tag.from_node(prev_node)
37
40
  next_node_tag = BetterHtml::Tree::Tag.from_node(next_node)
38
41
 
39
- # We only report if the text is nested between two link tags.
42
+ aria_label = possible_attribute_values(prev_node_tag, "aria-label")
43
+ aria_labelledby = possible_attribute_values(prev_node_tag, "aria-labelledby")
44
+
45
+ # Checks if nested between two link tags.
40
46
  if link_tag?(prev_node_tag) && link_tag?(next_node_tag) && next_node_tag.closing?
47
+ # Skip because we cannot reliably check accessible name from aria-labelledby, or an aria-label that is set to a variable
48
+ # with static code analysis.
49
+ next if aria_labelledby.present? || (aria_label.present? && aria_label.join.include?("<%="))
50
+ # Skip because aria-label starts with visible text which we allow. Related to Success Criterion 2.5.3: Label in Name
51
+ next if aria_label.present? && valid_accessible_name?(aria_label.join, text)
52
+
41
53
  range = prev_node_tag.loc.begin_pos...text_node_tag.loc.end_pos
42
54
  source_range = processed_source.to_source_range(range)
43
55
  generate_offense_from_source_range(self.class, source_range)
@@ -45,20 +57,40 @@ module ERBLint
45
57
  end
46
58
 
47
59
  # Checks Rails link helpers like `link_to`
48
- erb_node = node.type == :erb ? node : node.descendants(:erb).first
49
- next unless erb_node
50
-
51
- _, _, code_node = *erb_node
52
- source = code_node.loc.source
53
- ruby_node = extract_ruby_node(source)
54
- send_node = ruby_node&.descendants(:send)&.first
55
- next unless send_node.methods.include?(:method_name) && send_node.method_name == :link_to
56
-
57
- send_node.child_nodes.each do |child_node|
58
- if child_node.methods.include?(:type) && child_node.type == :str && banned_text?(child_node.children.join)
60
+ node.descendants(:erb).each do |erb_node|
61
+ _, _, code_node = *erb_node
62
+ source = code_node.loc.source
63
+ ruby_node = extract_ruby_node(source)
64
+ send_node = ruby_node&.descendants(:send)&.first
65
+ next unless send_node.methods.include?(:method_name) && send_node.method_name == :link_to
66
+
67
+ banned_text = nil
68
+
69
+ send_node.child_nodes.each do |child_node|
70
+ banned_text = child_node.children.join if child_node.methods.include?(:type) && child_node.type == :str && banned_text?(child_node.children.join)
71
+ next if banned_text.blank?
72
+ next unless child_node.methods.include?(:type) && child_node.type == :hash
73
+
74
+ child_node.descendants(:pair).each do |pair_node|
75
+ next unless pair_node.children.first.type?(:sym)
76
+
77
+ # Skips if `link_to` has `aria-labelledby` or `aria-label` which cannot be evaluated accurately with ERB lint alone.
78
+ # ERB lint removes Ruby string interpolation so the `aria-label` for "<%= link_to 'Learn more', "aria-label": "Learn #{@some_variable}" %>" will
79
+ # only be `Learn` which is unreliable so we can't do checks :(
80
+ key_value = pair_node.children.first.children.join
81
+ banned_text = nil if ARIA_LABEL_ATTRIBUTES.include?(key_value)
82
+ next unless key_value == "aria"
83
+
84
+ pair_node.children[1].descendants(:sym).each do |sym_node|
85
+ banned_text = nil if sym_node.children.join == "label" || sym_node.children.join == "labelledby"
86
+ end
87
+ end
88
+ end
89
+ if banned_text.present?
59
90
  tag = BetterHtml::Tree::Tag.from_node(code_node)
60
91
  generate_offense(self.class, processed_source, tag)
61
- end
92
+ end
93
+ banned_text = nil
62
94
  end
63
95
  end
64
96
  counter_correct?(processed_source)
@@ -80,8 +112,17 @@ module ERBLint
80
112
 
81
113
  private
82
114
 
115
+ # Downcase and strip punctuation and extra whitespaces.
116
+ def stripped_text(text)
117
+ text.downcase.gsub(/\W+/, " ").strip
118
+ end
119
+
83
120
  def banned_text?(text)
84
- BANNED_GENERIC_TEXT.map(&:downcase).include?(text.downcase)
121
+ BANNED_GENERIC_TEXT.map(&:downcase).include?(stripped_text(text))
122
+ end
123
+
124
+ def valid_accessible_name?(aria_label, text)
125
+ stripped_text(aria_label).include?(stripped_text(text))
85
126
  end
86
127
 
87
128
  def extract_ruby_node(source)
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.0.6
4
+ version: 0.0.9
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-06-15 00:00:00.000000000 Z
11
+ date: 2022-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erb_lint