yard-sorbet 0.7.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50408c1c7ce4b8fe04219273c326e3ac432fe8eaee9c02fe7ba243c204202ff3
4
- data.tar.gz: e01aabf41806def071f4807d5b4bd45e49c82cdb24360b9e3b9920361505b690
3
+ metadata.gz: 9b9dcb968aabdaa21a4f1eb74d7a0800e156fda50609b9e4df209795fe4f353f
4
+ data.tar.gz: bd98ccbde56a8fbb8a3d1058c64047b3ff0111912684dd454cf71f016abc5c88
5
5
  SHA512:
6
- metadata.gz: fa3a9a39d00923dd39824b553900dc12d30cebb3f3770580bbf6400272f52c1bd55905211de9372d7e1bd80ff26d3d2ddaa0c56c437c9a65bb41c24d53e60b08
7
- data.tar.gz: e322305cd757bb65135a90e9f9bf166161a98756449110714a4ce6dc7f47657cc539d72175c303114e67de7ac5c750c8216c31d8a1d8c818dacdeb5b404cbe1f
6
+ metadata.gz: c42c6277c2ebe6eac00e8bad6c68528d23aa1066ce23d79276a8dce062a064f8dcda87c77eff00ace7d125685a503b17c62357c50b59212b1507cb5880db5d26
7
+ data.tar.gz: 8209d82a15513c42d1d3371be854a7d2d63989e0c1552eb53e34b87aba6578cca8caf4f46a439474df193dd28951872fbed2af72ff63065a8b17adf8d4969614
@@ -16,10 +16,8 @@ module YARDSorbet
16
16
  def process
17
17
  statement.parameters(false).each do |mixin|
18
18
  obj = YARD::CodeObjects::Proxy.new(namespace, mixin.source)
19
- class_methods_namespace = MixesInClassMethodsHandler.mixed_in_class_methods(obj.to_s)
20
- next unless class_methods_namespace
21
-
22
- included_in.mixins(:class) << YARD::CodeObjects::Proxy.new(obj, class_methods_namespace)
19
+ class_methods_namespaces = MixesInClassMethodsHandler.mixed_in_class_methods(obj.to_s)
20
+ class_methods_namespaces&.each { included_in.mixins(:class) << YARD::CodeObjects::Proxy.new(obj, _1) }
23
21
  end
24
22
  end
25
23
 
@@ -12,16 +12,17 @@ module YARDSorbet
12
12
  handles method_call(:mixes_in_class_methods)
13
13
  namespace_only
14
14
 
15
- @@mix_in_class_methods = T.let({}, T::Hash[String, String]) # rubocop:disable Style/ClassVars
15
+ @@mix_in_class_methods = T.let({}, T::Hash[String, T::Array[String]]) # rubocop:disable Style/ClassVars
16
16
 
17
- sig { params(code_obj: String).returns(T.nilable(String)) }
17
+ sig { params(code_obj: String).returns(T.nilable(T::Array[String])) }
18
18
  def self.mixed_in_class_methods(code_obj)
19
19
  @@mix_in_class_methods[code_obj]
20
20
  end
21
21
 
22
22
  sig { void }
23
23
  def process
24
- @@mix_in_class_methods[namespace.to_s] = statement.parameters(false)[0].source
24
+ @@mix_in_class_methods[namespace.to_s] ||= []
25
+ @@mix_in_class_methods.fetch(namespace.to_s) << statement.parameters(false)[0].source
25
26
  end
26
27
  end
27
28
  end
@@ -10,59 +10,104 @@ module YARDSorbet
10
10
  handles method_call(:sig)
11
11
  namespace_only
12
12
 
13
- # These node types attached to sigs represent attr_* declarations
14
- ATTR_NODE_TYPES = T.let(%i[command fcall].freeze, T::Array[Symbol])
15
- private_constant :ATTR_NODE_TYPES
13
+ # YARD types that can have docstrings attached to them
14
+ Documentable = T.type_alias do
15
+ T.any(
16
+ YARD::CodeObjects::MethodObject, YARD::Parser::Ruby::MethodCallNode, YARD::Parser::Ruby::MethodDefinitionNode
17
+ )
18
+ end
19
+ private_constant :Documentable
16
20
 
