primer_view_components 0.0.52 → 0.0.53

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: ad52227798e79cb0259c00e61d24a3e72854dfb4fa4ffb4901fb30a2fa7f3370
4
- data.tar.gz: 5f2e4decc740b1e9712744819d655091a2a45e9ac8b403beed54c8c9e6a6e332
3
+ metadata.gz: 4df5bb105c8b48aed71b4652afbf6814257fcb2c344085b328c27f8f109a80c1
4
+ data.tar.gz: 72ff93288cac5eb1cabdc7cb8031c488452499203d768fcf3795bbe18cb31a43
5
5
  SHA512:
6
- metadata.gz: c7cac3105837c025730e7c6e01395db680d1c750bf4d2240594f00c4758a7d404802d184dd3bd53a14c8a2e14e25776152792e97fceb2a686182aaf1474ae162
7
- data.tar.gz: f296ae7b5e8f6217b05e719169db5f08b1d1d8d7fb9293e083ae9a836f12d98c73e88cc320df3522a902f4dada28ac10ce7c9f37a96f0b175aaa1e2940e1bec9
6
+ metadata.gz: 3af26e886cc8998ef3d449471400319615c0e820ce7265316e6de6fda2b55340f7f7a82d3c7c78f5c4e393f60d7638126bd8e8a88675735bfe570d2958ee2484
7
+ data.tar.gz: aff9d0ca813126c33daab60f57bb01915ea8b779f17df99e648ec236f0da12bb9b16f54af24dfa871a50253663d71813533386457424f09f46a5458d5556a5b2
data/CHANGELOG.md CHANGED
@@ -30,6 +30,48 @@ The category for changes related to documentation, testing and tooling. Also, fo
30
30
 
31
31
  ## main
32
32
 
33
+ ## 0.0.53
34
+
35
+ ### New
36
+
37
+ * Add autocorrection to `FlashComponent` linter when the context is basic text.
38
+
39
+ *Manuel Puyol*
40
+
41
+ ### Updates
42
+
43
+ * Linters won't mark offenses when the ignore count is correct unless explicitly configured to do so.
44
+
45
+ *Manuel Puyol*
46
+
47
+ * Map the `for` argument when autofixing `ClipboardCopy` migrations.
48
+
49
+ *Kristján Oddsson*
50
+
51
+ * Add autocorrection for `CloseButton` linter.
52
+
53
+ *Manuel Puyol*
54
+
55
+ ### Bug fixes
56
+
57
+ * Linters won't convert HTML special elements.
58
+
59
+ *Manuel Puyol*
60
+
61
+ ### Misc
62
+
63
+ * Only run CHANGELOG CI on pull requests.
64
+
65
+ *Manuel Puyol*
66
+
67
+ * Run CI actions on pushes to main.
68
+
69
+ *Cameron Dutro*
70
+
71
+ * Get to 100% code coverage.
72
+
73
+ *Cameron Dutro*
74
+
33
75
  ## 0.0.52
34
76
 
35
77
  ### New
@@ -84,6 +126,10 @@ The category for changes related to documentation, testing and tooling. Also, fo
84
126
 
85
127
  *Manuel Puyol*
86
128
 
129
+ * Add a linter generator.
130
+
131
+ *Manuel Puyol*
132
+
87
133
  ## 0.0.51
88
134
 
89
135
  ### Breaking changes
@@ -40,7 +40,7 @@ module Primer
40
40
 
41
41
  # @example Default
42
42
  # <%= render(Primer::TabNavComponent.new(label: "Default")) do |c| %>
43
- # <% c.tab(selected: true, href: "#") { "Tab 1" }%>
43
+ # <% c.tab(selected: true, href: "#") { "Tab 1" } %>
44
44
  # <% c.tab(href: "#") { "Tab 2" } %>
45
45
  # <% c.tab(href: "#") { "Tab 3" } %>
46
46
  # <% end %>
@@ -212,8 +212,6 @@ module Primer
212
212
  else
213
213
  "color-shadow-#{val.to_s.dasherize}"
214
214
  end
215
- else
216
- memo[:classes] << "#{key.to_s.dasherize}#{breakpoint}-#{val.to_s.dasherize}"
217
215
  end
218
216
  end
219
217
 
@@ -29,7 +29,7 @@ module Primer
29
29
  private
30
30
 
31
31
  def format_hash(values, invert, symbolize)
32
- val = values.invert if invert
32
+ val = invert ? values.invert : values
33
33
  # remove defaults
34
34
  val = val.except("", nil)
35
35
 
