yard-sorbet 0.1.0 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47fca84744393f88777d1cb1355df3ffb693e4b5edb982a5497903da1c86daf7
4
- data.tar.gz: 6cd24b1d8796de8def62dcbc02383b8de27aa60a32a00b82c9d974332e1f8e36
3
+ metadata.gz: 360c73bcd93390b21ebf0206cce339822368fca005d03fa3d08a4444a3cab367
4
+ data.tar.gz: 7b03b59846235fd395bca99868561eaa299b7dbe21eea7c91307c602236baec9
5
5
  SHA512:
6
- metadata.gz: d666a9079c7190e905c1c190b014037d3bf4b0bd4fa75aa74b9c2221878f82cc88b6523b5ac14af5de981e1b157452341a196145bcc28f8ebc567fae3f10eee8
7
- data.tar.gz: 7635542b9b48b775050ec0e417a23fc0700326bd733ba46293592c156a9c49cb7dc2a1800e3909c1c5ae10aacb15e03142dda44e589a8a5e9fc706388da1827c
6
+ metadata.gz: 364ee6ff02687a3a4e2ffd3384c2eb68a848afe60ad0e94c8d675df81ae9a820e805ed07ce1537cee59eb3e979ce2488a1a2210aa19cc1b40365b9dc97368864
7
+ data.tar.gz: f26eb01fcad908815f27afc9a42ad72050625e5279e3b3b7576991aa1b14ba685148c12d74bbc2cdba19e69b1f416f48fa89253d34a5635259794d088ad7415f
data/lib/yard-sorbet.rb CHANGED
@@ -8,6 +8,7 @@ require 'yard'
8
8
  module YARDSorbet; end
9
9
 
10
10
  require_relative 'yard-sorbet/directives'
11
- require_relative 'yard-sorbet/sig_handler'
11
+ require_relative 'yard-sorbet/handlers'
12
+ require_relative 'yard-sorbet/node_utils'
12
13
  require_relative 'yard-sorbet/sig_to_yard'
13
- require_relative 'yard-sorbet/struct_handler'
14
+ require_relative 'yard-sorbet/version'
@@ -1,8 +1,11 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Extract & re-add directives to a docstring
5
5
  module YARDSorbet::Directives
6
+ extend T::Sig
7
+
8
+ sig { params(docstring: T.nilable(String)).returns([YARD::Docstring, T::Array[String]]) }
6
9
  def self.extract_directives(docstring)
7
10
  parser = YARD::DocstringParser.new.parse(docstring)
8
11
  # Directives are already parsed at this point, and there doesn't
@@ -16,6 +19,7 @@ module YARDSorbet::Directives
16
19
  [parser.to_docstring, directives]
17
20
  end
18
21
 
22
+ sig { params(docstring: String, directives: T::Array[String]).void }
19
23
  def self.add_directives(docstring, directives)
20
24
  directives.each do |directive|
21
25
  docstring.concat("\n#{directive}")