17
21
  # Swap the method definition docstring and the sig docstring.
18
22
  # Parse relevant parts of the `sig` and include them as well.
19
23
  sig { void }
20
24
  def process
21
25
  method_node = NodeUtils.get_method_node(NodeUtils.sibling_node(statement))
22
- docstring, directives = Directives.extract_directives(statement.docstring)
23
- parse_sig(method_node, docstring)
24
- method_node.docstring = docstring.to_raw
25
- Directives.add_directives(method_node.docstring, directives)
26
+ case method_node
27
+ when YARD::Parser::Ruby::MethodDefinitionNode then process_def(method_node)
28
+ when YARD::Parser::Ruby::MethodCallNode then process_attr(method_node)
29
+ end
26
30
  statement.docstring = nil
27
31
  end
28
32
 
29
33
  private
30
34
 
31
- sig { params(method_node: YARD::Parser::Ruby::AstNode, docstring: YARD::Docstring).void }
32
- def parse_sig(method_node, docstring)
33
- NodeUtils.bfs_traverse(statement) do |n|
34
- case n.source
35
- when 'abstract'
36
- YARDSorbet::TagUtils.upsert_tag(docstring, 'abstract')
37
- when 'params'
38
- parse_params(method_node, n, docstring)
39
- when 'returns', 'void'
40
- parse_return(n, docstring)
41
- end
35
+ sig { params(def_node: YARD::Parser::Ruby::MethodDefinitionNode).void }
36
+ def process_def(def_node)
37
+ separator = scope == :instance && def_node.type == :def ? '#' : '.'
38
+ registered = YARD::Registry.at("#{namespace}#{separator}#{def_node.method_name(true)}")
39
+ if registered
40
+ parse_node(registered, statement.docstring || registered.docstring)
41
+ # Since we're probably in an RBI file, delete the def node, which could otherwise erroneously override the
42
+ # visibility setting
43
+ NodeUtils.delete_node(def_node)
44
+ else
45
+ parse_node(def_node, statement.docstring)
42
46
  end
43
47
  end
44
48
 
45
- sig do
46
- params(
47
- method_node: YARD::Parser::Ruby::AstNode,
48
- node: YARD::Parser::Ruby::AstNode,
49
- docstring: YARD::Docstring
50
- ).void
49
+ sig { params(attr_node: YARD::Parser::Ruby::MethodCallNode).void }
50
+ def process_attr(attr_node)
51
+ return if merged_into_attr?(attr_node)
52
+
53
+ parse_node(attr_node, statement.docstring, include_params: false)
51
54
  end
52
- def parse_params(method_node, node, docstring)
53
- return if ATTR_NODE_TYPES.include?(method_node.type)
54
55
 
56
+ # An attr* sig can be merged into a previous attr* docstring if it is the only parameter passed to the attr*
57
+ # declaration. This is to avoid needing to rewrite the source code to separate merged and unmerged attr*
58
+ # declarations.
59
+ sig { params(attr_node: YARD::Parser::Ruby::MethodCallNode).returns(T::Boolean) }
60
+ def merged_into_attr?(attr_node)
61
+ names = NodeUtils.validated_attribute_names(attr_node)
62
+ return false if names.size != 1
63
+
64
+ attrs = namespace.attributes[scope][names[0]]
65
+ return false if attrs.nil? || attrs.empty?
66
+
67
+ document_attr_methods(attrs.values.compact)
68
+ attr_node.docstring = nil
69
+ true
70
+ end
71
+
72
+ sig { params(method_objects: T::Array[YARD::CodeObjects::MethodObject]).void }
73
+ def document_attr_methods(method_objects)
74
+ method_objects.each { parse_node(_1, _1.docstring, include_params: false) }
75
+ end
76
+
77
+ sig { params(attach_to: Documentable, docstring: T.nilable(String), include_params: T::Boolean).void }
78
+ def parse_node(attach_to, docstring, include_params: true)
79
+ existing_docstring = docstring.is_a?(YARD::Docstring)
80
+ docstring, directives = Directives.extract_directives(docstring) unless existing_docstring
81
+ parse_sig(docstring, include_params: include_params)
82
+ attach_to.docstring = docstring.to_raw
83
+ Directives.add_directives(attach_to.docstring, directives) unless existing_docstring
84
+ end
85
+
86
+ sig { params(docstring: YARD::Docstring, include_params: T::Boolean).void }
87
+ def parse_sig(docstring, include_params: true)
88
+ NodeUtils.bfs_traverse(statement) do |node|
89
+ case node.source
90
+ when 'returns' then parse_return(node, docstring)
91
+ when 'params' then parse_params(node, docstring) if include_params
92
+ when 'void' then TagUtils.upsert_tag(docstring, 'return', TagUtils::VOID_RETURN_TYPE)
93
+ when 'abstract' then TagUtils.upsert_tag(docstring, 'abstract')
94
+ end
95
+ end
96
+ end
97
+
98
+ sig { params(node: YARD::Parser::Ruby::AstNode, docstring: YARD::Docstring).void }
99
+ def parse_params(node, docstring)
55
100
  sibling = NodeUtils.sibling_node(node)
