ruby-lsp-ree 0.1.21 → 0.1.22

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: 3f11e82aca2c43fe42fb37077f3bc8590c5c68e06c13d9068c6872ae859faaad
4
- data.tar.gz: 07fa4705541847c82764e5c4e27c13b190c240e63c12bb86a98fd49577be6090
3
+ metadata.gz: be41c6719d100fed8169e29ecfb808cf73611625cd14982727ee7763ab55d809
4
+ data.tar.gz: 2dac21136c9605aadeb19544f3efb6d9cf3044b40cfeaca2279203ba846f101d
5
5
  SHA512:
6
- metadata.gz: b7bc67742989ee60af3e3b9f4dd38b44183522e86d7b8f1af90c255edb10179086e55255312fd80abf7306af37d318f0e8343f6183926ffb424288ff479fce4f
7
- data.tar.gz: 593ebeac60988a3a9f9db7137d99a313b07d7ebd6385e7e3a566c93960a7ebfd803ce1fccef8d595b12ecd53c5e22a3afa41b4fad279d8de49870ffa9a1c4737
6
+ metadata.gz: 03f9fd7161d065c127b7f479b547b92edad8923b9a24eaa12b687382ad50b1946fa37029281bdda7aa9b9159ddc19f281f304479ec9c35e8516701eaf13b4e6b
7
+ data.tar.gz: d2324472049d592331c2ad8a32e156fa374f85f644ab67ce366cecdd486260804c0830aa6372c040669ca291584cd39368860b8ebc29f1c4013bb927a20e5a12
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.1.22] - 2025-05-30
2
+
3
+ - unused links formatter: improve usage detection
4
+ - Go To Definition: handle link aliases
5
+ - Go To Definition: go to package from link params
6
+
1
7
  ## [0.1.21] - 2025-05-21
2
8
 
3
9
  - formatter: deduplicate dao columns
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp-ree (0.1.21)
4
+ ruby-lsp-ree (0.1.22)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -26,7 +26,7 @@ module RubyLsp
26
26
  remove_imports = []
27
27
 
28
28
  if link_node.has_import_section?
29
- remove_imports = link_node.imports.reject{ |imp| import_is_used?(link_node, imp) }
29
+ remove_imports = link_node.imports.reject{ |imp| import_is_used?(parsed_doc, link_node, imp) }
30
30
  editor.remove_link_imports(link_node, remove_imports)
31
31
 
32
32
  if link_node.imports.size == remove_imports.size
@@ -34,7 +34,7 @@ module RubyLsp
34
34
  end
35
35
  end
36
36
 
37
- next if link_is_used?(link_node, remove_imports) || parsed_doc.includes_mapper_dsl?
37
+ next if link_is_used?(parsed_doc, link_node, remove_imports) || parsed_doc.includes_mapper_dsl?
38
38
 
39
39
  editor.remove_link(link_node)
40
40
  removed_links += 1
@@ -50,12 +50,12 @@ module RubyLsp
50
50
 
51
51
  private
52
52
 
53
- def import_is_used?(link_node, link_import)
54
- editor.contains_link_import_usage?(link_node, link_import) || dsl_parser.contains_object_usage?(link_import)
53
+ def import_is_used?(parsed_doc, link_node, link_import)
54
+ editor.contains_link_import_usage?(parsed_doc, link_node, link_import) || dsl_parser.contains_object_usage?(link_import)
55
55
  end
56
56
 
57
- def link_is_used?(link_node, remove_imports)
58
- editor.contains_link_usage?(link_node) || link_node.imports.size > remove_imports.size || dsl_parser.contains_object_usage?(link_node.name)
57
+ def link_is_used?(parsed_doc, link_node, remove_imports)
58
+ editor.contains_link_usage?(parsed_doc, link_node) || link_node.imports.size > remove_imports.size || dsl_parser.contains_object_usage?(link_node.name)
59
59
  end
