primer_view_components 0.0.48 → 0.0.52

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +155 -0
  3. data/app/components/primer/base_component.rb +2 -2
  4. data/app/components/primer/beta/avatar.rb +1 -1
  5. data/app/components/primer/{avatar_stack_component.html.erb → beta/avatar_stack.html.erb} +0 -0
  6. data/app/components/primer/beta/avatar_stack.rb +92 -0
  7. data/app/components/primer/beta/truncate.html.erb +5 -0
  8. data/app/components/primer/beta/truncate.rb +110 -0
  9. data/app/components/primer/border_box_component.rb +27 -1
  10. data/app/components/primer/clipboard_copy.html.erb +2 -2
  11. data/app/components/primer/clipboard_copy.rb +1 -1
  12. data/app/components/primer/dropdown.rb +7 -7
  13. data/app/components/primer/icon_button.rb +1 -1
  14. data/app/components/primer/image_crop.html.erb +4 -4
  15. data/app/components/primer/label_component.rb +13 -12
  16. data/app/components/primer/navigation/tab_component.rb +16 -2
  17. data/app/components/primer/progress_bar_component.rb +0 -3
  18. data/app/components/primer/tab_nav_component.rb +4 -3
  19. data/app/components/primer/truncate.rb +1 -1
  20. data/app/components/primer/underline_nav_component.rb +3 -2
  21. data/app/lib/primer/fetch_or_fallback_helper.rb +2 -0
  22. data/app/lib/primer/octicon/cache.rb +1 -1
  23. data/app/lib/primer/tabbed_component_helper.rb +1 -1
  24. data/app/lib/primer/view_helper.rb +1 -0
  25. data/lib/primer/classify.rb +4 -16
  26. data/lib/primer/classify/cache.rb +0 -5
  27. data/lib/primer/classify/flex.rb +1 -1
  28. data/lib/primer/classify/functional_colors.rb +1 -1
  29. data/lib/primer/classify/utilities.rb +51 -13
  30. data/lib/primer/classify/utilities.yml +16 -0
  31. data/lib/primer/classify/validation.rb +18 -0
  32. data/lib/primer/view_components.rb +34 -6
  33. data/lib/primer/view_components/constants.rb +55 -0
  34. data/lib/primer/view_components/linters/argument_mappers/base.rb +100 -0
  35. data/lib/primer/view_components/linters/argument_mappers/button.rb +33 -46
  36. data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +19 -0
  37. data/lib/primer/view_components/linters/argument_mappers/helpers/erb_block.rb +67 -0
  38. data/lib/primer/view_components/linters/argument_mappers/label.rb +49 -0
  39. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +6 -5
  40. data/lib/primer/view_components/linters/autocorrectable.rb +30 -0
  41. data/lib/primer/view_components/linters/button_component_migration_counter.rb +9 -23
  42. data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +21 -0
  43. data/lib/primer/view_components/linters/close_button_component_migration_counter.rb +16 -0
  44. data/lib/primer/view_components/linters/helpers.rb +47 -42
  45. data/lib/primer/view_components/linters/label_component_migration_counter.rb +25 -0
  46. data/lib/primer/view_components/version.rb +1 -1
  47. data/lib/rubocop/config/default.yml +5 -0
  48. data/lib/rubocop/cop/primer.rb +1 -2
  49. data/lib/rubocop/cop/primer/deprecated_arguments.rb +173 -0
  50. data/lib/rubocop/cop/primer/no_tag_memoize.rb +1 -0
  51. data/lib/rubocop/cop/primer/primer_octicon.rb +178 -0
  52. data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +12 -16
  53. data/lib/tasks/constants.rake +12 -0
  54. data/lib/tasks/coverage.rake +4 -0
  55. data/lib/tasks/docs.rake +27 -25
  56. data/lib/tasks/utilities.rake +9 -13
  57. data/lib/yard/docs_helper.rb +15 -5
  58. data/static/arguments.yml +980 -0
  59. data/static/assets/view-components.svg +18 -0
  60. data/static/classes.yml +182 -0
  61. data/static/constants.json +640 -0
  62. data/static/statuses.json +4 -2
  63. metadata +29 -10
  64. data/app/components/primer/avatar_stack_component.rb +0 -90
