erblint-github 0.0.5 → 0.0.6

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: 48eba970607504df53f6b0f2ce5cff3b07051148eb1f4dca2fd78fa8287671a9
4
- data.tar.gz: 820da77f5a3ad624c32f4de22817e1c3d80ed755ddbe717368ef97e17e87e262
3
+ metadata.gz: 310138254b0989437e8cf803d52cba66ad005d7cae43b8b6233e638a20e40868
4
+ data.tar.gz: 654d731eb0c99317883327dd401726582d7df70995350d0006b365fe1b9670b6
5
5
  SHA512:
6
- metadata.gz: 34b69cd67df4ea14698098a1331bd787cc9c653cb616f8020c0767478427a41144d177706397eaedc7f7f3767b60758231a000ab45d3fef2dcd8ee07249b49ad
7
- data.tar.gz: d34ed13a0a85b146f4b2eff4e6fcbe00bbe7aef41d7168c6dadb2cc78a3fd49b42cc5dc92e6669cffb7b9bb81cf982495862fb46acb166a49dd63c9813d31d60
6
+ metadata.gz: ce1a90a1c2482b29b406787a1c530614718242de1b9fac828617c2f476db00578872bcddf52037bf8195c71beb8750916e853b5127f4de036aea5771a8edbe2b
7
+ data.tar.gz: 2a1e8844fdae5d352a6798937629e4ae70bea7d3a16c00e1a6de363dcc805044164b55e5166d9ffaf6f288bbdb135c373c2f1b1b40d27ecb0705c2cb616a833c
data/README.md CHANGED
@@ -42,6 +42,7 @@ linters:
42
42
  ## Rules
43
43
 
44
44
  - [GitHub::Accessibility::AvoidBothDisabledAndAriaDisabled](./docs/rules/accessibility/avoid-both-disabled-and-aria-disabled.md)
45
+ - [GitHub::Accessibility::AvoidGenericLinkTextCounter](./docs/rules/accessibility/avoid-generic-link-text-counter.md)
45
46
  - [GitHub::Accessibility::IframeHasTitle](./docs/rules/accessibility/iframe-has-title.md)
46
47
  - [GitHub::Accessibility::ImageHasAlt](./docs/rules/accessibility/image-has-alt.md)
47
48
  - [GitHub::Accessibility::NoAriaLabelMisuseCounter](./docs/rules/accessibility/no-aria-label-misuse-counter.md)
@@ -64,6 +64,13 @@ module ERBLint
64
64
  add_offense(processed_source.to_source_range(tag.loc), offense, replacement)
65
65
  end
66
66
 
67
+ def generate_offense_from_source_range(klass, source_range, message = nil, replacement = nil)
68
+ message ||= klass::MESSAGE
69
+ message += "\nLearn more at https://github.com/github/erblint-github#rules.\n"
70
+ offense = ["#{simple_class_name}:#{message}", source_range.source].join("\n")
71
+ add_offense(source_range, offense, replacement)
72
+ end
73
+
67
74
  def possible_attribute_values(tag, attr_name)
68
75
  value = tag.attributes[attr_name]&.value || nil
69
76
  basic_conditional_code_check(value || "") || [value].compact
@@ -0,0 +1,104 @@
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 AvoidGenericLinkTextCounter < Linter
10
+ include ERBLint::Linters::CustomHelpers
11
+ include LinterRegistry
12
+
13
+ BANNED_GENERIC_TEXT = [
14
+ "Read more",
15
+ "Learn more",
16
+ "Click here",
17
+ "More",
18
+ "Link",
19
+ "Here"
20
+ ].freeze
21
+ MESSAGE = "Avoid using generic link text such as #{BANNED_GENERIC_TEXT.join(', ')} which do not make sense in isolation."
22
+
23
+ def run(processed_source)
24
+ processed_source.ast.children.each_with_index do |node, index|
25
+ next unless node.methods.include?(:type) && node.type == :text
26
+
27
+ text = node.children.join.strip
28
+ # Checks HTML tags
29
+ if banned_text?(text)
30
+ prev_node = processed_source.ast.children[index - 1]
31
+ next_node = processed_source.ast.children[index + 1]
32
+
33
+ next unless tag_type?(prev_node) && tag_type?(next_node)
34
+
35
+ text_node_tag = BetterHtml::Tree::Tag.from_node(node)
36
+ prev_node_tag = BetterHtml::Tree::Tag.from_node(prev_node)
37
+ next_node_tag = BetterHtml::Tree::Tag.from_node(next_node)
38
+
39
+ # We only report if the text is nested between two link tags.
40
+ if link_tag?(prev_node_tag) && link_tag?(next_node_tag) && next_node_tag.closing?
41
+ range = prev_node_tag.loc.begin_pos...text_node_tag.loc.end_pos
42
+ source_range = processed_source.to_source_range(range)
43
+ generate_offense_from_source_range(self.class, source_range)
44
+ end
45
+ end
46
+
47
+ # 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)
59
+ tag = BetterHtml::Tree::Tag.from_node(code_node)
60
+ generate_offense(self.class, processed_source, tag)
61
+ end
62
+ end
63
+ end
64
+ counter_correct?(processed_source)
65
+ end
66
+
67
+ def autocorrect(processed_source, offense)
68
+ return unless offense.context
69
+
70
+ lambda do |corrector|
71
+ if processed_source.file_content.include?("erblint:counter #{simple_class_name}")
72
+ # update the counter if exists
73
+ corrector.replace(offense.source_range, offense.context)
74
+ else
75
+ # add comment with counter if none
76
+ corrector.insert_before(processed_source.source_buffer.source_range, "#{offense.context}\n")
77
+ end
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def banned_text?(text)
84
+ BANNED_GENERIC_TEXT.map(&:downcase).include?(text.downcase)
85
+ end
86
+
87
+ def extract_ruby_node(source)
88
+ BetterHtml::TestHelper::RubyNode.parse(source)
89
+ rescue ::Parser::SyntaxError
90
+ nil
91
+ end
92
+
93
+ def link_tag?(tag_node)
94
+ tag_node.name == "a"
95
+ end
96
+
97
+ def tag_type?(node)
98
+ node.methods.include?(:type) && node.type == :tag
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -10,8 +10,8 @@ module ERBLint
10
10
  include ERBLint::Linters::CustomHelpers
