ruby-lsp-rails 0.3.26 → 0.3.27
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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2df24f43b3e6666c310cb91e43d3b4311eea8326e27aa7bb4278c9fd03de42d1
|
4
|
+
data.tar.gz: 116f736d81055adf4a287d3d76a4f9e641cf2ac81f2a39b63ccb9603bfbd351e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c462629b903ebbee663323f52385423fb697bd338bcf7c57574874de21f323230d381c5d6e5eb30602248f33021bc2d0082602fa3b5c0b65d674f9c9c1668ff5
|
7
|
+
data.tar.gz: e909ea43dc3a8012f1de165e1aa4cbf4ad0873134199273103e329fec5ac141792113adb5eb1eb788f065f63e3c2fba299c0501a837719a816b2698e119e50bf
|
@@ -56,7 +56,6 @@ module RubyLsp
|
|
56
56
|
@outgoing_queue << Notification.window_log_message("Activating Ruby LSP Rails add-on v#{VERSION}")
|
57
57
|
|
58
58
|
register_additional_file_watchers(global_state: global_state, outgoing_queue: outgoing_queue)
|
59
|
-
@global_state.index.register_enhancement(IndexingEnhancement.new(@global_state.index))
|
60
59
|
|
61
60
|
# Start booting the real client in a background thread. Until this completes, the client will be a NullClient
|
62
61
|
@client_mutex.unlock
|
@@ -8,25 +8,32 @@ module RubyLsp
|
|
8
8
|
|
9
9
|
sig do
|
10
10
|
override.params(
|
11
|
-
|
12
|
-
node: Prism::CallNode,
|
13
|
-
file_path: String,
|
14
|
-
code_units_cache: T.any(
|
15
|
-
T.proc.params(arg0: Integer).returns(Integer),
|
16
|
-
Prism::CodeUnitsCache,
|
17
|
-
),
|
11
|
+
call_node: Prism::CallNode,
|
18
12
|
).void
|
19
13
|
end
|
20
|
-
def on_call_node_enter(
|
14
|
+
def on_call_node_enter(call_node)
|
15
|
+
owner = @listener.current_owner
|
21
16
|
return unless owner
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
case name
|
18
|
+
case call_node.name
|
26
19
|
when :extend
|
27
|
-
handle_concern_extend(owner,
|
20
|
+
handle_concern_extend(owner, call_node)
|
28
21
|
when :has_one, :has_many, :belongs_to, :has_and_belongs_to_many
|
29
|
-
handle_association(owner,
|
22
|
+
handle_association(owner, call_node)
|
23
|
+
# for `class_methods do` blocks within concerns
|
24
|
+
when :class_methods
|
25
|
+
handle_class_methods(owner, call_node)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
sig do
|
30
|
+
override.params(
|
31
|
+
call_node: Prism::CallNode,
|
32
|
+
).void
|
33
|
+
end
|
34
|
+
def on_call_node_leave(call_node)
|
35
|
+
if call_node.name == :class_methods && call_node.block
|
36
|
+
@listener.pop_namespace_stack
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
@@ -35,16 +42,11 @@ module RubyLsp
|
|
35
42
|
sig do
|
36
43
|
params(
|
37
44
|
owner: RubyIndexer::Entry::Namespace,
|
38
|
-
|
39
|
-
file_path: String,
|
40
|
-
code_units_cache: T.any(
|
41
|
-
T.proc.params(arg0: Integer).returns(Integer),
|
42
|
-
Prism::CodeUnitsCache,
|
43
|
-
),
|
45
|
+
call_node: Prism::CallNode,
|
44
46
|
).void
|
45
47
|
end
|
46
|
-
def handle_association(owner,
|
47
|
-
arguments =
|
48
|
+
def handle_association(owner, call_node)
|
49
|
+
arguments = call_node.arguments&.arguments
|
48
50
|
return unless arguments
|
49
51
|
|
50
52
|
name_arg = arguments.first
|
@@ -58,41 +60,22 @@ module RubyLsp
|
|
58
60
|
|
59
61
|
return unless name
|
60
62
|
|
61
|
-
loc =
|
63
|
+
loc = name_arg.location
|
62
64
|
|
63
65
|
# Reader
|
64
|
-
|
65
|
-
|
66
|
-
file_path,
|
67
|
-
loc,
|
68
|
-
loc,
|
69
|
-
nil,
|
70
|
-
[RubyIndexer::Entry::Signature.new([])],
|
71
|
-
RubyIndexer::Entry::Visibility::PUBLIC,
|
72
|
-
owner,
|
73
|
-
))
|
66
|
+
reader_signatures = [RubyIndexer::Entry::Signature.new([])]
|
67
|
+
@listener.add_method(name, loc, reader_signatures)
|
74
68
|
|
75
69
|
# Writer
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
loc,
|
81
|
-
nil,
|
82
|
-
[RubyIndexer::Entry::Signature.new([RubyIndexer::Entry::RequiredParameter.new(name: name.to_sym)])],
|
83
|
-
RubyIndexer::Entry::Visibility::PUBLIC,
|
84
|
-
owner,
|
85
|
-
))
|
70
|
+
writer_signatures = [
|
71
|
+
RubyIndexer::Entry::Signature.new([RubyIndexer::Entry::RequiredParameter.new(name: name.to_sym)]),
|
72
|
+
]
|
73
|
+
@listener.add_method("#{name}=", loc, writer_signatures)
|
86
74
|
end
|
87
75
|
|
88
|
-
sig
|
89
|
-
|
90
|
-
|
91
|
-
node: Prism::CallNode,
|
92
|
-
).void
|
93
|
-
end
|
94
|
-
def handle_concern_extend(owner, node)
|
95
|
-
arguments = node.arguments&.arguments
|
76
|
+
sig { params(owner: RubyIndexer::Entry::Namespace, call_node: Prism::CallNode).void }
|
77
|
+
def handle_concern_extend(owner, call_node)
|
78
|
+
arguments = call_node.arguments&.arguments
|
96
79
|
return unless arguments
|
97
80
|
|
98
81
|
arguments.each do |node|
|
@@ -101,7 +84,7 @@ module RubyLsp
|
|
101
84
|
module_name = node.full_name
|
102
85
|
next unless module_name == "ActiveSupport::Concern"
|
103
86
|
|
104
|
-
@
|
87
|
+
@listener.register_included_hook do |index, base|
|
105
88
|
class_methods_name = "#{owner.name}::ClassMethods"
|
106
89
|
|
107
90
|
if index.indexed?(class_methods_name)
|
@@ -114,6 +97,13 @@ module RubyLsp
|
|
114
97
|
# Do nothing
|
115
98
|
end
|
116
99
|
end
|
100
|
+
|
101
|
+
sig { params(owner: RubyIndexer::Entry::Namespace, call_node: Prism::CallNode).void }
|
102
|
+
def handle_class_methods(owner, call_node)
|
103
|
+
return unless call_node.block
|
104
|
+
|
105
|
+
@listener.add_module("ClassMethods", call_node.location, call_node.location)
|
106
|
+
end
|
117
107
|
end
|
118
108
|
end
|
119
109
|
end
|
@@ -27,7 +27,7 @@ module RubyLsp
|
|
27
27
|
|
28
28
|
NullClient.new
|
29
29
|
end
|
30
|
-
rescue
|
30
|
+
rescue StandardError => e
|
31
31
|
unless outgoing_queue.closed?
|
32
32
|
outgoing_queue << RubyLsp::Notification.window_log_message(
|
33
33
|
<<~MESSAGE.chomp,
|
@@ -44,7 +44,6 @@ module RubyLsp
|
|
44
44
|
|
45
45
|
class InitializationError < StandardError; end
|
46
46
|
class MessageError < StandardError; end
|
47
|
-
class IncompleteMessageError < MessageError; end
|
48
47
|
class EmptyMessageError < MessageError; end
|
49
48
|
|
50
49
|
extend T::Sig
|
@@ -109,7 +108,7 @@ module RubyLsp
|
|
109
108
|
end,
|
110
109
|
Thread,
|
111
110
|
)
|
112
|
-
rescue
|
111
|
+
rescue StandardError
|
113
112
|
raise InitializationError, @stderr.read
|
114
113
|
end
|
115
114
|
|
@@ -19,7 +19,43 @@ module RubyLsp
|
|
19
19
|
# Log a message to the editor's output panel
|
20
20
|
def log_message(message)
|
21
21
|
$stderr.puts(message)
|
22
|
-
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sends an error result to a request, if the request failed. DO NOT INVOKE THIS METHOD FOR NOTIFICATIONS! Use
|
25
|
+
# `log_message` instead, otherwise the client/server communication will go out of sync
|
26
|
+
def send_error_response(message)
|
27
|
+
send_message({ error: message })
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sends a result back to the client
|
31
|
+
def send_result(result)
|
32
|
+
send_message({ result: result })
|
33
|
+
end
|
34
|
+
|
35
|
+
# Handle possible errors for a request. This should only be used for requests, which means messages that return a
|
36
|
+
# response back to the client. Errors are returned as an error object back to the client
|
37
|
+
def with_request_error_handling(request_name, &block)
|
38
|
+
block.call
|
39
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
40
|
+
# Since this is a common problem, we show a specific error message to the user, instead of the full stack trace.
|
41
|
+
send_error_response("Request #{request_name} failed because database connection was not established.")
|
42
|
+
rescue ActiveRecord::NoDatabaseError
|
43
|
+
send_error_response("Request #{request_name} failed because the database does not exist.")
|
44
|
+
rescue => e
|
45
|
+
send_error_response("Request #{request_name} failed:\n#{e.full_message(highlight: false)}")
|
46
|
+
end
|
47
|
+
|
48
|
+
# Handle possible errors for a notification. This should only be used for notifications, which means messages that
|
49
|
+
# do not return a response back to the client. Errors are logged to the editor's output panel
|
50
|
+
def with_notification_error_handling(notification_name, &block)
|
51
|
+
block.call
|
52
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
53
|
+
# Since this is a common problem, we show a specific error message to the user, instead of the full stack trace.
|
54
|
+
log_message("Request #{notification_name} failed because database connection was not established.")
|
55
|
+
rescue ActiveRecord::NoDatabaseError
|
56
|
+
log_message("Request #{notification_name} failed because the database does not exist.")
|
57
|
+
rescue => e
|
58
|
+
log_message("Request #{notification_name} failed:\n#{e.full_message(highlight: false)}")
|
23
59
|
end
|
24
60
|
end
|
25
61
|
|
@@ -88,11 +124,8 @@ module RubyLsp
|
|
88
124
|
end
|
89
125
|
|
90
126
|
def start
|
91
|
-
|
92
|
-
|
93
|
-
routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
|
94
|
-
|
95
|
-
send_message({ result: { message: "ok", root: ::Rails.root.to_s } })
|
127
|
+
load_routes
|
128
|
+
send_result({ message: "ok", root: ::Rails.root.to_s })
|
96
129
|
|
97
130
|
while @running
|
98
131
|
headers = @stdin.gets("\r\n\r\n")
|
@@ -104,41 +137,50 @@ module RubyLsp
|
|
104
137
|
end
|
105
138
|
|
106
139
|
def execute(request, params)
|
107
|
-
request_name = request
|
108
|
-
request_name = "#{params[:server_addon_name]}##{params[:request_name]}" if request == "server_addon/delegate"
|
109
|
-
|
110
140
|
case request
|
111
141
|
when "shutdown"
|
112
142
|
@running = false
|
113
143
|
when "model"
|
114
|
-
|
144
|
+
with_request_error_handling(request) do
|
145
|
+
send_result(resolve_database_info_from_model(params.fetch(:name)))
|
146
|
+
end
|
115
147
|
when "association_target_location"
|
116
|
-
|
148
|
+
with_request_error_handling(request) do
|
149
|
+
send_result(resolve_association_target(params))
|
150
|
+
end
|
117
151
|
when "pending_migrations_message"
|
118
|
-
|
152
|
+
with_request_error_handling(request) do
|
153
|
+
send_result({ pending_migrations_message: pending_migrations_message })
|
154
|
+
end
|
119
155
|
when "run_migrations"
|
120
|
-
|
156
|
+
with_request_error_handling(request) do
|
157
|
+
send_result(run_migrations)
|
158
|
+
end
|
121
159
|
when "reload"
|
122
|
-
|
160
|
+
with_notification_error_handling(request) do
|
161
|
+
::Rails.application.reloader.reload!
|
162
|
+
end
|
123
163
|
when "route_location"
|
124
|
-
|
164
|
+
with_request_error_handling(request) do
|
165
|
+
send_result(route_location(params.fetch(:name)))
|
166
|
+
end
|
125
167
|
when "route_info"
|
126
|
-
|
168
|
+
with_request_error_handling(request) do
|
169
|
+
send_result(resolve_route_info(params))
|
170
|
+
end
|
127
171
|
when "server_addon/register"
|
128
|
-
|
129
|
-
|
172
|
+
with_notification_error_handling(request) do
|
173
|
+
require params[:server_addon_path]
|
174
|
+
ServerAddon.finalize_registrations!(@stdout)
|
175
|
+
end
|
130
176
|
when "server_addon/delegate"
|
131
177
|
server_addon_name = params[:server_addon_name]
|
132
178
|
request_name = params[:request_name]
|
179
|
+
|
180
|
+
# Do not wrap this in error handlers. Server add-ons need to have the flexibility to choose if they want to
|
181
|
+
# include a response or not as part of error handling, so a blanket approach is not appropriate.
|
133
182
|
ServerAddon.delegate(server_addon_name, request_name, params.except(:request_name, :server_addon_name))
|
134
183
|
end
|
135
|
-
# Since this is a common problem, we show a specific error message to the user, instead of the full stack trace.
|
136
|
-
rescue ActiveRecord::ConnectionNotEstablished
|
137
|
-
log_message("Request #{request_name} failed because database connection was not established.")
|
138
|
-
rescue ActiveRecord::NoDatabaseError
|
139
|
-
log_message("Request #{request_name} failed because the database does not exist.")
|
140
|
-
rescue => e
|
141
|
-
log_message("Request #{request_name} failed:\n" + e.full_message(highlight: false))
|
142
184
|
end
|
143
185
|
|
144
186
|
private
|
@@ -156,19 +198,15 @@ module RubyLsp
|
|
156
198
|
end
|
157
199
|
|
158
200
|
source_location = route&.respond_to?(:source_location) && route.source_location
|
201
|
+
return unless source_location
|
159
202
|
|
160
|
-
|
161
|
-
file, _, line = source_location.rpartition(":")
|
162
|
-
body = {
|
163
|
-
source_location: [::Rails.root.join(file).to_s, line],
|
164
|
-
verb: route.verb,
|
165
|
-
path: route.path.spec.to_s,
|
166
|
-
}
|
203
|
+
file, _, line = source_location.rpartition(":")
|
167
204
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
205
|
+
{
|
206
|
+
source_location: [::Rails.root.join(file).to_s, line],
|
207
|
+
verb: route.verb,
|
208
|
+
path: route.path.spec.to_s,
|
209
|
+
}
|
172
210
|
end
|
173
211
|
|
174
212
|
# Older versions of Rails don't support `route_source_locations`.
|
@@ -182,74 +220,48 @@ module RubyLsp
|
|
182
220
|
end
|
183
221
|
|
184
222
|
match_data = name.match(/^(.+)(_path|_url)$/)
|
185
|
-
return
|
223
|
+
return unless match_data
|
186
224
|
|
187
225
|
key = match_data[1]
|
188
226
|
|
189
227
|
# A token could match the _path or _url pattern, but not be an actual route.
|
190
228
|
route = ::Rails.application.routes.named_routes.get(key)
|
191
|
-
return
|
192
|
-
|
193
|
-
{
|
194
|
-
result: {
|
195
|
-
location: ::Rails.root.join(route.source_location).to_s,
|
196
|
-
},
|
197
|
-
}
|
198
|
-
rescue => e
|
199
|
-
{ error: e.full_message(highlight: false) }
|
229
|
+
return unless route&.source_location
|
230
|
+
|
231
|
+
{ location: ::Rails.root.join(route.source_location).to_s }
|
200
232
|
end
|
201
233
|
else
|
202
234
|
def route_location(name)
|
203
|
-
|
235
|
+
nil
|
204
236
|
end
|
205
237
|
end
|
206
238
|
|
207
239
|
def resolve_database_info_from_model(model_name)
|
208
240
|
const = ActiveSupport::Inflector.safe_constantize(model_name)
|
209
|
-
unless active_record_model?(const)
|
210
|
-
return {
|
211
|
-
result: nil,
|
212
|
-
}
|
213
|
-
end
|
241
|
+
return unless active_record_model?(const)
|
214
242
|
|
215
243
|
info = {
|
216
|
-
|
217
|
-
|
218
|
-
primary_keys: Array(const.primary_key),
|
219
|
-
},
|
244
|
+
columns: const.columns.map { |column| [column.name, column.type, column.default, column.null] },
|
245
|
+
primary_keys: Array(const.primary_key),
|
220
246
|
}
|
221
247
|
|
222
248
|
if ActiveRecord::Tasks::DatabaseTasks.respond_to?(:schema_dump_path)
|
223
|
-
info[:
|
224
|
-
ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
|
225
|
-
|
249
|
+
info[:schema_file] = ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
|
226
250
|
end
|
251
|
+
|
227
252
|
info
|
228
|
-
rescue => e
|
229
|
-
{ error: e.full_message(highlight: false) }
|
230
253
|
end
|
231
254
|
|
232
255
|
def resolve_association_target(params)
|
233
256
|
const = ActiveSupport::Inflector.safe_constantize(params[:model_name])
|
234
|
-
unless active_record_model?(const)
|
235
|
-
return {
|
236
|
-
result: nil,
|
237
|
-
}
|
238
|
-
end
|
257
|
+
return unless active_record_model?(const)
|
239
258
|
|
240
259
|
association_klass = const.reflect_on_association(params[:association_name].intern).klass
|
241
|
-
|
242
260
|
source_location = Object.const_source_location(association_klass.to_s)
|
243
261
|
|
244
|
-
{
|
245
|
-
result: {
|
246
|
-
location: source_location.first + ":" + source_location.second.to_s,
|
247
|
-
},
|
248
|
-
}
|
262
|
+
{ location: source_location.first + ":" + source_location.second.to_s }
|
249
263
|
rescue NameError
|
250
|
-
|
251
|
-
result: nil,
|
252
|
-
}
|
264
|
+
nil
|
253
265
|
end
|
254
266
|
|
255
267
|
def active_record_model?(const)
|
@@ -282,6 +294,14 @@ module RubyLsp
|
|
282
294
|
|
283
295
|
{ message: stdout, status: status.exitstatus }
|
284
296
|
end
|
297
|
+
|
298
|
+
def load_routes
|
299
|
+
with_notification_error_handling("initial_load_routes") do
|
300
|
+
# Load routes if they haven't been loaded yet (see https://github.com/rails/rails/pull/51614).
|
301
|
+
routes_reloader = ::Rails.application.routes_reloader
|
302
|
+
routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
|
303
|
+
end
|
304
|
+
end
|
285
305
|
end
|
286
306
|
end
|
287
307
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.27
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-lsp
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.22.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.
|
22
|
+
version: 0.23.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
29
|
+
version: 0.22.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
32
|
+
version: 0.23.0
|
33
33
|
description: A Ruby LSP addon that adds extra editor functionality for Rails applications
|
34
34
|
email:
|
35
35
|
- ruby@shopify.com
|