primer_view_components 0.0.49 → 0.0.53
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/CHANGELOG.md +158 -0
- data/app/components/primer/base_component.rb +2 -2
- data/app/components/primer/beta/avatar_stack.rb +9 -9
- data/app/components/primer/beta/truncate.html.erb +5 -0
- data/app/components/primer/beta/truncate.rb +110 -0
- data/app/components/primer/border_box_component.rb +27 -1
- data/app/components/primer/clipboard_copy.html.erb +2 -2
- data/app/components/primer/clipboard_copy.rb +1 -1
- data/app/components/primer/dropdown.rb +7 -7
- data/app/components/primer/icon_button.rb +1 -1
- data/app/components/primer/label_component.rb +13 -12
- data/app/components/primer/navigation/tab_component.rb +1 -1
- data/app/components/primer/progress_bar_component.rb +0 -3
- data/app/components/primer/tab_nav_component.rb +1 -1
- data/app/lib/primer/fetch_or_fallback_helper.rb +2 -0
- data/app/lib/primer/octicon/cache.rb +1 -1
- data/app/lib/primer/tabbed_component_helper.rb +1 -1
- data/app/lib/primer/view_helper.rb +1 -0
- data/lib/primer/classify/cache.rb +0 -5
- data/lib/primer/classify/flex.rb +1 -1
- data/lib/primer/classify/functional_colors.rb +1 -1
- data/lib/primer/classify/utilities.rb +19 -2
- data/lib/primer/classify/utilities.yml +16 -0
- data/lib/primer/classify/validation.rb +18 -0
- data/lib/primer/classify.rb +4 -18
- data/lib/primer/view_components/constants.rb +1 -1
- data/lib/primer/view_components/linters/argument_mappers/base.rb +63 -2
- data/lib/primer/view_components/linters/argument_mappers/button.rb +7 -11
- data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +2 -6
- data/lib/primer/view_components/linters/argument_mappers/close_button.rb +43 -0
- data/lib/primer/view_components/linters/argument_mappers/flash.rb +32 -0
- data/lib/primer/view_components/linters/argument_mappers/helpers/erb_block.rb +67 -0
- data/lib/primer/view_components/linters/argument_mappers/label.rb +5 -12
- data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +6 -5
- data/lib/primer/view_components/linters/autocorrectable.rb +6 -4
- data/lib/primer/view_components/linters/{helpers.rb → base_linter.rb} +69 -29
- data/lib/primer/view_components/linters/button_component_migration_counter.rb +4 -3
- data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +3 -4
- data/lib/primer/view_components/linters/close_button_component_migration_counter.rb +123 -0
- data/lib/primer/view_components/linters/flash_component_migration_counter.rb +18 -3
- data/lib/primer/view_components/linters/label_component_migration_counter.rb +2 -3
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/rubocop/config/default.yml +5 -0
- data/lib/rubocop/cop/primer/deprecated_arguments.rb +173 -0
- data/lib/rubocop/cop/primer/no_tag_memoize.rb +1 -0
- data/lib/rubocop/cop/primer/primer_octicon.rb +178 -0
- data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +12 -16
- data/lib/rubocop/cop/primer.rb +1 -2
- data/lib/tasks/coverage.rake +4 -0
- data/lib/tasks/docs.rake +3 -2
- data/lib/tasks/utilities.rake +7 -3
- data/lib/yard/docs_helper.rb +6 -3
- data/static/arguments.yml +7 -4
- data/static/classes.yml +8 -0
- data/static/constants.json +13 -1
- data/static/statuses.json +3 -1
- metadata +32 -9
@@ -8,16 +8,12 @@ module ERBLint
|
|
8
8
|
# Maps attributes in the clipboard-copy element to arguments for the ClipboardCopy component.
|
9
9
|
class ClipboardCopy < Base
|
10
10
|
DEFAULT_TAG = "clipboard-copy"
|
11
|
+
ATTRIBUTES = %w[role tabindex for value id style].freeze
|
11
12
|
|
12
13
|
def attribute_to_args(attribute)
|
13
14
|
attr_name = attribute.name
|
14
15
|
|
15
|
-
|
16
|
-
{ value: attribute.value.to_json }
|
17
|
-
else
|
18
|
-
# Assume the attribute is a system argument.
|
19
|
-
SystemArguments.new(attribute).to_args
|
20
|
-
end
|
16
|
+
{ attr_name.to_sym => erb_helper.convert(attribute) }
|
21
17
|
end
|
22
18
|
end
|
23
19
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module ArgumentMappers
|
8
|
+
# Maps classes in a close-button element to arguments for the CloseButton component.
|
9
|
+
class CloseButton < Base
|
10
|
+
ATTRIBUTES = %w[type].freeze
|
11
|
+
|
12
|
+
TYPE_OPTIONS = Primer::ViewComponents::Constants.get(
|
13
|
+
component: "Primer::CloseButton",
|
14
|
+
constant: "TYPE_OPTIONS"
|
15
|
+
).freeze
|
16
|
+
|
17
|
+
DEFAULT_TYPE = Primer::ViewComponents::Constants.get(
|
18
|
+
component: "Primer::CloseButton",
|
19
|
+
constant: "DEFAULT_TYPE"
|
20
|
+
).freeze
|
21
|
+
|
22
|
+
DEFAULT_CLASS = "close-button"
|
23
|
+
|
24
|
+
def attribute_to_args(attribute)
|
25
|
+
# button is the default type, so we don't need to do anything.
|
26
|
+
return {} if attribute.value == DEFAULT_TYPE
|
27
|
+
|
28
|
+
raise ConversionError, "CloseButton component does not support type \"#{attribute.value}\"" unless TYPE_OPTIONS.include?(attribute.value)
|
29
|
+
|
30
|
+
{ type: ":#{attribute.value}" }
|
31
|
+
end
|
32
|
+
|
33
|
+
def classes_to_args(classes)
|
34
|
+
classes.each_with_object({ classes: [] }) do |class_name, acc|
|
35
|
+
next if class_name == DEFAULT_CLASS
|
36
|
+
|
37
|
+
acc[:classes] << class_name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module ArgumentMappers
|
8
|
+
# Maps classes in a flash element to arguments for the Flash component.
|
9
|
+
class Flash < Base
|
10
|
+
SCHEME_MAPPINGS = Primer::ViewComponents::Constants.get(
|
11
|
+
component: "Primer::FlashComponent",
|
12
|
+
constant: "SCHEME_MAPPINGS",
|
13
|
+
symbolize: true
|
14
|
+
).freeze
|
15
|
+
|
16
|
+
def classes_to_args(classes)
|
17
|
+
classes.each_with_object({ classes: [] }) do |class_name, acc|
|
18
|
+
next if class_name == "flash"
|
19
|
+
|
20
|
+
if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
|
21
|
+
acc[:scheme] = SCHEME_MAPPINGS[class_name]
|
22
|
+
elsif class_name == "flash-full"
|
23
|
+
acc[:full] = true
|
24
|
+
else
|
25
|
+
acc[:classes] << class_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../conversion_error"
|
4
|
+
|
5
|
+
module ERBLint
|
6
|
+
module Linters
|
7
|
+
module ArgumentMappers
|
8
|
+
module Helpers
|
9
|
+
# provides helpers to identify and deal with ERB blocks.
|
10
|
+
class ErbBlock
|
11
|
+
INTERPOLATION_REGEX = /^<%=(?<rb>.*)%>$/.freeze
|
12
|
+
|
13
|
+
def raise_if_erb_block(attribute)
|
14
|
+
raise_error(attribute) if any?(attribute)
|
15
|
+
end
|
16
|
+
|
17
|
+
def convert(attribute)
|
18
|
+
raise_error(attribute) unless interpolation?(attribute)
|
19
|
+
|
20
|
+
if any?(attribute)
|
21
|
+
convert_interpolation(attribute)
|
22
|
+
else
|
23
|
+
attribute.value.to_json
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def interpolation?(attribute)
|
30
|
+
erb_blocks(attribute).all? do |erb|
|
31
|
+
# If the blocks does not have an indicator, it's not an interpolation.
|
32
|
+
erb.children.to_a.compact.any? { |node| node.type == :indicator }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def raise_error(attribute)
|
37
|
+
raise ERBLint::Linters::ArgumentMappers::ConversionError, "Cannot convert attribute \"#{attribute.name}\" because its value contains an erb block"
|
38
|
+
end
|
39
|
+
|
40
|
+
def any?(attribute)
|
41
|
+
erb_blocks(attribute).any?
|
42
|
+
end
|
43
|
+
|
44
|
+
def basic?(attribute)
|
45
|
+
return false if erb_blocks(attribute).size != 1
|
46
|
+
|
47
|
+
attribute.value.match?(INTERPOLATION_REGEX)
|
48
|
+
end
|
49
|
+
|
50
|
+
def erb_blocks(attribute)
|
51
|
+
(attribute.value_node&.children || []).select { |n| n.try(:type) == :erb }
|
52
|
+
end
|
53
|
+
|
54
|
+
def convert_interpolation(attribute)
|
55
|
+
if basic?(attribute)
|
56
|
+
m = attribute.value.match(INTERPOLATION_REGEX)
|
57
|
+
return m[:rb].strip
|
58
|
+
end
|
59
|
+
|
60
|
+
# we use `source` instead of `value` because it does not convert encoded HTML entities.
|
61
|
+
attribute.value_node.loc.source.gsub("<%=", '#{').gsub("%>", "}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -24,21 +24,14 @@ module ERBLint
|
|
24
24
|
constant: "DEFAULT_TAG"
|
25
25
|
).freeze
|
26
26
|
|
27
|
+
ATTRIBUTES = %w[title].freeze
|
28
|
+
|
27
29
|
def attribute_to_args(attribute)
|
28
|
-
|
29
|
-
|
30
|
-
if attr_name == "class"
|
31
|
-
classes_to_args(attribute)
|
32
|
-
elsif attr_name == "title"
|
33
|
-
{ title: attribute.value.to_json }
|
34
|
-
else
|
35
|
-
# Assume the attribute is a system argument.
|
36
|
-
SystemArguments.new(attribute).to_args
|
37
|
-
end
|
30
|
+
{ title: erb_helper.convert(attribute) }
|
38
31
|
end
|
39
32
|
|
40
33
|
def classes_to_args(classes)
|
41
|
-
classes.
|
34
|
+
classes.each_with_object({ classes: [] }) do |class_name, acc|
|
42
35
|
next if class_name == "Label"
|
43
36
|
|
44
37
|
if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
|
@@ -46,7 +39,7 @@ module ERBLint
|
|
46
39
|
elsif VARIANT_MAPPINGS[class_name] && acc[:variant].nil?
|
47
40
|
acc[:variant] = VARIANT_MAPPINGS[class_name]
|
48
41
|
else
|
49
|
-
|
42
|
+
acc[:classes] << class_name
|
50
43
|
end
|
51
44
|
end
|
52
45
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "conversion_error"
|
4
|
+
require_relative "helpers/erb_block"
|
4
5
|
|
5
6
|
module ERBLint
|
6
7
|
module Linters
|
@@ -10,9 +11,11 @@ module ERBLint
|
|
10
11
|
STRING_PARAMETERS = %w[aria- data-].freeze
|
11
12
|
TEST_SELECTOR_REGEX = /test_selector\((?<selector>.+)\)$/.freeze
|
12
13
|
|
13
|
-
attr_reader :attribute
|
14
|
+
attr_reader :attribute, :erb_helper
|
15
|
+
|
14
16
|
def initialize(attribute)
|
15
17
|
@attribute = attribute
|
18
|
+
@erb_helper = Helpers::ErbBlock.new
|
16
19
|
end
|
17
20
|
|
18
21
|
def to_args
|
@@ -28,11 +31,9 @@ module ERBLint
|
|
28
31
|
|
29
32
|
{ test_selector: m[:selector].tr("'", '"') }
|
30
33
|
elsif attr_name == "data-test-selector"
|
31
|
-
{ test_selector: attribute
|
34
|
+
{ test_selector: erb_helper.convert(attribute) }
|
32
35
|
elsif attr_name.start_with?(*STRING_PARAMETERS)
|
33
|
-
|
34
|
-
|
35
|
-
{ "\"#{attr_name}\"" => attribute.value.to_json }
|
36
|
+
{ "\"#{attr_name}\"" => erb_helper.convert(attribute) }
|
36
37
|
else
|
37
38
|
raise ConversionError, "Cannot convert attribute \"#{attr_name}\""
|
38
39
|
end
|
@@ -4,9 +4,11 @@ require_relative "argument_mappers/conversion_error"
|
|
4
4
|
|
5
5
|
module ERBLint
|
6
6
|
module Linters
|
7
|
-
#
|
7
|
+
# Provides the autocorrection functionality for the linter. Once included, you should define the following constants:
|
8
|
+
# * `ARGUMENT_MAPPER` - required - The class responsible for transforming classes and attributes into arguments for the component.
|
9
|
+
# * `COMPONENT` - required - The component name for the linter. It will be used to generate the correction.
|
8
10
|
module Autocorrectable
|
9
|
-
def map_arguments(tag)
|
11
|
+
def map_arguments(tag, _tag_tree)
|
10
12
|
self.class::ARGUMENT_MAPPER.new(tag).to_s
|
11
13
|
rescue ArgumentMappers::ConversionError
|
12
14
|
nil
|
@@ -20,10 +22,10 @@ module ERBLint
|
|
20
22
|
"#{correction} do %>"
|
21
23
|
end
|
22
24
|
|
23
|
-
def message(args)
|
25
|
+
def message(args, processed_source)
|
24
26
|
return self.class::MESSAGE if args.nil?
|
25
27
|
|
26
|
-
"#{self.class::MESSAGE}\
|
28
|
+
"#{self.class::MESSAGE}\nTry using:\n\n#{correction(args)}\n\nYou can also run erblint in autocorrect mode:\n\nbundle exec erblint -a #{processed_source.filename}\n"
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
@@ -4,10 +4,16 @@ require "json"
|
|
4
4
|
require "openssl"
|
5
5
|
require "primer/view_components/constants"
|
6
6
|
|
7
|
+
# :nocov:
|
8
|
+
|
7
9
|
module ERBLint
|
8
10
|
module Linters
|
9
|
-
#
|
10
|
-
|
11
|
+
# Provides the basic linter logic. When inherited, you should define:
|
12
|
+
# * `TAGS` - required - The HTML tags that the component supports. It will be used by the linter to match elements.
|
13
|
+
# * `MESSAGE` - required - The message shown when there's an offense.
|
14
|
+
# * `CLASSES` - optional - The CSS classes that the component needs. The linter will only match elements with one of those classes.
|
15
|
+
# * `REQUIRED_ARGUMENTS` - optional - A list of HTML attributes that are required by the component.
|
16
|
+
class BaseLinter < Linter
|
11
17
|
# from https://github.com/Shopify/erb-lint/blob/6179ee2d9d681a6ec4dd02351a1e30eefa748d3d/lib/erb_lint/linters/self_closing_tag.rb
|
12
18
|
SELF_CLOSING_TAGS = %w[
|
13
19
|
area base br col command embed hr input keygen
|
@@ -15,33 +21,44 @@ module ERBLint
|
|
15
21
|
].freeze
|
16
22
|
|
17
23
|
DUMP_FILE = ".erblint-counter-ignore.json"
|
24
|
+
DISALLOWED_CLASSES = [].freeze
|
25
|
+
CLASSES = [].freeze
|
26
|
+
REQUIRED_ARGUMENTS = [].freeze
|
27
|
+
|
28
|
+
class ConfigSchema < LinterConfig
|
29
|
+
property :override_ignores_if_correctable, accepts: [true, false], default: false, reader: :override_ignores_if_correctable?
|
30
|
+
end
|
18
31
|
|
19
|
-
def self.
|
32
|
+
def self.inherited(base)
|
33
|
+
super
|
20
34
|
base.include(ERBLint::LinterRegistry)
|
35
|
+
base.config_schema = ConfigSchema
|
21
36
|
end
|
22
37
|
|
23
38
|
def run(processed_source)
|
24
39
|
@total_offenses = 0
|
25
40
|
@offenses_not_corrected = 0
|
26
|
-
tags =
|
27
|
-
tag_tree = build_tag_tree(tags)
|
41
|
+
(tags, tag_tree) = build_tag_tree(processed_source)
|
28
42
|
|
29
43
|
tags.each do |tag|
|
30
44
|
next if tag.closing?
|
31
45
|
next unless self.class::TAGS&.include?(tag.name)
|
32
46
|
|
33
47
|
classes = tag.attributes["class"]&.value&.split(" ") || []
|
34
|
-
|
35
48
|
tag_tree[tag][:offense] = false
|
36
49
|
|
50
|
+
next if (classes & self.class::DISALLOWED_CLASSES).any?
|
37
51
|
next unless self.class::CLASSES.blank? || (classes & self.class::CLASSES).any?
|
38
52
|
|
39
|
-
args = map_arguments(tag)
|
53
|
+
args = map_arguments(tag, tag_tree[tag])
|
40
54
|
correction = correction(args)
|
41
55
|
|
56
|
+
attributes = tag.attributes.each.map(&:name).join(" ")
|
57
|
+
matches_required_attributes = self.class::REQUIRED_ARGUMENTS.blank? || self.class::REQUIRED_ARGUMENTS.all? { |arg| attributes.match?(arg) }
|
58
|
+
|
42
59
|
tag_tree[tag][:offense] = true
|
43
|
-
tag_tree[tag][:correctable] = !correction.nil?
|
44
|
-
tag_tree[tag][:message] = message(args)
|
60
|
+
tag_tree[tag][:correctable] = matches_required_attributes && !correction.nil?
|
61
|
+
tag_tree[tag][:message] = message(args, processed_source)
|
45
62
|
tag_tree[tag][:correction] = correction
|
46
63
|
end
|
47
64
|
|
@@ -51,8 +68,7 @@ module ERBLint
|
|
51
68
|
@total_offenses += 1
|
52
69
|
# We always fix the offenses using blocks. The closing tag corresponds to `<% end %>`.
|
53
70
|
if h[:correctable]
|
54
|
-
|
55
|
-
add_offense(h[:closing].loc, h[:message], "<% end %>")
|
71
|
+
add_correction(tag, h)
|
56
72
|
else
|
57
73
|
@offenses_not_corrected += 1
|
58
74
|
generate_offense(self.class, processed_source, tag, h[:message])
|
@@ -78,11 +94,16 @@ module ERBLint
|
|
78
94
|
|
79
95
|
private
|
80
96
|
|
97
|
+
def add_correction(tag, tag_tree)
|
98
|
+
add_offense(tag.loc, tag_tree[:message], tag_tree[:correction])
|
99
|
+
add_offense(tag_tree[:closing].loc, tag_tree[:message], "<% end %>")
|
100
|
+
end
|
101
|
+
|
81
102
|
# Override this function to convert the HTML element attributes to argument for a component.
|
82
103
|
#
|
83
104
|
# @return [Hash] if possible to map all attributes to arguments.
|
84
105
|
# @return [Nil] if cannot map to arguments.
|
85
|
-
def map_arguments(_tag)
|
106
|
+
def map_arguments(_tag, _tag_tree)
|
86
107
|
nil
|
87
108
|
end
|
88
109
|
|
@@ -97,7 +118,7 @@ module ERBLint
|
|
97
118
|
# Override this function to customize the linter message.
|
98
119
|
#
|
99
120
|
# @return [String] message to show on linter error.
|
100
|
-
def message(_tag)
|
121
|
+
def message(_tag, _processed_source)
|
101
122
|
self.class::MESSAGE
|
102
123
|
end
|
103
124
|
|
@@ -118,31 +139,44 @@ module ERBLint
|
|
118
139
|
# This assumes that the AST provided represents valid HTML, where each tag has a corresponding closing tag.
|
119
140
|
# From the tags, we build a structured tree which represents the tag hierarchy.
|
120
141
|
# With this, we are able to know where the tags start and end.
|
121
|
-
def build_tag_tree(
|
142
|
+
def build_tag_tree(processed_source)
|
143
|
+
nodes = processed_source.ast.children
|
122
144
|
tag_tree = {}
|
145
|
+
tags = []
|
123
146
|
current_opened_tag = nil
|
124
147
|
|
125
|
-
|
126
|
-
if tag
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
end
|
148
|
+
nodes.each do |node|
|
149
|
+
if node.type == :tag
|
150
|
+
# get the tag from previously calculated list so the references are the same
|
151
|
+
tag = BetterHtml::Tree::Tag.from_node(node)
|
152
|
+
tags << tag
|
131
153
|
|
132
|
-
|
133
|
-
|
154
|
+
if tag.closing?
|
155
|
+
if current_opened_tag && tag.name == current_opened_tag.name
|
156
|
+
tag_tree[current_opened_tag][:closing] = tag
|
157
|
+
current_opened_tag = tag_tree[current_opened_tag][:parent]
|
158
|
+
end
|
159
|
+
|
160
|
+
next
|
161
|
+
end
|
134
162
|
|
135
|
-
|
163
|
+
self_closing = self_closing?(tag)
|
136
164
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
165
|
+
tag_tree[tag] = {
|
166
|
+
tag: tag,
|
167
|
+
closing: self_closing ? tag : nil,
|
168
|
+
parent: current_opened_tag,
|
169
|
+
children: []
|
170
|
+
}
|
141
171
|
|
142
|
-
|
172
|
+
tag_tree[current_opened_tag][:children] << tag_tree[tag] if current_opened_tag
|
173
|
+
current_opened_tag = tag unless self_closing
|
174
|
+
elsif current_opened_tag
|
175
|
+
tag_tree[current_opened_tag][:children] << node
|
176
|
+
end
|
143
177
|
end
|
144
178
|
|
145
|
-
tag_tree
|
179
|
+
[tags, tag_tree]
|
146
180
|
end
|
147
181
|
|
148
182
|
def self_closing?(tag)
|
@@ -169,6 +203,12 @@ module ERBLint
|
|
169
203
|
end
|
170
204
|
end
|
171
205
|
|
206
|
+
# Unless explicitly set, we don't want to mark correctable offenses if the counter is correct.
|
207
|
+
if !@config.override_ignores_if_correctable? && expected_count == @total_offenses
|
208
|
+
clear_offenses
|
209
|
+
return
|
210
|
+
end
|
211
|
+
|
172
212
|
if @offenses_not_corrected.zero?
|
173
213
|
# have to adjust to get `\n` so we delete the whole line
|
174
214
|
add_offense(processed_source.to_source_range(comment_node.loc.adjust(end_pos: 1)), "Unused erblint:count comment for #{rule_name}", "") if comment_node
|
@@ -1,14 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
3
|
+
require_relative "base_linter"
|
4
4
|
require_relative "autocorrectable"
|
5
5
|
require_relative "argument_mappers/button"
|
6
6
|
|
7
7
|
module ERBLint
|
8
8
|
module Linters
|
9
9
|
# Counts the number of times a HTML button is used instead of the component.
|
10
|
-
class ButtonComponentMigrationCounter <
|
11
|
-
include Helpers
|
10
|
+
class ButtonComponentMigrationCounter < BaseLinter
|
12
11
|
include Autocorrectable
|
13
12
|
|
14
13
|
TAGS = Primer::ViewComponents::Constants.get(
|
@@ -16,6 +15,8 @@ module ERBLint
|
|
16
15
|
constant: "TAG_OPTIONS"
|
17
16
|
).freeze
|
18
17
|
|
18
|
+
# CloseButton component has preference when this class is seen in conjuction with `btn`.
|
19
|
+
DISALLOWED_CLASSES = %w[close-button].freeze
|
19
20
|
CLASSES = %w[btn btn-link].freeze
|
20
21
|
MESSAGE = "We are migrating buttons to use [Primer::ButtonComponent](https://primer.style/view-components/components/button), please try to use that instead of raw HTML."
|
21
22
|
ARGUMENT_MAPPER = ArgumentMappers::Button
|