60
60
  end
61
61
  end
@@ -75,10 +75,10 @@ module RubyLsp
75
75
  result = []
76
76
 
77
77
  parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@root_node, @uri)
78
- link_node = parsed_doc.find_link_node(message)
78
+ link_node = parsed_doc.find_link_by_usage_name(message)
79
79
 
80
80
  definition_item = if link_node
81
- @finder.find_object_for_package(message, link_node.link_package_name)
81
+ @finder.find_object_for_package(link_node.name, link_node.link_package_name)
82
82
  else
83
83
  @finder.find_object(message)
84
84
  end
@@ -106,7 +106,7 @@ module RubyLsp
106
106
  link_node = RubyLsp::Ree::ParsedLinkNode.new(parent_node, package_name_from_uri(@uri))
107
107
  package_name = link_node.link_package_name
108
108
 
109
- method_candidates = @index[node.unescaped]
109
+ method_candidates = @index[link_node.name]
110
110
  return [] if !method_candidates || method_candidates.size == 0
111
111
 
112
112
  method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
@@ -225,6 +225,32 @@ module RubyLsp
225
225
 
226
226
  result
227
227
  end
228
+
229
+ def get_package_definition_items(node)
230
+ package_name = node.unescaped
231
+
232
+ parent_node = @node_context.parent
233
+ link_node = RubyLsp::Ree::ParsedLinkNode.new(parent_node, package_name_from_uri(@uri))
234
+
235
+ method_candidates = @index[link_node.name]
236
+ return [] if !method_candidates || method_candidates.size == 0
237
+
238
+ method = method_candidates.detect{ package_name_from_uri(_1.uri) == package_name }
239
+ return [] unless method
240
+
241
+ package_path = package_path_from_uri(method.uri.to_s)
242
+ package_main_file_path = File.join(package_path, 'package', "#{package_name}.rb")
243
+
244
+ [
245
+ Interface::Location.new(
246
+ uri: package_main_file_path,
247
+ range: Interface::Range.new(
248
+ start: Interface::Position.new(line: 0, character: 0),
249
+ end: Interface::Position.new(line: 0, character: 0),
250
+ ),
251
+ )
252
+ ]
253
+ end
228
254
  end
229
255
  end
230
256
  end
@@ -45,7 +45,11 @@ module RubyLsp
45
45
  definition_items = if @ree_context.is_error_definition?
46
46
  @handler.get_error_code_definition_items(node)
47
47
  elsif @ree_context.is_link_object?
48
- @handler.get_linked_object_definition_items(node)
48
+ if @ree_context.is_package_argument?
49
+ @handler.get_package_definition_items(node)
50
+ else
51
+ @handler.get_linked_object_definition_items(node)
52
+ end
49
53
  else
50
54
  @handler.get_routes_definition_items(node)
51
55
  end
