ruby-lsp 0.11.2 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +11 -2
  4. data/exe/ruby-lsp-check +2 -1
  5. data/exe/ruby-lsp-doctor +15 -0
  6. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +125 -0
  7. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +10 -2
  8. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +205 -0
  9. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +23 -106
  10. data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +1 -1
  11. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +6 -6
  12. data/lib/ruby_indexer/lib/ruby_indexer/visitor.rb +101 -49
  13. data/lib/ruby_indexer/ruby_indexer.rb +4 -3
  14. data/lib/ruby_indexer/test/classes_and_modules_test.rb +49 -16
  15. data/lib/ruby_indexer/test/constant_test.rb +99 -36
  16. data/lib/ruby_indexer/test/index_test.rb +1 -1
  17. data/lib/ruby_indexer/test/method_test.rb +73 -0
  18. data/lib/ruby_indexer/test/test_case.rb +5 -1
  19. data/lib/ruby_lsp/addon.rb +8 -8
  20. data/lib/ruby_lsp/document.rb +14 -14
  21. data/lib/ruby_lsp/executor.rb +89 -53
  22. data/lib/ruby_lsp/internal.rb +7 -2
  23. data/lib/ruby_lsp/listener.rb +6 -6
  24. data/lib/ruby_lsp/requests/base_request.rb +1 -9
  25. data/lib/ruby_lsp/requests/code_action_resolve.rb +3 -3
  26. data/lib/ruby_lsp/requests/code_lens.rb +47 -31
  27. data/lib/ruby_lsp/requests/completion.rb +83 -32
  28. data/lib/ruby_lsp/requests/definition.rb +21 -15
  29. data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
  30. data/lib/ruby_lsp/requests/document_highlight.rb +508 -31
  31. data/lib/ruby_lsp/requests/document_link.rb +24 -17
  32. data/lib/ruby_lsp/requests/document_symbol.rb +42 -42
  33. data/lib/ruby_lsp/requests/folding_ranges.rb +83 -77
  34. data/lib/ruby_lsp/requests/hover.rb +22 -17
  35. data/lib/ruby_lsp/requests/inlay_hints.rb +6 -6
  36. data/lib/ruby_lsp/requests/selection_ranges.rb +13 -105
  37. data/lib/ruby_lsp/requests/semantic_highlighting.rb +92 -92
  38. data/lib/ruby_lsp/requests/support/annotation.rb +3 -3
  39. data/lib/ruby_lsp/requests/support/common.rb +5 -5
  40. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +21 -7
  41. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +19 -0
  42. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +10 -7
  43. data/lib/ruby_lsp/requests/support/sorbet.rb +28 -28
  44. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
  45. data/lib/ruby_lsp/requests.rb +0 -1
  46. data/lib/ruby_lsp/setup_bundler.rb +26 -17
  47. metadata +20 -17
  48. data/lib/ruby_lsp/event_emitter.rb +0 -351
  49. data/lib/ruby_lsp/requests/support/highlight_target.rb +0 -118
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 836f512695d45c2b360a2a6533185bd489a7d1c45eda21c0e67a2602cff23712
4
- data.tar.gz: bdf8fdeefffbb7620ba60cdd91e7e73d7ee9121c5bd810f3456fd46835f5bf5e
3
+ metadata.gz: 2774623b2161a416bfb07769e8eb5ccf3d40177f98edf9e4d4ed4c7e3f7fd47b
4
+ data.tar.gz: 23626aa84fdaf85571c7d039d670f9131409ccb7a8cd2c61d4889ffd08ecb8de
5
5
  SHA512:
6
- metadata.gz: 4be56dc36e58719d4ccdaea4b720507f21178b0fcfbbc9f634374dd808c33f46872c1cb25dc427f25f007d9b9b1333404c5724e8bbf8bab71ff1a3700c9a766d
7
- data.tar.gz: 6afc266ad6ae954492d9603e456ba1f65ed00ec6fdc31984b1c42c6597867224d2a230ad165ee2c18afc39d7e5e6eb0f88fc2f4f53e09a724ef67cd4e87e53b2
6
+ metadata.gz: ffd099ba6d95ce10cd3fd2c3fb1e431d5481e0e8bad77c062fdd9b2f9fce534f9c58319672e508d17ca089e10ba9fdf398479dd9dfac3adbc347912815800cdd
7
+ data.tar.gz: fb0f4c3111718c5f792266459e2694787ea7939b63c819707bba764395dc6cc3bf1d925517a1fa412b362fbd0b3222e8460723df4f2c3a4272ac73dc62eb872a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.2
1
+ 0.12.1
data/exe/ruby-lsp CHANGED
@@ -25,6 +25,13 @@ parser = OptionParser.new do |opts|
25
25
  options[:branch] = branch
