solargraph 0.56.1 → 0.57.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.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +125 -0
  3. data/.github/workflows/plugins.yml +148 -6
  4. data/.github/workflows/rspec.yml +39 -4
  5. data/.github/workflows/typecheck.yml +5 -2
  6. data/.gitignore +5 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +2627 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +50 -0
  13. data/README.md +8 -4
  14. data/Rakefile +125 -13
  15. data/lib/solargraph/api_map/cache.rb +3 -2
  16. data/lib/solargraph/api_map/constants.rb +218 -0
  17. data/lib/solargraph/api_map/index.rb +20 -26
  18. data/lib/solargraph/api_map/source_to_yard.rb +10 -4
  19. data/lib/solargraph/api_map/store.rb +126 -18
  20. data/lib/solargraph/api_map.rb +212 -234
  21. data/lib/solargraph/bench.rb +1 -0
  22. data/lib/solargraph/complex_type/type_methods.rb +1 -0
  23. data/lib/solargraph/complex_type/unique_type.rb +7 -7
  24. data/lib/solargraph/complex_type.rb +5 -1
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  26. data/lib/solargraph/convention/base.rb +17 -0
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  29. data/lib/solargraph/convention/data_definition.rb +105 -0
  30. data/lib/solargraph/convention/gemspec.rb +3 -2
  31. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -2
  33. data/lib/solargraph/convention/struct_definition.rb +87 -24
  34. data/lib/solargraph/convention.rb +32 -2
  35. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  36. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
  37. data/lib/solargraph/doc_map.rb +40 -12
  38. data/lib/solargraph/environ.rb +9 -2
  39. data/lib/solargraph/gem_pins.rb +17 -11
  40. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  41. data/lib/solargraph/language_server/host/message_worker.rb +3 -0
  42. data/lib/solargraph/language_server/host.rb +2 -1
  43. data/lib/solargraph/language_server/message/base.rb +2 -1
  44. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
  45. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  46. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
  47. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  48. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  49. data/lib/solargraph/language_server/progress.rb +8 -0
  50. data/lib/solargraph/language_server/request.rb +1 -0
  51. data/lib/solargraph/library.rb +17 -24
  52. data/lib/solargraph/location.rb +2 -0
  53. data/lib/solargraph/logging.rb +11 -2
  54. data/lib/solargraph/page.rb +4 -0
  55. data/lib/solargraph/parser/comment_ripper.rb +8 -1
  56. data/lib/solargraph/parser/flow_sensitive_typing.rb +32 -4
  57. data/lib/solargraph/parser/node_methods.rb +2 -2
  58. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  59. data/lib/solargraph/parser/node_processor.rb +24 -8
  60. data/lib/solargraph/parser/parser_gem/class_methods.rb +1 -1
  61. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  62. data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
  63. data/lib/solargraph/parser/parser_gem/node_methods.rb +4 -2
  64. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
  65. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +1 -21
  66. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
  68. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +0 -22
  69. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +1 -0
  70. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  71. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +1 -0
  72. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +35 -14
  73. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +1 -0
  74. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  75. data/lib/solargraph/parser/region.rb +3 -0
  76. data/lib/solargraph/parser/snippet.rb +2 -0
  77. data/lib/solargraph/pin/base.rb +65 -8
  78. data/lib/solargraph/pin/base_variable.rb +1 -2
  79. data/lib/solargraph/pin/callable.rb +9 -0
  80. data/lib/solargraph/pin/closure.rb +2 -0
  81. data/lib/solargraph/pin/common.rb +6 -2
  82. data/lib/solargraph/pin/constant.rb +2 -0
  83. data/lib/solargraph/pin/delegated_method.rb +1 -0
  84. data/lib/solargraph/pin/local_variable.rb +4 -1
  85. data/lib/solargraph/pin/method.rb +12 -7
  86. data/lib/solargraph/pin/method_alias.rb +3 -0
  87. data/lib/solargraph/pin/parameter.rb +18 -8
  88. data/lib/solargraph/pin/proxy_type.rb +1 -0
  89. data/lib/solargraph/pin/reference/override.rb +15 -1
  90. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  91. data/lib/solargraph/pin/reference.rb +26 -0
  92. data/lib/solargraph/pin/search.rb +3 -1
  93. data/lib/solargraph/pin/signature.rb +2 -0
  94. data/lib/solargraph/pin/symbol.rb +5 -0
  95. data/lib/solargraph/pin_cache.rb +64 -4
  96. data/lib/solargraph/position.rb +2 -0
  97. data/lib/solargraph/range.rb +1 -0
  98. data/lib/solargraph/rbs_map/conversions.rb +47 -18
  99. data/lib/solargraph/rbs_map/core_map.rb +3 -0
  100. data/lib/solargraph/rbs_map.rb +15 -2
  101. data/lib/solargraph/shell.rb +3 -0
  102. data/lib/solargraph/source/chain/link.rb +10 -1
  103. data/lib/solargraph/source/chain.rb +9 -2
  104. data/lib/solargraph/source/change.rb +2 -2
  105. data/lib/solargraph/source/cursor.rb +2 -3
  106. data/lib/solargraph/source/source_chainer.rb +1 -1
  107. data/lib/solargraph/source.rb +5 -2
  108. data/lib/solargraph/source_map/clip.rb +1 -1
  109. data/lib/solargraph/source_map/data.rb +4 -0
  110. data/lib/solargraph/source_map/mapper.rb +4 -2
  111. data/lib/solargraph/source_map.rb +21 -14
  112. data/lib/solargraph/type_checker/param_def.rb +2 -0
  113. data/lib/solargraph/type_checker/rules.rb +8 -0
  114. data/lib/solargraph/type_checker.rb +173 -120
  115. data/lib/solargraph/version.rb +1 -1
  116. data/lib/solargraph/workspace/config.rb +1 -3
  117. data/lib/solargraph/workspace/require_paths.rb +98 -0
  118. data/lib/solargraph/workspace.rb +16 -48
  119. data/lib/solargraph/yard_map/helpers.rb +29 -1
  120. data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -5
  121. data/lib/solargraph/yard_map/mapper/to_method.rb +3 -8
  122. data/lib/solargraph/yard_map/mapper/to_namespace.rb +7 -7
  123. data/lib/solargraph/yardoc.rb +16 -3
  124. data/lib/solargraph.rb +15 -0
  125. data/rbs/fills/tuple.rbs +2 -3
  126. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  127. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  128. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  129. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  130. data/solargraph.gemspec +14 -4
  131. metadata +126 -9
  132. data/lib/.rubocop.yml +0 -22