@@ -0,0 +1,11 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ # Custom YARD Handlers
5
+ # @see https://rubydoc.info/gems/yard/YARD/Handlers/Base YARD Base Handler documentation
6
+ module YARDSorbet::Handlers; end
7
+
8
+ require_relative 'handlers/abstract_dsl_handler'
9
+ require_relative 'handlers/enums_handler'
10
+ require_relative 'handlers/sig_handler'
11
+ require_relative 'handlers/struct_handler'
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # Apllies an +@abstract+ tag to +abstract!+/+interface!+ modules (if not alerady present).
5
+ class YARDSorbet::Handlers::AbstractDSLHandler < YARD::Handlers::Ruby::Base
6
+ extend T::Sig
7
+
8
+ handles method_call(:abstract!), method_call(:interface!)
9
+ namespace_only
10
+
11
+ # The text accompanying the `@abstract` tag.
12
+ # @see https://github.com/lsegal/yard/blob/main/templates/default/docstring/html/abstract.erb
13
+ # The `@abstract` tag template
14
+ TAG_TEXT = 'Subclasses must implement the `abstract` methods below.'
15
+ # Extra text for class namespaces
16
+ CLASS_TAG_TEXT = T.let("It cannont be directly instantiated. #{TAG_TEXT}", String)
17
+
18
+ sig { void }
19
+ def process
20
+ return if namespace.has_tag?(:abstract)
21
+
22
+ text = namespace.is_a?(YARD::CodeObjects::ClassObject) ? CLASS_TAG_TEXT : TAG_TEXT
23
+ tag = YARD::Tags::Tag.new(:abstract, text)
24
+ namespace.add_tag(tag)
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # Handle +enums+ calls, registering enum values as constants
5
+ class YARDSorbet::Handlers::EnumsHandler < YARD::Handlers::Ruby::Base
6
+ extend T::Sig
7
+
8
+ handles method_call(:enums)
9
+ namespace_only
10
+
11
+ sig { void }
12
+ def process
13
+ statement.traverse do |node|
14
+ if const_assign_node?(node)
15
+ register YARD::CodeObjects::ConstantObject.new(namespace, node.first.source) do |obj|
16
+ obj.docstring = node.docstring
17
+ obj.source = node
18
+ obj.value = node.last.source
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Boolean) }
25
+ private def const_assign_node?(node)
26
+ node.type == :assign && node.children.first.children.first.type == :const
27
+ end
28
+ end
@@ -0,0 +1,100 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # A YARD Handler for Sorbet type declarations
5
+ class YARDSorbet::Handlers::SigHandler < YARD::Handlers::Ruby::Base
6
+ extend T::Sig
7
+
8
+ handles method_call(:sig)
9
+ namespace_only
10
+
11
+ # A struct that holds the parsed contents of a Sorbet type signature
12
+ class ParsedSig < T::Struct
13
+ prop :abstract, T::Boolean, default: false
14
+ prop :params, T::Hash[String, T::Array[String]], default: {}
15
+ prop :return, T.nilable(T::Array[String])
16
+ end
17
+
18
+ # Skip these node types when parsing `sig` params
19
+ PARAM_EXCLUDES = T.let(%i[array call hash].freeze, T::Array[Symbol])
20
+ # Skip these node types when parsing `sig`s
21
+ SIG_EXCLUDES = T.let(%i[array hash].freeze, T::Array[Symbol])
22
+
23
+ private_constant :ParsedSig, :PARAM_EXCLUDES, :SIG_EXCLUDES
24
+
25
+ # Swap the method definition docstring and the sig docstring.
26
+ # Parse relevant parts of the +sig+ and include them as well.
27
+ sig { void }
28
+ def process
29
+ method_node = YARDSorbet::NodeUtils.get_method_node(YARDSorbet::NodeUtils.sibling_node(statement))
30
+ docstring, directives = YARDSorbet::Directives.extract_directives(statement.docstring)
31
+ parsed_sig = parse_sig(statement)
32
+ enhance_tag(docstring, :abstract, parsed_sig)
33
+ enhance_tag(docstring, :return, parsed_sig)
34
+ if method_node.type != :command
35
+ parsed_sig.params.each do |name, types|
36
+ enhance_param(docstring, name, types)
37
+ end
38
+ end
39
+ method_node.docstring = docstring.to_raw
40
+ YARDSorbet::Directives.add_directives(method_node.docstring, directives)
41
+ statement.docstring = nil
42
+ end
43
+
44
+ sig { params(docstring: YARD::Docstring, name: String, types: T::Array[String]).void }
45
+ private def enhance_param(docstring, name, types)
46
+ tag = docstring.tags.find { |t| t.tag_name == 'param' && t.name == name }
47
+ if tag
48
+ docstring.delete_tag_if { |t| t == tag }
49
+ tag.types = types
50
+ else
51
+ tag = YARD::Tags::Tag.new(:param, '', types, name)
52
+ end
53
+ docstring.add_tag(tag)
54
+ end
55
+
56
+ sig { params(docstring: YARD::Docstring, type: Symbol, parsed_sig: ParsedSig).void }
57
+ private def enhance_tag(docstring, type, parsed_sig)
58
+ type_value = parsed_sig.public_send(type)
59
+ return unless type_value
60
+
61
+ tag = docstring.tags.find { |t| t.tag_name == type.to_s }
62
+ if tag
63
+ docstring.delete_tags(type)
64
+ else
65
+ tag = YARD::Tags::Tag.new(type, '')
66
+ end
67
+ if type_value.is_a?(Array)
68
+ tag.types = type_value
69
+ end
70
+ docstring.add_tag(tag)
71
+ end
72
+
73
+ sig { params(sig_node: YARD::Parser::Ruby::MethodCallNode).returns(ParsedSig) }
74
+ private def parse_sig(sig_node)
75
+ parsed = ParsedSig.new
76
+ found_params = T.let(false, T::Boolean)
77
+ found_return = T.let(false, T::Boolean)
78
+ YARDSorbet::NodeUtils.bfs_traverse(sig_node, exclude: SIG_EXCLUDES) do |n|
79
+ if n.source == 'abstract'
80
+ parsed.abstract = true
81
+ elsif n.source == 'params' && !found_params
82
+ found_params = true
83
+ sibling = YARDSorbet::NodeUtils.sibling_node(n)
84
+ YARDSorbet::NodeUtils.bfs_traverse(sibling, exclude: PARAM_EXCLUDES) do |p|
85
+ if p.type == :assoc
86
+ param_name = p.children.first.source[0...-1]
87
+ types = YARDSorbet::SigToYARD.convert(p.children.last)
88
+ parsed.params[param_name] = types
89
+ end
90
+ end
91
+ elsif n.source == 'returns' && !found_return
92
+ found_return = true
93
+ parsed.return = YARDSorbet::SigToYARD.convert(YARDSorbet::NodeUtils.sibling_node(n))
94
+ elsif n.source == 'void'
95
+ parsed.return ||= ['void']
96
+ end
97
+ end
98
+ parsed
99
+ end
100
+ end
@@ -1,15 +1,23 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- # Handle all `const` calls, creating accessor methods, and compiles them for later usage at the class level
4
+ # Handles all +const+/+prop+ calls, creating accessor methods, and compiles them for later usage at the class level
5
5
  # in creating a constructor
6
- class YARDSorbet::StructHandler < YARD::Handlers::Ruby::Base
7
- handles method_call(:const)
6
+ class YARDSorbet::Handlers::StructHandler < YARD::Handlers::Ruby::Base
7
+ extend T::Sig
8
+
9
+ handles method_call(:const), method_call(:prop)
8
10
  namespace_only
9
11
 
12
+ sig { void }
10
13
  def process
11
14
  # Store the property for use in the constructor definition
12
- name = statement.parameters[0].jump(:ident).source
15
+ name = statement.parameters[0].jump(
16
+ :ident, # handles most "normal" identifiers
17
+ :kw, # handles prop names using reserved words like `end` or `def`
18
+ :const # handles capitalized prop names like Foo
19
+ ).source
20
+
13
21
  doc = statement.docstring.to_s
14
22
  source = statement.source
15
23
  types = YARDSorbet::SigToYARD.convert(statement.parameters[1])