@@ -51,7 +51,7 @@ module ERBLint
51
51
  erb_helper.raise_if_erb_block(classes_node)
52
52
 
53
53
  system_arguments = system_arguments_to_args(classes_node.value)
54
- args = classes_to_args(system_arguments[:classes])
54
+ args = classes_to_args(system_arguments[:classes]&.split || [])
55
55
 
56
56
  invalid_classes = args[:classes].select { |class_name| Primer::Classify::Validation.invalid?(class_name) }
57
57
 
@@ -77,7 +77,7 @@ module ERBLint
77
77
  # including a `classes` key that will contain all classes that the mapper couldn't handle.
78
78
  # @returns { classes: Array, ... }
79
79
  def classes_to_args(classes)
80
- { classes: classes&.split(" ") || [] }
80
+ { classes: classes }
81
81
  end
82
82
 
83
83
  def system_arguments_to_args(classes)
@@ -47,7 +47,7 @@ module ERBLint
47
47
  end
48
48
 
49
49
  def classes_to_args(classes)
50
- classes.split.each_with_object({ classes: [] }) do |class_name, acc|
50
+ classes.each_with_object({ classes: [] }) do |class_name, acc|
51
51
  next if class_name == "btn"
52
52
 
53
53
  if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
@@ -8,10 +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[value].freeze
11
+ ATTRIBUTES = %w[role tabindex for value id style].freeze
12
12
 
13
13
  def attribute_to_args(attribute)
14
- { value: erb_helper.convert(attribute) }
14
+ attr_name = attribute.name
15
+
16
+ { attr_name.to_sym => erb_helper.convert(attribute) }
15
17
  end
16
18
  end
17
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
@@ -57,8 +57,8 @@ module ERBLint
57
57
  return m[:rb].strip
58
58
  end
59
59
 
60
- # wrap the result in `""` so it is printed as a string
61
- "\"#{attribute.value.gsub('<%=', '#{').gsub('%>', '}')}\""
60
+ # we use `source` instead of `value` because it does not convert encoded HTML entities.
61
+ attribute.value_node.loc.source.gsub("<%=", '#{').gsub("%>", "}")
62
62
  end
63
63
  end
64
64
  end
@@ -31,7 +31,7 @@ module ERBLint
31
31
  end
32
32
 
33
33
  def classes_to_args(classes)
34
- classes.split.each_with_object({ classes: [] }) do |class_name, acc|
34
+ classes.each_with_object({ classes: [] }) do |class_name, acc|
35
35
  next if class_name == "Label"
36
36
 
37
37
  if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
@@ -4,9 +4,11 @@ require_relative "argument_mappers/conversion_error"
4
4
 
5
5
  module ERBLint
6
6
  module Linters
7
- # Helper methods for autocorrectable ERB linters.
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
@@ -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
- # Helper methods for linting ERB.
10
- module Helpers
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,18 +21,24 @@ module ERBLint
15
21
  ].freeze
16
22
 
17
23
  DUMP_FILE = ".erblint-counter-ignore.json"
24
+ DISALLOWED_CLASSES = [].freeze
18
25
  CLASSES = [].freeze
19
26
  REQUIRED_ARGUMENTS = [].freeze
20
27
 
21
- def self.included(base)
28
+ class ConfigSchema < LinterConfig
29
+ property :override_ignores_if_correctable, accepts: [true, false], default: false, reader: :override_ignores_if_correctable?
30
+ end
31
+
32
+ def self.inherited(base)
33
+ super
22
34
  base.include(ERBLint::LinterRegistry)
35
+ base.config_schema = ConfigSchema
23
36
  end
24
37
 
25
38
  def run(processed_source)
26
39
  @total_offenses = 0
27
40
  @offenses_not_corrected = 0
28
- tags = tags(processed_source)
29
- tag_tree = build_tag_tree(tags)
41
+ (tags, tag_tree) = build_tag_tree(processed_source)
30
42
 
31
43
  tags.each do |tag|
32
44
  next if tag.closing?
@@ -35,9 +47,10 @@ module ERBLint
35
47
  classes = tag.attributes["class"]&.value&.split(" ") || []
36
48
  tag_tree[tag][:offense] = false
37
49
 
50
+ next if (classes & self.class::DISALLOWED_CLASSES).any?
38
51
  next unless self.class::CLASSES.blank? || (classes & self.class::CLASSES).any?
39
52
 
40
- args = map_arguments(tag)
53
+ args = map_arguments(tag, tag_tree[tag])
41
54
  correction = correction(args)