56
- sibling[0][0].each do |p|
57
- param_name = p[0][0]
58
- types = SigToYARD.convert(p.last)
101
+ sibling[0][0].each do |param|
102
+ param_name = param[0][0]
103
+ types = SigToYARD.convert(param.last)
59
104
  TagUtils.upsert_tag(docstring, 'param', types, param_name)
60
105
  end
61
106
  end
62
107
 
63
108
  sig { params(node: YARD::Parser::Ruby::AstNode, docstring: YARD::Docstring).void }
64
109
  def parse_return(node, docstring)
65
- type = node.source == 'void' ? ['void'] : SigToYARD.convert(NodeUtils.sibling_node(node))
110
+ type = SigToYARD.convert(NodeUtils.sibling_node(node))
66
111
  TagUtils.upsert_tag(docstring, 'return', type)
67
112
  end
68
113
  end
@@ -35,7 +35,7 @@ module YARDSorbet
35
35
  docstring, directives = Directives.extract_directives(object.docstring)
36
36
  object.tags.each { docstring.add_tag(_1) }
37
37
  props.each { TagUtils.upsert_tag(docstring, 'param', _1.types, _1.prop_name, _1.doc) }
38
- TagUtils.upsert_tag(docstring, 'return', ['void'])
38
+ TagUtils.upsert_tag(docstring, 'return', TagUtils::VOID_RETURN_TYPE)
39
39
  decorate_t_struct_init(object, props, docstring, directives)
40
40
  end
41
41
 
@@ -13,7 +13,7 @@ module YARDSorbet
13
13
 
14
14
  sig { void }
15
15
  def process
16
- name = statement.parameters.first.last.last.source
16
+ name = params.dig(0, -1, -1).source
17
17
  prop = make_prop(name)
18
18
  update_state(prop)
19
19
  object = YARD::CodeObjects::MethodObject.new(namespace, name, scope)
@@ -27,36 +27,45 @@ module YARDSorbet
27
27
  sig { params(object: YARD::CodeObjects::MethodObject, prop: TStructProp).void }
28
28
  def decorate_object(object, prop)
29
29
  object.source = prop.source
30
- # TODO: this should use `+` to delimit the attribute name when markdown is disabled
31
- reader_docstring = prop.doc.empty? ? "Returns the value of attribute `#{prop.prop_name}`." : prop.doc
30
+ # TODO: this should use `+` to delimit the prop name when markdown is disabled
31
+ reader_docstring = prop.doc.empty? ? "Returns the value of prop `#{prop.prop_name}`." : prop.doc
32
32
  docstring = YARD::DocstringParser.new.parse(reader_docstring).to_docstring
33
33
  docstring.add_tag(YARD::Tags::Tag.new(:return, '', prop.types))
34
34
  object.docstring = docstring.to_raw
35
35
  end
36
36
 
