ruby-lsp-rails 0.3.31 → 0.4.8

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.
@@ -1,36 +1,66 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "json"
5
5
  require "open3"
6
+ require "delegate"
6
7
 
7
8
  module RubyLsp
8
9
  module Rails
10
+ # @requires_ancestor: ServerComponent
9
11
  module Common
10
- # Write a message to the client. Can be used for sending notifications to the editor
11
- def send_message(message)
12
- json_message = message.to_json
13
- @stdout.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
12
+ class Progress
13
+ #: (IO | StringIO, String, bool) -> void
14
+ def initialize(stderr, id, supports_progress)
15
+ @stderr = stderr
16
+ @id = id
17
+ @supports_progress = supports_progress
18
+ end
19
+
20
+ #: (?percentage: Integer?, ?message: String?) -> void
21
+ def report(percentage: nil, message: nil)
22
+ return unless @supports_progress
23
+ return unless percentage || message
24
+
25
+ json_message = {
26
+ method: "$/progress",
27
+ params: {
28
+ token: @id,
29
+ value: {
30
+ kind: "report",
31
+ percentage: percentage,
32
+ message: message,
33
+ },
34
+ },
35
+ }.to_json
36
+
37
+ @stderr.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
38
+ end
14
39
  end
15
40
 
16
- # Log a message to the editor's output panel
17
- def log_message(message)
18
- $stderr.puts(message)
41
+ # Log a message to the editor's output panel. The type is the number of the message type, which can be found in
42
+ # the specification https://microsoft.github.io/language-server-protocol/specification/#messageType
43
+ #: (String, ?type: Integer) -> void
44
+ def log_message(message, type: 4)
45
+ send_notification({ method: "window/logMessage", params: { type: type, message: message } })
19
46
  end
20
47
 
21
48
  # Sends an error result to a request, if the request failed. DO NOT INVOKE THIS METHOD FOR NOTIFICATIONS! Use
22
49
  # `log_message` instead, otherwise the client/server communication will go out of sync
50
+ #: (String) -> void
23
51
  def send_error_response(message)
24
52
  send_message({ error: message })
25
53
  end
26
54
 
27
55
  # Sends a result back to the client
56
+ #: (Hash[Symbol | String, untyped]?) -> void
28
57
  def send_result(result)
29
58
  send_message({ result: result })
30
59
  end
31
60
 
32
61
  # Handle possible errors for a request. This should only be used for requests, which means messages that return a
33
62
  # response back to the client. Errors are returned as an error object back to the client
63
+ #: (String) { () -> void } -> void
34
64
  def with_request_error_handling(request_name, &block)
35
65
  block.call
36
66
  rescue ActiveRecord::ConnectionNotEstablished
@@ -38,12 +68,15 @@ module RubyLsp
38
68
  send_error_response("Request #{request_name} failed because database connection was not established.")
39
69
  rescue ActiveRecord::NoDatabaseError
40
70
  send_error_response("Request #{request_name} failed because the database does not exist.")
41
- rescue => e
42
- send_error_response("Request #{request_name} failed:\n#{e.full_message(highlight: false)}")
71
+ rescue NotImplementedError, LoadError, SyntaxError, SystemExit, SystemStackError => e
72
+ send_error_response("Request #{request_name} failed with #{e.class}:\n#{e.full_message(highlight: false)}")
73
+ rescue StandardError => e
74
+ send_error_response("Request #{request_name} failed with StandardError:\n#{e.full_message(highlight: false)}")
43
75
  end
44
76
 
45
77
  # Handle possible errors for a notification. This should only be used for notifications, which means messages that
46
78
  # do not return a response back to the client. Errors are logged to the editor's output panel
79
+ #: (String) { () -> void } -> void
47
80
  def with_notification_error_handling(notification_name, &block)
48
81
  block.call
49
82
  rescue ActiveRecord::ConnectionNotEstablished
@@ -51,60 +84,188 @@ module RubyLsp
51
84
  log_message("Request #{notification_name} failed because database connection was not established.")
52
85
  rescue ActiveRecord::NoDatabaseError
53
86
  log_message("Request #{notification_name} failed because the database does not exist.")
