primer_view_components 0.0.59 → 0.0.60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/components/primer/alpha/border_box/header.html.erb +4 -0
  6. data/app/components/primer/alpha/border_box/header.rb +51 -0
  7. data/app/components/primer/alpha/tab_nav.rb +1 -2
  8. data/app/components/primer/base_component.rb +2 -2
  9. data/app/components/primer/beta/avatar.rb +18 -11
  10. data/app/components/primer/beta/breadcrumbs.rb +7 -0
  11. data/app/components/primer/border_box_component.rb +8 -12
  12. data/app/components/primer/clipboard_copy.html.erb +1 -1
  13. data/app/components/primer/component.rb +1 -0
  14. data/app/components/primer/label_component.rb +7 -7
  15. data/app/components/primer/markdown.rb +0 -10
  16. data/app/components/primer/spinner_component.html.erb +7 -4
  17. data/app/components/primer/timeline_item_component.rb +2 -2
  18. data/app/lib/primer/audited/dsl.rb +32 -0
  19. data/lib/primer/classify/cache.rb +0 -16
  20. data/lib/primer/classify/utilities.rb +13 -6
  21. data/lib/primer/classify/utilities.yml +199 -22
  22. data/lib/primer/classify.rb +2 -9
  23. data/lib/primer/view_components/engine.rb +6 -0
  24. data/lib/primer/view_components/linters/blankslate_component_migration_counter.rb +14 -0
  25. data/lib/primer/view_components/linters/subhead_component_migration_counter.rb +14 -0
  26. data/lib/primer/view_components/version.rb +1 -1
  27. data/lib/primer/view_components.rb +17 -29
  28. data/lib/rubocop/cop/primer/deprecated_arguments.rb +35 -1
  29. data/lib/rubocop/cop/primer/primer_octicon.rb +25 -4
  30. data/lib/tasks/docs.rake +2 -0
  31. data/lib/tasks/helpers/ast_processor.rb +44 -0
  32. data/lib/tasks/helpers/ast_traverser.rb +77 -0
  33. data/lib/tasks/primer_view_components.rake +47 -0
  34. data/lib/tasks/{constants.rake → static.rake} +5 -2
  35. data/lib/tasks/utilities.rake +40 -26
  36. data/static/arguments.yml +36 -5
  37. data/static/audited_at.json +61 -0
  38. data/static/classes.yml +3 -0
  39. data/static/constants.json +26 -0
  40. data/static/statuses.json +1 -0
  41. metadata +14 -7
  42. data/lib/primer/classify/grid.rb +0 -45
  43. data/lib/tasks/statuses.rake +0 -12
@@ -23,6 +23,30 @@
23
23
  :rotate:
24
24
  - anim-rotate
25
25
  :color:
26
+ :default:
27
+ - color-fg-default
28
+ :muted:
29
+ - color-fg-muted
30
+ :subtle:
31
+ - color-fg-subtle
32
+ :accent:
33
+ - color-fg-accent
34
+ :success:
35
+ - color-fg-success
36
+ :attention:
37
+ - color-fg-attention
38
+ :severe:
39
+ - color-fg-severe
40
+ :danger:
41
+ - color-fg-danger
42
+ :done:
43
+ - color-fg-done
44
+ :sponsors:
45
+ - color-fg-sponsors
46
+ :on_emphasis:
47
+ - color-fg-on-emphasis
48
+ :inherit:
49
+ - color-fg-inherit
26
50
  :text_primary:
27
51
  - color-text-primary
28
52
  :text_secondary:
@@ -55,24 +79,45 @@
55
79
  - color-icon-success
56
80
  :icon_warning:
57
81
  - color-icon-warning
