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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +746 -613
- data/app/components/primer/alpha/border_box/header.rb +1 -2
- data/app/components/primer/alpha/button_marketing.rb +4 -4
- data/app/components/primer/alpha/tab_nav.rb +1 -1
- data/app/components/primer/alpha/tab_panels.rb +2 -2
- data/app/components/primer/alpha/underline_nav.rb +2 -1
- data/app/components/primer/alpha/underline_panels.rb +2 -2
- data/app/components/primer/base_component.rb +8 -36
- data/app/components/primer/beta/auto_complete/item.rb +1 -1
- data/app/components/primer/beta/auto_complete.rb +4 -2
- data/app/components/primer/beta/avatar.rb +1 -1
- data/app/components/primer/beta/blankslate.html.erb +2 -2
- data/app/components/primer/beta/blankslate.rb +7 -6
- data/app/components/primer/beta/breadcrumbs.rb +2 -2
- data/app/components/primer/beta/text.rb +1 -1
- data/app/components/primer/border_box_component.rb +1 -1
- data/app/components/primer/box_component.rb +3 -2
- data/app/components/primer/button_component.html.erb +3 -9
- data/app/components/primer/button_component.rb +61 -28
- data/app/components/primer/button_group.rb +9 -15
- data/app/components/primer/clipboard_copy.rb +1 -1
- data/app/components/primer/close_button.rb +1 -1
- data/app/components/primer/component.rb +77 -0
- data/app/components/primer/counter_component.rb +1 -1
- data/app/components/primer/details_component.rb +1 -1
- data/app/components/primer/dropdown/menu.rb +1 -1
- data/app/components/primer/dropdown.html.erb +0 -1
- data/app/components/primer/dropdown.rb +2 -1
- data/app/components/primer/dropdown_menu_component.rb +1 -1
- data/app/components/primer/flash_component.rb +3 -2
- data/app/components/primer/flex_component.rb +16 -16
- data/app/components/primer/flex_item_component.rb +1 -1
- data/app/components/primer/hellip_button.rb +1 -1
- data/app/components/primer/hidden_text_expander.rb +1 -1
- data/app/components/primer/image.rb +3 -3
- data/app/components/primer/image_crop.rb +2 -1
- data/app/components/primer/label_component.rb +23 -13
- data/app/components/primer/layout_component.rb +1 -0
- data/app/components/primer/local_time.rb +1 -1
- data/app/components/primer/markdown.rb +1 -1
- data/app/components/primer/menu_component.rb +2 -1
- data/app/components/primer/navigation/tab_component.rb +1 -0
- data/app/components/primer/octicon_component.rb +4 -2
- data/app/components/primer/octicon_symbols_component.rb +2 -2
- data/app/components/primer/popover_component.rb +3 -3
- data/app/components/primer/progress_bar_component.rb +7 -6
- data/app/components/primer/spinner_component.html.erb +4 -7
- data/app/components/primer/spinner_component.rb +1 -1
- data/app/components/primer/subhead_component.rb +3 -1
- data/app/components/primer/tab_container_component.rb +1 -1
- data/app/components/primer/time_ago_component.rb +1 -1
- data/app/components/primer/timeline_item_component.rb +4 -3
- data/app/components/primer/tooltip.rb +1 -0
- data/app/lib/primer/octicon/cache.rb +4 -10
- data/lib/primer/classify/utilities.rb +17 -44
- data/lib/primer/classify/utilities.yml +298 -68
- data/lib/primer/classify.rb +92 -178
- data/lib/primer/view_components/engine.rb +1 -0
- data/lib/primer/view_components/linters/argument_mappers/button.rb +4 -4
- data/lib/primer/view_components/linters/blankslate_api_migration.rb +11 -5
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/rubocop/cop/primer/deprecated_arguments.rb +1 -1
- data/lib/rubocop/cop/primer/deprecated_button_arguments.rb +51 -0
- data/lib/rubocop/cop/primer/deprecated_label_schemes.rb +68 -0
- data/lib/rubocop/cop/primer/deprecated_layout_component.rb +30 -0
- data/lib/rubocop/cop/primer/primer_octicon.rb +1 -3
- data/lib/tasks/custom_utilities.yml +298 -0
- data/lib/tasks/docs.rake +1 -1
- data/lib/tasks/utilities.rake +21 -4
- data/static/arguments.yml +16 -7
- data/static/classes.yml +19 -18
- data/static/constants.json +25 -15
- metadata +10 -12
- data/app/components/primer/auto_complete/auto_complete.d.ts +0 -1
- data/app/components/primer/auto_complete/auto_complete.js +0 -1
- data/app/components/primer/auto_complete/auto_component.d.ts +0 -1
- data/app/components/primer/auto_complete/auto_component.js +0 -1
- data/lib/primer/classify/cache.rb +0 -109
- data/lib/primer/classify/flex.rb +0 -111
data/lib/primer/classify.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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
|
-
|
19
|
+
FLEX_DIRECTION_VALUES = [:column, :column_reverse, :row, :row_reverse].freeze
|
97
20
|
|
98
|
-
|
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
|
-
|
106
|
-
return if classes.blank?
|
23
|
+
FLEX_ALIGN_ITEMS_VALUES = [:flex_start, :flex_end, :center, :baseline, :stretch].freeze
|
107
24
|
|
108
|
-
|
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
|
-
|
115
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
144
|
-
|
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.
|
153
|
-
style:
|
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
|
-
|
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
|
-
|
165
|
-
|
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
|
169
|
-
|
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
|
-
|
174
|
-
|
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
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
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
|
-
|
16
|
+
SIZE_MAPPINGS = Primer::ViewComponents::Constants.get(
|
17
17
|
component: "Primer::ButtonComponent",
|
18
|
-
constant: "
|
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
|
59
|
-
acc[:
|
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
|
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
|
76
|
+
new_blankslate[:slots][:description][:content] = extract_value(pair.value)
|
77
77
|
when :button_text
|
78
|
-
new_blankslate[:slots][:primary_action][:content] = pair.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
|
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
|
@@ -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
|
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
|