primer_view_components 0.0.61 → 0.0.65

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +746 -613
  3. data/app/components/primer/alpha/border_box/header.rb +1 -2
  4. data/app/components/primer/alpha/button_marketing.rb +4 -4
  5. data/app/components/primer/alpha/tab_nav.rb +1 -1
  6. data/app/components/primer/alpha/tab_panels.rb +2 -2
  7. data/app/components/primer/alpha/underline_nav.rb +2 -1
  8. data/app/components/primer/alpha/underline_panels.rb +2 -2
  9. data/app/components/primer/base_component.rb +8 -36
  10. data/app/components/primer/beta/auto_complete/item.rb +1 -1
  11. data/app/components/primer/beta/auto_complete.rb +4 -2
  12. data/app/components/primer/beta/avatar.rb +1 -1
  13. data/app/components/primer/beta/blankslate.html.erb +2 -2
  14. data/app/components/primer/beta/blankslate.rb +7 -6
  15. data/app/components/primer/beta/breadcrumbs.rb +2 -2
  16. data/app/components/primer/beta/text.rb +1 -1
  17. data/app/components/primer/border_box_component.rb +1 -1
  18. data/app/components/primer/box_component.rb +3 -2
  19. data/app/components/primer/button_component.html.erb +3 -9
  20. data/app/components/primer/button_component.rb +61 -28
  21. data/app/components/primer/button_group.rb +9 -15
  22. data/app/components/primer/clipboard_copy.rb +1 -1
  23. data/app/components/primer/close_button.rb +1 -1
  24. data/app/components/primer/component.rb +77 -0
  25. data/app/components/primer/counter_component.rb +1 -1
  26. data/app/components/primer/details_component.rb +1 -1
  27. data/app/components/primer/dropdown/menu.rb +1 -1
  28. data/app/components/primer/dropdown.html.erb +0 -1
  29. data/app/components/primer/dropdown.rb +2 -1
  30. data/app/components/primer/dropdown_menu_component.rb +1 -1
  31. data/app/components/primer/flash_component.rb +3 -2
  32. data/app/components/primer/flex_component.rb +16 -16
  33. data/app/components/primer/flex_item_component.rb +1 -1
  34. data/app/components/primer/hellip_button.rb +1 -1
  35. data/app/components/primer/hidden_text_expander.rb +1 -1
  36. data/app/components/primer/image.rb +3 -3
  37. data/app/components/primer/image_crop.rb +2 -1
  38. data/app/components/primer/label_component.rb +23 -13
  39. data/app/components/primer/layout_component.rb +1 -0
  40. data/app/components/primer/local_time.rb +1 -1
  41. data/app/components/primer/markdown.rb +1 -1
  42. data/app/components/primer/menu_component.rb +2 -1
  43. data/app/components/primer/navigation/tab_component.rb +1 -0
  44. data/app/components/primer/octicon_component.rb +4 -2
  45. data/app/components/primer/octicon_symbols_component.rb +2 -2
  46. data/app/components/primer/popover_component.rb +3 -3
  47. data/app/components/primer/progress_bar_component.rb +7 -6
  48. data/app/components/primer/spinner_component.html.erb +4 -7
  49. data/app/components/primer/spinner_component.rb +1 -1
  50. data/app/components/primer/subhead_component.rb +3 -1
  51. data/app/components/primer/tab_container_component.rb +1 -1
  52. data/app/components/primer/time_ago_component.rb +1 -1
  53. data/app/components/primer/timeline_item_component.rb +4 -3
  54. data/app/components/primer/tooltip.rb +1 -0
  55. data/app/lib/primer/octicon/cache.rb +4 -10
  56. data/lib/primer/classify/utilities.rb +17 -44
  57. data/lib/primer/classify/utilities.yml +298 -68
  58. data/lib/primer/classify.rb +92 -178
  59. data/lib/primer/view_components/engine.rb +1 -0
  60. data/lib/primer/view_components/linters/argument_mappers/button.rb +4 -4
  61. data/lib/primer/view_components/linters/blankslate_api_migration.rb +11 -5
  62. data/lib/primer/view_components/version.rb +1 -1
  63. data/lib/rubocop/cop/primer/deprecated_arguments.rb +1 -1
  64. data/lib/rubocop/cop/primer/deprecated_button_arguments.rb +51 -0
  65. data/lib/rubocop/cop/primer/deprecated_label_schemes.rb +68 -0
  66. data/lib/rubocop/cop/primer/deprecated_layout_component.rb +30 -0
  67. data/lib/rubocop/cop/primer/primer_octicon.rb +1 -3
  68. data/lib/tasks/custom_utilities.yml +298 -0
  69. data/lib/tasks/docs.rake +1 -1
  70. data/lib/tasks/utilities.rake +21 -4
  71. data/static/arguments.yml +16 -7
  72. data/static/classes.yml +19 -18
  73. data/static/constants.json +25 -15
  74. metadata +10 -12
  75. data/app/components/primer/auto_complete/auto_complete.d.ts +0 -1
  76. data/app/components/primer/auto_complete/auto_complete.js +0 -1
  77. data/app/components/primer/auto_complete/auto_component.d.ts +0 -1
  78. data/app/components/primer/auto_complete/auto_component.js +0 -1
  79. data/lib/primer/classify/cache.rb +0 -109
  80. data/lib/primer/classify/flex.rb +0 -111
