primer_view_components 0.0.61 → 0.0.65
Sign up to get free protection for your applications and to get access to all the features.
- 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
|