@@ -0,0 +1,117 @@
1
+ require 'prism'
2
+
3
+ class RubyLsp::Ree::BodyObjectsParser
4
+ class ConstObject
5
+ attr_reader :name
6
+
7
+ def initialize(name:)
8
+ @name = name
9
+ end
10
+ end
11
+
12
+ class CallObject
13
+ attr_reader :name, :type, :receiver_name, :method_name
14
+
15
+ def initialize(name:, type:, receiver_name: nil)
16
+ @name = name
17
+ @type = type
18
+ @receiver_name = receiver_name
19
+ @method_name = nil
20
+ end
21
+
22
+ def set_method_name(method_name)
23
+ @method_name = method_name
24
+ end
25
+
26
+ def has_receiver?
27
+ !!@receiver_name
28
+ end
29
+ end
30
+
31
+ def initialize(target_type)
32
+ @target_type = target_type
33
+ end
34
+
35
+ def parse(node_body)
36
+ target_objects = []
37
+
38
+ return target_objects unless node_body
39
+
40
+ node_body.each do |node|
41
+ if node.is_a?(Prism::ConstantReadNode) && @target_type == :const_object
42
+ target_objects << ConstObject.new(name: node.name)
43
+ end
44
+
45
+ if node.is_a?(Prism::CallNode)
46
+ if node.receiver
47
+ target_objects += parse([node.receiver])
48
+ else
49
+ if @target_type == :call_object
50
+ target_objects << CallObject.new(name: node.name, type: :method_call)
51
+ end
52
+ end
53
+
54
+ target_objects += parse_target_objects_from_args(node.arguments)
55
+ else
56
+ if node.respond_to?(:elements)
57
+ target_objects += parse(node.elements)
58
+ end
59
+
60
+ if node.respond_to?(:predicate)
61
+ target_objects += parse([node.predicate])
62
+ end
63
+
64
+ if node.respond_to?(:statements)
65
+ target_objects += parse(node.statements.body)
66
+ end
67
+
68
+ if node.respond_to?(:subsequent)
69
+ target_objects += parse([node.subsequent])
70
+ end
71
+
72
+ if node.respond_to?(:value) && node.value
73
+ target_objects += parse([node.value])
74
+ end
75
+
76
+ if node.respond_to?(:key) && node.key
77
+ target_objects += parse([node.key])
78
+ end
79
+
80
+ if node.respond_to?(:left) && node.left
81
+ target_objects += parse([node.left])
82
+ end
83
+
84
+ if node.respond_to?(:right) && node.right
85
+ target_objects += parse([node.right])
86
+ end
87
+
88
+ if node.respond_to?(:parts) && node.parts
89
+ target_objects += parse(node.parts)
90
+ end
91
+ end
92
+
93
+ if node.respond_to?(:block) && node.block && node.block.is_a?(Prism::BlockNode)
94
+ target_objects += parse(get_method_body(node.block))
95
+ end
96
+ end
97
+
98
+ target_objects
99
+ end
100
+
101
+ private
102
+
103
+ def parse_target_objects_from_args(node_arguments)
104
+ return [] if !node_arguments || !node_arguments.arguments
105
+ parse(node_arguments.arguments)
106
+ end
107
+
108
+ def get_method_body(node)
109
+ return unless node.body
110
+
111
+ if node.body.is_a?(Prism::BeginNode)
112
+ node.body.statements.body
113
+ else
114
+ node.body.body
115
+ end
116
+ end
117
+ end
@@ -1,33 +1,20 @@
1
+ require_relative 'body_objects_parser'
2
+
1
3
  class RubyLsp::Ree::CallObjectsParser
2
4
  attr_reader :parsed_doc
3
5
 
4
- class CallObject
5
- attr_reader :name, :type, :receiver_name, :method_name
6
-
7
- def initialize(name:, type:, receiver_name: nil)
8
- @name = name
9
- @type = type
10
- @receiver_name = receiver_name
11
- @method_name = nil
12
- end
13
-
14
- def set_method_name(method_name)
15
- @method_name = method_name
16
- end
17
- end
18
-
19
6
  def initialize(parsed_doc)
20
7
  @parsed_doc = parsed_doc
8
+ @body_parser = RubyLsp::Ree::BodyObjectsParser.new(:call_object)
21
9
  end
22
10
 
23
11
  def class_call_objects
24
12
  call_objects = []
25
13
  return unless parsed_doc.has_body?
26
14
 
27
- call_objects += parse_body_call_objects(parsed_doc.class_node.body.body)
15
+ call_objects += @body_parser.parse(parsed_doc.class_node.body.body)
28
16
 
29
17
  parsed_doc.parse_instance_methods
30
-
31
18
  parsed_doc.doc_instance_methods.each do |doc_instance_method|
32
19
  call_objects += method_call_objects(doc_instance_method)
33
20
  end
@@ -39,107 +26,9 @@ class RubyLsp::Ree::CallObjectsParser
39
26
  method_body = method_object.method_body