37
- # Get the default prop value
38
- sig { returns(T.nilable(String)) }
39
- def default_value
40
- statement.traverse { break _1 if _1.type == :label && _1.source == 'default:' }&.parent&.[](1)&.source
37
+ sig { returns(T::Boolean) }
38
+ def immutable?
39
+ statement.method_name(true) == :const || kw_arg('immutable:') == 'true'
40
+ end
41
+
42
+ # @return the value passed to the keyword argument, or nil
43
+ sig { params(kwd: String).returns(T.nilable(String)) }
44
+ def kw_arg(kwd)
45
+ params[2]&.find { _1[0].source == kwd }&.[](1)&.source
41
46
  end
42
47
 
43
48
  sig { params(name: String).returns(TStructProp) }
44
49
  def make_prop(name)
45
50
  TStructProp.new(
46
- default: default_value,
51
+ default: kw_arg('default:'),
47
52
  doc: statement.docstring.to_s,
48
53
  prop_name: name,
49
54
  source: statement.source,
50
- types: SigToYARD.convert(statement.parameters[1])
55
+ types: SigToYARD.convert(params.fetch(1))
51
56
  )
52
57
  end
53
58
 
59
+ sig { returns(T::Array[YARD::Parser::Ruby::AstNode]) }
60
+ def params
61
+ @params ||= T.let(statement.parameters(false), T.nilable(T::Array[YARD::Parser::Ruby::AstNode]))
62
+ end
63
+
54
64
  # Register the field explicitly as an attribute.
55
- # While `const` attributes are immutable, `prop` attributes may be reassigned.
56
65
  sig { params(object: YARD::CodeObjects::MethodObject, name: String).void }
57
66
  def register_attrs(object, name)
58
- # Create the virtual method in our current scope
59
- write = statement.method_name(true) == :prop ? object : nil
67
+ write = immutable? ? nil : object
68
+ # Create the virtual attribute in our current scope
60
69
  namespace.attributes[scope][name] ||= SymbolHash[read: object, write: write]
61
70
  end
62
71
 
@@ -12,7 +12,6 @@ module YARDSorbet
12
12
  SKIP_METHOD_CONTENTS = T.let(%i[params returns].freeze, T::Array[Symbol])
13
13
  # Node types that can have type signatures
14
14
  SigableNode = T.type_alias { T.any(YARD::Parser::Ruby::MethodDefinitionNode, YARD::Parser::Ruby::MethodCallNode) }
15
-
16
15
  private_constant :ATTRIBUTE_METHODS, :SKIP_METHOD_CONTENTS, :SigableNode
17
16
 
18
17
  # Traverse AST nodes in breadth-first order
@@ -29,17 +28,15 @@ module YARDSorbet
29
28
  end
30
29
  end
31
30
 
31
+ sig { params(node: YARD::Parser::Ruby::AstNode).void }
32
+ def self.delete_node(node)
33
+ node.parent.children.delete(node)
34
+ end
35
+
32
36
  # Gets the node that a sorbet `sig` can be attached do, bypassing visisbility modifiers and the like
33
37
  sig { params(node: YARD::Parser::Ruby::AstNode).returns(SigableNode) }
34
38
  def self.get_method_node(node)
35
- case node
36
- when YARD::Parser::Ruby::MethodDefinitionNode
37
- return node
38
- when YARD::Parser::Ruby::MethodCallNode
39
- return node if ATTRIBUTE_METHODS.include?(node.method_name(true))
40
- end
41
-
42
- node.jump(:def, :defs)
39
+ sigable_node?(node) ? node : node.jump(:def, :defs)
43
40
  end
44
41
 
45
42
  # Find and return the adjacent node (ascending)
@@ -50,5 +47,26 @@ module YARDSorbet
50
47
  node_index = siblings.find_index { _1.equal?(node) }
51
48
  siblings.fetch(node_index + 1)
52
49
  end