54
- rescue => e
55
- log_message("Request #{notification_name} failed:\n#{e.full_message(highlight: false)}")
87
+ rescue NotImplementedError, LoadError, SyntaxError, SystemExit, SystemStackError => e
88
+ log_message("Request #{notification_name} failed with #{e.class}:\n#{e.full_message(highlight: false)}")
89
+ rescue StandardError => e
90
+ log_message("Request #{notification_name} failed with StandardError:\n#{e.full_message(highlight: false)}")
91
+ end
92
+
93
+ #: (String, String, ?percentage: Integer?, ?message: String?) -> void
94
+ def begin_progress(id, title, percentage: nil, message: nil)
95
+ return unless capabilities[:supports_progress]
96
+
97
+ # This is actually a request, but it is sent asynchronously and we do not return the response back to the
98
+ # server, so we consider it a notification from the perspective of the client/runtime server dynamic
99
+ send_notification({
100
+ id: "progress-request-#{id}",
101
+ method: "window/workDoneProgress/create",
102
+ params: { token: id },
103
+ })
104
+
105
+ send_notification({
106
+ method: "$/progress",
107
+ params: {
108
+ token: id,
109
+ value: {
110
+ kind: "begin",
111
+ title: title,
112
+ percentage: percentage,
113
+ message: message,
114
+ },
115
+ },
116
+ })
117
+ end
118
+
119
+ #: (String, ?percentage: Integer?, ?message: String?) -> void
120
+ def report_progress(id, percentage: nil, message: nil)
121
+ return unless capabilities[:supports_progress]
122
+
123
+ send_notification({
124
+ method: "$/progress",
125
+ params: {
126
+ token: id,
127
+ value: {
128
+ kind: "report",
129
+ percentage: percentage,
130
+ message: message,
131
+ },
132
+ },
133
+ })
134
+ end
135
+
136
+ #: (String) -> void
137
+ def end_progress(id)
138
+ return unless capabilities[:supports_progress]
139
+
140
+ send_notification({
141
+ method: "$/progress",
142
+ params: {
143
+ token: id,
144
+ value: { kind: "end" },
145
+ },
146
+ })
147
+ end
148
+
149
+ #: (String, String, ?percentage: Integer?, ?message: String?) { (Progress) -> void } -> void
150
+ def with_progress(id, title, percentage: nil, message: nil, &block)
151
+ progress_block = Progress.new(stderr, id, capabilities[:supports_progress])
152
+ return block.call(progress_block) unless capabilities[:supports_progress]
153
+
154
+ begin_progress(id, title, percentage: percentage, message: message)
155
+ block.call(progress_block)
156
+ end_progress(id)
157
+ end
158
+
159
+ private
160
+
161
+ # Write a response message back to the client
162
+ #: (Hash[String | Symbol, untyped]) -> void
163
+ def send_message(message)
164
+ json_message = message.to_json
165
+ stdout.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
166
+ end
167
+
168
+ # Write a notification to the client to be transmitted to the editor
169
+ #: (Hash[String | Symbol, untyped]) -> void
170
+ def send_notification(message)
171
+ json_message = message.to_json
172
+ stderr.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
173
+ end
174
+ end
175
+
176
+ class ServerComponent
177
+ #: IO | StringIO
178
+ attr_reader :stdout
179
+
180
+ #: IO | StringIO
181
+ attr_reader :stderr
182
+
183
+ #: Hash[Symbol | String, untyped]
184
+ attr_reader :capabilities
185
+
186
+ #: (IO | StringIO, IO | StringIO, Hash[Symbol | String, untyped]) -> void
187
+ def initialize(stdout, stderr, capabilities)
188
+ @stdout = stdout
189
+ @stderr = stderr
190
+ @capabilities = capabilities
56
191
  end
57
192
  end
58
193
 
59
- class ServerAddon
194
+ class ServerAddon < ServerComponent
60
195
  include Common
61
196
 
62
- @server_addon_classes = []
63
- @server_addons = {}
197
+ @server_addon_classes = [] #: Array[singleton(ServerAddon)]
198
+ @server_addons = {} #: Hash[String, ServerAddon]
64
199
 
65
200
  class << self
66
201
  # We keep track of runtime server add-ons the same way we track other add-ons, by storing classes that inherit
67
202
  # from the base one
203
+ #: (singleton(ServerAddon)) -> void
68
204
  def inherited(child)
69
205
  @server_addon_classes << child
70
206
  super
71
207
  end
72
208
 
73
209
  # Delegate `request` with `params` to the server add-on with the given `name`
210
+ #: (String, String, Hash[Symbol | String, untyped]) -> void
74
211
  def delegate(name, request, params)
75
212
  @server_addons[name]&.execute(request, params)
76
213
  end
77
214
 