26
26
  end
27
27
 
28
+ opts.on(
29
+ "--experimental",
30
+ "Run pre-release versions of the Ruby LSP",
31
+ ) do
32
+ options[:experimental] = true
33
+ end
34
+
28
35
  opts.on("-h", "--help", "Print this help") do
29
36
  puts opts.help
30
37
  puts
@@ -49,7 +56,7 @@ if ENV["BUNDLE_GEMFILE"].nil?
49
56
  require_relative "../lib/ruby_lsp/setup_bundler"
50
57
 
51
58
  begin
52
- bundle_gemfile, bundle_path = RubyLsp::SetupBundler.new(Dir.pwd, branch: options[:branch]).setup!
59
+ bundle_gemfile, bundle_path, bundle_app_config = RubyLsp::SetupBundler.new(Dir.pwd, **options).setup!
53
60
  rescue RubyLsp::SetupBundler::BundleNotLocked
54
61
  warn("Project contains a Gemfile, but no Gemfile.lock. Run `bundle install` to lock gems and restart the server")
55
62
  exit(78)
@@ -57,6 +64,7 @@ if ENV["BUNDLE_GEMFILE"].nil?
57
64
 
58
65
  env = { "BUNDLE_GEMFILE" => bundle_gemfile }
59
66
  env["BUNDLE_PATH"] = bundle_path if bundle_path
67
+ env["BUNDLE_APP_CONFIG"] = bundle_app_config if bundle_app_config
60
68
  exit exec(env, "bundle exec ruby-lsp #{original_args.join(" ")}")
61
69
  end
62
70
 
@@ -77,7 +85,8 @@ rescue
77
85
  nil
78
86
  end
79
87
 
80
- require_relative "../lib/ruby_lsp/internal"
88
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
89
+ require "ruby_lsp/internal"
81
90
 
82
91
  if options[:debug]
83
92
  if ["x64-mingw-ucrt", "x64-mingw32"].include?(RUBY_PLATFORM)
data/exe/ruby-lsp-check CHANGED
@@ -14,7 +14,8 @@ rescue
14
14
  nil
15
15
  end
16
16
 
17
- require_relative "../lib/ruby_lsp/internal"
17
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
18
+ require "ruby_lsp/internal"
18
19
 
19
20
  RubyLsp::Addon.load_addons