40
27
  return [] unless method_body
41
28
 
42
- call_nodes = parse_body_call_objects(method_body)
43
- call_expressions = [] # don't parse call expressions for now parse_body_call_expressions(method_body)
44
-
45
- call_objects = call_nodes + call_expressions
29
+ call_objects = @body_parser.parse(method_body)
46
30
 
47
31
  call_objects.each{ |call_object| call_object.set_method_name(method_object.name) }
48
32
  call_objects
49
33
  end
50
-
51
- private
52
-
53
- def parse_body_call_objects(node_body)
54
- call_objects = []
55
-
56
- return call_objects unless node_body
57
-
58
- node_body.each do |node|
59
- if node.is_a?(Prism::CallNode)
60
- if node.receiver
61
- receiver = get_first_receiver(node)
62
-
63
- if receiver.is_a?(Prism::CallNode)
64
- call_objects += parse_body_call_objects([receiver])
65
- end
66
- else
67
- call_objects << CallObject.new(name: node.name, type: :method_call)
68
- end
69
-
70
- call_objects += parse_call_objects_from_args(node.arguments)
71
- else
72
- if node.respond_to?(:elements)
73
- call_objects += parse_body_call_objects(node.elements)
74
- end
75
-
76
- if node.respond_to?(:predicate)
77
- call_objects += parse_body_call_objects([node.predicate])
78
- end
79
-
80
- if node.respond_to?(:statements)
81
- call_objects += parse_body_call_objects(node.statements.body)
82
- end
83
-
84
- if node.respond_to?(:value) && node.value
85
- call_objects += parse_body_call_objects([node.value])
86
- end
87
-
88
- if node.respond_to?(:left) && node.left
89
- call_objects += parse_body_call_objects([node.left])
90
- end
91
-
92
- if node.respond_to?(:right) && node.right
93
- call_objects += parse_body_call_objects([node.right])
94
- end
95
-
96
- if node.respond_to?(:parts) && node.parts
97
- call_objects += parse_body_call_objects(node.parts)
98
- end
99
- end
100
-
101
- if node.respond_to?(:block) && node.block && node.block.is_a?(Prism::BlockNode)
102
- call_objects += parse_body_call_objects(get_method_body(node.block))
103
- end
104
- end
105
-
106
- call_objects
107
- end
108
-
109
- def parse_call_objects_from_args(node_arguments)
110
- return [] if !node_arguments || !node_arguments.arguments
111
- parse_body_call_objects(node_arguments.arguments)
112
- end
113
-
114
- def parse_body_call_expressions(node_body)
115
- call_expressions = []
116
-
117
- node_body.each do |node|
118
- if node.respond_to?(:block) && node.block && node.block.is_a?(Prism::BlockArgumentNode) && node.block.expression.is_a?(Prism::SymbolNode)
119
- call_expressions << CallObject.new(name: node.block.expression.unescaped.to_sym, type: :proc_to_sym)
120
- end
121
- end
122
-
123
- call_expressions
124
- end
125
-
126
- def get_method_body(node)
127
- return unless node.body
128
-
129
- if node.body.is_a?(Prism::BeginNode)
130
- node.body.statements.body
131
- else
132
- node.body.body
133
- end
134
- end
135
-
136
- def get_first_receiver(node)
137
- return nil unless node.receiver
138
-
139
- if node.receiver.is_a?(Prism::CallNode) && node.receiver.receiver
140
- return get_first_receiver(node.receiver)
141
- end
142
-
143
- node.receiver
144
- end
145
34
  end