@@ -0,0 +1,49 @@
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 label element to arguments for the Label component.
9
+ class Label < Base
10
+ SCHEME_MAPPINGS = Primer::ViewComponents::Constants.get(
11
+ component: "Primer::LabelComponent",
12
+ constant: "SCHEME_MAPPINGS",
13
+ symbolize: true
14
+ ).freeze
15
+
16
+ VARIANT_MAPPINGS = Primer::ViewComponents::Constants.get(
17
+ component: "Primer::LabelComponent",
18
+ constant: "VARIANT_MAPPINGS",
19
+ symbolize: true
20
+ ).freeze
21
+
22
+ DEFAULT_TAG = Primer::ViewComponents::Constants.get(
23
+ component: "Primer::LabelComponent",
24
+ constant: "DEFAULT_TAG"
25
+ ).freeze
26
+
27
+ ATTRIBUTES = %w[title].freeze
28
+
29
+ def attribute_to_args(attribute)
30
+ { title: erb_helper.convert(attribute) }
31
+ end
32
+
33
+ def classes_to_args(classes)
34
+ classes.split.each_with_object({ classes: [] }) do |class_name, acc|
35
+ next if class_name == "Label"
36
+
37
+ if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
38
+ acc[:scheme] = SCHEME_MAPPINGS[class_name]
39
+ elsif VARIANT_MAPPINGS[class_name] && acc[:variant].nil?
40
+ acc[:variant] = VARIANT_MAPPINGS[class_name]
41
+ else
42
+ acc[:classes] << class_name
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ 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.value.to_json }
34
+ { test_selector: erb_helper.convert(attribute) }
32
35
  elsif attr_name.start_with?(*STRING_PARAMETERS)
33
- raise ConversionError, "Cannot convert attribute \"#{attr_name}\" because its value contains an erb block" if attribute.value_node&.children&.any? { |n| n.try(:type) == :erb }
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
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "argument_mappers/conversion_error"
4
+
5
+ module ERBLint
6
+ module Linters
7
+ # Helper methods for autocorrectable ERB linters.
8
+ module Autocorrectable
9
+ def map_arguments(tag)
10
+ self.class::ARGUMENT_MAPPER.new(tag).to_s
11
+ rescue ArgumentMappers::ConversionError
12
+ nil
13
+ end
14
+
15
+ def correction(args)
16
+ return nil if args.nil?
17
+
18
+ correction = "<%= render #{self.class::COMPONENT}.new"
19
+ correction += "(#{args})" if args.present?
20
+ "#{correction} do %>"
21
+ end
22
+
23
+ def message(args, processed_source)
24
+ return self.class::MESSAGE if args.nil?
25
+
26
+ "#{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
+ end
28
+ end
29
+ end
30
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "helpers"
4
+ require_relative "autocorrectable"
4
5
  require_relative "argument_mappers/button"
5
6
 
6
7
  module ERBLint
@@ -8,32 +9,17 @@ module ERBLint
8
9
  # Counts the number of times a HTML button is used instead of the component.
9
10
  class ButtonComponentMigrationCounter < Linter
10
11
  include Helpers
12
+ include Autocorrectable
13
+
14
+ TAGS = Primer::ViewComponents::Constants.get(
15
+ component: "Primer::BaseButton",
16
+ constant: "TAG_OPTIONS"
17
+ ).freeze
11
18
 
12
- TAGS = %w[button summary a].freeze
13
19
  CLASSES = %w[btn btn-link].freeze
14
20
  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."
15
-
16
- private
17
-
18
- def map_arguments(tag)
19
- ArgumentMappers::Button.new(tag).to_s
20
- rescue ArgumentMappers::ConversionError
21
- nil
22
- end
23
-
24
- def correction(args)
25
- return nil if args.nil?
26
-
27
- correction = "<%= render Primer::ButtonComponent.new"
28
- correction += "(#{args})" if args.present?
29
- "#{correction} do %>"
30
- end
31
-
32
- def message(args)
33
- return MESSAGE if args.nil?
34
-
35
- "#{MESSAGE}\n\nTry using:\n\n#{correction(args)}\n\nInstead of:\n"
36
- end
21
+ ARGUMENT_MAPPER = ArgumentMappers::Button
22
+ COMPONENT = "Primer::ButtonComponent"
37
23
  end
38
24
  end