@@ -37,6 +37,7 @@ module Solargraph
37
37
  .to_h
38
38
  end
39
39
 
40
+ # @return [Set<SourceMap>]
40
41
  def icebox
41
42
  @icebox ||= (source_maps - [live_map])
42
43
  end
@@ -130,6 +130,7 @@ module Solargraph
130
130
  end.call
131
131
  end
132
132
 
133
+ # @return [self]
133
134
  def namespace_type
134
135
  return ComplexType.parse('::Object') if duck_type?
135
136
  return ComplexType.parse('::NilClass') if nil_type?
@@ -49,11 +49,7 @@ module Solargraph
49
49
  parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
50
50
  if parameters_type == :hash
51
51
  raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring}" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
52
- # @todo should be able to resolve map; both types have it
53
- # with same return type
54
- # @sg-ignore
55
52
  key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
56
- # @sg-ignore
57
53
  subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
58
54
  elsif parameters_type == :list && name == 'Hash'
59
55
  # Treat Hash<A, B> as Hash{A => B}
@@ -105,6 +101,7 @@ module Solargraph
105
101
  tag
106
102
  end
107
103
 
104
+ # @return [self]
108
105
  def simplify_literals
109
106
  transform do |t|
110
107
  next t unless t.literal?
@@ -116,10 +113,12 @@ module Solargraph
116
113
  non_literal_name != name
117
114
  end
118
115
 
116
+ # @return [String]
119
117
  def non_literal_name
120
118
  @non_literal_name ||= determine_non_literal_name
121
119
  end
122
120
 
121
+ # @return [String]
123
122
  def determine_non_literal_name
124
123
  # https://github.com/ruby/rbs/blob/master/docs/syntax.md
125
124
  #
@@ -171,6 +170,7 @@ module Solargraph
171
170
  end
172
171
  end
173
172
 
173
+ # @return [String]
174
174
  def desc
175
175
  rooted_tags
176
176
  end
@@ -255,7 +255,7 @@ module Solargraph
255
255
 