@@ -1,221 +1,135 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "classify/cache"
4
- require_relative "classify/flex"
5
3
  require_relative "classify/utilities"
6
4
  require_relative "classify/validation"
7
5
 
8
6
  module Primer
9
7
  # :nodoc:
10
8
  class Classify
11
- # Keys where we can simply translate { key: value } into ".key-value"
12
- CONCAT_KEYS = %i[text box_shadow].freeze
13
-
14
- TEXT_KEYS = %i[font_family font_style font_weight text_align text_transform].freeze
15
- BOX_SHADOW_KEY = :box_shadow
16
-
17
- BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
18
-
19
- BOOLEAN_MAPPINGS = {
20
- underline: {
21
- mappings: [
22
- {
23
- value: true,
24
- css_class: "text-underline"
25
- },
26
- {
27
- value: false,
28
- css_class: "no-underline"
29
- }
30
- ]
31
- },
32
- top: {
33
- mappings: [
34
- {
35
- value: false,
36
- css_class: "top-0"
37
- }
38
- ]
39
- },
40
- bottom: {
41
- mappings: [
42
- {
43
- value: false,
44
- css_class: "bottom-0"
45
- }
46
- ]
47
- },
48
- left: {
49
- mappings: [
50
- {
51
- value: false,
52
- css_class: "left-0"
53
- }
54
- ]
55
- },
56
- right: {
57
- mappings: [
58
- {
59
- value: false,
60
- css_class: "right-0"
61
- }
62
- ]
63
- }
9
+ FLEX_VALUES = [1, :auto].freeze
10
+
11
+ FLEX_WRAP_MAPPINGS = {
12
+ wrap: "flex-wrap",
13
+ nowrap: "flex-nowrap",
14
+ reverse: "flex-wrap-reverse"
64
15
  }.freeze
65
- BORDER_KEY = :border
66
- BORDER_MARGIN_KEYS = %i[border_top border_bottom border_left border_right].freeze
67
- BORDER_RADIUS_KEY = :border_radius
68
- TYPOGRAPHY_KEYS = [:font_size].freeze
69
- VALID_KEYS = (
70
- Primer::Classify::Utilities::UTILITIES.keys +
71
- CONCAT_KEYS +
72
- BOOLEAN_MAPPINGS.keys +
73
- BORDER_MARGIN_KEYS +
74
- TYPOGRAPHY_KEYS +
75
- TEXT_KEYS +
76
- Primer::Classify::Flex::KEYS +
77
- [
78
- BORDER_KEY,
79
- BORDER_RADIUS_KEY,
80
- BOX_SHADOW_KEY
81
- ]
82
- ).freeze
83
16
 
84
- class << self
85
- def call(classes: "", style: nil, **args)
86
- extract_css_attrs(args).tap do |extracted_results|
87
- classes = +"#{validated_class_names(classes)} #{extracted_results[:class]}"
88
- classes.strip!
89
- extracted_results[:class] = presence(classes)
90
-
91
- styles = "#{extracted_results[:style]}#{style}"
92
- extracted_results[:style] = presence(styles)
93
- end
94
- end
17
+ FLEX_ALIGN_SELF_VALUES = [:auto, :start, :end, :center, :baseline, :stretch].freeze
95
18
 
96
- private
19
+ FLEX_DIRECTION_VALUES = [:column, :column_reverse, :row, :row_reverse].freeze
97
20
 
98
- # do this instead of using Rails' presence/blank?, which are a lot slower
99
- def presence(obj)
100
- # rubocop:disable Rails/Blank
101
- !obj || obj.empty? ? nil : obj
102
- # rubocop:enable Rails/Blank
103
- end
21
+ FLEX_JUSTIFY_CONTENT_VALUES = [:flex_start, :flex_end, :center, :space_between, :space_around].freeze
104
22
 
105
- def validated_class_names(classes)
106
- return if classes.blank?
23
+ FLEX_ALIGN_ITEMS_VALUES = [:flex_start, :flex_end, :center, :baseline, :stretch].freeze
107
24
 
108
- if raise_on_invalid_options? && !ENV["PRIMER_WARNINGS_DISABLED"]
109
- invalid_class_names =
110
- classes.split.each_with_object([]) do |class_name, memo|
111
- memo << class_name if Primer::Classify::Validation.invalid?(class_name)
112
- end
25
+ LOOKUP = Primer::Classify::Utilities::UTILITIES
113
26
 
114
- if invalid_class_names.any?
115
- raise ArgumentError, "Use System Arguments (https://primer.style/view-components/system-arguments) "\
116
- "instead of Primer CSS class #{'name'.pluralize(invalid_class_names.length)} #{invalid_class_names.to_sentence}. "\
117
- "This warning will not be raised in production. Set PRIMER_WARNINGS_DISABLED=1 to disable this warning."
118
- end
119
- end
120
-
121
- classes
122
- end
123
-
124
- # NOTE: This is a fairly naive implementation that we're building as we go.
125
- # Feel free to refactor as this is thoroughly tested.
27
+ class << self
28
+ # Utility for mapping component configuration into Primer CSS class names.
126
29
  #
127
- # Utility for mapping component configuration into Primer CSS class names
30
+ # **args can contain utility keys that mimic the interface used by
31
+ # https://github.com/primer/components, as well as the special entries :classes
32
+ # and :style.
128
33
  #
129
- # styles_hash - A hash with utility keys that mimic the interface used by https://github.com/primer/components
34
+ # Returns a hash containing two entries. The :classes entry is a string of
35
+ # Primer CSS class names, including any classes given in the :classes entry
36
+ # in **args. The :style entry is the value of the given :style entry given in
37
+ # **args.
130
38
  #
131
- # Returns a string of Primer CSS class names and style attributes to be added to an HTML tag.
132
39
  #
133
40
  # Example usage:
134
- # extract_css_attrs({ mt: 4, py: 2 }) => "mt-4 py-2"
135
- def extract_css_attrs(styles_hash)
136
- classes = []
137
- styles = +""
138
-
139
- styles_hash.each do |key, value|
140
- if value.is_a?(Array)
141
- raise ArgumentError, "#{key} does not support responsive values" unless Primer::Classify::Flex::RESPONSIVE_KEYS.include?(key) || Primer::Classify::Utilities.supported_key?(key)
41
+ # extract_css_attrs({ mt: 4, py: 2 }) => { classes: "mt-4 py-2", style: nil }
42
+ # extract_css_attrs(classes: "d-flex", mt: 4, py: 2) => { classes: "d-flex mt-4 py-2", style: nil }
43
+ # extract_css_attrs(classes: "d-flex", style: "float: left", mt: 4, py: 2) => { classes: "d-flex mt-4 py-2", style: "float: left" }
44
+ #
45
+ def call(args = {})
46
+ style = nil
47
+ classes = [].tap do |result|
48
+ args.each do |key, val|
49
+ case key
50
+ when :classes
51
+ # insert :classes first to avoid huge doc diffs
52
+ if (class_names = validated_class_names(val))
53
+ result.unshift(class_names)
54
+ end
55
+ next
56
+ when :style
57
+ style = val
58
+ next
59
+ end
142
60
 
143
- value.each_with_index do |val, index|
144
- extract_one_css_attr(classes, styles, key, val, BREAKPOINTS[index])
61
+ next unless LOOKUP[key]
62
+
63
+ if val.is_a?(Array)
64
+ # A while loop is ~3.5x faster than Array#each.
65
+ brk = 0
66
+ while brk < val.size
67
+ item = val[brk]
68
+
69
+ if item.nil?
70
+ brk += 1
71
+ next
72
+ end
73
+
74
+ # Believe it or not, three calls to Hash#[] and an inline rescue
75
+ # are about 30% faster than Hash#dig. It also ensures validate is
76
+ # only called when necessary, i.e. when the class can't be found
77
+ # in the lookup table.
78
+ # rubocop:disable Style/RescueModifier
79
+ found = (LOOKUP[key][item][brk] rescue nil) || validate(key, item, brk)
80
+ # rubocop:enable Style/RescueModifier
81
+ result << found if found
82
+ brk += 1
83
+ end
84
+ else
85
+ next if val.nil?
86
+
87
+ # rubocop:disable Style/RescueModifier
88
+ found = (LOOKUP[key][val][0] rescue nil) || validate(key, val, 0)
89
+ # rubocop:enable Style/RescueModifier
90
+ result << found if found
145
91
  end
146
- else
147
- extract_one_css_attr(classes, styles, key, value, BREAKPOINTS[0])
148
92
  end
149
- end
93
+ end.join(" ")
150
94
 
95
+ # This is much faster than Rails' presence method.
96
+ # rubocop:disable Rails/Blank
151
97
  {
152
- class: classes.join(" "),
153
- style: styles
98
+ class: !classes || classes.empty? ? nil : classes,
99
+ style: !style || style.empty? ? nil : style
154
100
  }
101
+ # rubocop:enable Rails/Blank
155
102
  end
156
103
 
157
- def extract_one_css_attr(classes, styles, key, val, breakpoint)
158
- found_classes = Primer::Classify::Cache.instance.fetch(breakpoint, key, val) do
159
- classes_from(key, val, breakpoint)
160
- end
161
-
162
- classes << found_classes if found_classes
104
+ private
163
105
 
164
- found_styles = styles_from(key, val, breakpoint)
165
- styles << found_styles if found_styles
106
+ def validate(key, val, brk)
107
+ brk_str = Primer::Classify::Utilities::BREAKPOINTS[brk]
108
+ Primer::Classify::Utilities.validate(key, val, brk_str)
166
109
  end
167
110
 
168
- def styles_from(key, val, _breakpoint)
169
- # Turn this into an if/else like classes_from when we have more branches.
170
- # Could be that way now, but it makes Rubocop unhappy.
171
- end
111
+ def validated_class_names(classes)
112
+ return if classes.blank?
172
113
 
173
- def classes_from(key, val, breakpoint)
174
- return if val.nil? || val == ""
114
+ if raise_on_invalid_options? && !ENV["PRIMER_WARNINGS_DISABLED"]
115
+ invalid_class_names =
116
+ classes.split.each_with_object([]) do |class_name, memo|
117
+ memo << class_name if Primer::Classify::Validation.invalid?(class_name)
118
+ end
175
119
 
176
- if Primer::Classify::Utilities.supported_key?(key)
177
- Primer::Classify::Utilities.classname(key, val, breakpoint)
178
- elsif BOOLEAN_MAPPINGS.key?(key)
179
- bools = BOOLEAN_MAPPINGS[key][:mappings].each_with_object([]) do |m, memo|
180
- memo << m[:css_class] if m[:value] == val && m[:css_class].present?
181
- end
182
- bools.empty? ? nil : bools.join(" ")
183
- elsif key == BORDER_KEY
184
- if val == true
185
- "border"
186
- else
187
- "border-#{val.to_s.dasherize}"
188
- end
189
- elsif BORDER_MARGIN_KEYS.include?(key)
190
- "#{key.to_s.dasherize}-#{val}"
191
- elsif key == BORDER_RADIUS_KEY
192
- "rounded-#{val}"
193
- elsif Primer::Classify::Flex::KEYS.include?(key)
194
- Primer::Classify::Flex.classes(key, val, breakpoint)
195
- elsif TEXT_KEYS.include?(key)
196
- "text-#{val.to_s.dasherize}"
197
- elsif TYPOGRAPHY_KEYS.include?(key)
198
- if val == :small || val == :normal
199
- "text-#{val.to_s.dasherize}"
200
- else
201
- "f#{val.to_s.dasherize}"
202
- end
203
- elsif key == BOX_SHADOW_KEY
204
- if val == true
205
- "color-shadow-small"
206
- elsif val == :none || val.blank?
207
- "box-shadow-none"
208
- else
209
- "color-shadow-#{val.to_s.dasherize}"
120
+ if invalid_class_names.any?
121
+ raise ArgumentError, "Use System Arguments (https://primer.style/view-components/system-arguments) "\
122
+ "instead of Primer CSS class #{'name'.pluralize(invalid_class_names.length)} #{invalid_class_names.to_sentence}. "\
123
+ "This warning will not be raised in production. Set PRIMER_WARNINGS_DISABLED=1 to disable this warning."
210
124
  end
211
125
  end
126
+
127
+ classes
212
128
  end
213
129
 
214
130
  def raise_on_invalid_options?
215
131
  Rails.application.config.primer_view_components.raise_on_invalid_options
216
132
  end
217
133
  end
218
-
219
- Cache.instance.preload!
220
134
  end
221
135
  end
@@ -18,6 +18,7 @@ module Primer
18
18
  config.primer_view_components.raise_on_invalid_options = false
19
19
  config.primer_view_components.silence_deprecations = false
20
20
  config.primer_view_components.validate_class_names = !Rails.env.production?
21
+ config.primer_view_components.raise_on_invalid_aria = false
21
22
 
22
23
  initializer "primer_view_components.assets" do |app|
23
24
  app.config.assets.precompile += %w[primer_view_components] if app.config.respond_to?(:assets)
@@ -13,9 +13,9 @@ module ERBLint
13
13
  symbolize: true
14
14
  ).freeze