39
25
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helpers"
4
+ require_relative "autocorrectable"
5
+ require_relative "argument_mappers/clipboard_copy"
6
+
7
+ module ERBLint
8
+ module Linters
9
+ # Counts the number of times a HTML clipboard-copy is used instead of the component.
10
+ class ClipboardCopyComponentMigrationCounter < Linter
11
+ include Helpers
12
+ include Autocorrectable
13
+
14
+ TAGS = %w[clipboard-copy].freeze
15
+ REQUIRED_ARGUMENTS = [/for|value/, "aria-label"].freeze
16
+ MESSAGE = "We are migrating clipboard-copy to use [Primer::ClipboardCopy](https://primer.style/view-components/components/clipboardcopy), please try to use that instead of raw HTML."
17
+ ARGUMENT_MAPPER = ArgumentMappers::ClipboardCopy
18
+ COMPONENT = "Primer::ClipboardCopy"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helpers"
4
+
5
+ module ERBLint
6
+ module Linters
7
+ # Counts the number of times a HTML clipboard-copy is used instead of the component.
8
+ class CloseButtonComponentMigrationCounter < Linter
9
+ include Helpers
10
+
11
+ TAGS = %w[button].freeze
12
+ CLASSES = %w[close-button].freeze
13
+ 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."
14
+ end
15
+ end
16
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "json"
4
4
  require "openssl"
5
+ require "primer/view_components/constants"
5
6
 
6
7
  module ERBLint
7
8
  module Linters
@@ -14,63 +15,67 @@ module ERBLint
14
15
  ].freeze
15
16
 
16
17
  DUMP_FILE = ".erblint-counter-ignore.json"
18
+ CLASSES = [].freeze
19
+ REQUIRED_ARGUMENTS = [].freeze
17
20
 
18
21
  def self.included(base)
19
22
  base.include(ERBLint::LinterRegistry)
23
+ end
20
24
 
21
- define_method "run" do |processed_source|
22
- @total_offenses = 0
23
- @offenses_not_corrected = 0
24
- tags = tags(processed_source)
25
- tag_tree = build_tag_tree(tags)
25
+ def run(processed_source)
26
+ @total_offenses = 0
27
+ @offenses_not_corrected = 0
28
+ tags = tags(processed_source)
29
+ tag_tree = build_tag_tree(tags)
26
30
 
27
- tags.each do |tag|
28
- next if tag.closing?
29
- next unless self.class::TAGS&.include?(tag.name)
31
+ tags.each do |tag|
32
+ next if tag.closing?
33
+ next unless self.class::TAGS&.include?(tag.name)
30
34
 
31
- classes = tag.attributes["class"]&.value&.split(" ") || []
35
+ classes = tag.attributes["class"]&.value&.split(" ") || []
36
+ tag_tree[tag][:offense] = false
32
37
 
33
- tag_tree[tag][:offense] = false
38
+ next unless self.class::CLASSES.blank? || (classes & self.class::CLASSES).any?
34
39
 
35
- next unless self.class::CLASSES.blank? || (classes & self.class::CLASSES).any?
40
+ args = map_arguments(tag)
41
+ correction = correction(args)
36
42
 
37
- args = map_arguments(tag)
38
- correction = correction(args)
43
+ attributes = tag.attributes.each.map(&:name).join(" ")
44
+ matches_required_attributes = self.class::REQUIRED_ARGUMENTS.blank? || self.class::REQUIRED_ARGUMENTS.all? { |arg| attributes.match?(arg) }
39
45
 
40
- tag_tree[tag][:offense] = true
41
- tag_tree[tag][:correctable] = !correction.nil?
42
- tag_tree[tag][:message] = message(args)
43
- tag_tree[tag][:correction] = correction
44
- end
46
+ tag_tree[tag][:offense] = true
47
+ tag_tree[tag][:correctable] = matches_required_attributes && !correction.nil?
48
+ tag_tree[tag][:message] = message(args, processed_source)
49
+ tag_tree[tag][:correction] = correction
50
+ end
45
51
 
46
- tag_tree.each do |tag, h|
47
- next unless h[:offense]
48
-
49
- @total_offenses += 1
50
- # We always fix the offenses using blocks. The closing tag corresponds to `<% end %>`.
51
- if h[:correctable]
52
- add_offense(tag.loc, h[:message], h[:correction])
53
- add_offense(h[:closing].loc, h[:message], "<% end %>")
54
- else
55
- @offenses_not_corrected += 1
56
- generate_offense(self.class, processed_source, tag, h[:message])
57
- end
52
+ tag_tree.each do |tag, h|
53
+ next unless h[:offense]
54
+
55
+ @total_offenses += 1
56
+ # We always fix the offenses using blocks. The closing tag corresponds to `<% end %>`.
57
+ if h[:correctable]
58
+ add_offense(tag.loc, h[:message], h[:correction])
59
+ add_offense(h[:closing].loc, h[:message], "<% end %>")
60
+ else
61
+ @offenses_not_corrected += 1
62
+ generate_offense(self.class, processed_source, tag, h[:message])
58
63
  end