42
55
 
43
56
  attributes = tag.attributes.each.map(&:name).join(" ")
@@ -55,8 +68,7 @@ module ERBLint
55
68
  @total_offenses += 1
56
69
  # We always fix the offenses using blocks. The closing tag corresponds to `<% end %>`.
57
70
  if h[:correctable]
58
- add_offense(tag.loc, h[:message], h[:correction])
59
- add_offense(h[:closing].loc, h[:message], "<% end %>")
71
+ add_correction(tag, h)
60
72
  else
61
73
  @offenses_not_corrected += 1
62
74
  generate_offense(self.class, processed_source, tag, h[:message])
@@ -82,11 +94,16 @@ module ERBLint
82
94
 
83
95
  private
84
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
+
85
102
  # Override this function to convert the HTML element attributes to argument for a component.
86
103
  #
87
104
  # @return [Hash] if possible to map all attributes to arguments.
88
105
  # @return [Nil] if cannot map to arguments.
89
- def map_arguments(_tag)
106
+ def map_arguments(_tag, _tag_tree)
90
107
  nil
91
108
  end
92
109
 
@@ -122,31 +139,44 @@ module ERBLint
122
139
  # This assumes that the AST provided represents valid HTML, where each tag has a corresponding closing tag.
123
140
  # From the tags, we build a structured tree which represents the tag hierarchy.
124
141
  # With this, we are able to know where the tags start and end.
125
- def build_tag_tree(tags)
142
+ def build_tag_tree(processed_source)
143
+ nodes = processed_source.ast.children
126
144
  tag_tree = {}
145
+ tags = []
127
146
  current_opened_tag = nil
128
147
 
129
- tags.each do |tag|
130
- if tag.closing?
131
- if current_opened_tag && tag.name == current_opened_tag.name
132
- tag_tree[current_opened_tag][:closing] = tag
133
- current_opened_tag = tag_tree[current_opened_tag][:parent]
134
- 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
135
153
 
136
- next
137
- end
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
138
159
 
139
- self_closing = self_closing?(tag)
160
+ next
161
+ end
162
+
163
+ self_closing = self_closing?(tag)
140
164
 
141
- tag_tree[tag] = {
142
- closing: self_closing ? tag : nil,
143
- parent: current_opened_tag
144
- }
165
+ tag_tree[tag] = {
166
+ tag: tag,
167
+ closing: self_closing ? tag : nil,
168
+ parent: current_opened_tag,
169
+ children: []
170
+ }
145
171
 
146
- current_opened_tag = tag unless self_closing
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
147
177
  end
148
178
 
149
- tag_tree
179
+ [tags, tag_tree]
150
180
  end
151
181
 
152
182
  def self_closing?(tag)
@@ -173,6 +203,12 @@ module ERBLint
173
203
  end
174
204
  end
175
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
+
176
212
  if @offenses_not_corrected.zero?
177
213
  # have to adjust to get `\n` so we delete the whole line
178
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 "helpers"
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 < Linter
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
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "helpers"
3
+ require_relative "base_linter"
4
4
  require_relative "autocorrectable"
5
5
  require_relative "argument_mappers/clipboard_copy"
6
6
 
7
7
  module ERBLint
8
8
  module Linters
9
9
  # Counts the number of times a HTML clipboard-copy is used instead of the component.
10
- class ClipboardCopyComponentMigrationCounter < Linter
11
- include Helpers
10
+ class ClipboardCopyComponentMigrationCounter < BaseLinter
12
11
  include Autocorrectable
13
12
 
14
13
  TAGS = %w[clipboard-copy].freeze
@@ -1,16 +1,123 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "helpers"
3
+ require_relative "base_linter"
4
+ require_relative "autocorrectable"
5
+ require_relative "argument_mappers/close_button"
4
6
 
5
7
  module ERBLint
6
8
  module Linters
7
9
  # Counts the number of times a HTML clipboard-copy is used instead of the component.
8
- class CloseButtonComponentMigrationCounter < Linter
9
- include Helpers
10
+ class CloseButtonComponentMigrationCounter < BaseLinter
11
+ include Autocorrectable
10
12
 
11
13
  TAGS = %w[button].freeze
12
14
  CLASSES = %w[close-button].freeze
13
15
  MESSAGE = "We are migrating close-button to use [Primer::CloseButton](https://primer.style/view-components/components/closebutton), please try to use that instead of raw HTML."