78
215
  # Instantiate all server addons and store them in a hash for easy access after we have discovered the classes
79
- def finalize_registrations!(stdout)
216
+ #: (IO | StringIO, IO | StringIO, Hash[Symbol | String, untyped]) -> void
217
+ def finalize_registrations!(stdout, stderr, capabilities)
80
218
  until @server_addon_classes.empty?
81
- addon = @server_addon_classes.shift.new(stdout)
219
+ addon = @server_addon_classes.shift #: as !nil
220
+ .new(stdout, stderr, capabilities)
82
221
  @server_addons[addon.name] = addon
83
222
  end
84
223
  end
85
224
  end
86
225
 
87
- def initialize(stdout)
88
- @stdout = stdout
89
- end
90
-
226
+ #: -> String
91
227
  def name
92
228
  raise NotImplementedError, "Not implemented!"
93
229
  end
94
230
 
231
+ #: (String, Hash[String | Symbol, untyped]) -> untyped
95
232
  def execute(request, params)
96
233
  raise NotImplementedError, "Not implemented!"
97
234
  end
98
235
  end
99
236
 
100
- class Server
237
+ class IOWrapper < SimpleDelegator
238
+ #: (*untyped) -> void
239
+ def puts(*args)
240
+ args.each { |arg| log("#{arg}\n") }
241
+ end
242
+
243
+ #: (*untyped) -> void
244
+ def print(*args)
245
+ args.each { |arg| log(arg.to_s) }
246
+ end
247
+
248
+ private
249
+
250
+ #: (untyped) -> void
251
+ def log(message)
252
+ json_message = { method: "window/logMessage", params: { type: 4, message: message } }.to_json
253
+
254
+ self #: as untyped # rubocop:disable Style/RedundantSelf
255
+ .write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
256
+ end
257
+ end
258
+
259
+ class Server < ServerComponent
101
260
  include Common
102
261
 
103
- def initialize(stdout: $stdout, override_default_output_device: true)
262
+ #: (?stdout: IO | StringIO, ?stderr: IO | StringIO, ?override_default_output_device: bool, ?capabilities: Hash[Symbol | String, untyped]) -> void
263
+ def initialize(stdout: $stdout, stderr: $stderr, override_default_output_device: true, capabilities: {})
104
264
  # Grab references to the original pipes so that we can change the default output device further down
105
- @stdin = $stdin
106
- @stdout = stdout
107
- @stderr = $stderr
265
+
266
+ @stdin = $stdin #: IO
267
+ super(stdout, stderr, capabilities)
268
+
108
269
  @stdin.sync = true
109
270
  @stdout.sync = true
110
271
  @stderr.sync = true
@@ -115,25 +276,28 @@ module RubyLsp
115
276
  # # Set the default output device to be $stderr. This means that using `puts` by itself will default to printing
116
277
  # # to $stderr and only explicit `$stdout.puts` will go to $stdout. This reduces the chance that output coming
117
278
  # # from the Rails app will be accidentally sent to the client
118
- $> = $stderr if override_default_output_device
279
+ $> = IOWrapper.new(@stderr) if override_default_output_device
119
280
 
120
- @running = true
281
+ @running = true #: bool
282
+ @database_supports_indexing = nil #: bool?
121
283
  end
122
284
 
285
+ #: -> void
123
286
  def start
124
287
  load_routes
125
288
  clear_file_system_resolver_hooks
126
289
  send_result({ message: "ok", root: ::Rails.root.to_s })
127
290
 
128
291
  while @running
129
- headers = @stdin.gets("\r\n\r\n")
130
- json = @stdin.read(headers[/Content-Length: (\d+)/i, 1].to_i)
292
+ headers = @stdin.gets("\r\n\r\n") #: as String
293
+ json = @stdin.read(headers[/Content-Length: (\d+)/i, 1].to_i) #: as String
131
294
 
132
295
  request = JSON.parse(json, symbolize_names: true)
133
296
  execute(request.fetch(:method), request[:params])
134
297
  end
135
298
  end
136
299
 
300
+ #: (String, Hash[Symbol | String, untyped]) -> void
137
301
  def execute(request, params)
138
302
  case request
139
303
  when "shutdown"
@@ -142,7 +306,7 @@ module RubyLsp
142
306
  with_request_error_handling(request) do
143
307
  send_result(resolve_database_info_from_model(params.fetch(:name)))
144
308
  end
145
- when "association_target_location"
309
+ when "association_target"
146
310
  with_request_error_handling(request) do