256
256
  # @param generics_to_resolve [Enumerable<String>]
257
257
  # @param context_type [UniqueType, nil]
258
- # @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
258
+ # @param resolved_generic_values [Hash{String => ComplexType, ComplexType::UniqueType}] Added to as types are encountered or resolved
259
259
  # @return [UniqueType, ComplexType]
260
260
  def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
261
261
  if name == ComplexType::GENERIC_TAG_NAME
@@ -353,9 +353,9 @@ module Solargraph
353
353
 
354
354
  # @param new_name [String, nil]
355
355
  # @param make_rooted [Boolean, nil]
356
- # @param new_key_types [Array<UniqueType>, nil]
356
+ # @param new_key_types [Array<ComplexType>, nil]
357
357
  # @param rooted [Boolean, nil]
358
- # @param new_subtypes [Array<UniqueType>, nil]
358
+ # @param new_subtypes [Array<ComplexType>, nil]
359
359
  # @return [self]
360
360
  def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
361
361
  raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
@@ -155,10 +155,12 @@ module Solargraph
155
155
  map(&:tag).join(', ')
156
156
  end
157
157
 
158
+ # @return [String]
158
159
  def tags
159
160
  map(&:tag).join(', ')
160
161
  end
161
162
 
163
+ # @return [String]
162
164
  def simple_tags
163
165
  simplify_literals.tags
164
166
  end
@@ -172,10 +174,12 @@ module Solargraph
172
174
  ComplexType.new(items.map(&:downcast_to_literal_if_possible))
173
175
  end
174
176
 
177
+ # @return [String]
175
178
  def desc
176
179
  rooted_tags
177
180
  end
178
181
 
182
+ # @return [String]
179
183
  def rooted_tags
180
184
  map(&:rooted_tag).join(', ')
181
185
  end
@@ -200,6 +204,7 @@ module Solargraph
200
204
  any?(&:generic?)
201
205
  end
202
206
 
207
+ # @return [self]
203
208
  def simplify_literals
204
209
  ComplexType.new(map(&:simplify_literals))
205
210
  end
@@ -299,7 +304,6 @@ module Solargraph
299
304
  # # @todo Need ability to use a literal true as a type below
300
305
  # # @param partial [Boolean] True if the string is part of a another type
301
306
  # # @return [Array<UniqueType>]
302
- # @sg-ignore
303
307
  # @todo To be able to select the right signature above,
304
308
  # Chain::Call needs to know the decl type (:arg, :optarg,