58
- :border_color:
59
- :primary:
60
- - color-border-primary
61
- :secondary:
62
- - color-border-secondary
63
- :tertiary:
64
- - color-border-tertiary
65
- :inverse:
66
- - color-border-inverse
67
- :info:
68
- - color-border-info
82
+ :bg:
83
+ :default:
84
+ - color-bg-default
85
+ :overlay:
86
+ - color-bg-overlay
87
+ :inset:
88
+ - color-bg-inset
89
+ :subtle:
90
+ - color-bg-subtle
91
+ :emphasis:
92
+ - color-bg-emphasis
93
+ :accent:
94
+ - color-bg-accent
95
+ :accent_emphasis:
96
+ - color-bg-accent-emphasis
69
97
  :success:
70
- - color-border-success
98
+ - color-bg-success
99
+ :success_emphasis:
100
+ - color-bg-success-emphasis
101
+ :attention:
102
+ - color-bg-attention
103
+ :attention_emphasis:
104
+ - color-bg-attention-emphasis
105
+ :severe:
106
+ - color-bg-severe
107
+ :severe_emphasis:
108
+ - color-bg-severe-emphasis
71
109
  :danger:
72
- - color-border-danger
73
- :warning:
74
- - color-border-warning
75
- :bg:
110
+ - color-bg-danger
111
+ :danger_emphasis:
112
+ - color-bg-danger-emphasis
113
+ :done:
114
+ - color-bg-done
115
+ :done_emphasis:
116
+ - color-bg-done-emphasis
117
+ :sponsors:
118
+ - color-bg-sponsors
119
+ :sponsors_emphasis:
120
+ - color-bg-sponsors-emphasis
76
121
  :canvas:
77
122
  - color-bg-canvas
78
123
  :canvas_inverse:
@@ -85,24 +130,65 @@
85
130
  - color-bg-secondary
86
131
  :tertiary:
87
132
  - color-bg-tertiary
88
- :overlay:
89
- - color-bg-overlay
90
133
  :info:
91
134
  - color-bg-info
92
135
  :info_inverse:
93
136
  - color-bg-info-inverse
94
- :danger:
95
- - color-bg-danger
96
137
  :danger_inverse:
97
138
  - color-bg-danger-inverse
98
- :success:
99
- - color-bg-success
100
139
  :success_inverse:
101
140
  - color-bg-success-inverse
102
141
  :warning:
103
142
  - color-bg-warning
104
143
  :warning_inverse:
105
144
  - color-bg-warning-inverse
145
+ :border_color:
146
+ :default:
147
+ - color-border-default
148
+ :muted:
149
+ - color-border-muted
150
+ :subtle:
151
+ - color-border-subtle
152
+ :accent:
153
+ - color-border-accent
154
+ :accent_emphasis:
155
+ - color-border-accent-emphasis
156
+ :success:
157
+ - color-border-success
158
+ :success_emphasis:
159
+ - color-border-success-emphasis
160
+ :attention:
161
+ - color-border-attention
162
+ :attention_emphasis:
163
+ - color-border-attention-emphasis
164
+ :severe:
165
+ - color-border-severe
166
+ :severe_emphasis:
167
+ - color-border-severe-emphasis
168
+ :danger:
169
+ - color-border-danger
170
+ :danger_emphasis:
171
+ - color-border-danger-emphasis
172
+ :done:
173
+ - color-border-done
174
+ :done_emphasis:
175
+ - color-border-done-emphasis
176
+ :sponsors:
177
+ - color-border-sponsors
178
+ :sponsors_emphasis:
179
+ - color-border-sponsors-emphasis
180
+ :primary:
181
+ - color-border-primary
182
+ :secondary:
183
+ - color-border-secondary
184
+ :tertiary:
185
+ - color-border-tertiary
186
+ :inverse:
187
+ - color-border-inverse
188
+ :info:
189
+ - color-border-info
190
+ :warning:
191
+ - color-border-warning
106
192
  :position:
107
193
  :static:
108
194
  - position-static
@@ -147,6 +233,9 @@
147
233
  - v-align-text-bottom
148
234
  :baseline:
149
235
  - v-align-baseline
236
+ :clearfix:
237
+ true:
238
+ - clearfix
150
239
  :float:
151
240
  :left:
152
241
  - float-left
@@ -531,6 +620,8 @@
531
620
  - mb-md-n12
532
621
  - mb-lg-n12
533
622
  - mb-xl-n12
623
+ :auto:
624
+ - mb-auto
534
625
  :mr:
535
626
  0:
536
627
  - mr-0
@@ -610,6 +701,8 @@
610
701
  - mr-md-n6
611
702
  - mr-lg-n6
612
703
  - mr-xl-n6
704
+ :auto:
705
+ - mr-auto
613
706
  :ml:
614
707
  0:
615
708
  - ml-0
@@ -689,6 +782,8 @@
689
782
  - ml-md-n6
690
783
  - ml-lg-n6
691
784
  - ml-xl-n6
785
+ :auto:
786
+ - ml-auto
692
787
  :mx:
693
788
  0:
694
789
  - mx-0
@@ -1368,3 +1463,85 @@
1368
1463
  - hide-lg
1369
1464
  :xl:
1370
1465
  - hide-xl
1466
+ :container:
1467
+ :sm:
1468
+ - container-sm
1469
+ :md:
1470
+ - container-md
1471
+ :lg:
1472
+ - container-lg
1473
+ :xl:
1474
+ - container-xl
1475
+ :col:
1476
+ 1:
1477
+ - col-1
1478
+ - col-sm-1
1479
+ - col-md-1
1480
+ - col-lg-1
1481
+ - col-xl-1
1482
+ 2:
1483
+ - col-2
1484
+ - col-sm-2
1485
+ - col-md-2
1486
+ - col-lg-2
1487
+ - col-xl-2
1488
+ 3:
1489
+ - col-3
1490
+ - col-sm-3
1491
+ - col-md-3
1492
+ - col-lg-3
1493
+ - col-xl-3
1494
+ 4:
1495
+ - col-4
1496
+ - col-sm-4
1497
+ - col-md-4
1498
+ - col-lg-4
1499
+ - col-xl-4
1500
+ 5:
1501
+ - col-5
1502
+ - col-sm-5
1503
+ - col-md-5
1504
+ - col-lg-5
1505
+ - col-xl-5
1506
+ 6:
1507
+ - col-6
1508
+ - col-sm-6
1509
+ - col-md-6
1510
+ - col-lg-6
1511
+ - col-xl-6
1512
+ 7:
1513
+ - col-7
1514
+ - col-sm-7
1515
+ - col-md-7
1516
+ - col-lg-7
1517
+ - col-xl-7
1518
+ 8:
1519
+ - col-8
1520
+ - col-sm-8
1521
+ - col-md-8
1522
+ - col-lg-8
1523
+ - col-xl-8
1524
+ 9:
1525
+ - col-9
1526
+ - col-sm-9
1527
+ - col-md-9
1528
+ - col-lg-9
1529
+ - col-xl-9
1530
+ 10:
1531
+ - col-10
1532
+ - col-sm-10
1533
+ - col-md-10
1534
+ - col-lg-10
1535
+ - col-xl-10
1536
+ 11:
1537
+ - col-11
1538
+ - col-sm-11
1539
+ - col-md-11
1540
+ - col-lg-11
1541
+ - col-xl-11
1542
+ 12:
1543
+ - col-12
1544
+ - col-sm-12
1545
+ - col-md-12
1546
+ - col-lg-12
1547
+ - col-xl-12
@@ -2,7 +2,6 @@
2
2
 
3
3
  require_relative "classify/cache"
4
4
  require_relative "classify/flex"
5
- require_relative "classify/grid"
6
5
  require_relative "classify/utilities"
7
6
  require_relative "classify/validation"
8
7
 
@@ -14,10 +13,8 @@ module Primer
14
13
 