@@ -0,0 +1,37 @@
1
+ require_relative 'body_objects_parser'
2
+
3
+ class RubyLsp::Ree::ConstObjectsParser
4
+ attr_reader :parsed_doc
5
+
6
+ def initialize(parsed_doc)
7
+ @parsed_doc = parsed_doc
8
+ @body_parser = RubyLsp::Ree::BodyObjectsParser.new(:const_object)
9
+ end
10
+
11
+ def class_const_objects
12
+ const_objects = []
13
+ return unless parsed_doc.has_body?
14
+
15
+ const_objects += @body_parser.parse(parsed_doc.class_node.body.body)
16
+
17
+ parsed_doc.parse_instance_methods
18
+ parsed_doc.doc_instance_methods.each do |doc_instance_method|
19
+ const_objects += method_const_objects(doc_instance_method)
20
+ end
21
+
22
+ const_objects
23
+ end
24
+
25
+ def method_const_objects(method_object)
26
+ method_body = method_object.method_body
27
+ return [] unless method_body
28
+
29
+ const_objects = @body_parser.parse(method_body)
30
+
31
+ if method_object.has_contract?
32
+ const_objects += @body_parser.parse([method_object.contract_node])
33
+ end
34
+
35
+ const_objects
36
+ end
37
+ end
@@ -44,6 +44,10 @@ class RubyLsp::Ree::ParsedBaseDocument
44
44
  @link_nodes.detect{ node_name(_1) == name }
45
45
  end
46
46
 
47
+ def find_link_by_usage_name(name)
48
+ @link_nodes.detect{ _1.usage_name == name }
49
+ end
50
+
47
51
  def find_import_for_package(name, package_name)
48
52
  @link_nodes.detect do |link_node|
49
53
  link_node.imports.include?(name) && link_node.link_package_name == package_name
@@ -3,6 +3,7 @@ require_relative 'parsed_link_node'
3
3
  require_relative 'parsed_method_node'
4
4
  require_relative "../ree_constants"
5
5
  require_relative "body_parsers/call_objects_parser"
6
+ require_relative "body_parsers/const_objects_parser"
6
7
 
7
8
  require 'ostruct'
8
9
 
@@ -195,6 +196,10 @@ class RubyLsp::Ree::ParsedClassDocument < RubyLsp::Ree::ParsedBaseDocument
195
196
  RubyLsp::Ree::CallObjectsParser.new(self).class_call_objects
196
197
  end
197
198
 
199
+ def parse_const_objects
200
+ RubyLsp::Ree::ConstObjectsParser.new(self).class_const_objects
201
+ end
202
+
198
203
  def class_name
199
204
  class_node.constant_path.name.to_s
200
205
  end
@@ -6,21 +6,41 @@ module RubyLsp
6
6
  class ReeContext
7
7
  include RubyLsp::Ree::ReeConstants
8
8
 
9
+ FROM_ARG_KEY = 'from'
10
+
9
11
  def initialize(node_context)
10
12
  @node_context = node_context
11
13
  end
12
14
 
13
15
  def is_error_definition?
14
- return false if !@node_context || !@node_context.parent || !@node_context.parent.is_a?(Prism::CallNode)
16
+ return false unless has_call_parent?
15
17
 
16
18
  ERROR_DEFINITION_NAMES.include?(@node_context.parent.name)
17
19
  end
18
20
 
19
21
  def is_link_object?
20
- return false if !@node_context || !@node_context.parent || !@node_context.parent.is_a?(Prism::CallNode)
22
+ return false unless has_call_parent?
21
23
 
22
24
  @node_context.parent.name == :link
23
25
  end
26
+
27
+ def is_package_argument?
28
+ return false unless has_call_parent?
29
+ return false if !@node_context.parent.arguments || @node_context.parent.arguments.arguments.size < 2
30
+ return false if @node_context.node.unescaped == @node_context.parent.arguments.arguments.first.unescaped
31
+
32
+ kw_args = @node_context.parent.arguments.arguments.detect{ |arg| arg.is_a?(Prism::KeywordHashNode) }
33
+ return false unless kw_args
34
+
35
+ package_param = kw_args.elements.detect{ _1.key.unescaped == FROM_ARG_KEY }
36
+ package_param.value.unescaped == @node_context.node.unescaped
37
+ end
38
+
39
+ private
40
+
41
+ def has_call_parent?
42
+ @node_context && @node_context.parent && @node_context.parent.is_a?(Prism::CallNode)
43
+ end
24
44
  end