305
309
  # :kwarg, etc) of the arguments given, instead of just having
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ # ActiveSupport::Concern is syntactic sugar for a common
6
+ # pattern to include class methods while mixing-in a Module
7
+ # See https://api.rubyonrails.org/classes/ActiveSupport/Concern.html
8
+ class ActiveSupportConcern < Base
9
+ include Logging
10
+
11
+ # @return [Array<Pin::Base>]
12
+ attr_reader :pins
13
+
14
+ # @param api_map [ApiMap]
15
+ # @param rooted_tag [String]
16
+ # @param scope [Symbol] :class or :instance
17
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
18
+ # @param deep [Boolean] whether to include methods from included modules
19
+ # @param skip [Set<String>]
20
+ # @param _no_core [Boolean]n whether to skip core methods
21
+ def object api_map, rooted_tag, scope, visibility, deep, skip, _no_core
22
+ moo = ObjectProcessor.new(api_map, rooted_tag, scope, visibility, deep, skip)
23
+ moo.environ
24
+ end
25
+
26
+ # yard-activesupport-concern pulls methods inside
27
+ # 'class_methods' blocks into main class visible from YARD
28
+ #
29
+ # @param _doc_map [DocMap]
30
+ def global _doc_map
31
+ Environ.new(yard_plugins: ['activesupport-concern'])
32
+ end
33
+
34
+ # Process an object to add any class methods brought in via
35
+ # ActiveSupport::Concern
36
+ class ObjectProcessor
37
+ include Logging
38
+
39
+ attr_reader :environ
40
+
41
+ # @param api_map [ApiMap]
42
+ # @param rooted_tag [String] the tag of the class or module being processed
43
+ # @param scope [Symbol] :class or :instance
44
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
45
+ # @param deep [Boolean] whether to include methods from included modules
46
+ # @param skip [Set<String>] a set of tags to skip
47
+ def initialize api_map, rooted_tag, scope, visibility, deep, skip
48
+ @api_map = api_map
49
+ @rooted_tag = rooted_tag
50
+ @scope = scope
51
+ @visibility = visibility
52
+ @deep = deep
53
+ @skip = skip
54
+
55
+ @environ = Environ.new
56
+ return unless scope == :class
57
+
58
+ @rooted_type = ComplexType.parse(rooted_tag).force_rooted
59
+ @fqns = rooted_type.namespace
60
+ @namespace_pin = api_map.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
61
+
62
+ api_map.get_includes(fqns).reverse.each do |include_tag|
63
+ process_include include_tag
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ attr_reader :api_map, :rooted_tag, :rooted_type, :scope,
70
+ :visibility, :deep, :skip, :namespace_pin,
71
+ :fqns
72
+
73
+ # @param include_tag [Pin::Reference::Include] the include reference pin
74
+ #
75
+ # @return [void]
76
+ def process_include include_tag
77
+ rooted_include_tag = api_map.dereference(include_tag)
78
+ return if rooted_include_tag.nil?
79
+ logger.debug do
80
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
81
+ "Handling class include include_tag=#{include_tag}"
82
+ end
83
+ module_extends = api_map.get_extends(rooted_include_tag).map(&:parametrized_tag).map(&:to_s)
84
+ logger.debug do
85
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
86
+ "found module extends of #{rooted_include_tag}: #{module_extends}"
87
+ end
88
+ return unless module_extends.include? 'ActiveSupport::Concern'
89
+ included_class_pins = api_map.inner_get_methods_from_reference(rooted_include_tag, namespace_pin, rooted_type,
90
+ :class, visibility, deep, skip, true)
91
+ logger.debug do
92
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
93
+ "Found #{included_class_pins.length} inluded class methods for #{rooted_include_tag}"
94
+ end
95
+ environ.pins.concat included_class_pins
96
+ # another pattern is to put class methods inside a submodule
97
+ classmethods_include_tag = "#{rooted_include_tag}::ClassMethods"
98
+ included_classmethods_pins =
99
+ api_map.inner_get_methods_from_reference(classmethods_include_tag, namespace_pin, rooted_type,
100
+ :instance, visibility, deep, skip, true)
101
+ logger.debug do
102
+ "ActiveSupportConcern#object(#{fqns}, #{scope}, #{visibility}, #{deep}) - " \
103
+ "Found #{included_classmethods_pins.length} included classmethod " \
104
+ "class methods for #{classmethods_include_tag}"
105
+ end
106
+ environ.pins.concat included_classmethods_pins
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -28,6 +28,23 @@ module Solargraph
28
28
  def global doc_map
29
29
  EMPTY_ENVIRON
30
30
  end
31
+
32
+ # Provides any additional method pins based on e the described object.
33
+ #
34
+ # @param api_map [ApiMap]
35
+ # @param rooted_tag [String] A fully qualified namespace, with
36
+ # generic parameter values if applicable
37
+ # @param scope [Symbol] :class or :instance
38
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
39
+ # @param deep [Boolean]
40
+ # @param skip [Set<String>]
41
+ # @param no_core [Boolean] Skip core classes if true
42
+ #
43
+ # @return [Environ]
44
+ def object api_map, rooted_tag, scope, visibility,
45
+ deep, skip, no_core
46
+ EMPTY_ENVIRON
47
+ end
31
48
  end
32
49
  end