147
311
  send_result(resolve_association_target(params))
148
312
  end
@@ -155,8 +319,10 @@ module RubyLsp
155
319
  send_result(run_migrations)
156
320
  end
157
321
  when "reload"
158
- with_notification_error_handling(request) do
159
- ::Rails.application.reloader.reload!
322
+ with_progress("rails-reload", "Reloading Ruby LSP Rails instance") do
323
+ with_notification_error_handling(request) do
324
+ ::Rails.application.reloader.reload!
325
+ end
160
326
  end
161
327
  when "route_location"
162
328
  with_request_error_handling(request) do
@@ -169,7 +335,7 @@ module RubyLsp
169
335
  when "server_addon/register"
170
336
  with_notification_error_handling(request) do
171
337
  require params[:server_addon_path]
172
- ServerAddon.finalize_registrations!(@stdout)
338
+ ServerAddon.finalize_registrations!(@stdout, @stderr, @capabilities)
173
339
  end
174
340
  when "server_addon/delegate"
175
341
  server_addon_name = params[:server_addon_name]
@@ -183,6 +349,7 @@ module RubyLsp
183
349
 
184
350
  private
185
351
 
352
+ #: (Hash[Symbol | String, untyped]) -> Hash[Symbol | String, untyped]?
186
353
  def resolve_route_info(requirements)
187
354
  if requirements[:controller]
188
355
  requirements[:controller] = requirements.fetch(:controller).underscore.delete_suffix("_controller")
@@ -211,6 +378,7 @@ module RubyLsp
211
378
  # We also check that it's enabled.
212
379
  if ActionDispatch::Routing::Mapper.respond_to?(:route_source_locations) &&
213
380
  ActionDispatch::Routing::Mapper.route_source_locations
381
+ #: (String) -> Hash[Symbol | String, untyped]?
214
382
  def route_location(name)
215
383
  # In Rails 8, Rails.application.routes.named_routes is not populated by default
216
384
  if ::Rails.application.respond_to?(:reload_routes_unless_loaded)
@@ -229,18 +397,22 @@ module RubyLsp
229
397
  { location: ::Rails.root.join(route.source_location).to_s }
230
398
  end
231
399
  else
400
+ #: (String) -> Hash[Symbol | String, untyped]?
232
401
  def route_location(name)
233
402
  nil
234
403
  end
235
404
  end
236
405
 
406
+ #: (String) -> Hash[Symbol | String, untyped]?
237
407
  def resolve_database_info_from_model(model_name)
238
- const = ActiveSupport::Inflector.safe_constantize(model_name)
408
+ const = ActiveSupport::Inflector.safe_constantize(model_name) # rubocop:disable Sorbet/ConstantsFromStrings
239
409
  return unless active_record_model?(const)
240
410
 
241
411
  info = {
242
412
  columns: const.columns.map { |column| [column.name, column.type, column.default, column.null] },
243
413
  primary_keys: Array(const.primary_key),
414
+ foreign_keys: collect_model_foreign_keys(const),
415
+ indexes: collect_model_indexes(const),
244
416
  }
245
417
 
246
418
  if ActiveRecord::Tasks::DatabaseTasks.respond_to?(:schema_dump_path)
@@ -250,28 +422,33 @@ module RubyLsp
250
422
  info
251
423
  end
252
424
 
425
+ #: (Hash[Symbol | String, untyped]) -> Hash[Symbol | String, untyped]?
253
426
  def resolve_association_target(params)
254
- const = ActiveSupport::Inflector.safe_constantize(params[:model_name])
427
+ const = ActiveSupport::Inflector.safe_constantize(params[:model_name]) # rubocop:disable Sorbet/ConstantsFromStrings
255
428
  return unless active_record_model?(const)
256
429
 
257
430
  association_klass = const.reflect_on_association(params[:association_name].intern).klass
258
431
  source_location = Object.const_source_location(association_klass.to_s)
432
+ return unless source_location
259
433
 
260
- { location: source_location.first + ":" + source_location.second.to_s }
434
+ { location: "#{source_location[0]}:#{source_location[1]}", name: association_klass.name }
261
435
  rescue NameError
262
436
  nil
263
437
  end
264
438
 
439
+ #: (Module?) -> bool
265
440
  def active_record_model?(const)