16
+ ARGUMENT_MAPPER = ArgumentMappers::CloseButton
17
+ COMPONENT = "Primer::CloseButton"
18
+
19
+ ALLOWED_OCTICON_ARGS = %w[icon aria-label aria].freeze
20
+
21
+ private
22
+
23
+ def map_arguments(tag, tag_tree)
24
+ # We can only autocorrect cases where the tag only has an octicon as content.
25
+ return if tag_tree[:children].size != 1
26
+
27
+ nodes = tag_tree[:children].first.children
28
+ erb_nodes = nodes.select { |node| node.try(:type) == :erb }
29
+
30
+ # Don't correct if there are multiple ERB nodes.
31
+ return if erb_nodes.size != 1
32
+
33
+ _, _, code_node = *erb_nodes.first
34
+ code = code_node.children.first.strip
35
+ ast = erb_ast(code)
36
+
37
+ # We'll only autocorrect cases where the only content is an octicon.
38
+ if ast.method_name == :primer_octicon || ast.method_name == :octicon
39
+ octicon_kwargs = ast.arguments[1]
40
+ icon = icon(ast.arguments)
41
+ elsif ast.method_name == :render && code.include?("Primer::OcticonComponent")
42
+ octicon_kwargs = ast.arguments.first.arguments.last
43
+ icon = icon(ast.arguments.first.arguments)
44
+ else
45
+ return
46
+ end
47
+
48
+ # Don't autocorrect if using a custom icon
49
+ return unless icon == :x
50
+ # Don't autocorrect if the octicon has custom arguments
51
+ return if custom_attributes?(octicon_kwargs)
52
+
53
+ octicon_aria_label = aria_label_from_octicon(octicon_kwargs)
54
+ tag_aria_label = tag.attributes.each.find { |a| a.name == "aria-label" }
55
+
56
+ # Can't autocorrect if there is no aria-label.
57
+ return if octicon_aria_label.blank? && tag_aria_label.blank?
58
+
59
+ args = ARGUMENT_MAPPER.new(tag).to_s
60
+
61
+ # Argument mapper will add the `aria-label` if the tag has it.
62
+ return args if tag_aria_label.present?
63
+
64
+ aria_label_arg = "\"aria-label\": #{octicon_aria_label}"
65
+
66
+ return aria_label_arg if args.blank?
67
+
68
+ "#{args}, #{aria_label_arg}"
69
+ rescue ArgumentMappers::ConversionError
70
+ nil
71
+ end
72
+
73
+ # Overriding the basic correction since this component does not uses content blocks.
74
+ def correction(args)
75
+ return if args.nil?
76
+
77
+ correction = "<%= render #{self.class::COMPONENT}.new"
78
+ correction += "(#{args})" if args.present?
79
+ "#{correction} %>"
80
+ end
81
+
82
+ # Overriding the basic correction since this component will rewrite the whole tag block.
83
+ def add_correction(tag, tag_tree)
84
+ offense_loc = tag.loc.with(end_pos: tag_tree[:closing].loc.to_range.last)
85
+ add_offense(offense_loc, tag_tree[:message], tag_tree[:correction])
86
+ end
87
+
88
+ # Extracts the aria-label value from the octicon kwargs.
89
+ # It can either be in `"aria-label": "value"`` or `aria: { label: "value" } }`.
90
+ def aria_label_from_octicon(kwargs)
91
+ return if kwargs.blank? || kwargs.type != :hash || kwargs.pairs.blank?
92
+
93
+ aria_label = kwargs.pairs.find { |x| x.key.value == :"aria-label" }
94
+
95
+ return aria_label.value.source if aria_label
96
+
97
+ aria_hash = kwargs.pairs.find { |x| x.key.value == :aria }
98
+
99
+ return if aria_hash.blank?
100
+
101
+ aria_label = aria_hash.value.pairs.find { |x| x.key.value == :label }
102
+
103
+ aria_label&.value&.source
104
+ end
105
+
106
+ def custom_attributes?(kwargs)
107
+ return false if kwargs.blank? || kwargs.type != :hash || kwargs.pairs.blank?
108
+
109
+ (kwargs.keys.map { |key| key.value.to_s } - ALLOWED_OCTICON_ARGS).present?
110
+ end
111
+
112
+ def erb_ast(code)
113
+ RuboCop::AST::ProcessedSource.new(code, RUBY_VERSION.to_f).ast
114
+ end
115
+
116
+ def icon(args)
117
+ return args.first.value.to_sym if args.first.type == :sym || args.first.type == :str
118
+
119
+ args.last.pairs.find { |x| x.key.value == :icon }.value.value.to_sym
120
+ end
14
121
  end