@@ -36,24 +44,34 @@ class YARDSorbet::StructHandler < YARD::Handlers::Ruby::Base
36
44
  docstring.add_tag(YARD::Tags::Tag.new(:return, '', types))
37
45
  object.docstring = docstring.to_raw
38
46
 
39
- # Register the object explicitly as an attribute
47
+ # Register the object explicitly as an attribute.
48
+ # While `const` attributes are immutable, `prop` attributes may be reassigned.
49
+ if statement.method_name.source == 'prop'
50
+ namespace.attributes[scope][name][:write] = object
51
+ end
40
52
  namespace.attributes[scope][name][:read] = object
41
53
  end
42
54
  end
43
55
 
44
- # Class-level handler that folds all `const` declarations into the constructor documentation
56
+ # Class-level handler that folds all +const+ and +prop+ declarations into the constructor documentation
45
57
  # this needs to be injected as a module otherwise the default Class handler will overwrite documentation
46
58
  module YARDSorbet::StructClassHandler
59
+ extend T::Helpers
60
+ extend T::Sig
61
+
62
+ requires_ancestor YARD::Handlers::Ruby::ClassHandler
63
+
64
+ sig { void }
47
65
  def process
48
- ret = super
66
+ super
49
67
 
50
- return ret if extra_state.prop_docs.nil?
68
+ return if extra_state.prop_docs.nil?
51
69
 
52
70
  # lookup the full YARD path for the current class
53
71
  class_ns = YARD::CodeObjects::ClassObject.new(namespace, statement[0].source.gsub(/\s/, ''))
54
72
  props = extra_state.prop_docs[class_ns]
55
73
 
56
- return ret if props.empty?
74
+ return if props.empty?
57
75
 
58
76
  # Create a virtual `initialize` method with all the `prop`/`const` arguments
59
77
  # having the name :initialize & the scope :instance marks this as the constructor.
@@ -85,8 +103,6 @@ module YARDSorbet::StructClassHandler
85
103
  object.docstring = docstring.to_raw
86
104
 
87
105
  YARDSorbet::Directives.add_directives(object.docstring, directives)
88
-
89
- ret
90
106
  end
91
107
  end
92
108
 
@@ -0,0 +1,68 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # Helper methods for working with YARD AST Nodes
5
+ module YARDSorbet::NodeUtils
6
+ extend T::Sig
7
+
8
+ # Command node types that can have type signatures
9
+ ATTRIBUTE_METHODS = T.let(%i[attr attr_accessor attr_reader attr_writer].freeze, T::Array[Symbol])
10
+ # Node types that can have type signatures
11
+ SIGABLE_NODE = T.type_alias do
12
+ T.any(YARD::Parser::Ruby::MethodDefinitionNode, YARD::Parser::Ruby::MethodCallNode)
13
+ end
14
+
15
+ private_constant :ATTRIBUTE_METHODS, :SIGABLE_NODE
16
+
17
+ # @yield [YARD::Parser::Ruby::AstNode]
18
+ sig do
19
+ params(
20
+ node: YARD::Parser::Ruby::AstNode,
21
+ exclude: T::Array[Symbol],
22
+ _blk: T.proc.params(n: YARD::Parser::Ruby::AstNode).void
23
+ ).void
24
+ end
25
+ def self.bfs_traverse(node, exclude: [], &_blk)
26
+ queue = [node]
27
+ until queue.empty?
28
+ n = T.must(queue.shift)
29
+ yield n
30
+ n.children.each do |c|
31
+ unless exclude.include?(c.type)
32
+ queue.push(c)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ # Gets the node that a sorbet `sig` can be attached do, bypassing visisbility modifiers and the like
39
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(SIGABLE_NODE) }
40
+ def self.get_method_node(node)
41
+ case node
42
+ when YARD::Parser::Ruby::MethodDefinitionNode
43
+ return node
44
+ when YARD::Parser::Ruby::MethodCallNode
45
+ return node if ATTRIBUTE_METHODS.include?(node.method_name(true))
46
+ end
47
+
48
+ node.jump(:def, :defs)
49
+ end
50
+
51
+ # Find and return the adjacent node (ascending)
52
+ # @raise [IndexError] if the node does not have an adjacent sibling (ascending)
53
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(YARD::Parser::Ruby::AstNode) }
54
+ def self.sibling_node(node)
55
+ siblings = node.parent.children
56
+ siblings.each_with_index.find do |sibling, i|
57
+ if sibling.equal?(node)
58
+ return siblings.fetch(i + 1)
59
+ end
60
+ end
61
+ end
62
+
63
+ # Returns true if the given node represents a type signature.
64
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Boolean) }
65
+ def self.type_signature?(node)
66
+ node.is_a?(YARD::Parser::Ruby::MethodCallNode) && node.method_name(true) == :sig
67
+ end
68
+ end
@@ -1,106 +1,135 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- # Translate sig type syntax to YARD type syntax.
4
+ # Translate +sig+ type syntax to +YARD+ type syntax.
5
5
  module YARDSorbet::SigToYARD
6
- IS_LEGACY_RUBY_VERSION = RUBY_VERSION.match?(/\A2\.[45]\./)
6
+ extend T::Sig
7
+
8
+ # Ruby 2.5 parsed call nodes slightly differently
9
+ IS_LEGACY_RUBY_VERSION = T.let(RUBY_VERSION.start_with?('2.5.'), T::Boolean)
10
+ private_constant :IS_LEGACY_RUBY_VERSION
7
11
 
8
12
  # @see https://yardoc.org/types.html
13
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
9
14
  def self.convert(node)
10
15
  types = convert_type(node)
11
16
  # scrub newlines, as they break the YARD parser
12
17
  types.map { |type| type.gsub(/\n\s*/, ' ') }