25
45
  end
26
46
  end
@@ -13,12 +13,23 @@ module RubyLsp
13
13
  @source_lines.join
14
14
  end
15
15
 
16
- def contains_link_usage?(link_node)
16
+ def contains_link_usage?(parsed_doc, link_node)
17
+ if parsed_doc.respond_to?(:parse_method_calls)
18
+ method_calls = parsed_doc.parse_method_calls
19
+ no_receiver_method_names = method_calls.reject(&:has_receiver?).map(&:name).map(&:to_s)
20
+ return no_receiver_method_names.include?(link_node.usage_name)
21
+ end
22
+
17
23
  source_lines_except_link = source_lines[0...(link_node.location.start_line-1)] + source_lines[(link_node.location.end_line)..-1]
18
24
  source_lines_except_link.any?{ |source_line| source_line.match?(/\W#{link_node.usage_name}\W/)}
19
25
  end
20
26
 
21
- def contains_link_import_usage?(link_node, link_import)
27
+ def contains_link_import_usage?(parsed_doc, link_node, link_import)
28
+ if parsed_doc.respond_to?(:parse_const_objects)
29
+ const_objects = parsed_doc.parse_const_objects
30
+ return const_objects.map(&:name).map(&:to_s).include?(link_import)
31
+ end
32
+
22
33
  source_lines_except_link = source_lines[0...(link_node.location.start_line-1)] + source_lines[(link_node.location.end_line)..-1]
23
34
  source_lines_except_link.any?{ |source_line| source_line.match?(/\W#{link_import}\W/)}
24
35
  end
@@ -11,7 +11,7 @@ module RubyLsp
11
11
  file_name = file_path + ".rb"
12
12
  Dir[File.join('**', file_name)].first
13
13
  end
14
-
14
+
15
15
  def package_name_from_uri(uri)
16
16
  uri_parts = uri.to_s.split('/')
17
17
 
@@ -30,6 +30,15 @@ module RubyLsp
30
30
  uri_parts[spec_folder_index + 1]
31
31
  end
32
32
 
33
+ def package_path_from_uri(uri)
34
+ uri_parts = uri.to_s.split('/')
35
+
36
+ package_folder_index = uri_parts.find_index('package')
37
+ return unless package_folder_index
38
+
39
+ uri_parts.take(package_folder_index).join('/')
40
+ end
41
+
33
42
  def path_from_package_folder(uri)
34
43
  uri_parts = uri.to_s.chomp(File.extname(uri.to_s)).split('/')
35
44
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RubyLsp
4
4
  module Ree
5
- VERSION = "0.1.21"
5
+ VERSION = "0.1.22"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp-ree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.21
4
+ version: 0.1.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-05-21 00:00:00.000000000 Z
11
+ date: 2025-05-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby LSP addon that adds extra editor functionality for Ree applications
14
14
  email:
@@ -44,7 +44,9 @@ files:
44
44
  - lib/ruby_lsp/ruby_lsp_ree/listeners/completion_listener.rb
45
45
  - lib/ruby_lsp/ruby_lsp_ree/listeners/definition_listener.rb
46
46
  - lib/ruby_lsp/ruby_lsp_ree/listeners/hover_listener.rb
47
+ - lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/body_objects_parser.rb
47
48
  - lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/call_objects_parser.rb
49
+ - lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/const_objects_parser.rb
48
50
  - lib/ruby_lsp/ruby_lsp_ree/parsing/body_parsers/local_variables_parser.rb
49
51
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_base_document.rb
50
52
  - lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_class_document.rb