15
122
  end
16
123
  end
@@ -1,16 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "helpers"
3
+ require_relative "base_linter"
4
+ require_relative "autocorrectable"
5
+ require_relative "argument_mappers/flash"
4
6
 
5
7
  module ERBLint
6
8
  module Linters
7
9
  # Counts the number of times a HTML flash is used instead of the component.
8
- class FlashComponentMigrationCounter < Linter
9
- include Helpers
10
+ class FlashComponentMigrationCounter < BaseLinter
11
+ include Autocorrectable
10
12
 
11
13
  TAGS = %w[div].freeze
12
14
  CLASSES = %w[flash].freeze
13
15
  MESSAGE = "We are migrating flashes to use [Primer::FlashComponent](https://primer.style/view-components/components/flash), please try to use that instead of raw HTML."
16
+ ARGUMENT_MAPPER = ArgumentMappers::Flash
17
+ COMPONENT = "Primer::FlashComponent"
18
+
19
+ def map_arguments(tag, tag_tree)
20
+ # We can only autocorrect elements with simple text as content.
21
+ return nil if tag_tree[:children].size != 1
22
+ # Hash children indicates that there are tags in the content.
23
+ return nil if tag_tree[:children].first.is_a?(Hash)
24
+
25
+ ARGUMENT_MAPPER.new(tag).to_s
26
+ rescue ArgumentMappers::ConversionError
27
+ nil
28
+ end
14
29
  end
15
30
  end
16
31
  end
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "helpers"
3
+ require_relative "base_linter"
4
4
  require_relative "autocorrectable"
5
5
  require_relative "argument_mappers/label"
6
6
 
7
7
  module ERBLint
8
8
  module Linters
9
9
  # Counts the number of times a HTML label is used instead of the component.
10
- class LabelComponentMigrationCounter < Linter
11
- include Helpers
10
+ class LabelComponentMigrationCounter < BaseLinter
12
11
  include Autocorrectable
13
12
 
14
13
  TAGS = Primer::ViewComponents::Constants.get(
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 52
8
+ PATCH = 53
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :nocov:
4
+
3
5
  module YARD
4
6
  # Helper methods to use for yard documentation
5
7
  module DocsHelper
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: primer_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.52
4
+ version: 0.0.53
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: 2021-08-18 00:00:00.000000000 Z
11
+ date: 2021-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -324,6 +324,20 @@ dependencies:
324
324
  - - ">="
325
325
  - !ruby/object:Gem::Version
326
326
  version: '0'
327
+ - !ruby/object:Gem::Dependency
328
+ name: timecop
329
+ requirement: !ruby/object:Gem::Requirement
330
+ requirements:
331
+ - - ">="
332
+ - !ruby/object:Gem::Version
333
+ version: '0'
334
+ type: :development
335
+ prerelease: false
336
+ version_requirements: !ruby/object:Gem::Requirement
337
+ requirements:
338
+ - - ">="
339
+ - !ruby/object:Gem::Version
340
+ version: '0'
327
341
  - !ruby/object:Gem::Dependency
328
342
  name: yard
329
343
  requirement: !ruby/object:Gem::Requirement
@@ -486,16 +500,18 @@ files:
486
500
  - lib/primer/view_components/linters/argument_mappers/base.rb
487
501
  - lib/primer/view_components/linters/argument_mappers/button.rb
488
502
  - lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb
503
+ - lib/primer/view_components/linters/argument_mappers/close_button.rb
489
504
  - lib/primer/view_components/linters/argument_mappers/conversion_error.rb
505
+ - lib/primer/view_components/linters/argument_mappers/flash.rb
490
506
  - lib/primer/view_components/linters/argument_mappers/helpers/erb_block.rb
491
507
  - lib/primer/view_components/linters/argument_mappers/label.rb
492
508
  - lib/primer/view_components/linters/argument_mappers/system_arguments.rb
493
509
  - lib/primer/view_components/linters/autocorrectable.rb
510
+ - lib/primer/view_components/linters/base_linter.rb
494
511
  - lib/primer/view_components/linters/button_component_migration_counter.rb
495
512
  - lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb
496
513
  - lib/primer/view_components/linters/close_button_component_migration_counter.rb
497
514
  - lib/primer/view_components/linters/flash_component_migration_counter.rb
498
- - lib/primer/view_components/linters/helpers.rb
499
515
  - lib/primer/view_components/linters/label_component_migration_counter.rb
500
516
  - lib/primer/view_components/statuses.rb
501
517
  - lib/primer/view_components/version.rb