266
441
  !!(
267
442
  const &&
268
443
  defined?(ActiveRecord) &&
269
444
  const.is_a?(Class) &&
270
445
  ActiveRecord::Base > const && # We do this 'backwards' in case the class overwrites `<`
271
- !const.abstract_class?
446
+ !const #: as singleton(ActiveRecord::Base)
447
+ .abstract_class?
272
448
  )
273
449
  end
274
450
 
451
+ #: -> String?
275
452
  def pending_migrations_message
276
453
  # `check_all_pending!` is only available since Rails 7.1
277
454
  return unless defined?(ActiveRecord) && ActiveRecord::Migration.respond_to?(:check_all_pending!)
@@ -282,6 +459,7 @@ module RubyLsp
282
459
  e.message
283
460
  end
284
461
 
462
+ #: -> Hash[Symbol | String, untyped]
285
463
  def run_migrations
286
464
  # Running migrations invokes `load` which will repeatedly load the same files. It's not designed to be invoked
287
465
  # multiple times within the same process. To avoid any memory bloat, we run migrations in a separate process
@@ -293,6 +471,7 @@ module RubyLsp
293
471
  { message: stdout, status: status.exitstatus }
294
472
  end
295
473
 
474
+ #: -> void
296
475
  def load_routes
297
476
  with_notification_error_handling("initial_load_routes") do
298
477
  # Load routes if they haven't been loaded yet (see https://github.com/rails/rails/pull/51614).
@@ -305,6 +484,7 @@ module RubyLsp
305
484
  # watches files. Since the Rails application is already booted by the time we reach this script, we can't no-op
306
485
  # the file watcher implementation. Instead, we clear the hooks to prevent the registered file watchers from being
307
486
  # instantiated
487
+ #: -> void
308
488
  def clear_file_system_resolver_hooks
309
489
  return unless defined?(::ActionView::PathRegistry)
310
490
 
@@ -312,8 +492,43 @@ module RubyLsp
312
492
  ::ActionView::PathRegistry.file_system_resolver_hooks.clear
313
493
  end
314
494
  end
495
+
496
+ #: (singleton(ActiveRecord::Base)) -> Array[String]
497
+ def collect_model_foreign_keys(model)
498
+ return [] unless model.connection.respond_to?(:supports_foreign_keys?) &&
499
+ model.connection.supports_foreign_keys?
500
+
501
+ model.connection.foreign_keys(model.table_name).map do |key_definition|
502
+ key_definition.options[:column]
503
+ end
504
+ end
505
+
506
+ #: (singleton(ActiveRecord::Base)) -> Array[Hash[Symbol, untyped]]
507
+ def collect_model_indexes(model)
508
+ return [] unless database_supports_indexing?(model)
509
+
510
+ model.connection.indexes(model.table_name).map do |index_definition|
511
+ {
512
+ name: index_definition.name,
513
+ columns: index_definition.columns,
514
+ unique: index_definition.unique,
515
+ }
516
+ end
517
+ end
518
+
519
+ #: (singleton(ActiveRecord::Base)) -> bool
520
+ def database_supports_indexing?(model)
521
+ return @database_supports_indexing unless @database_supports_indexing.nil?
522
+
523
+ model.connection.indexes(model.table_name)
524
+ @database_supports_indexing = true
525
+ rescue NotImplementedError
526
+ @database_supports_indexing = false
527
+ end
315
528
  end
316
529
  end
317
530
  end
318
531
 
319
- RubyLsp::Rails::Server.new.start if ARGV.first == "start"
532
+ if ARGV.first == "start"
533
+ RubyLsp::Rails::Server.new(capabilities: JSON.parse(ARGV[1], symbolize_names: true)).start
534
+ end
@@ -4,9 +4,7 @@
4
4
  module RubyLsp
5
5
  module Rails
6
6
  module ActiveSupportTestCaseHelper
7
- extend T::Sig
8
-
9
- sig { params(node: Prism::CallNode).returns(T.nilable(String)) }
7
+ #: (Prism::CallNode node) -> String?
10
8
  def extract_test_case_name(node)
11
9
  message_value = node.message
12
10
  return unless message_value == "test" || message_value == "it"
@@ -21,7 +19,8 @@ module RubyLsp
21
19
  parts = first_argument.parts
22
20
 
23
21
  if parts.all? { |part| part.is_a?(Prism::StringNode) }
24
- T.cast(parts, T::Array[Prism::StringNode]).map(&:content).join
22
+ parts #: as Array[Prism::StringNode]
23
+ .map(&:content).join
25
24
  end
26
25
  when Prism::StringNode
27
26
  first_argument.content