15
14
  TEXT_KEYS = %i[font_family font_style font_weight text_align text_transform].freeze
16
15
  BOX_SHADOW_KEY = :box_shadow
17
- CONTAINER_KEY = :container
18
16
 
19
17
  BREAKPOINTS = ["", "-sm", "-md", "-lg", "-xl"].freeze
20
- RESPONSIVE_KEYS = ([Primer::Classify::Grid::COL_KEY] + Primer::Classify::Flex::RESPONSIVE_KEYS).freeze
21
18
 
22
19
  BOOLEAN_MAPPINGS = {
23
20
  underline: {
@@ -77,12 +74,10 @@ module Primer
77
74
  TYPOGRAPHY_KEYS +
78
75
  TEXT_KEYS +
79
76
  Primer::Classify::Flex::KEYS +
80
- Primer::Classify::Grid::KEYS +
81
77
  [
82
78
  BORDER_KEY,
83
79
  BORDER_RADIUS_KEY,
84
- BOX_SHADOW_KEY,
85
- CONTAINER_KEY
80
+ BOX_SHADOW_KEY
86
81
  ]
87
82
  ).freeze
88
83
 
@@ -143,7 +138,7 @@ module Primer
143
138
 
144
139
  styles_hash.each do |key, value|
145
140
  if value.is_a?(Array)
146
- raise ArgumentError, "#{key} does not support responsive values" unless RESPONSIVE_KEYS.include?(key) || Primer::Classify::Utilities.supported_key?(key)
141
+ raise ArgumentError, "#{key} does not support responsive values" unless Primer::Classify::Flex::RESPONSIVE_KEYS.include?(key) || Primer::Classify::Utilities.supported_key?(key)
147
142
 
148
143
  value.each_with_index do |val, index|
149
144
  extract_one_css_attr(classes, styles, key, val, BREAKPOINTS[index])
@@ -197,8 +192,6 @@ module Primer
197
192
  "rounded-#{val}"
198
193
  elsif Primer::Classify::Flex::KEYS.include?(key)
199
194
  Primer::Classify::Flex.classes(key, val, breakpoint)
200
- elsif Primer::Classify::Grid::KEYS.include?(key)
201
- Primer::Classify::Grid.classes(key, val, breakpoint)
202
195
  elsif TEXT_KEYS.include?(key)
203
196
  "text-#{val.to_s.dasherize}"
204
197
  elsif TYPOGRAPHY_KEYS.include?(key)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/engine"
4
+ require "primer/classify/utilities"
4
5
 
5
6
  module Primer
6
7
  module ViewComponents
@@ -16,10 +17,15 @@ module Primer
16
17
 
17
18
  config.primer_view_components.force_system_arguments = false
18
19
  config.primer_view_components.silence_deprecations = false
20
+ config.primer_view_components.validate_class_names = !Rails.env.production?
19
21
 
20
22
  initializer "primer_view_components.assets" do |app|
21
23
  app.config.assets.precompile += %w[primer_view_components] if app.config.respond_to?(:assets)
22
24
  end
25
+
26
+ config.after_initialize do |app|
27
+ ::Primer::Classify::Utilities.validate_class_names = app.config.primer_view_components.delete(:validate_class_names)
28
+ end
23
29
  end
24
30
  end
25
31
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_linter"
4
+
5
+ module ERBLint
6
+ module Linters
7
+ # Counts the number of times a HTML Blankslate is used instead of the component.
8
+ class BlankslateComponentMigrationCounter < BaseLinter
9
+ MESSAGE = "We are migrating Blankslate to use [Primer::BlankslateComponent](https://primer.style/view-components/components/blankslate), please try to use that instead of raw HTML."
10
+ CLASSES = %w[blankslate].freeze
11
+ TAGS = %w[div].freeze
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_linter"
4
+
5
+ module ERBLint
6
+ module Linters
7
+ # Counts the number of times a HTML Subhead is used instead of the component.
8
+ class SubheadComponentMigrationCounter < BaseLinter
9
+ MESSAGE = "We are migrating Subhead to use [Primer::SubheadComponent](https://primer.style/view-components/components/subhead), please try to use that instead of raw HTML."
10
+ CLASSES = %w[Subhead].freeze
11
+ TAGS = %w[div].freeze
12
+ end
13
+ end
14
+ end
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 59
8
+ PATCH = 60
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -8,8 +8,11 @@ module Primer
8
8
  # :nodoc:
9
9
  module ViewComponents
10
10
  DEFAULT_STATIC_PATH = File.expand_path("static")
11
- DEFAULT_STATUS_FILE_NAME = "statuses.json"
12
- DEFAULT_CONSTANTS_FILE_NAME = "constants.json"
11
+ FILE_NAMES = {
12
+ statuses: "statuses.json",
13
+ constants: "constants.json",
14
+ audited_at: "audited_at.json"
15
+ }.freeze
13
16
 
14
17
  # generate_statuses returns a hash mapping component name to
15
18
  # the component's status sorted alphabetically by the component name.
@@ -19,25 +22,14 @@ module Primer
19
22
  end
20
23
  end
21
24
 
22
- # dump_statuses generates the status hash and then serializes
23
- # it as json at the given path
24
- def self.dump_statuses(path: DEFAULT_STATIC_PATH)
25
- require "json"
26
-
27
- statuses = generate_statuses
28
-
29
- File.open(File.join(path, DEFAULT_STATUS_FILE_NAME), "w") do |f|
30
- f.write(JSON.pretty_generate(statuses))
31
- f.write($INPUT_RECORD_SEPARATOR)
25
+ # generate_audited_at returns a hash mapping component name to
26
+ # the day the component has passed an accessibility audit.
27
+ def self.generate_audited_at
28
+ Primer::Component.descendants.sort_by(&:name).each_with_object({}) do |component, mem|
29
+ mem[component.to_s] = component.audited_at.to_s
32
30
  end
33
31
  end
34
32
 
35
- # read_statuses returns a JSON string matching the output of
36
- # generate_statuses
37
- def self.read_statuses(path: DEFAULT_STATIC_PATH)
38
- File.read(File.join(path, DEFAULT_STATUS_FILE_NAME))
39
- end
40
-
41
33
  # generate_constants returns a hash mapping component name to
42
34
  # all of its constants.
43
35
  def self.generate_constants
@@ -48,23 +40,19 @@ module Primer
48
40
  end
49
41
  end
50
42
 
51
- # dump_constants generates the constants hash and then serializes
52
- # it as json at the given path
53
- def self.dump_constants(path: DEFAULT_STATIC_PATH)
43
+ # dump generates the requested stat hash and outputs it to a file.
44
+ def self.dump(stats)
54
45
  require "json"
55
46
 
56
- constants = generate_constants
57
-
58
- File.open(File.join(path, DEFAULT_CONSTANTS_FILE_NAME), "w") do |f|
59
- f.write(JSON.pretty_generate(constants))
47
+ File.open(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[stats]), "w") do |f|
48
+ f.write(JSON.pretty_generate(send("generate_#{stats}")))
60
49
  f.write($INPUT_RECORD_SEPARATOR)