64
+ end
59
65
 
60
- counter_correct?(processed_source)
66
+ counter_correct?(processed_source)
61
67
 
62
- dump_data(processed_source) if ENV["DUMP_LINT_DATA"] == "1"
63
- end
68
+ dump_data(processed_source) if ENV["DUMP_LINT_DATA"] == "1"
69
+ end
64
70
 
65
- define_method "autocorrect" do |processed_source, offense|
66
- return unless offense.context
71
+ def autocorrect(processed_source, offense)
72
+ return unless offense.context
67
73
 
68
- lambda do |corrector|
69
- if offense.context.include?(counter_disable)
70
- correct_counter(corrector, processed_source, offense)
71
- else
72
- corrector.replace(offense.source_range, offense.context)
73
- end
74
+ lambda do |corrector|
75
+ if offense.context.include?(counter_disable)
76
+ correct_counter(corrector, processed_source, offense)
77
+ else
78
+ corrector.replace(offense.source_range, offense.context)
74
79
  end
75
80
  end
76
81
  end
@@ -96,7 +101,7 @@ module ERBLint
96
101
  # Override this function to customize the linter message.
97
102
  #
98
103
  # @return [String] message to show on linter error.
99
- def message(_tag)
104
+ def message(_tag, _processed_source)
100
105
  self.class::MESSAGE
101
106
  end
102
107
 
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helpers"
4
+ require_relative "autocorrectable"
5
+ require_relative "argument_mappers/label"
6
+
7
+ module ERBLint
8
+ module Linters
9
+ # Counts the number of times a HTML label is used instead of the component.
10
+ class LabelComponentMigrationCounter < Linter
11
+ include Helpers
12
+ include Autocorrectable
13
+
14
+ TAGS = Primer::ViewComponents::Constants.get(
15
+ component: "Primer::LabelComponent",
16
+ constant: "TAG_OPTIONS"
17
+ ).freeze
18
+
19
+ CLASSES = %w[Label].freeze
20
+ MESSAGE = "We are migrating labels to use [Primer::LabelComponent](https://primer.style/view-components/components/label), please try to use that instead of raw HTML."
21
+ ARGUMENT_MAPPER = ArgumentMappers::Label
22
+ COMPONENT = "Primer::LabelComponent"
23
+ end
24
+ end
25
+ end
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 48
8
+ PATCH = 52
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -10,3 +10,8 @@ Primer/SystemArgumentInsteadOfClass:
10
10
  Primer/NoTagMemoize:
11
11
  Enabled: false
12
12
 