15
15
 
16
- VARIANT_MAPPINGS = Primer::ViewComponents::Constants.get(
16
+ SIZE_MAPPINGS = Primer::ViewComponents::Constants.get(
17
17
  component: "Primer::ButtonComponent",
18
- constant: "VARIANT_MAPPINGS",
18
+ constant: "SIZE_MAPPINGS",
19
19
  symbolize: true
20
20
  ).freeze
21
21
 
@@ -55,8 +55,8 @@ module ERBLint
55
55
 
56
56
  if SCHEME_MAPPINGS[class_name] && acc[:scheme].nil?
57
57
  acc[:scheme] = SCHEME_MAPPINGS[class_name]
58
- elsif VARIANT_MAPPINGS[class_name] && acc[:variant].nil?
59
- acc[:variant] = VARIANT_MAPPINGS[class_name]
58
+ elsif SIZE_MAPPINGS[class_name] && acc[:size].nil?
59
+ acc[:size] = SIZE_MAPPINGS[class_name]
60
60
  elsif class_name == "btn-block"
61
61
  acc[:block] = true
62
62
  elsif class_name == "BtnGroup-item"
@@ -17,7 +17,7 @@ module ERBLint
17
17
 
18
18
  next unless code.include?("Primer::BlankslateComponent")
19
19
  # Don't fix custom blankslates
20
- next if code.end_with?("do")
20
+ next if code.end_with?("do", "|")
21
21
 
22
22
  line = erb_node.loc.source_line
23
23
  indent = line.split("<%=").first.size
@@ -61,7 +61,7 @@ module ERBLint
61
61
 
62
62
  case pair.key.value.to_sym
63
63
  when :title
64
- new_blankslate[:slots][:heading][:content] = pair.value.value
64
+ new_blankslate[:slots][:heading][:content] = extract_value(pair.value)
65
65
  when :title_tag
66
66
  new_blankslate[:slots][:heading][:tag] = source_value
67
67
  when :icon
@@ -73,15 +73,15 @@ module ERBLint
73
73
  when :image_alt
74
74
  new_blankslate[:slots][:visual_image][:alt] = source_value
75
75
  when :description
76
- new_blankslate[:slots][:description][:content] = pair.value.value
76
+ new_blankslate[:slots][:description][:content] = extract_value(pair.value)
77
77
  when :button_text
78
- new_blankslate[:slots][:primary_action][:content] = pair.value.value
78
+ new_blankslate[:slots][:primary_action][:content] = extract_value(pair.value)
79
79
  when :button_url
80
80
  new_blankslate[:slots][:primary_action][:href] = source_value
81
81
  when :button_classes
82
82
  new_blankslate[:slots][:primary_action][:classes] = source_value
83
83
  when :link_text
84
- new_blankslate[:slots][:secondary_action][:content] = pair.value.value
84
+ new_blankslate[:slots][:secondary_action][:content] = extract_value(pair.value)
85
85
  when :link_url
86
86
  new_blankslate[:slots][:secondary_action][:href] = source_value
87
87
  when :large
@@ -141,6 +141,12 @@ module ERBLint
141
141
 
142
142
  "(#{string_args})"
143
143
  end
144
+
145
+ def extract_value(value)
146
+ return value.value if value.type == :str
147
+
148
+ "<%= #{value.source} %>"
149
+ end
144
150
  end
145
151
  end
146
152
  end
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 61
8
+ PATCH = 65
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -22,7 +22,7 @@ module RuboCop
22
22
  #
23
23
  # * The top level key is the argument.
24
24
  # * The second level key is the value.
25
- # * The seceond level value is a string of the full replacement. e.g. "new_argument: :new_value"
25
+ # * The second level value is a string of the full replacement. e.g. "new_argument: :new_value"
26
26
  # If the value is nil, then there is no replacement.
27
27
  #
28
28
  # e.g.
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ # :nocov:
6
+ module RuboCop
7
+ module Cop
8
+ module Primer
9
+ # This cop ensures that `ButtonComponent` doesn't use deprecated arguments.
10
+ #
11
+ # bad
12
+ # ButtonComponent.new(variant: :small)
13
+ #
14
+ # good
15
+ # ButtonComponent.new(size: :small)
16
+ class DeprecatedButtonArguments < BaseCop
17
+ INVALID_MESSAGE = <<~STR
18
+ `variant` is deprecated. Use `size` instead.
19
+ STR
20
+
21
+ def_node_matcher :button_component?, <<~PATTERN
22
+ (send (const (const nil? :Primer) :ButtonComponent) :new ...)
23
+ PATTERN
24
+
25
+ DEPRECATIONS = {
26
+ variant: :size
27
+ }.freeze
28
+
29
+ def on_send(node)
30
+ return unless button_component?(node)
31
+
32
+ kwargs = node.arguments.last
33
+
34
+ return if kwargs.nil?
35
+
36
+ pair = kwargs.pairs.find { |x| x.key.value == :variant }
37
+
38
+ return if pair.nil?
39
+
40
+ add_offense(pair.key, message: INVALID_MESSAGE)
41
+ end
42
+
43
+ def autocorrect(node)
44
+ lambda do |corrector|
45
+ corrector.replace(node, DEPRECATIONS[node.value])
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ # :nocov:
6
+ module RuboCop
7
+ module Cop
8
+ module Primer
9
+ # This cop ensures that components don't use deprecated `Label` schemes.
10
+ #
11
+ # bad
12
+ # Primer::LabelComponent.new(scheme: :info)
13
+ #
14
+ # good
15
+ # Primer::LabelComponent.new(scheme: :accent)
16
+ class DeprecatedLabelSchemes < BaseCop
17
+ INVALID_MESSAGE = <<~STR
18
+ Avoid using deprecated schemes: https://primer.style/view-components/deprecated#labelcomponent.
19
+ STR
20
+
21
+ # This is a hash of deprecated schemes and their replacements.
22
+ DEPRECATIONS = {
23
+ info: ":accent",
24
+ warning: ":attention",
25
+ orange: ":severe",
26
+ purple: ":done"
27
+ }.freeze
28
+
29
+ def on_send(node)
30
+ return unless label_node?(node)
31
+ return unless node.arguments?
32
+
33
+ # we are looking for hash arguments and they are always last
34
+ kwargs = node.arguments.last
35
+
36
+ return unless kwargs.type == :hash
37
+
38
+ kwargs.pairs.each do |pair|
39
+ # Skip if we're not dealing with a symbol
40
+ next if pair.key.type != :sym
41
+ next unless pair.value.type == :sym || pair.value.type == :str
42
+
43
+ value = pair.value.value.to_sym
44
+
45
+ next unless DEPRECATIONS.key?(value)
46
+
47
+ add_offense(pair.value, message: INVALID_MESSAGE)
48
+ end
49
+ end
50
+
51
+ def autocorrect(node)
52
+ lambda do |corrector|
53
+ replacement = DEPRECATIONS[node.value.to_sym]
54
+ corrector.replace(node, replacement)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def label_node?(node)
61
+ return if node.nil?
62
+
63
+ node.method_name == :new && !node.receiver.nil? && node.receiver.const_name == "Primer::LabelComponent"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Primer
8
+ # This cop ensures that the deprecated `Primer::LayoutComponent` isn't used.
9
+ #
10
+ # bad
11
+ # Primer::LayoutComponent.new(foo: :deprecated)
12
+ #
13
+ # good
14
+ # Primer::Alpha::Layout.new(foo: :deprecated)
15
+ class DeprecatedLayoutComponent < BaseCop
16
+ MSG = "Please try Primer::Alpha::Layout instead."
17
+
18
+ def_node_matcher :legacy_component?, <<~PATTERN
19
+ (send (const (const nil? :Primer) :LayoutComponent) :new ...)
20
+ PATTERN
21
+
22
+ def on_send(node)
23
+ return unless legacy_component?(node)
24
+
25
+ add_offense(node, message: MSG)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -163,9 +163,7 @@ module RuboCop
163
163
 
164
164
  color = case args[:color]
165
165
  when :text_white
166
- :text_white
167
- when :text_link
168
- :icon_info
166
+ :on_emphasis
169
167
  when Symbol
170
168
  args[:color].to_s.gsub("text_", "icon_").to_sym
171
169
  end