11
11
  include LinterRegistry
12
12
 
13
- MESSAGE = "<iframe> with meaningful content should have a title attribute that identifies the content."\
14
- " If <iframe> has no meaningful content, hide it from assistive technology with `aria-hidden='true'`."\
13
+ MESSAGE = "`<iframe>` with meaningful content should have a title attribute that identifies the content."\
14
+ " If `<iframe>` has no meaningful content, hide it from assistive technology with `aria-hidden='true'`."\
15
15
 
16
16
  def run(processed_source)
17
17
  tags(processed_source).each do |tag|
data/lib/tasks/docs.rake CHANGED
@@ -4,10 +4,9 @@ namespace :docs do
4
4
  task :coverage do
5
5
  require "erb_lint/all"
6
6
  require "erblint-github/linters"
7
-
8
- Dir[File.join(__dir__, "linters", "github/**/*.rb")].sort.each do |file|
7
+ Dir[File.join("lib", "erblint-github", "linters", "github/**/*.rb")].sort.each do |file|
9
8
  rule_documentation_path = file
10
- .gsub("#{__dir__}linters/github/", "docs/rules/")
9
+ .gsub("lib/erblint-github/linters/github/", "docs/rules/")
11
10
  .gsub(".rb", ".md")
12
11
  .tr("_", "-")
13
12
  raise "Missing rule documentation. Please document rule in #{rule_documentation_path}" unless File.file?(rule_documentation_path.to_s)
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :tests do
4
+ task :coverage do
5
+ require "erb_lint/all"
6
+ require "erblint-github/linters"
7
+
8
+ Dir[File.join("lib", "erblint-github", "linters", "github/**/*.rb")].sort.each do |file|
9
+ test_path = file.gsub("lib/erblint-github/linters/github/", "test/linters/").gsub(".rb", "_test.rb")
10
+ raise "Missing test. Please add test in #{test_path}" unless File.file?(test_path.to_s)
11
+ end
12
+ puts "All rules have test coverage."
13
+ end
14
+ 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.0.5
4
+ version: 0.0.6
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-02-23 00:00:00.000000000 Z
11
+ date: 2022-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erb_lint
@@ -16,84 +16,84 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.1'
19
+ version: 0.1.1
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.1'
26
+ version: 0.1.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '5.14'
33
+ version: '5.15'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '5.14'
40
+ version: '5.15'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mocha
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1'
47
+ version: '1.14'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1'
54
+ version: '1.14'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '12.0'
61
+ version: 13.0.6
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '12.0'
68
+ version: 13.0.6
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 1.13.0
75
+ version: 1.30.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 1.13.0
82
+ version: 1.30.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rubocop-github
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.16.0
89
+ version: 0.17.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.16.0
96
+ version: 0.17.0
97
97
  description: Template style checking for GitHub Ruby repositories
98
98
  email:
99
99
  - opensource+erblint-github@github.com
@@ -106,6 +106,7 @@ files:
106
106
  - lib/erblint-github/linters.rb
107
107
  - lib/erblint-github/linters/custom_helpers.rb
108
108
  - lib/erblint-github/linters/github/accessibility/avoid_both_disabled_and_aria_disabled.rb
109
+ - lib/erblint-github/linters/github/accessibility/avoid_generic_link_text_counter.rb
109
110
  - lib/erblint-github/linters/github/accessibility/iframe_has_title.rb
110
111
  - lib/erblint-github/linters/github/accessibility/image_has_alt.rb
111
112
  - lib/erblint-github/linters/github/accessibility/no_aria_label_misuse_counter.rb
@@ -113,10 +114,12 @@ files:
113
114
  - lib/erblint-github/linters/github/accessibility/no_redundant_image_alt.rb
114
115
  - lib/erblint-github/linters/github/accessibility/no_title_attribute_counter.rb
115
116
  - lib/tasks/docs.rake
117
+ - lib/tasks/tests.rake
116
118
  homepage: https://github.com/github/erblint-github
117
119
  licenses:
118
120
  - MIT
119
- metadata: {}
121
+ metadata:
122
+ rubygems_mfa_required: 'true'
120
123
  post_install_message:
121
124
  rdoc_options: []
122
125
  require_paths:
@@ -125,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
128
  requirements:
126
129
  - - ">="
127
130
  - !ruby/object:Gem::Version
128
- version: 2.5.0
131
+ version: 2.6.0
129
132
  required_rubygems_version: !ruby/object:Gem::Requirement
130
133
  requirements:
131
134
  - - ">="