primer_view_components 0.0.119 → 0.0.120

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -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/modal_dialog.js +2 -0
  6. data/app/components/primer/alpha/modal_dialog.ts +2 -0
  7. data/lib/primer/deprecations.yml +0 -13
  8. data/lib/primer/view_components/linters/button_component_migration_counter.rb +2 -2
  9. data/lib/primer/view_components/version.rb +1 -1
  10. data/lib/primer/view_components.rb +5 -0
  11. data/lib/primer/yard/backend.rb +38 -0
  12. data/lib/primer/yard/component_manifest.rb +123 -0
  13. data/lib/primer/yard/docs_helper.rb +81 -0
  14. data/lib/primer/yard/legacy_gatsby_backend.rb +271 -0
  15. data/lib/primer/yard/registry.rb +146 -0
  16. data/lib/primer/yard/renders_many_handler.rb +23 -0
  17. data/lib/primer/yard/renders_one_handler.rb +23 -0
  18. data/lib/rubocop/config/default.yml +3 -0
  19. data/lib/rubocop/cop/primer/test_selector.rb +48 -0
  20. data/lib/tasks/docs.rake +37 -405
  21. data/previews/primer/alpha/dialog_preview/body_has_scrollbar_overflow.html.erb +9 -0
  22. data/previews/primer/alpha/dialog_preview.rb +15 -0
  23. data/static/arguments.json +0 -32
  24. data/static/audited_at.json +0 -3
  25. data/static/constants.json +0 -20
  26. data/static/statuses.json +0 -3
  27. metadata +17 -15
  28. data/app/components/primer/box_component.rb +0 -7
  29. data/app/components/primer/clipboard_copy.rb +0 -7
  30. data/app/components/primer/dropdown_menu_component.html.erb +0 -8
  31. data/app/components/primer/dropdown_menu_component.rb +0 -58
  32. data/lib/yard/docs_helper.rb +0 -79
  33. data/lib/yard/renders_many_handler.rb +0 -19
  34. data/lib/yard/renders_one_handler.rb +0 -19
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nocov:
4
+
5
+ require "primer/view_components"
6
+ require "primer/yard/docs_helper"
7
+ require "view_component/test_helpers"
8
+
9
+ module Primer
10
+ module YARD
11
+ # A wrapper around a YARD class reference that provides convenience methods
12
+ # for extracting component parameters, accessibility status, etc.
13
+ class RegistryEntry
14
+ include DocsHelper
15
+
16
+ attr_reader :component, :docs
17
+
18
+ delegate_missing_to :docs
19
+
20
+ def initialize(component, docs)
21
+ @component = component
22
+ @docs = docs
23
+ end
24
+
25
+ def metadata
26
+ @metadata ||= begin
27
+ status_module, short_name, class_name = status_module_and_short_name(component)
28
+ status = component.status.to_s
29
+ a11y_reviewed = component.audited_at.nil? ? "false" : "true"
30
+
31
+ {
32
+ title: class_name,
33
+ component_id: short_name.underscore,
34
+ status: status.capitalize,
35
+ status_module: status_module,
36
+ short_name: short_name,
37
+ a11y_reviewed: a11y_reviewed
38
+ }
39
+ end
40
+ end
41
+
42
+ def constructor
43
+ docs.meths.find(&:constructor?)
44
+ end
45
+
46
+ def params
47
+ constructor.tags(:param)
48
+ end
49
+
50
+ def slot_methods
51
+ public_methods.select { |mtd| slot_method?(mtd) }
52
+ end
53
+
54
+ def non_slot_methods
55
+ public_methods.reject { |mtd| slot_method?(mtd) }
56
+ end
57
+
58
+ def slot_method?(mtd)
59
+ mtd[:renders_one] || mtd[:renders_many]
60
+ end
61
+
62
+ def public_methods
63
+ # Returns: only public methods that belong to this class (i.e. no inherited methods)
64
+ # excluding the constructor
65
+ @public_methods ||=
66
+ docs.meths.reject { |mtd| mtd.tag(:private) || mtd.name == :initialize }
67
+ end
68
+
69
+ def title
70
+ metadata[:title]
71
+ end
72
+
73
+ def component_id
74
+ metadata[:component_id]
75
+ end
76
+
77
+ def status
78
+ metadata[:status]
79
+ end
80
+
81
+ def status_module
82
+ metadata[:status_module]
83
+ end
84
+
85
+ def short_name
86
+ metadata[:short_name]
87
+ end
88
+
89
+ def a11y_reviewed?
90
+ metadata[:a11y_reviewed]
91
+ end
92
+
93
+ def requires_js?
94
+ manifest.components_requiring_js.include?(component)
95
+ end
96
+
97
+ def includes_examples?
98
+ manifest.components_with_examples.include?(component)
99
+ end
100
+
101
+ private
102
+
103
+ def manifest
104
+ Primer::YARD::ComponentManifest
105
+ end
106
+ end
107
+
108
+ # Wrapper around an instance of YARD::Registry that provides easy access to component
109
+ # documentation.
110
+ class Registry
111
+ class << self
112
+ include ViewComponent::TestHelpers
113
+ include Primer::ViewHelper
114
+ include Primer::YARD::DocsHelper
115
+
116
+ def make
117
+ registry = ::YARD::RegistryStore.new
118
+ registry.load!(".yardoc")
119
+
120
+ new(registry)
121
+ end
122
+ end
123
+
124
+ attr_reader :yard_registry
125
+
126
+ def initialize(yard_registry)
127
+ @yard_registry = yard_registry
128
+ end
129
+
130
+ def find(component)
131
+ return entries[component] if entries.include?(component)
132
+
133
+ return unless (docs = yard_registry.get(component.name))
134
+
135
+ entries[component] = RegistryEntry.new(component, docs)
136
+ end
137
+
138
+ private
139
+
140
+ def entries
141
+ @entries ||= {}
142
+ end
143
+ end
144
+ end
145
+ end
146
+ # :nocov:
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nocov:
4
+ module Primer
5
+ module YARD
6
+ # YARD Handler to parse `renders_many` calls.
7
+ class RendersManyHandler < ::YARD::Handlers::Ruby::Base
8
+ handles method_call(:renders_many)
9
+ namespace_only
10
+
11
+ process do
12
+ name = statement.parameters.first.jump(:tstring_content, :ident).source
13
+ object = ::YARD::CodeObjects::MethodObject.new(namespace, name)
14
+ register(object)
15
+ parse_block(statement.last, owner: object)
16
+
17
+ object.dynamic = true
18
+ object[:renders_many] = true
19
+ end
20
+ end
21
+ end
22
+ end
23
+ # :nocov:
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nocov:
4
+ module Primer
5
+ module YARD
6
+ # YARD Handler to parse `renders_one` calls.
7
+ class RendersOneHandler < ::YARD::Handlers::Ruby::Base
8
+ handles method_call(:renders_one)
9
+ namespace_only
10
+
11
+ process do
12
+ name = statement.parameters.first.jump(:tstring_content, :ident).source
13
+ object = ::YARD::CodeObjects::MethodObject.new(namespace, name)
14
+ register(object)
15
+ parse_block(statement.last, owner: object)
16
+
17
+ object.dynamic = true
18
+ object[:renders_one] = true
19
+ end
20
+ end
21
+ end
22
+ end
23
+ # :nocov:
@@ -15,3 +15,6 @@ Primer/DeprecatedArguments:
15
15
 