50
+
51
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Boolean) }
52
+ def self.sigable_node?(node)
53
+ case node
54
+ when YARD::Parser::Ruby::MethodDefinitionNode then true
55
+ when YARD::Parser::Ruby::MethodCallNode then ATTRIBUTE_METHODS.include?(node.method_name(true))
56
+ else false
57
+ end
58
+ end
59
+
60
+ # @see https://github.com/lsegal/yard/blob/main/lib/yard/handlers/ruby/attribute_handler.rb
61
+ # YARD::Handlers::Ruby::AttributeHandler.validated_attribute_names
62
+ sig { params(attr_node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) }
63
+ def self.validated_attribute_names(attr_node)
64
+ attr_node.parameters(false).map do |obj|
65
+ case obj
66
+ when YARD::Parser::Ruby::LiteralNode then obj[0][0].source
67
+ else raise YARD::Parser::UndocumentableError, obj.source
68
+ end
69
+ end
70
+ end
53
71
  end
54
72
  end
@@ -4,127 +4,124 @@
4
4
  module YARDSorbet
5
5
  # Translate `sig` type syntax to `YARD` type syntax.
6
6
  module SigToYARD
7
- extend T::Sig
8
-
9
- REF_TYPES = T.let({
10
- 'T::Boolean' => ['Boolean'].freeze, # YARD convention for booleans
11
- # YARD convention is use singleton objects when applicable:
12
- # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Literals
13
- 'FalseClass' => ['false'].freeze,
14
- 'NilClass' => ['nil'].freeze,
15
- 'TrueClass' => ['true'].freeze
16
- }.freeze, T::Hash[String, [String]])
17
- private_constant :REF_TYPES
18
-
19
- # @see https://yardoc.org/types.html
20
- sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
21
- def self.convert(node)
22
- # scrub newlines, as they break the YARD parser
23
- convert_node(node).map { _1.gsub(/\n\s*/, ' ') }
24
- end
25
-
26
- sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
27
- private_class_method def self.convert_node(node)
28
- case node
29
- when YARD::Parser::Ruby::MethodCallNode then convert_call(node)
30
- when YARD::Parser::Ruby::ReferenceNode then convert_ref(node.source)
31
- else convert_node_type(node)
7
+ class << self
8
+ extend T::Sig
9
+
10
+ # Map of common types to YARD conventions (in order to reduce allocations)
11
+ REF_TYPES = T.let({
12
+ 'T::Boolean' => ['Boolean'].freeze, # YARD convention for booleans
13
+ # YARD convention is use singleton objects when applicable:
14
+ # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Literals
15
+ 'FalseClass' => ['false'].freeze,
16
+ 'NilClass' => ['nil'].freeze,
17
+ 'TrueClass' => ['true'].freeze
18
+ }.freeze, T::Hash[String, [String]])
19
+ private_constant :REF_TYPES
20
+
21
+ # @see https://yardoc.org/types.html
22
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
23
+ def convert(node)
24
+ # scrub newlines, as they break the YARD parser
25
+ convert_node(node).map { _1.gsub(/\n\s*/, ' ') }
32
26
  end
33
- end
34
27
 
35
- sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
36
- private_class_method def self.convert_node_type(node)
37
- case node.type
38
- when :aref then convert_aref(node)
39
- when :arg_paren then convert_node(node.first)
40
- when :array then convert_array(node)
41
- # Fixed hashes as return values are unsupported:
42
- # https://github.com/lsegal/yard/issues/425
43
- #
44
- # Hash key params can be individually documented with `@option`, but
45
- # sig translation is currently unsupported.
46
- when :hash then ['Hash']
47
- # seen when sig methods omit parentheses
48
- when :list then convert_list(node)
49
- else convert_unknown(node)
28
+ private
29
+
30
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
31
+ def convert_node(node)
32
+ case node
33
+ when YARD::Parser::Ruby::MethodCallNode
34
+ node.namespace.source == 'T' ? convert_t_method(node) : [node.source]
35
+ when YARD::Parser::Ruby::ReferenceNode
36
+ node_source = node.source
37
+ REF_TYPES[node_source] || [node_source]
38
+ else convert_node_type(node)
39
+ end
50
40
  end
51
- end
52
41
 