13
18
  end
14
19
 
15
- def self.convert_type(node)
16
- children = node.children
20
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
21
+ private_class_method def self.convert_type(node)
17
22
  case node.type
18
- when :aref
19
- # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Parametrized_Types
20
- case children.first.source
21
- when 'T::Array', 'T::Enumerable', 'T::Range', 'T::Set'
22
- collection_type = children.first.source.split('::').last
23
- member_type = convert(children.last.children.first).join(', ')
24
- ["#{collection_type}<#{member_type}>"]
25
- when 'T::Hash'
26
- key_type = convert(children.last.children.first).join(', ')
27
- value_type = convert(children.last.children.last).join(', ')
28
- ["Hash{#{key_type} => #{value_type}}"]
29
- else
30
- log.info("Unsupported sig aref node #{node.source}")
31
- [build_generic_type(node)]
32
- end
33
- when :arg_paren
34
- convert(children.first.children.first)
35
- when :array
36
- # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Order-Dependent_Lists
37
- member_types = children.first.children.map { |n| convert(n) }.join(', ')
38
- ["Array(#{member_types})"]
39
- when :call
40
- if children[0].source == 'T'
41
- t_method = IS_LEGACY_RUBY_VERSION ? children[1].source : children[2].source
42
- case t_method
43
- when 'all', 'attached_class', 'class_of', 'enum', 'noreturn', 'self_type', 'type_parameter', 'untyped'
44
- # YARD doesn't have equivalent notions, so we just use the raw source
45
- [node.source]
46
- when 'any'
47
- children.last.children.first.children.map { |n| convert(n) }.flatten
48
- when 'nilable'
49
- # Order matters here, putting `nil` last results in a more concise
50
- # return syntax in the UI (superscripted `?`)
51
- convert(children.last) + ['nil']
52
- else
53
- log.warn("Unsupported T method #{node.source}")
54
- [node.source]
55
- end
56
- else
57
- [node.source]
58
- end
59
- when :const_path_ref, :const
60
- case node.source
61
- when 'T::Boolean'
62
- ['Boolean'] # YARD convention for booleans
63
- else
64
- [node.source]
65
- end
66
- when :hash, :list
67
- # Fixed hashes as return values are unsupported:
68
- # https://github.com/lsegal/yard/issues/425
69
- #
70
- # Hash key params can be individually documented with `@option`, but
71
- # sig translation is unsupported.
72
- ['Hash']
73
- when :var_ref
74
- # YARD convention is use singleton objects when applicable:
75
- # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Literals
76
- case node.source
77
- when 'FalseClass'
78
- ['false']
79
- when 'NilClass'
80
- ['nil']
81
- when 'TrueClass'
82
- ['true']
83
- else
84
- [node.source]
85
- end
86
- when :top_const_ref
87
- # A top-level constant reference, such as ::Klass
88
- # It contains a child node of type :const
89
- convert(children.first)
23
+ when :aref then handle_aref(node)
24
+ when :arg_paren then handle_arg_paren(node)
25
+ when :array then handle_array(node)
26
+ when :call then handle_call(node)
27
+ when :const_path_ref, :const then handle_const(node)
28
+ # Fixed hashes as return values are unsupported:
29
+ # https://github.com/lsegal/yard/issues/425
30
+ #
31
+ # Hash key params can be individually documented with `@option`, but
32
+ # sig translation is unsupported.
33
+ when :hash, :list then ['Hash']
34
+ when :var_ref then handle_var_ref(node)
35
+ # A top-level constant reference, such as ::Klass
36
+ # It contains a child node of type :const
37
+ when :top_const_ref then convert(node.children.first)
90
38
  else
91
39
  log.warn("Unsupported sig #{node.type} node #{node.source}")
92
40
  [node.source]
93
41
  end
94
42
  end
95
43
 
96
- def self.build_generic_type(node)
97
- return node.source if node.children.empty? || node.type != :aref
44
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(String) }
45
+ private_class_method def self.build_generic_type(node)
46
+ children = node.children
47
+ return node.source if children.empty? || node.type != :aref
98
48
 
99
- collection_type = node.children.first.source
100
- member_type = node.children.last.children
101
- .map { |child| build_generic_type(child) }
102
- .join(', ')
49
+ collection_type = children.first.source
50
+ member_type = children.last.children.map { |child| build_generic_type(child) }.join(', ')
103
51
 
104
52
  "#{collection_type}[#{member_type}]"
105
53
  end