33
50
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module DataDefinition
6
+ # A node wrapper for a Data definition via const assignment.
7
+ # @example
8
+ # MyData = Data.new(:bar, :baz) do
9
+ # def foo
10
+ # end
11
+ # end
12
+ class DataAssignmentNode < DataDefintionNode
13
+ class << self
14
+ # @example
15
+ # s(:casgn, nil, :Foo,
16
+ # s(:block,
17
+ # s(:send,
18
+ # s(:const, nil, :Data), :define,
19
+ # s(:sym, :bar),
20
+ # s(:sym, :baz)),
21
+ # s(:args),
22
+ # s(:def, :foo,
23
+ # s(:args),
24
+ # s(:send, nil, :bar))))
25
+ # @param node [::Parser::AST::Node]
26
+ def match?(node)
27
+ return false unless node&.type == :casgn
28
+ return false if node.children[2].nil?
29
+
30
+ data_node = if node.children[2].type == :block
31
+ node.children[2].children[0]
32
+ else
33
+ node.children[2]
34
+ end
35
+
36
+ data_definition_node?(data_node)
37
+ end
38
+ end
39
+
40
+ def class_name
41
+ if node.children[0]
42
+ Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
43
+ else
44
+ node.children[1].to_s
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # @return [Parser::AST::Node]
51
+ def data_node
52
+ if node.children[2].type == :block
53
+ node.children[2].children[0]
54
+ else
55
+ node.children[2]
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module DataDefinition
6
+ # A node wrapper for a Data definition via inheritance.
7
+ # @example
8
+ # class MyData < Data.new(:bar, :baz)
9
+ # def foo
10
+ # end
11
+ # end
12
+ class DataDefintionNode
13
+ class << self
14
+ # @example
15
+ # s(:class,
16
+ # s(:const, nil, :Foo),
17
+ # s(:send,
18
+ # s(:const, nil, :Data), :define,
19
+ # s(:sym, :bar),
20
+ # s(:sym, :baz)),
21
+ # s(:hash,
22
+ # s(:pair,
23
+ # s(:sym, :keyword_init),
24
+ # s(:true)))),
25
+ # s(:def, :foo,
26
+ # s(:args),
27
+ # s(:send, nil, :bar)))
28
+ #
29
+ # @param node [Parser::AST::Node]
30
+ def match?(node)
31
+ return false unless node&.type == :class
32
+
33
+ data_definition_node?(node.children[1])
34
+ end
35
+
36
+ private
37
+
38
+ # @param data_node [Parser::AST::Node]
39
+ # @return [Boolean]
40
+ def data_definition_node?(data_node)
41
+ return false unless data_node.is_a?(::Parser::AST::Node)
42
+ return false unless data_node&.type == :send
43
+ return false unless data_node.children[0]&.type == :const
44
+ return false unless data_node.children[0].children[1] == :Data
45
+ return false unless data_node.children[1] == :define
46
+
47
+ true
48
+ end
49
+ end
50
+
51
+ # @param node [Parser::AST::Node]
52
+ def initialize(node)
53
+ @node = node
54
+ end
55
+
56
+ # @return [String]
57
+ def class_name
58
+ Parser::NodeMethods.unpack_name(node)
59
+ end
60
+
61
+ # @return [Array<Array(Parser::AST::Node, String)>]
62
+ def attributes
63
+ data_attribute_nodes.map do |data_def_param|
64
+ next unless data_def_param.type == :sym
65
+ [data_def_param, data_def_param.children[0].to_s]
66
+ end.compact
67
+ end
68
+
69
+ # @return [Parser::AST::Node]
70
+ def body_node
71
+ node.children[2]
72
+ end
73
+
74
+ private
75
+
76
+ # @return [Parser::AST::Node]
77
+ attr_reader :node
78
+
79
+ # @return [Parser::AST::Node]
80
+ def data_node
81
+ node.children[1]
82
+ end
83
+
84
+ # @return [Array<Parser::AST::Node>]
85
+ def data_attribute_nodes
86
+ data_node.children[2..-1]
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ module DataDefinition
6
+ autoload :DataDefintionNode, 'solargraph/convention/data_definition/data_definition_node'
7
+ autoload :DataAssignmentNode, 'solargraph/convention/data_definition/data_assignment_node'
8
+
9
+ module NodeProcessors
10
+ class DataNode < Parser::NodeProcessor::Base
11
+ # @return [Boolean] continue processing the next processor of the same node.
12
+ def process
13
+ return true if data_definition_node.nil?
14
+
15
+ loc = get_node_location(node)
16
+ nspin = Solargraph::Pin::Namespace.new(
17
+ type: :class,
18
+ location: loc,
19
+ closure: region.closure,
20
+ name: data_definition_node.class_name,
21
+ comments: comments_for(node),
22
+ visibility: :public,
23
+ gates: region.closure.gates.freeze
24
+ )
25
+ pins.push nspin
26
+
27
+ # define initialize method
28
+ initialize_method_pin = Pin::Method.new(
29
+ name: 'initialize',
30
+ parameters: [],
31
+ scope: :instance,
32
+ location: get_node_location(node),
33
+ closure: nspin,
34
+ visibility: :private,
35
+ comments: comments_for(node)
36
+ )
37
+
38
+ # @todo Support both arg and kwarg initializers for Data.define
39
+ # Solargraph::SourceMap::Clip#complete_keyword_parameters does not seem to currently take into account [Pin::Method#signatures] hence we only one for :kwarg
40
+ pins.push initialize_method_pin
41
+
42
+ data_definition_node.attributes.map do |attribute_node, attribute_name|
43
+ initialize_method_pin.parameters.push(
44
+ Pin::Parameter.new(
45
+ name: attribute_name,
46
+ decl: :kwarg,
47
+ location: get_node_location(attribute_node),
48
+ closure: initialize_method_pin
49
+ )
50
+ )
51
+ end
52
+
53
+ # define attribute readers and instance variables
54
+ data_definition_node.attributes.each do |attribute_node, attribute_name|
55
+ name = attribute_name.to_s
56
+ method_pin = Pin::Method.new(
57
+ name: name,
58
+ parameters: [],
59
+ scope: :instance,
60
+ location: get_node_location(attribute_node),
61
+ closure: nspin,
62
+ comments: attribute_comments(attribute_node, attribute_name),
63
+ visibility: :public
64
+ )
65
+
66
+ pins.push method_pin
67
+
68
+ pins.push Pin::InstanceVariable.new(name: "@#{attribute_name}",
69
+ closure: method_pin,
70
+ location: get_node_location(attribute_node),
71
+ comments: attribute_comments(attribute_node, attribute_name))
72
+ end
73
+
74
+ process_children region.update(closure: nspin, visibility: :public)
75
+
76
+ false
77
+ end
78
+
79
+ private
80
+
81
+ # @return [DataDefintionNode, nil]
82
+ def data_definition_node
83
+ @data_definition_node ||= if DataDefintionNode.match?(node)
84
+ DataDefintionNode.new(node)
85
+ elsif DataAssignmentNode.match?(node)
86
+ DataAssignmentNode.new(node)
87
+ end
88
+ end
89
+
90
+ # @param attribute_node [Parser::AST::Node]
91
+ # @param attribute_name [String]
92
+ # @return [String, nil]
93
+ def attribute_comments(attribute_node, attribute_name)
94
+ data_comments = comments_for(attribute_node)
95
+ return if data_comments.nil? || data_comments.empty?
96
+
97
+ data_comments.split("\n").find do |row|
98
+ row.include?(attribute_name)
99
+ end&.gsub('@param', '@return')&.gsub(attribute_name, '')
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -4,7 +4,7 @@ module Solargraph
4
4
  module Convention