20
21
 
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
+ require "ruby_lsp/internal"
6
+
7
+ index = RubyIndexer::Index.new
8
+
9
+ RubyIndexer.configuration.indexables.each do |indexable|
10
+ puts "indexing: #{indexable.full_path}"
11
+ content = File.read(indexable.full_path)
12
+ result = Prism.parse(content)
13
+ visitor = RubyIndexer::IndexVisitor.new(index, result, indexable.full_path)
14
+ result.value.accept(visitor)
15
+ end
@@ -0,0 +1,125 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "rubocop"
5
+ require "sorbet-runtime"
6
+
7
+ module RuboCop
8
+ module Cop
9
+ module RubyLsp
10
+ # Avoid using register without handler method, or handler without register.
11
+ #
12
+ # @example
13
+ # # Register without handler method.
14
+ #
15
+ # # bad
16
+ # class MyListener < Listener
17
+ # def initialize(dispatcher)
18
+ # super()
19
+ # dispatcher.register(
20
+ # self,
21
+ # :on_string_node_enter,
22
+ # )
23
+ # end
24
+ # end
25
+ #
26
+ # # good
27
+ # class MyListener < Listener
28
+ # def initialize(dispatcher)
29
+ # super()
30
+ # dispatcher.register(
31
+ # self,
32
+ # :on_string_node_enter,
33
+ # )
34
+ # end
35
+ #
36
+ # def on_string_node_enter(node)
37
+ # end
38
+ # end
39
+ #
40
+ # @example
41
+ # # Handler method without register.
42
+ #
43
+ # # bad
44
+ # class MyListener < Listener
45
+ # def initialize(dispatcher)
46
+ # super()
47
+ # dispatcher.register(
48
+ # self,
49
+ # )
50
+ # end
51
+ #
52
+ # def on_string_node_enter(node)
53
+ # end
54
+ # end
55
+ #
56
+ # # good
57
+ # class MyListener < Listener
58
+ # def initialize(dispatcher)
59
+ # super()
60
+ # dispatcher.register(
61
+ # self,
62
+ # :on_string_node_enter,
63
+ # )
64
+ # end
65
+ #
66
+ # def on_string_node_enter(node)
67
+ # end
68
+ # end
69
+ class UseRegisterWithHandlerMethod < RuboCop::Cop::Base
70
+ extend T::Sig
71
+
72
+ MSG_MISSING_HANDLER = "Registered to `%{listener}` without a handler defined."
73
+ MSG_MISSING_LISTENER = "Created a handler without registering the associated `%{listener}` event."
74
+
75
+ def_node_search(
76
+ :find_all_listeners,
77
+ "(send
78
+ (_ :dispatcher) :register
79
+ (self)
80
+ $(sym _)+)",
81
+ )
82
+
83
+ def_node_search(
84
+ :find_all_handlers,
85
+ "$(def [_ #valid_event_name?] (args (arg _)) ...)",
86
+ )
87
+
88
+ def on_new_investigation
89
+ return if processed_source.blank?
90
+
91
+ listeners = find_all_listeners(processed_source.ast).flat_map { |listener| listener }
92
+ handlers = find_all_handlers(processed_source.ast).flat_map { |handler| handler }
93
+
94
+ add_offense_to_listeners_without_handler(listeners, handlers)
95
+ add_offense_handlers_without_listener(listeners, handlers)
96
+ end
97
+
98
+ private
99
+
100
+ sig { params(event_name: Symbol).returns(T::Boolean) }
101
+ def valid_event_name?(event_name)
102
+ /^on_.*(node_enter|node_leave)$/.match?(event_name)
103
+ end
104
+
105
+ sig { params(listeners: T::Array[RuboCop::AST::SymbolNode], handlers: T::Array[RuboCop::AST::DefNode]).void }
106
+ def add_offense_to_listeners_without_handler(listeners, handlers)
107
+ return if listeners.none?
108
+
109
+ listeners
110
+ .filter { |node| handlers.map(&:method_name).none?(node.value) }
111
+ .each { |node| add_offense(node, message: format(MSG_MISSING_HANDLER, listener: node.value)) }
112
+ end
113
+
114
+ sig { params(listeners: T::Array[RuboCop::AST::SymbolNode], handlers: T::Array[RuboCop::AST::DefNode]).void }
115
+ def add_offense_handlers_without_listener(listeners, handlers)
116
+ return if handlers.none?
117
+
118
+ handlers
119
+ .filter { |node| listeners.map(&:value).none?(node.method_name) }
120
+ .each { |node| add_offense(node, message: format(MSG_MISSING_LISTENER, listener: node.method_name)) }
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -67,8 +67,12 @@ module RubyIndexer
67
67
 
68
68
  # Add user specified patterns
69
69
  indexables = @included_patterns.flat_map do |pattern|
70
+ load_path_entry = T.let(nil, T.nilable(String))
71
+
70
72
  Dir.glob(pattern, File::FNM_PATHNAME | File::FNM_EXTGLOB).map! do |path|
71
- load_path_entry = $LOAD_PATH.find { |load_path| path.start_with?(load_path) }
73
+ # All entries for the same pattern match the same $LOAD_PATH entry. Since searching the $LOAD_PATH for every
74
+ # entry is expensive, we memoize it for the entire pattern
75
+ load_path_entry ||= $LOAD_PATH.find { |load_path| path.start_with?(load_path) }
72
76
  IndexablePath.new(load_path_entry, path)
73
77
  end
74
78
  end
@@ -98,6 +102,10 @@ module RubyIndexer
98
102
  next if locked_gems&.any? do |locked_spec|
99
103
  locked_spec.name == short_name &&
100
104
  !Gem::Specification.find_by_name(short_name).full_gem_path.start_with?(RbConfig::CONFIG["rubylibprefix"])
105
+ rescue Gem::MissingSpecError
106
+ # If a default gem is scoped to a specific platform, then `find_by_name` will raise. We want to skip those
107
+ # cases
108
+ true
101
109
  end
102
110
 
103
111
  if pathname.directory?
@@ -142,7 +150,7 @@ module RubyIndexer
142
150
 
143
151
  sig { returns(Regexp) }
144
152
  def magic_comment_regex