53
- sig { params(node: YARD::Parser::Ruby::AstNode).returns(String) }
54
- private_class_method def self.build_generic_type(node)
55
- return node.source if node.empty? || node.type != :aref
42
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
43
+ def convert_node_type(node)
44
+ case node.type
45
+ when :aref then convert_aref(node)
46
+ when :arg_paren then convert_node(node.first)
47
+ when :array then convert_array(node)
48
+ # Fixed hashes as return values are unsupported:
49
+ # https://github.com/lsegal/yard/issues/425
50
+ #
51
+ # Hash key params can be individually documented with `@option`, but
52
+ # sig translation is currently unsupported.
53
+ when :hash then ['Hash']
54
+ # seen when sig methods omit parentheses
55
+ when :list then convert_list(node)
56
+ else convert_unknown(node)
57
+ end
58
+ end
56
59
 
57
- collection_type = node.first.source
58
- member_type = node.last.children.map { build_generic_type(_1) }.join(', ')
59
- "#{collection_type}[#{member_type}]"
60
- end
60
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(String) }
61
+ def build_generic_type(node)
62
+ return node.source if node.empty? || node.type != :aref
61
63
 
62
- sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
63
- private_class_method def self.convert_aref(node)
64
- # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Parametrized_Types
65
- case node.first.source
66
- when 'T::Array', 'T::Enumerable', 'T::Range', 'T::Set' then convert_collection(node)
67
- when 'T::Hash' then convert_hash(node)
68
- else
69
- log.info("Unsupported sig aref node #{node.source}")
70
- [build_generic_type(node)]
64
+ collection_type = node.first.source
65
+ member_type = node.last.children.map { build_generic_type(_1) }.join(', ')
66
+ "#{collection_type}[#{member_type}]"
71
67
  end
72
- end
73
68
 
74
- sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
75
- private_class_method def self.convert_array(node)
76
- # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Order-Dependent_Lists
77
- member_types = node.first.children.map { convert_node(_1) }
78
- sequence = member_types.map { _1.size == 1 ? _1[0] : _1.to_s.tr('"', '') }.join(', ')
79
- ["Array(#{sequence})"]
80
- end
81
-
82
- sig { params(node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) }
83
- private_class_method def self.convert_call(node)
84
- node.namespace.source == 'T' ? convert_t_method(node) : [node.source]
85
- end
69
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
70
+ def convert_aref(node)
71
+ # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Parametrized_Types
72
+ case node.first.source
73
+ when 'T::Array', 'T::Enumerable', 'T::Range', 'T::Set' then convert_collection(node)
74
+ when 'T::Hash' then convert_hash(node)
75
+ else
76
+ log.info("Unsupported sig aref node #{node.source}")
77
+ [build_generic_type(node)]
78
+ end
79
+ end
86
80
 
87
- sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
88
- private_class_method def self.convert_collection(node)
89
- collection_type = node.first.source.split('::').last
90
- member_type = convert_node(node.last.first).join(', ')
91
- ["#{collection_type}<#{member_type}>"]
92
- end
81
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
82
+ def convert_array(node)
83
+ # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Order-Dependent_Lists
84
+ member_types = node.first.children.map { convert_node(_1) }
85
+ sequence = member_types.map { _1.size == 1 ? _1[0] : _1.to_s.tr('"', '') }.join(', ')
86
+ ["Array(#{sequence})"]
87
+ end
93
88
 
94
- sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
95
- private_class_method def self.convert_hash(node)
96
- kv = node.last.children
97
- key_type = convert_node(kv.first).join(', ')
98
- value_type = convert_node(kv.last).join(', ')
99
- ["Hash{#{key_type} => #{value_type}}"]
100
- end
89
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
90
+ def convert_collection(node)
91
+ collection_type = node.first.source.split('::').last
92
+ member_type = convert_node(node[-1][0]).join(', ')
93
+ ["#{collection_type}<#{member_type}>"]
94
+ end
101
95
 
102
- sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
103
- private_class_method def self.convert_list(node)
104
- node.children.size == 1 ? convert_node(node.children.first) : [node.source]
105
- end
96
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
97
+ def convert_hash(node)
98
+ kv = node.last.children
99
+ key_type = convert_node(kv.first).join(', ')
100
+ value_type = convert_node(kv.last).join(', ')
101
+ ["Hash{#{key_type} => #{value_type}}"]
102
+ end
106
103
 