5
5
  class Gemspec < Base
6
6
  def local source_map
7
- return EMPTY_ENVIRON unless File.basename(source_map.filename).end_with?('.gemspec')
7
+ return Convention::Base::EMPTY_ENVIRON unless File.basename(source_map.filename).end_with?('.gemspec')
8
8
  @environ ||= Environ.new(
9
9
  requires: ['rubygems'],
10
10
  pins: [
@@ -12,7 +12,8 @@ module Solargraph
12
12
  'Gem::Specification.new',
13
13
  %(
14
14
  @yieldparam [self]
15
- )
15
+ ),
16
+ source: :gemspec
16
17
  )
17
18
  ]
18
19
  )
@@ -22,7 +22,8 @@ module Solargraph
22
22
  # s(:def, :foo,
23
23
  # s(:args),
24
24
  # s(:send, nil, :bar))))
25
- def valid?(node)
25
+ # @param node [Parser::AST::Node]
26
+ def match?(node)
26
27
  return false unless node&.type == :casgn
27
28
  return false if node.children[2].nil?
28
29
 
@@ -25,7 +25,9 @@ module Solargraph
25
25
  # s(:def, :foo,
26
26
  # s(:args),
27
27
  # s(:send, nil, :bar)))
28
- def valid?(node)
28
+ #
29
+ # @param node [Parser::AST::Node]
30
+ def match?(node)
29
31
  return false unless node&.type == :class
30
32
 
31
33
  struct_definition_node?(node.children[1])
@@ -46,7 +48,7 @@ module Solargraph
46
48
  end
47
49
  end
48
50
 
49
- # @return [Parser::AST::Node]
51
+ # @param node [Parser::AST::Node]
50
52
  def initialize(node)
51
53
  @node = node
52
54
  end