145
- @magic_comment_regex ||= T.let(/^\s*#\s*#{@excluded_magic_comments.join("|")}/, T.nilable(Regexp))
153
+ @magic_comment_regex ||= T.let(/^#\s*#{@excluded_magic_comments.join("|")}/, T.nilable(Regexp))
146
154
  end
147
155
 
148
156
  private
@@ -0,0 +1,205 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyIndexer
5
+ class Entry
6
+ extend T::Sig
7
+
8
+ sig { returns(String) }
9
+ attr_reader :name
10
+
11
+ sig { returns(String) }
12
+ attr_reader :file_path
13
+
14
+ sig { returns(Prism::Location) }
15
+ attr_reader :location
16
+
17
+ sig { returns(T::Array[String]) }
18
+ attr_reader :comments
19
+
20
+ sig { returns(Symbol) }
21
+ attr_accessor :visibility
22
+
23
+ sig { params(name: String, file_path: String, location: Prism::Location, comments: T::Array[String]).void }
24
+ def initialize(name, file_path, location, comments)
25
+ @name = name
26
+ @file_path = file_path
27
+ @location = location
28
+ @comments = comments
29
+ @visibility = T.let(:public, Symbol)
30
+ end
31
+
32
+ sig { returns(String) }
33
+ def file_name
34
+ File.basename(@file_path)
35
+ end
36
+
37
+ class Namespace < Entry
38
+ extend T::Sig
39
+ extend T::Helpers
40
+
41
+ abstract!
42
+
43
+ sig { returns(String) }
44
+ def short_name
45
+ T.must(@name.split("::").last)
46
+ end
47
+ end
48
+
49
+ class Module < Namespace
50
+ end
51
+
52
+ class Class < Namespace
53
+ extend T::Sig
54
+
55
+ # The unresolved name of the parent class. This may return `nil`, which indicates the lack of an explicit parent
56
+ # and therefore ::Object is the correct parent class
57
+ sig { returns(T.nilable(String)) }
58
+ attr_reader :parent_class
59
+
60
+ sig do
61
+ params(
62
+ name: String,
63
+ file_path: String,
64
+ location: Prism::Location,
65
+ comments: T::Array[String],
66
+ parent_class: T.nilable(String),
67
+ ).void
68
+ end
69
+ def initialize(name, file_path, location, comments, parent_class)
70
+ super(name, file_path, location, comments)
71
+ @parent_class = T.let(parent_class, T.nilable(String))
72
+ end
73
+ end
74
+
75
+ class Constant < Entry
76
+ end
77
+
78
+ class Parameter
79
+ extend T::Helpers
80
+ extend T::Sig
81
+
82
+ abstract!
83
+
84
+ sig { returns(Symbol) }
85
+ attr_reader :name
86
+
87
+ sig { params(name: Symbol).void }
88
+ def initialize(name:)
89
+ @name = name
90
+ end
91
+ end
92
+
93
+ class RequiredParameter < Parameter
94
+ end
95
+
96
+ class Method < Entry
97
+ extend T::Sig
98
+ extend T::Helpers
99
+ abstract!
100
+
101
+ sig { returns(T::Array[Parameter]) }
102
+ attr_reader :parameters
103
+
104
+ sig do
105
+ params(
106
+ name: String,
107
+ file_path: String,
108
+ location: Prism::Location,
109
+ comments: T::Array[String],
110
+ parameters_node: T.nilable(Prism::ParametersNode),
111
+ ).void
112
+ end
113
+ def initialize(name, file_path, location, comments, parameters_node)
114
+ super(name, file_path, location, comments)
115
+ @parameters = T.let(list_params(parameters_node), T::Array[Parameter])
116
+ end
117
+
118
+ private
119
+
120
+ sig { params(parameters_node: T.nilable(Prism::ParametersNode)).returns(T::Array[Parameter]) }
121
+ def list_params(parameters_node)
122
+ return [] unless parameters_node
123
+
124
+ parameters_node.requireds.filter_map do |required|
125
+ name = parameter_name(required)
126
+ next unless name
127
+
128
+ RequiredParameter.new(name: name)
129
+ end
130
+ end
131
+
132
+ sig do
133
+ params(node: Prism::Node).returns(T.nilable(Symbol))
134
+ end
135
+ def parameter_name(node)
136
+ case node
137
+ when Prism::RequiredParameterNode
138
+ node.name
139
+ when Prism::RequiredDestructuredParameterNode
140
+ names = node.parameters.map { |parameter_node| parameter_name(parameter_node) }
141
+ names_with_commas = names.join(", ")
142
+ :"(#{names_with_commas})"
143
+ end
144
+ end
145
+ end
146
+
147
+ class SingletonMethod < Method
148
+ end
149
+
150
+ class InstanceMethod < Method
151
+ end
152
+
153
+ # An UnresolvedAlias points to a constant alias with a right hand side that has not yet been resolved. For
154
+ # example, if we find
155
+ #
156
+ # ```ruby
157
+ # CONST = Foo
158
+ # ```
159
+ # Before we have discovered `Foo`, there's no way to eagerly resolve this alias to the correct target constant.
160
+ # All aliases are inserted as UnresolvedAlias in the index first and then we lazily resolve them to the correct
161
+ # target in [rdoc-ref:Index#resolve]. If the right hand side contains a constant that doesn't exist, then it's not
162
+ # possible to resolve the alias and it will remain an UnresolvedAlias until the right hand side constant exists
163
+ class UnresolvedAlias < Entry
164
+ extend T::Sig
165
+
166
+ sig { returns(String) }
167
+ attr_reader :target
168
+
169
+ sig { returns(T::Array[String]) }
170
+ attr_reader :nesting
171
+
172
+ sig do
173
+ params(
174
+ target: String,
175
+ nesting: T::Array[String],
176
+ name: String,
177
+ file_path: String,
178
+ location: Prism::Location,
179
+ comments: T::Array[String],
180
+ ).void
181
+ end
182
+ def initialize(target, nesting, name, file_path, location, comments) # rubocop:disable Metrics/ParameterLists
183
+ super(name, file_path, location, comments)
184
+
185
+ @target = target
186
+ @nesting = nesting
187
+ end
188
+ end
189
+
190
+ # Alias represents a resolved alias, which points to an existing constant target
191
+ class Alias < Entry
192
+ extend T::Sig
193
+
194
+ sig { returns(String) }
195
+ attr_reader :target
196
+
197
+ sig { params(target: String, unresolved_alias: UnresolvedAlias).void }
198
+ def initialize(target, unresolved_alias)
199
+ super(unresolved_alias.name, unresolved_alias.file_path, unresolved_alias.location, unresolved_alias.comments)
200
+
201
+ @target = target
202
+ end
203
+ end
204
+ end
205
+ end
@@ -95,7 +95,7 @@ module RubyIndexer
95
95
  # ```
96
96
  sig { params(query: String, nesting: T::Array[String]).returns(T::Array[T::Array[Entry]]) }
97
97
  def prefix_search(query, nesting)
98
- results = (nesting.length + 1).downto(0).flat_map do |i|
98
+ results = nesting.length.downto(0).flat_map do |i|
99
99
  prefix = T.must(nesting[0...i]).join("::")
100
100
  namespaced_query = prefix.empty? ? query : "#{prefix}::#{query}"
101
101
  @entries_tree.search(namespaced_query)
@@ -153,15 +153,33 @@ module RubyIndexer
153
153
  nil
154
154
  end
155
155
 
156
- sig { params(indexable_paths: T::Array[IndexablePath]).void }
157
- def index_all(indexable_paths: RubyIndexer.configuration.indexables)
158
- indexable_paths.each { |path| index_single(path) }
156
+ # Index all files for the given indexable paths, which defaults to what is configured. A block can be used to track
157
+ # and control indexing progress. That block is invoked with the current progress percentage and should return `true`
158
+ # to continue indexing or `false` to stop indexing.
159
+ sig do
160
+ params(
161
+ indexable_paths: T::Array[IndexablePath],
162
+ block: T.nilable(T.proc.params(progress: Integer).returns(T::Boolean)),
163
+ ).void
164
+ end
165
+ def index_all(indexable_paths: RubyIndexer.configuration.indexables, &block)
166
+ # Calculate how many paths are worth 1% of progress
167
+ progress_step = (indexable_paths.length / 100.0).ceil
168
+
169
+ indexable_paths.each_with_index do |path, index|
170
+ if block && index % progress_step == 0
171
+ progress = (index / progress_step) + 1
172
+ break unless block.call(progress)
173
+ end
174
+
175
+ index_single(path)
176
+ end
159
177
  end
160
178
 
161
179
  sig { params(indexable_path: IndexablePath, source: T.nilable(String)).void }
162
180
  def index_single(indexable_path, source = nil)
163
181
  content = source || File.read(indexable_path.full_path)
164
- result = YARP.parse(content)
182
+ result = Prism.parse(content)
165
183
  visitor = IndexVisitor.new(self, result, indexable_path.full_path)
166
184
  result.value.accept(visitor)
167
185
 
@@ -234,106 +252,5 @@ module RubyIndexer
234
252
 
235
253
  resolved_alias
236
254
  end
237
-
238
- class Entry
239
- extend T::Sig
240
-
241
- sig { returns(String) }
242
- attr_reader :name
243
-
244
- sig { returns(String) }
245
- attr_reader :file_path
246
-
247
- sig { returns(YARP::Location) }
248
- attr_reader :location
249
-
250
- sig { returns(T::Array[String]) }
251
- attr_reader :comments
252
-
253
- sig { returns(Symbol) }
254
- attr_accessor :visibility
255
-
256
- sig { params(name: String, file_path: String, location: YARP::Location, comments: T::Array[String]).void }
257
- def initialize(name, file_path, location, comments)
258
- @name = name
259
- @file_path = file_path
260
- @location = location
261
- @comments = comments
262
- @visibility = T.let(:public, Symbol)
263
- end
264
-
265
- sig { returns(String) }
266
- def file_name
267
- File.basename(@file_path)
268
- end
269
-
270
- class Namespace < Entry
271
- sig { returns(String) }
272
- def short_name
273
- T.must(@name.split("::").last)
274
- end
275
- end
276
-
277
- class Module < Namespace
278
- end
279
-
280
- class Class < Namespace
281
- end
282
-
283
- class Constant < Entry
284
- end
285
-
286
- # An UnresolvedAlias points to a constant alias with a right hand side that has not yet been resolved. For
287
- # example, if we find
288
- #
289
- # ```ruby
290
- # CONST = Foo
291
- # ```
292
- # Before we have discovered `Foo`, there's no way to eagerly resolve this alias to the correct target constant.
293
- # All aliases are inserted as UnresolvedAlias in the index first and then we lazily resolve them to the correct
294
- # target in [rdoc-ref:Index#resolve]. If the right hand side contains a constant that doesn't exist, then it's not
295
- # possible to resolve the alias and it will remain an UnresolvedAlias until the right hand side constant exists
296
- class UnresolvedAlias < Entry
297
- extend T::Sig
298
-
299
- sig { returns(String) }
300
- attr_reader :target
301
-
302
- sig { returns(T::Array[String]) }
303
- attr_reader :nesting
304
-
305
- sig do
306
- params(
307
- target: String,
308
- nesting: T::Array[String],
309
- name: String,
310
- file_path: String,
311
- location: YARP::Location,
312
- comments: T::Array[String],
313
- ).void
314
- end
315
- def initialize(target, nesting, name, file_path, location, comments) # rubocop:disable Metrics/ParameterLists
316
- super(name, file_path, location, comments)
317
-
318
- @target = target
319
- @nesting = nesting
320
- end
321
- end
322
-
323
- # Alias represents a resolved alias, which points to an existing constant target
324
- class Alias < Entry
325
- extend T::Sig
326
-
327
- sig { returns(String) }
328
- attr_reader :target
329
-
330
- sig { params(target: String, unresolved_alias: UnresolvedAlias).void }
331
- def initialize(target, unresolved_alias)
332
- super(unresolved_alias.name, unresolved_alias.file_path, unresolved_alias.location, unresolved_alias.comments)
333
-
334
- @target = target
335
- end
336
- end
337
- end
338
255
  end
339
256
  end
@@ -21,7 +21,7 @@ module RubyIndexer
21
21
  def initialize(load_path_entry, full_path)
22
22
  @full_path = full_path
23
23
  @require_path = T.let(
24
- load_path_entry ? Pathname.new(full_path).relative_path_from(load_path_entry).to_s.delete_suffix(".rb") : nil,
24
+ load_path_entry ? full_path.delete_prefix("#{load_path_entry}/").delete_suffix(".rb") : nil,
25
25
  T.nilable(String),
26
26
  )
27
27
  end
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyIndexer
@@ -133,16 +133,16 @@ module RubyIndexer
133
133
  @key = key
134
134
  @value = value
135
135
  @parent = parent
136
- @children = T.let({}, T::Hash[String, Node[Value]])
137
- @leaf = T.let(false, T::Boolean)
136
+ @children = {}
137
+ @leaf = false
138
138
  end
139
139
 
140
140
  sig { returns(T::Array[Value]) }
141
141
  def collect
142
- result = T.let([], T::Array[Value])
143
- result << value if leaf
142
+ result = []
143
+ result << @value if @leaf
144
144
 
145
- children.each_value do |node|
145
+ @children.each_value do |node|
146
146
  result.concat(node.collect)
147
147
  end
148
148