107
- sig { params(node_source: String).returns([String]) }
108
- private_class_method def self.convert_ref(node_source)
109
- REF_TYPES.fetch(node_source, [node_source])
110
- end
104
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
105
+ def convert_list(node)
106
+ node.children.size == 1 ? convert_node(node.children.first) : [node.source]
107
+ end
111
108
 
112
- sig { params(node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) }
113
- private_class_method def self.convert_t_method(node)
114
- case node.method_name(true)
115
- when :any then node.last.first.children.flat_map { convert_node(_1) }
116
- # Order matters here, putting `nil` last results in a more concise
117
- # return syntax in the UI (superscripted `?`)
118
- # https://github.com/lsegal/yard/blob/cfa62ae/lib/yard/templates/helpers/html_helper.rb#L499-L500
119
- when :nilable then convert_node(node.last) + ['nil']
120
- else [node.source]
109
+ sig { params(node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) }
110
+ def convert_t_method(node)
111
+ case node.method_name(true)
112
+ # Order matters here, putting `nil` last results in a more concise return syntax in the UI (superscripted `?`):
113
+ # https://github.com/lsegal/yard/blob/cfa62ae/lib/yard/templates/helpers/html_helper.rb#L499-L500
114
+ when :nilable then convert_node(node.last) + REF_TYPES.fetch('NilClass')
115
+ when :any then node[-1][0].children.flat_map { convert_node(_1) }
116
+ else [node.source]
117
+ end
121
118
  end
122
- end
123
119
 
124
- sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
125
- private_class_method def self.convert_unknown(node)
126
- log.warn("Unsupported sig #{node.type} node #{node.source}")
127
- [node.source]
120
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns([String]) }
121
+ def convert_unknown(node)
122
+ log.warn("Unsupported sig #{node.type} node #{node.source}")
123
+ [node.source]
124
+ end
128
125
  end
129
126
  end
130
127
  end
@@ -6,6 +6,9 @@ module YARDSorbet
6
6
  module TagUtils
7
7
  extend T::Sig
8
8
 
9
+ # The `void` return type, as a constant to reduce array allocations
10
+ VOID_RETURN_TYPE = T.let(['void'].freeze, [String])
11
+
9
12
  # @return the tag with the matching `tag_name` and `name`, or `nil`
10
13
  sig do
11
14
  params(docstring: YARD::Docstring, tag_name: String, name: T.nilable(String)).returns(T.nilable(YARD::Tags::Tag))
@@ -4,5 +4,5 @@
4
4
  # Types are documentation
5
5
  module YARDSorbet
6
6
  # {https://rubygems.org/gems/yard-sorbet Version history}
7
- VERSION = '0.7.0'
7
+ VERSION = '0.8.1'
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard-sorbet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Douglas Eichelberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-24 00:00:00.000000000 Z
11
+ date: 2023-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler-audit
@@ -86,28 +86,28 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.35.0
89
+ version: 1.49.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 1.35.0
96
+ version: 1.49.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop-performance
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 1.14.0
103
+ version: 1.16.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 1.14.0
110
+ version: 1.16.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rubocop-rake
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -128,28 +128,28 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 2.12.1
131
+ version: 2.19.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 2.12.1
138
+ version: 2.19.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rubocop-sorbet
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 0.6.0
145
+ version: 0.7.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 0.6.0
152
+ version: 0.7.0
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: sorbet
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -170,14 +170,14 @@ dependencies:
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: 0.9.4
173
+ version: 0.11.1
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: 0.9.4
180
+ version: 0.11.1
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: sorbet-runtime
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -206,9 +206,7 @@ dependencies:
206
206
  - - ">="
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0.9'
209
- description: 'A YARD plugin that incorporates Sorbet type information
210
-
211
- '
209
+ description: A YARD plugin that incorporates Sorbet type information
212
210
  email: dduugg@gmail.com
213
211
  executables: []
214
212
  extensions: []