61
50
  end
62
51
  end
63
52
 
64
- # read_constants returns a JSON string matching the output of
65
- # generate_constants
66
- def self.read_constants(path: DEFAULT_STATIC_PATH)
67
- File.read(File.join(path, DEFAULT_CONSTANTS_FILE_NAME))
53
+ # read returns a JSON string matching the output of the corresponding stat.
54
+ def self.read(stats)
55
+ File.read(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[stats]))
68
56
  end
69
57
  end
70
58
  end
@@ -46,6 +46,18 @@ module RuboCop
46
46
  yellow: "bg: :warning_inverse",
47
47
  red_light: "bg: :danger",
48
48
  red: "bg: :danger_inverse",
49
+ canvas: "bg: :default",
50
+ canvas_inverse: "bg: :emphasis",
51
+ canvas_inset: "bg: :inset",
52
+ primary: "bg: :default",
53
+ secondary: "bg: :subtle",
54
+ tertiary: "bg: :subtle",
55
+ info: "bg: :accent",
56
+ info_inverse: "bg: :accent_emphasis",
57
+ danger_inverse: "bg: :danger_emphasis",
58
+ success_inverse: "bg: :success_emphasis",
59
+ warning: "bg: :attention",
60
+ warning_inverse: "bg: :attention_emphasis",
49
61
  gray_0: nil,