54
+
55
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
56
+ private_class_method def self.handle_aref(node)
57
+ children = node.children
58
+ # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Parametrized_Types
59
+ case children.first.source
60
+ when 'T::Array', 'T::Enumerable', 'T::Range', 'T::Set'
61
+ collection_type = children.first.source.split('::').last
62
+ member_type = convert(children.last.children.first).join(', ')
63
+ ["#{collection_type}<#{member_type}>"]
64
+ when 'T::Hash'
65
+ kv = children.last.children
66
+ key_type = convert(kv.first).join(', ')
67
+ value_type = convert(kv.last).join(', ')
68
+ ["Hash{#{key_type} => #{value_type}}"]
69
+ else
70
+ log.info("Unsupported sig aref node #{node.source}")
71
+ [build_generic_type(node)]
72
+ end
73
+ end
74
+
75
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
76
+ private_class_method def self.handle_arg_paren(node)
77
+ convert(node.children.first.children.first)
78
+ end
79
+
80
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
81
+ private_class_method def self.handle_array(node)
82
+ # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Order-Dependent_Lists
83
+ member_types = node.children.first.children.map { |n| convert(n) }.join(', ')
84
+ ["Array(#{member_types})"]
85
+ end
86
+
87
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
88
+ private_class_method def self.handle_const(node)
89
+ source = node.source
90
+ case source
91
+ # YARD convention for booleans
92
+ when 'T::Boolean' then ['Boolean']
93
+ else [source]
94
+ end
95
+ end
96
+
97
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
98
+ private_class_method def self.handle_call(node)
99
+ children = node.children
100
+ if children[0].source == 'T'
101
+ t_method = IS_LEGACY_RUBY_VERSION ? children[1].source : children[2].source
102
+ handle_t_method(t_method, node)
103
+ else
104
+ [node.source]
105
+ end
106
+ end
107
+
108
+ sig { params(method_name: String, node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
109
+ private_class_method def self.handle_t_method(method_name, node)
110
+ case method_name
111
+ # YARD doesn't have equivalent notions, so we just use the raw source
112
+ when 'all', 'attached_class', 'class_of', 'enum', 'noreturn', 'self_type', 'type_parameter', 'untyped'
113
+ [node.source]
114
+ when 'any' then node.children.last.children.first.children.map { |n| convert(n) }.flatten
115
+ # Order matters here, putting `nil` last results in a more concise
116
+ # return syntax in the UI (superscripted `?`)
117
+ when 'nilable' then convert(node.children.last) + ['nil']
118
+ else
119
+ log.warn("Unsupported T method #{node.source}")
120
+ [node.source]
121
+ end
122
+ end
123
+
124
+ sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
125
+ private_class_method def self.handle_var_ref(node)
126
+ # YARD convention is use singleton objects when applicable:
127
+ # https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Literals
128
+ case node.source
129
+ when 'FalseClass' then ['false']
130
+ when 'NilClass' then ['nil']
131
+ when 'TrueClass' then ['true']
132
+ else [node.source]
133
+ end
134
+ end
106
135
  end
@@ -2,5 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module YARDSorbet
5
- VERSION = '0.1.0'
5
+ # {https://rubygems.org/gems/yard-sorbet Version history}
6
+ VERSION = '0.5.0'
6
7
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard-sorbet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Douglas Eichelberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-01 00:00:00.000000000 Z
11
+ date: 2021-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler-audit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: codecov
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
- - - "~>"
31
+ - - ">="
18
32
  - !ruby/object:Gem::Version
19
- version: 0.2.12
33
+ version: '0'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
- - - "~>"
38
+ - - ">="
25
39
  - !ruby/object:Gem::Version
26
- version: 0.2.12
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +72,28 @@ dependencies:
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: 1.5.0
75
+ version: 1.15.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.15.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-performance
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.11.0
62
90
  type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: 1.5.0
96
+ version: 1.11.0
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: rubocop-rake
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -86,84 +114,84 @@ dependencies:
86
114
  requirements:
87
115
  - - "~>"
88
116
  - !ruby/object:Gem::Version
89
- version: 2.0.0
117
+ version: 2.3.0
90
118
  type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
122
  - - "~>"
95
123
  - !ruby/object:Gem::Version
96
- version: 2.0.0
124
+ version: 2.3.0
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: rubocop-sorbet
99
127
  requirement: !ruby/object:Gem::Requirement
100
128
  requirements:
101
129
  - - "~>"
102
130
  - !ruby/object:Gem::Version
103
- version: 0.5.1
131
+ version: 0.6.0
104
132
  type: :development
105
133
  prerelease: false
106
134
  version_requirements: !ruby/object:Gem::Requirement
107
135
  requirements:
108
136
  - - "~>"
109
137
  - !ruby/object:Gem::Version
110
- version: 0.5.1
138
+ version: 0.6.0
111
139
  - !ruby/object:Gem::Dependency
112
140
  name: simplecov
113
141
  requirement: !ruby/object:Gem::Requirement
114
142
  requirements:
115
- - - "~>"
143
+ - - ">="
116
144
  - !ruby/object:Gem::Version
117
- version: 0.20.0
145
+ version: '0'
118
146
  type: :development
119
147
  prerelease: false
120
148
  version_requirements: !ruby/object:Gem::Requirement
121
149
  requirements:
122
- - - "~>"
150
+ - - ">="
123
151
  - !ruby/object:Gem::Version
124
- version: 0.20.0
152
+ version: '0'
125
153
  - !ruby/object:Gem::Dependency
126
154
  name: sorbet
127
155
  requirement: !ruby/object:Gem::Requirement
128
156
  requirements:
129
157
  - - "~>"
130
158
  - !ruby/object:Gem::Version
131
- version: 0.5.6083
159
+ version: 0.5.6289
132
160
  type: :development
133
161
  prerelease: false
134
162
  version_requirements: !ruby/object:Gem::Requirement
135
163
  requirements:
136
164
  - - "~>"
137
165
  - !ruby/object:Gem::Version
138
- version: 0.5.6083
166
+ version: 0.5.6289
139
167
  - !ruby/object:Gem::Dependency
140
168
  name: sorbet-runtime
141
169
  requirement: !ruby/object:Gem::Requirement
142
170
  requirements:
143
171
  - - ">="
144
172
  - !ruby/object:Gem::Version
145
- version: '0.5'
173
+ version: 0.5.6289
146
174
  type: :runtime
147
175
  prerelease: false
148
176
  version_requirements: !ruby/object:Gem::Requirement
149
177
  requirements:
150
178
  - - ">="
151
179
  - !ruby/object:Gem::Version
152
- version: '0.5'
180
+ version: 0.5.6289
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: yard
155
183
  requirement: !ruby/object:Gem::Requirement
156
184
  requirements:
157
185
  - - ">="
158
186
  - !ruby/object:Gem::Version
159
- version: '0.9'
187
+ version: 0.9.21
160
188
  type: :runtime
161
189
  prerelease: false
162
190
  version_requirements: !ruby/object:Gem::Requirement
163
191
  requirements:
164
192
  - - ">="
165
193
  - !ruby/object:Gem::Version
166
- version: '0.9'
194
+ version: 0.9.21
167
195
  description: 'A YARD plugin that incorporates Sorbet type information
168
196
 
169
197
  '
@@ -172,31 +200,27 @@ executables: []
172
200
  extensions: []
173
201
  extra_rdoc_files: []
174
202
  files:
175
- - ".editorconfig"
176
- - ".gitignore"
177
- - ".rspec"
178
- - ".rubocop.yml"
179
- - ".travis.yml"
180
- - ".yardopts"
181
- - CHANGELOG.md
182
- - Gemfile
183
203
  - LICENSE
184
- - README.md
185
- - Rakefile
186
204
  - lib/yard-sorbet.rb
187
205
  - lib/yard-sorbet/directives.rb
188
- - lib/yard-sorbet/sig_handler.rb
206
+ - lib/yard-sorbet/handlers.rb
207
+ - lib/yard-sorbet/handlers/abstract_dsl_handler.rb
208
+ - lib/yard-sorbet/handlers/enums_handler.rb
209
+ - lib/yard-sorbet/handlers/sig_handler.rb
210
+ - lib/yard-sorbet/handlers/struct_handler.rb
211
+ - lib/yard-sorbet/node_utils.rb
189
212
  - lib/yard-sorbet/sig_to_yard.rb
190
- - lib/yard-sorbet/struct_handler.rb
191
213
  - lib/yard-sorbet/version.rb
192
- - yard-sorbet.gemspec
193
214
  homepage: https://github.com/dduugg/yard-sorbet
194
215
  licenses:
195
216
  - Apache-2.0
196
217
  metadata:
218
+ bug_tracker_uri: https://github.com/dduugg/yard-sorbet/issues
219
+ changelog_uri: https://github.com/dduugg/yard-sorbet/blob/master/CHANGELOG.md
220
+ documentation_uri: https://dduugg.github.io/yard-sorbet/
197
221
  homepage_uri: https://github.com/dduugg/yard-sorbet
198
222
  source_code_uri: https://github.com/dduugg/yard-sorbet
199
- changelog_uri: https://github.com/dduugg/yard-sorbet/blob/master/CHANGELOG.md
223
+ wiki_uri: https://github.com/dduugg/yard-sorbet/wiki
200
224
  post_install_message:
201
225
  rdoc_options: []
202
226
  require_paths:
@@ -212,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
236
  - !ruby/object:Gem::Version
213
237
  version: '0'
214
238
  requirements: []
215
- rubygems_version: 3.0.3
239
+ rubygems_version: 3.1.4
216
240
  signing_key:
217
241
  specification_version: 4
218
242
  summary: Create YARD docs from Sorbet type signatures
data/.editorconfig DELETED
@@ -1,9 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = space
5
- indent_size = 2
6
- end_of_line = lf
7
- charset = utf-8
8
- trim_trailing_whitespace = true
9
- insert_final_newline = true
data/.gitignore DELETED
@@ -1,40 +0,0 @@
1
- *.gem
2
- *.rbc
3
- /.config
4
- /coverage/
5
- /InstalledFiles
6
- /pkg/
7
- /spec/reports/
8
- /spec/examples.txt
9
- /test/tmp/
10
- /test/version_tmp/
11
- /tmp/
12
-
13
- # Used by dotenv library to load environment variables.
14
- # .env
15
-
16
- # Ignore Byebug command history file.
17
- .byebug_history
18
-
19
- ## Documentation cache and generated files:
20
- /.yardoc/
21
- /_yardoc/
22
- /doc/
23
- /rdoc/
24
-
25
- ## Environment normalization:
26
- /.bundle/
27
- /vendor/bundle
28
- /lib/bundler/man/
29
-
30
- # for a library or gem, you might want to ignore these files since the code is
31
- # intended to run in multiple environments; otherwise, check them in:
32
- Gemfile.lock
33
- .ruby-version
34
- .ruby-gemset
35
-
36
- # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
37
- .rvmrc
38
-
39
- # Used by RuboCop. Remote config files pulled in from inherit_from directive.
40
- # .rubocop-https?--*
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,62 +0,0 @@
1
- ---
2
- require:
3
- - rubocop-rake
4
- - rubocop-rspec
5
- - rubocop-sorbet
6
-
7
- AllCops:
8
- NewCops: enable
9
- TargetRubyVersion: 2.5
10
-
11
- Layout/ClassStructure:
12
- Enabled: true
13
- # doesn't recognize sorbet magic comments
14
- Layout/EmptyLineAfterMagicComment:
15
- Enabled: false
16
- Layout/LineLength:
17
- Enabled: false
18
- Metrics/AbcSize:
19
- Enabled: false
20
- Metrics/BlockLength:
21
- Enabled: false
22
- Metrics/BlockNesting:
23
- Enabled: false
24
- Metrics/ClassLength:
25
- Enabled: false
26
- Metrics/CyclomaticComplexity:
27
- Enabled: false
28
- Metrics/MethodLength:
29
- Enabled: false
30
- Metrics/PerceivedComplexity:
31
- Enabled: false
32
- Naming/FileName:
33
- Exclude:
34
- - lib/yard-sorbet.rb
35
- RSpec/EmptyExampleGroup:
36
- Enabled: false
37
- RSpec/ExampleLength:
38
- Enabled: false
39
- RSpec/MultipleExpectations:
40
- Enabled: false
41
- Sorbet/EnforceSignatures:
42
- Enabled: false
43
- Sorbet/StrictSigil:
44
- Enabled: false
45
- Sorbet/StrongSigil:
46
- Enabled: false
47
- Sorbet/TrueSigil:
48
- Exclude:
49
- - lib/yard-sorbet/struct_handler.rb
50
- - spec/**/*
51
- Style/AccessModifierDeclarations:
52
- EnforcedStyle: inline
53
- Style/ClassAndModuleChildren:
54
- EnforcedStyle: compact
55
- Style/NegatedIf:
56
- Enabled: false
57
- Style/NegatedWhile:
58
- Enabled: false
59
- Style/Next:
60
- Enabled: false
61
- Style/IfUnlessModifier:
62
- Enabled: false
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.5
6
- - 2.6
7
- - 2.7
8
- before_install: gem install bundler -v 2.1.4
data/.yardopts DELETED
@@ -1,2 +0,0 @@
1
- --plugin sorbet
2
-
data/CHANGELOG.md DELETED
@@ -1,30 +0,0 @@
1
- # Change log
2
-
3
- ## master (unreleased)
4
-
5
- ## 0.1.0 (2020-12-01)
6
-
7
- ### New features
8
-
9
- * [#8](https://github.com/dduugg/yard-sorbet/pull/8): Add support for singleton class syntax.
10
- * [#7](https://github.com/dduugg/yard-sorbet/pull/7): Add support for top-level constants in sigs.
11
-
12
- ### Bug fixes
13
-
14
- * [#9](https://github.com/dduugg/yard-sorbet/pull/9): Remove warning for use of `T.attached_class`.
15
- * [#11](https://github.com/dduugg/yard-sorbet/pull/11): Fix parsing of custom parameterized types.
16
- * [#12](https://github.com/dduugg/yard-sorbet/pull/12): Fix parsing of recursive custom parameterized types.
17
-
18
- ### Changes
19
-
20
- * [#10](https://github.com/dduugg/yard-sorbet/pull/10): Downgrade log level of unsupported `sig` `aref` nodes.
21
- * Drop Ruby 2.4 support
22
-
23
- ## 0.0.1 (2020-01-24)
24
-
25
- * [#1](https://github.com/dduugg/yard-sorbet/pull/1): Add `T::Struct` support.
26
- * [#3](https://github.com/dduugg/yard-sorbet/pull/3): Rename require path to be conistent with gem name.
27
-
28
- ## 0.0.0 (2020-01-05)
29
-
30
- * Initial Release
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- source 'https://rubygems.org'
5
-
6
- gemspec
7
-
8
- gem 'pry-byebug'
data/README.md DELETED
@@ -1,17 +0,0 @@
1
- # yard-sorbet
2
- [![Gem Version](https://badge.fury.io/rb/yard-sorbet.svg)](https://badge.fury.io/rb/yard-sorbet)
3
- [![Build Status](https://travis-ci.com/dduugg/yard-sorbet.svg?branch=master)](https://travis-ci.com/dduugg/yard-sorbet)
4
- [![codecov](https://codecov.io/gh/dduugg/yard-sorbet/branch/master/graph/badge.svg)](https://codecov.io/gh/dduugg/yard-sorbet)
5
-
6
- A YARD [plugin](https://rubydoc.info/gems/yard/file/docs/GettingStarted.md#Plugin_Support) that parses Sorbet type annotations
7
-
8
- ## Install
9
-
10
- ```shell
11
- gem install yard-sorbet
12
- ```
13
-
14
- ## Usage
15
- ```bash
16
- yard doc --plugin sorbet
17
- ```
data/Rakefile DELETED
@@ -1,19 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- require 'bundler/gem_tasks'
5
- require 'rspec/core/rake_task'
6
-
7
- RSpec::Core::RakeTask.new(:spec)
8
-
9
- desc 'Lint files with Rubocop'
10
- task :lint do
11
- sh 'rubocop'
12
- end
13
-
14
- desc 'Typecheck files with Sorbet'
15
- task :typecheck do
16
- sh 'srb tc --ignore=vendor/'
17
- end
18
-
19
- task default: %i[lint spec typecheck]
@@ -1,147 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- # A YARD Handler for Sorbet type declarations
5
- class YARDSorbet::SigHandler < YARD::Handlers::Ruby::Base
6
- extend T::Sig
7
- handles :class, :module, :singleton_class?
8
-
9
- sig { returns(String).checked(:never) }
10
- def process
11
- # Find the list of declarations inside the class
12
- class_def = statement.children.find { |c| c.type == :list }
13
- class_contents = class_def.children
14
-
15
- process_class_contents(class_contents)
16
- end
17
-
18
- private def process_class_contents(class_contents)
19
- class_contents.each_with_index do |child, i|
20
- if child.type == :sclass && child.children.size == 2 && child.children[1].type == :list
21
- singleton_class_contents = child.children[1]
22
- process_class_contents(singleton_class_contents)
23
- end
24
- next unless type_signature?(child)
25
-
26
- next_statement = class_contents[i + 1]
27
- next unless processable_method?(next_statement)
28
-
29
- process_method_definition(next_statement, child)
30
- end
31
- end
32
-
33
- private def processable_method?(next_statement)
34
- %i[def defs command].include?(next_statement&.type) && !next_statement.docstring
35
- end
36
-
37
- private def process_method_definition(method_node, sig_node)
38
- # Swap the method definition docstring and the sig docstring.
39
- # Parse relevant parts of the `sig` and include them as well.
40
- docstring, directives = YARDSorbet::Directives.extract_directives(sig_node.docstring)
41
- parsed_sig = parse_sig(sig_node)
42
- enhance_tag(docstring, :abstract, parsed_sig)
43
- enhance_tag(docstring, :return, parsed_sig)
44
- if method_node.type != :command
45
- parsed_sig[:params]&.each do |name, types|
46
- enhance_param(docstring, name, types)
47
- end
48
- end
49
- method_node.docstring = docstring.to_raw
50
- YARDSorbet::Directives.add_directives(method_node.docstring, directives)
51
- sig_node.docstring = nil
52
- end
53
-
54
- private def enhance_param(docstring, name, types)
55
- tag = docstring.tags.find { |t| t.tag_name == 'param' && t.name == name }
56
- if tag
57
- docstring.delete_tag_if { |t| t == tag }
58
- tag.types = types
59
- else
60
- tag = YARD::Tags::Tag.new(:param, '', types, name)
61
- end
62
- docstring.add_tag(tag)
63
- end
64
-
65
- private def enhance_tag(docstring, type, parsed_sig)
66
- return if !parsed_sig[type]
67
-
68
- tag = docstring.tags.find { |t| t.tag_name == type.to_s }
69
- if tag
70
- docstring.delete_tags(type)
71
- else
72
- tag = YARD::Tags::Tag.new(type, '')
73
- end
74
- if parsed_sig[type].is_a?(Array)
75
- tag.types = parsed_sig[type]
76
- end
77
- docstring.add_tag(tag)
78
- end
79
-
80
- private def parse_sig(sig_node)
81
- parsed = {}
82
- parsed[:abstract] = false
83
- parsed[:params] = {}
84
- found_params = T.let(false, T::Boolean)
85
- found_return = T.let(false, T::Boolean)
86
- bfs_traverse(sig_node, exclude: %i[array hash]) do |n|
87
- if n.source == 'abstract'
88
- parsed[:abstract] = true
89
- elsif n.source == 'params' && !found_params
90
- found_params = true
91
- sibling = T.must(sibling_node(n))
92
- bfs_traverse(sibling, exclude: %i[array call hash]) do |p|
93
- if p.type == :assoc
94
- param_name = p.children.first.source[0...-1]
95
- types = YARDSorbet::SigToYARD.convert(p.children.last)
96
- parsed[:params][param_name] = types
97
- end
98
- end
99
- elsif n.source == 'returns' && !found_return
100
- found_return = true
101
- parsed[:return] = YARDSorbet::SigToYARD.convert(T.must(sibling_node(n)))
102
- elsif n.source == 'void'
103
- parsed[:return] ||= ['void']
104
- end
105
- end
106
- parsed
107
- end
108
-
109
- # Returns true if the given node is part of a type signature.
110
- private def type_signature?(node)
111
- loop do
112
- return false if node.nil?
113
- return false unless %i[call vcall fcall].include?(node.type)
114
- return true if T.unsafe(node).method_name(true) == :sig
115
-
116
- node = node.children.first
117
- end
118
- end
119
-
120
- private def sibling_node(node)
121
- found_sibling = T.let(false, T::Boolean)
122
- node.parent.children.each do |n|
123
- if found_sibling
124
- return n
125
- end
126
-
127
- if n == node
128
- found_sibling = true
129
- end
130
- end
131
- nil
132
- end
133
-
134
- # @yield [YARD::Parser::Ruby::AstNode]
135
- private def bfs_traverse(node, exclude: [])
136
- queue = [node]
137
- while !queue.empty?
138
- n = T.must(queue.shift)
139
- yield n
140
- n.children.each do |c|
141
- if !exclude.include?(c.type)
142
- queue.push(c)
143
- end
144
- end
145
- end
146
- end
147
- end
data/yard-sorbet.gemspec DELETED
@@ -1,39 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- require_relative 'lib/yard-sorbet/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = 'yard-sorbet'
8
- spec.version = YARDSorbet::VERSION
9
- spec.author = 'Douglas Eichelberger'
10
- spec.email = 'dduugg@gmail.com'
11
- spec.license = 'Apache-2.0'
12
-
13
- spec.summary = 'Create YARD docs from Sorbet type signatures'
14
- spec.description = <<~DESC
15
- A YARD plugin that incorporates Sorbet type information
16
- DESC
17
- spec.homepage = 'https://github.com/dduugg/yard-sorbet'
18
- spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
19
-
20
- spec.metadata['homepage_uri'] = spec.homepage
21
- spec.metadata['source_code_uri'] = spec.homepage
22
- spec.metadata['changelog_uri'] = 'https://github.com/dduugg/yard-sorbet/blob/master/CHANGELOG.md'
23
-
24
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(sorbet|spec)/}) }
26
- end
27
-
28
- spec.add_development_dependency 'codecov', '~> 0.2.12'
29
- spec.add_development_dependency 'rake', '~> 13.0'
30
- spec.add_development_dependency 'rspec', '~> 3.10'
31
- spec.add_development_dependency 'rubocop', '~> 1.5.0'
32
- spec.add_development_dependency 'rubocop-rake', '~> 0.5.1'
33
- spec.add_development_dependency 'rubocop-rspec', '~> 2.0.0'
34
- spec.add_development_dependency 'rubocop-sorbet', '~> 0.5.1'
35
- spec.add_development_dependency 'simplecov', '~> 0.20.0'
36
- spec.add_development_dependency 'sorbet', '~> 0.5.6083'
37
- spec.add_runtime_dependency 'sorbet-runtime', '>= 0.5'
38
- spec.add_runtime_dependency 'yard', '>= 0.9'
39
- end