16
16
  Primer/DeprecatedComponents:
17
17
  Enabled: true
18
+
19
+ Primer/TestSelector:
20
+ Enabled: true
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ # :nocov:
6
+ module RuboCop
7
+ module Cop
8
+ module Primer
9
+ # Prefer the `test_selector` argument over manually generating
10
+ # a `data-test-selector` attribute.
11
+ #
12
+ # Bad:
13
+ #
14
+ # Primer::BaseComponent.new(data: { "test-selector": "the-component" })
15
+ #
16
+ # Good:
17
+ #
18
+ # Primer::BaseComponent.new(test_selector: "the-component")
19
+ class TestSelector < BaseCop
20
+ INVALID_MESSAGE = <<~STR
21
+ Prefer the `test_selector` argument over manually generating a `data-test-selector` attribute: https://primer.style/view-components/system-arguments.
22
+ STR
23
+
24
+ def on_send(node)
25
+ return unless valid_node?(node)
26
+ return unless node.arguments?
27
+
28
+ kwargs = node.arguments.last
29
+ return unless kwargs.type == :hash
30
+
31
+ data_arg = kwargs.pairs.find { |kwarg| kwarg.key.value == :data }
32
+ return if data_arg.nil?
33
+ return unless data_arg.value.type == :hash
34
+
35
+ hash = data_arg.child_nodes.find { |arg| arg.type == :hash }
36
+ return unless hash
37
+
38
+ test_selector = hash.pairs.find do |pair|
39
+ pair.key.value == :"test-selector" || pair.key.value == "test-selector"
40
+ end
41
+ return unless test_selector
42
+
43
+ add_offense(data_arg, message: INVALID_MESSAGE)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end