@@ -5,15 +5,12 @@ module RubyLsp
5
5
  module Rails
6
6
  module Support
7
7
  module Associations
8
- ALL = T.let(
9
- [
10
- "belongs_to",
11
- "has_many",
12
- "has_one",
13
- "has_and_belongs_to_many",
14
- ].freeze,
15
- T::Array[String],
16
- )
8
+ ALL = [
9
+ "belongs_to",
10
+ "has_many",
11
+ "has_one",
12
+ "has_and_belongs_to_many",
13
+ ].freeze
17
14
  end
18
15
  end
19
16
  end
@@ -5,66 +5,63 @@ module RubyLsp
5
5
  module Rails
6
6
  module Support
7
7
  module Callbacks
8
- MODELS = T.let(
9
- [
10
- "before_validation",
11
- "after_validation",
12
- "before_save",
13
- "around_save",
14
- "after_save",
15
- "before_create",
16
- "around_create",
17
- "after_create",
18
- "after_commit",
19
- "after_create_commit",
20
- "after_update_commit",
21
- "after_destroy_commit",
22
- "after_save_commit",
23
- "after_rollback",
24
- "before_update",
25
- "around_update",
26
- "after_update",
27
- "before_destroy",
28
- "around_destroy",
29
- "after_destroy",
30
- "after_initialize",
31
- "after_find",
32
- "after_touch",
33
- ].freeze,
34
- T::Array[String],
35
- )
8
+ MODELS = [
9
+ "before_validation",
10
+ "after_validation",
11
+ "before_save",
12
+ "around_save",
13
+ "after_save",
14
+ "before_create",
15
+ "around_create",
16
+ "after_create",
17
+ "after_commit",
18
+ "after_create_commit",
19
+ "after_update_commit",
20
+ "after_destroy_commit",
21
+ "after_save_commit",
22
+ "after_rollback",
23
+ "before_update",
24
+ "around_update",
25
+ "after_update",
26
+ "before_destroy",
27
+ "around_destroy",
28
+ "after_destroy",
29
+ "after_initialize",
30
+ "after_find",
31
+ "after_touch",
32
+ ].freeze
36
33
 
37
- CONTROLLERS = T.let(
38
- [
39
- "after_action",
40
- "append_after_action",
41
- "append_around_action",
42
- "append_before_action",
43
- "around_action",
44
- "before_action",
45
- "prepend_after_action",
46
- "prepend_around_action",
47
- "prepend_before_action",
48
- "skip_after_action",
49
- "skip_around_action",
50
- "skip_before_action",
51
- ].freeze,
52
- T::Array[String],
53
- )
34
+ CONTROLLERS = [
35
+ "after_action",
36
+ "append_after_action",
37
+ "append_around_action",
38
+ "append_before_action",
39
+ "around_action",
40
+ "before_action",
41
+ "prepend_after_action",
42
+ "prepend_around_action",
43
+ "prepend_before_action",
44
+ "skip_after_action",
45
+ "skip_around_action",
46
+ "skip_before_action",
47
+ ].freeze
54
48
 
55
- JOBS = T.let(
56
- [
57
- "after_enqueue",
58
- "after_perform",
59
- "around_enqueue",
60
- "around_perform",
61
- "before_enqueue",
62
- "before_perform",
63
- ].freeze,
64
- T::Array[String],
65
- )
49
+ JOBS = [
50
+ "after_enqueue",
51
+ "after_perform",
52
+ "around_enqueue",
53
+ "around_perform",
54
+ "before_enqueue",
55
+ "before_perform",
56
+ ].freeze
66
57
 
67
- ALL = T.let((MODELS + CONTROLLERS + JOBS).freeze, T::Array[String])
58
+ MAILBOX = [
59
+ "after_processing",
60
+ "before_processing",
61
+ "around_processing",
62
+ ].freeze
63
+
64
+ ALL = (MODELS + CONTROLLERS + JOBS + MAILBOX).freeze #: Array[String]
68
65
  end
69
66
  end
70
67
  end
@@ -6,9 +6,7 @@ module RubyLsp
6
6
  module Support
7
7
  class LocationBuilder
8
8
  class << self
9
- extend T::Sig
10
-
11
- sig { params(location_string: String).returns(Interface::Location) }
9
+ #: (String location_string) -> Interface::Location
12
10
  def line_location_from_s(location_string)
13
11
  *file_parts, line = location_string.split(":")
14
12
  raise ArgumentError, "Invalid location string given" if file_parts.empty?