13
+ Primer/PrimerOcticon:
14
+ Enabled: true
15
+
16
+ Primer/DeprecatedArguments:
17
+ Enabled: true
@@ -1,4 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rubocop/cop/primer/no_tag_memoize"
4
- require "rubocop/cop/primer/system_argument_instead_of_class"
3
+ Dir[File.join(__dir__, "primer", "*.rb")].sort.each { |file| require file }
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+ require "primer/view_components/statuses"
5
+ require_relative "../../../../app/lib/primer/view_helper"
6
+
7
+ # :nocov:
8
+ module RuboCop
9
+ module Cop
10
+ module Primer
11
+ # This cop ensures that components don't use deprecated arguments
12
+ #
13
+ # bad
14
+ # Component.new(foo: :deprecated)
15
+ #
16
+ # good
17
+ # Component.new(foo: :bar)
18
+ class DeprecatedArguments < RuboCop::Cop::Cop
19
+ INVALID_MESSAGE = <<~STR
20
+ Avoid using deprecated arguments: https://primer.style/view-components/deprecated.
21
+ STR
22
+
23
+ # This is a hash of deprecated arguments and their replacements.
24
+ #
25
+ # * The top level key is the argument.
26
+ # * The second level key is the value.
27
+ # * The seceond level value is a string of the full replacement. e.g. "new_argument: :new_value"
28
+ # If the value is nil, then there is no replacement.
29
+ #
30
+ # e.g.
31
+ # DEPRECATED = {
32
+ # argument: {
33
+ # value: "new_argument: :new_value"
34
+ # }
35
+ # }
36
+ #
37
+ DEPRECATED = {
38
+ color: {
39
+ blue: "color: :text_link",
40
+ gray_dark: "color: :text_primary",
41
+ gray: "color: :text_secondary",
42
+ gray_light: "color: :text_tertiary",
43
+ green: "color: :text_success",
44
+ yellow: "color: :text_warning",
45
+ red: "color: :text_danger",
46
+ gray_0: nil,
47
+ gray_1: nil,
48
+ gray_2: nil,
49
+ gray_3: nil,
50
+ gray_4: nil,
51
+ gray_5: nil,
52
+ gray_6: nil,
53
+ gray_7: nil,
54
+ gray_8: nil,
55
+ gray_9: nil,
56
+ blue_0: nil,
57
+ blue_1: nil,
58
+ blue_2: nil,
59
+ blue_3: nil,
60
+ blue_4: nil,
61
+ blue_5: nil,
62
+ blue_6: nil,
63
+ blue_7: nil,
64
+ blue_8: nil,
65
+ blue_9: nil,
66
+ green_0: nil,
67
+ green_1: nil,
68
+ green_2: nil,
69
+ green_3: nil,
70
+ green_4: nil,
71
+ green_5: nil,
72
+ green_6: nil,
73
+ green_7: nil,
74
+ green_8: nil,
75
+ green_9: nil,
76
+ yellow_0: nil,
77
+ yellow_1: nil,
78
+ yellow_2: nil,
79
+ yellow_3: nil,
80
+ yellow_4: nil,
81
+ yellow_5: nil,
82
+ yellow_6: nil,
83
+ yellow_7: nil,
84
+ yellow_8: nil,
85
+ yellow_9: nil,
86
+ red_0: nil,
87
+ red_1: nil,
88
+ red_2: nil,
89
+ red_3: nil,
90
+ red_4: nil,
91
+ red_5: nil,
92
+ red_6: nil,
93
+ red_7: nil,
94
+ red_8: nil,
95
+ red_9: nil,
96
+ purple_0: nil,
97
+ purple_1: nil,
98
+ purple_2: nil,
99
+ purple_3: nil,
100
+ purple_4: nil,
101
+ purple_5: nil,
102
+ purple_6: nil,
103
+ purple_7: nil,
104
+ purple_8: nil,
105
+ purple_9: nil,
106
+ pink_0: nil,
107
+ pink_1: nil,
108
+ pink_2: nil,
109
+ pink_3: nil,
110
+ pink_4: nil,
111
+ pink_5: nil,
112
+ pink_6: nil,
113
+ pink_7: nil,
114
+ pink_8: nil,
115
+ pink_9: nil,
116
+ orange_0: nil,
117
+ orange_1: nil,
118
+ orange_2: nil,
119
+ orange_3: nil,
120
+ orange_4: nil,
121
+ orange_5: nil,
122
+ orange_6: nil,
123
+ orange_7: nil,
124
+ orange_8: nil,
125
+ orange_9: nil
126
+ }
127
+ }.freeze
128
+
129
+ def on_send(node)
130
+ return unless valid_node?(node)
131
+ return unless node.arguments?
132
+
133
+ # we are looking for hash arguments and they are always last
134
+ kwargs = node.arguments.last
135
+
136
+ return unless kwargs.type == :hash
137
+
138
+ kwargs.pairs.each do |pair|
139
+ # Skip if we're not dealing with a symbol
140
+ next if pair.key.type != :sym
141
+ next unless pair.value.type == :sym || pair.value.type == :str
142
+
143
+ key = pair.key.value
144
+ value = pair.value.value.to_sym
145
+
146
+ next unless DEPRECATED.key?(key) && DEPRECATED[key].key?(value)
147
+
148
+ add_offense(pair, message: INVALID_MESSAGE)
149
+ end
150
+ end
151
+
152
+ def autocorrect(node)
153
+ lambda do |corrector|
154
+ replacement = DEPRECATED[node.key.value][node.value.value.to_sym]
155
+ corrector.replace(node, replacement) if replacement.present?
156
+ end
157
+ end
158
+
159
+ private
160
+
161
+ # We only verify SystemArguments if it's a `.new` call on a component or
162
+ # a ViewHleper call.
163
+ def valid_node?(node)
164
+ view_helpers.include?(node.method_name) || (node.method_name == :new && ::Primer::ViewComponents::STATUSES.key?(node.receiver.const_name))
165
+ end
166
+
167
+ def view_helpers
168
+ ::Primer::ViewHelper::HELPERS.keys.map { |key| "primer_#{key}".to_sym }
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end