50
62
  gray_1: nil,
51
63
  gray_2: nil,
@@ -140,9 +152,31 @@ module RuboCop
140
152
  green: "border_color: :success",
141
153
  yellow: "border_color: :warning",
142
154
  red: "border_color: :danger",
143
- white: "border_color: :inverse"
155
+ white: "border_color: :inverse",
156
+ primary: "border_color: :default",
157
+ secondary: "border_color: :muted",
158
+ tertiary: "border_color: :default",
159
+ inverse: nil,
160
+ info: "border_color: :accent_emphasis",
161
+ warning: "border_color: :attention_emphasis"
144
162
  },
145
163
  color: {
164
+ text_primary: "color: :default",
165
+ text_secondary: "color: :muted",
166
+ text_tertiary: "color: :muted",
167
+ text_link: "color: :accent",
168
+ text_success: "color: :success",
169
+ text_warning: "color: :attention",
170
+ text_danger: "color: :danger",
171
+ text_inverse: "color: :on_emphasis",
172
+ text_white: "color: :on_emphasis",
173
+ icon_primary: "color: :default",
174
+ icon_secondary: "color: :muted",
175
+ icon_tertiary: "color: :muted",
176
+ icon_info: "color: :accent",
177
+ icon_danger: "color: :danger",
178
+ icon_success: "color: :success",
179
+ icon_warning: "color: :attention",
146
180
  blue: "color: :text_link",
147
181
  gray_dark: "color: :text_primary",
148
182
  gray: "color: :text_secondary",
@@ -29,7 +29,8 @@ module RuboCop
29
29
 
30
30
  SIZE_ATTRIBUTES = %w[height width size].freeze
31
31
  STRING_ATTRIBUTES = %w[aria- data-].freeze
32
- VALID_ATTRIBUTES = [*SIZE_ATTRIBUTES, *STRING_ATTRIBUTES, "class"].freeze
32
+ REST_ATTRIBUTES = %w[title].freeze
33
+ VALID_ATTRIBUTES = [*SIZE_ATTRIBUTES, *STRING_ATTRIBUTES, *REST_ATTRIBUTES, "class"].freeze
33
34
 
34
35
  STRING_ATTRIBUTE_REGEX = Regexp.union(STRING_ATTRIBUTES).freeze
35
36
  ATTRIBUTE_REGEX = Regexp.union(VALID_ATTRIBUTES).freeze
@@ -74,7 +75,9 @@ module RuboCop
74
75
  # Converting arguments for the component
75
76
  classes = classes(kwargs)
76
77
  size_attributes = transform_sizes(kwargs)
77
- args = arguments_as_string(node, size_attributes, classes)
78
+ rest_attributes = rest_args(kwargs)
79
+
80
+ args = arguments_as_string(node, size_attributes, rest_attributes, classes)
78
81
  if node.dot?
79
82
  corrector.replace(node.loc.expression, "#{node.receiver.source}.primer_octicon(#{args})")
80
83
  else
@@ -99,6 +102,14 @@ module RuboCop
99
102
  end
100
103
  end
101
104
 
105
+ def rest_args(kwargs)
106
+ kwargs.pairs.each_with_object({}) do |pair, h|
107
+ next unless REST_ATTRIBUTES.include?(pair.key.value.to_s)
108
+
109
+ h[pair.key.value] = pair.value.source
110
+ end
111
+ end
112
+
102
113
  def octicon_size_attributes(kwargs)
103
114
  kwargs.pairs.each_with_object({}) do |pair, h|
104
115
  next unless SIZE_ATTRIBUTES.include?(pair.key.value.to_s)
@@ -125,18 +136,28 @@ module RuboCop
125
136
  class_arg.value.value
126
137
  end
127
138
 
128
- def arguments_as_string(node, size_attributes, classes)
139
+ def arguments_as_string(node, size_attributes, rest_attributes, classes)
129
140
  args = icon(node.arguments.first)
130
141
  size_args = size_attributes_to_string(size_attributes)
131
142
  string_args = string_args_to_string(node)
143
+ rest_args = rest_args_to_string(rest_attributes)
132
144
 
133
- args = "#{args}, #{size_attributes_to_string(size_attributes)}" if size_args.present?
145
+ args = "#{args}, #{size_args}" if size_args.present?
146
+ args = "#{args}, #{rest_args}" if rest_args.present?
134
147
  args = "#{args}, #{utilities_args(classes)}" if classes.present?
135
148
  args = "#{args}, #{string_args}" if string_args.present?
136
149
 
137
150
  args
138
151
  end
139
152
 
153
+ def rest_args_to_string(attrs)
154
+ return if attrs.blank?
155
+
156
+ attrs.map do |key, value|
157
+ "#{key}: #{value}"
158
+ end.join(", ")
159
+ end
160
+
140
161
  def utilities_args(classes)
141
162
  args = ::Primer::Classify::Utilities.classes_to_hash(classes)
142
163
 
data/lib/tasks/docs.rake CHANGED
@@ -27,6 +27,7 @@ namespace :docs do
27
27
  # Rails controller for rendering arbitrary ERB
28
28
  view_context = ApplicationController.new.tap { |c| c.request = ActionDispatch::TestRequest.create }.view_context
29
29
  components = [
30
+ Primer::Alpha::BorderBox::Header,
30
31
  Primer::Image,
31
32
  Primer::LocalTime,
32
33
  Primer::OcticonSymbolsComponent,
@@ -75,6 +76,7 @@ namespace :docs do
75
76
  Primer::Truncate,
76
77
  Primer::Beta::Truncate,
77
78
  Primer::Alpha::UnderlineNav,
79
+ Primer::Alpha::UnderlinePanels,
78
80
  Primer::Alpha::TabNav,
79
81
  Primer::Alpha::TabPanels
80
82
  ]
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ast_traverser"
4
+
5
+ # :nodoc:
6
+ class AstProcessor
7
+ class << self
8
+ def increment(stats, component, arg_name, value)
9
+ stats[component][:arguments][arg_name][value] = 0 unless stats[component][:arguments][arg_name][value]
10
+ stats[component][:arguments][arg_name][value] += 1
11
+ end
12
+
13
+ def process_ast(ast, stats)
14
+ traverser = AstTraverser.new
15
+ traverser.walk(ast)
16
+
17
+ return if traverser.stats.empty?
18
+
19
+ traverser.stats.each do |component, component_info|
20
+ stats[component] ||= {
21
+ paths: []
22
+ }
23
+
24
+ stats[component][:paths] << component_info[:path]
25
+ stats[component][:paths].uniq!
26
+ stats[component][:arguments] ||= {}
27
+
28
+ component_info[:arguments]&.each do |arg, value|
29
+ arg_name = arg.to_s
30
+ stats[component][:arguments][arg_name] ||= {}
31
+
32
+ # we want to count each class separately
33
+ if arg_name == "classes"
34
+ value.split.each do |val|
35
+ increment(stats, component, arg_name, val)
36
+ end
37
+ else
38
+ increment(stats, component, arg_name, value)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end