ruby-lsp 0.3.8 → 0.4.1

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.
@@ -16,6 +16,22 @@ end
16
16
  module RubyLsp
17
17
  module Requests
18
18
  module Support
19
+ class InternalRuboCopError < StandardError
20
+ extend T::Sig
21
+
22
+ MESSAGE = <<~EOS
23
+ An internal error occurred for the %s cop.
24
+ Updating to a newer version of RuboCop may solve this.
25
+ For more details, run RuboCop on the command line.
26
+ EOS
27
+
28
+ sig { params(rubocop_error: RuboCop::ErrorWithAnalyzedFileLocation).void }
29
+ def initialize(rubocop_error)
30
+ message = format(MESSAGE, rubocop_error.cop.name)
31
+ super(message)
32
+ end
33
+ end
34
+
19
35
  # :nodoc:
20
36
  class RuboCopRunner < RuboCop::Runner
21
37
  extend T::Sig
@@ -31,10 +47,18 @@ module RubyLsp
31
47
  "--force-exclusion",
32
48
  "--format",
33
49
  "RuboCop::Formatter::BaseFormatter", # Suppress any output by using the base formatter
34
- ].freeze,
50
+ ],
35
51
  T::Array[String],
36
52
  )
37
53
 
54
+ begin
55
+ RuboCop::Options.new.parse(["--raise-cop-error"])
56
+ DEFAULT_ARGS << "--raise-cop-error"
57
+ rescue OptionParser::InvalidOption
58
+ # older versions of RuboCop don't support this flag
59
+ end
60
+ DEFAULT_ARGS.freeze
61
+
38
62
  sig { params(args: String).void }
39
63
  def initialize(*args)
40
64
  @options = T.let({}, T::Hash[Symbol, T.untyped])
@@ -63,6 +87,8 @@ module RubyLsp
63
87
  raise Formatting::Error, error.message
64
88
  rescue RuboCop::ValidationError => error
65
89
  raise ConfigurationError, error.message
90
+ rescue RuboCop::ErrorWithAnalyzedFileLocation => error
91
+ raise InternalRuboCopError, error
66
92
  end
67
93
 
68
94
  sig { returns(String) }
@@ -0,0 +1,120 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ module Support
7
+ class Sorbet
8
+ class << self
9
+ extend T::Sig
10
+
11
+ ANNOTATIONS = T.let(
12
+ {
13
+ "abstract!" => Annotation.new(arity: 0),
14
+ "absurd" => Annotation.new(arity: 1, receiver: true),
15
+ "all" => Annotation.new(arity: (2..), receiver: true),
16
+ "any" => Annotation.new(arity: (2..), receiver: true),
17
+ "assert_type!" => Annotation.new(arity: 2, receiver: true),
18
+ "attached_class" => Annotation.new(arity: 0, receiver: true),
19
+ "bind" => Annotation.new(arity: 2, receiver: true),
20
+ "cast" => Annotation.new(arity: 2, receiver: true),
21
+ "class_of" => Annotation.new(arity: 1, receiver: true),
22
+ "enums" => Annotation.new(arity: 0),
23
+ "interface!" => Annotation.new(arity: 0),
24
+ "let" => Annotation.new(arity: 2, receiver: true),
25
+ "mixes_in_class_methods" => Annotation.new(arity: 1),
26
+ "must" => Annotation.new(arity: 1, receiver: true),
27
+ "must_because" => Annotation.new(arity: 1, receiver: true),
28
+ "nilable" => Annotation.new(arity: 1, receiver: true),
29
+ "noreturn" => Annotation.new(arity: 0, receiver: true),
30
+ "requires_ancestor" => Annotation.new(arity: 0),
31
+ "reveal_type" => Annotation.new(arity: 1, receiver: true),
32
+ "sealed!" => Annotation.new(arity: 0),
33
+ "self_type" => Annotation.new(arity: 0, receiver: true),
34
+ "sig" => Annotation.new(arity: 0),
35
+ "type_member" => Annotation.new(arity: (0..1)),
36
+ "type_template" => Annotation.new(arity: 0),
37
+ "unsafe" => Annotation.new(arity: 1),
38
+ "untyped" => Annotation.new(arity: 0, receiver: true),
39
+ },
40
+ T::Hash[String, Annotation],
41
+ )
42
+
43
+ sig do
44
+ params(
45
+ node: T.any(SyntaxTree::CallNode, SyntaxTree::VCall),
46
+ ).returns(T::Boolean)
47
+ end
48
+ def annotation?(node)
49
+ annotation = annotation(node)
50
+
51
+ return false if annotation.nil?
52
+
53
+ return false unless annotation.supports_receiver?(receiver_name(node))
54
+
55
+ annotation.supports_arity?(node.arity)
56
+ end
57
+
58
+ private
59
+
60
+ sig { params(node: T.any(SyntaxTree::CallNode, SyntaxTree::VCall)).returns(T.nilable(Annotation)) }
61
+ def annotation(node)
62
+ case node
63
+ when SyntaxTree::VCall
64
+ ANNOTATIONS[node.value.value]
65
+ when SyntaxTree::CallNode
66
+ ANNOTATIONS[node.message.value]
67
+ else
68
+ T.absurd(node)
69
+ end
70
+ end
71
+
72
+ sig do
73
+ params(receiver: T.any(SyntaxTree::CallNode, SyntaxTree::VCall)).returns(T.nilable(String))
74
+ end
75
+ def receiver_name(receiver)
76
+ case receiver
77
+ when SyntaxTree::CallNode
78
+ node_name(receiver.receiver)
79
+ when SyntaxTree::VCall
80
+ nil
81
+ else
82
+ T.absurd(receiver)
83
+ end
84
+ end
85
+
86
+ sig do
87
+ params(node: T.nilable(T.any(
88
+ SyntaxTree::VarRef,
89
+ SyntaxTree::CallNode,
90
+ SyntaxTree::VCall,
91
+ SyntaxTree::Ident,
92
+ SyntaxTree::Backtick,
93
+ SyntaxTree::Const,
94
+ SyntaxTree::Op,
95
+ Symbol,
96
+ ))).returns(T.nilable(String))
97
+ end
98
+ def node_name(node)
99
+ case node
100
+ when NilClass
101
+ nil
102
+ when SyntaxTree::VarRef
103
+ node.value.value
104
+ when SyntaxTree::CallNode
105
+ node_name(node.receiver)
106
+ when SyntaxTree::VCall
107
+ node_name(node.value)
108
+ when SyntaxTree::Ident, SyntaxTree::Backtick, SyntaxTree::Const, SyntaxTree::Op
109
+ node.value
110
+ when Symbol
111
+ node.to_s
112
+ else
113
+ T.absurd(node)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -14,8 +14,10 @@ module RubyLsp
14
14
  # - {RubyLsp::Requests::OnTypeFormatting}
15
15
  # - {RubyLsp::Requests::Diagnostics}
16
16
  # - {RubyLsp::Requests::CodeActions}
17
+ # - {RubyLsp::Requests::CodeActionResolve}
17
18
  # - {RubyLsp::Requests::DocumentHighlight}
18
19
  # - {RubyLsp::Requests::InlayHints}
20
+ # - {RubyLsp::Requests::PathCompletion}
19
21
 
20
22
  module Requests
21
23
  autoload :BaseRequest, "ruby_lsp/requests/base_request"
@@ -29,17 +31,21 @@ module RubyLsp
29
31
  autoload :OnTypeFormatting, "ruby_lsp/requests/on_type_formatting"
30
32
  autoload :Diagnostics, "ruby_lsp/requests/diagnostics"
31
33
  autoload :CodeActions, "ruby_lsp/requests/code_actions"
34
+ autoload :CodeActionResolve, "ruby_lsp/requests/code_action_resolve"
32
35
  autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
33
36
  autoload :InlayHints, "ruby_lsp/requests/inlay_hints"
37
+ autoload :PathCompletion, "ruby_lsp/requests/path_completion"
34
38
 
35
39
  # :nodoc:
36
40
  module Support
37
41
  autoload :RuboCopDiagnostic, "ruby_lsp/requests/support/rubocop_diagnostic"
38
42
  autoload :SelectionRange, "ruby_lsp/requests/support/selection_range"
39
43
  autoload :SemanticTokenEncoder, "ruby_lsp/requests/support/semantic_token_encoder"
40
- autoload :SyntaxErrorDiagnostic, "ruby_lsp/requests/support/syntax_error_diagnostic"
44
+ autoload :Annotation, "ruby_lsp/requests/support/annotation"
45
+ autoload :Sorbet, "ruby_lsp/requests/support/sorbet"
41
46
  autoload :HighlightTarget, "ruby_lsp/requests/support/highlight_target"
42
47
  autoload :RailsDocumentClient, "ruby_lsp/requests/support/rails_document_client"
48
+ autoload :PrefixTree, "ruby_lsp/requests/support/prefix_tree"
43
49
  end
44
50
  end
45
51
  end
@@ -1,250 +1,158 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "ruby_lsp/internal"
5
-
6
4
  module RubyLsp
7
- Handler.start do
8
- on("initialize") do |request|
9
- store.clear
10
- store.encoding = request.dig(:params, :capabilities, :general, :positionEncodings)
11
-
12
- initialization_options = request.dig(:params, :initializationOptions)
13
- enabled_features = initialization_options.fetch(:enabledFeatures, [])
14
-
15
- document_symbol_provider = if enabled_features.include?("documentSymbols")
16
- Interface::DocumentSymbolClientCapabilities.new(
17
- hierarchical_document_symbol_support: true,
18
- symbol_kind: {
19
- value_set: Requests::DocumentSymbol::SYMBOL_KIND.values,
20
- },
21
- )
22
- end
23
-
24
- document_link_provider = if enabled_features.include?("documentLink")
25
- Interface::DocumentLinkOptions.new(resolve_provider: false)
26
- end
27
-
28
- hover_provider = if enabled_features.include?("hover")
29
- Interface::HoverClientCapabilities.new(dynamic_registration: false)
30
- end
31
-
32
- folding_ranges_provider = if enabled_features.include?("foldingRanges")
33
- Interface::FoldingRangeClientCapabilities.new(line_folding_only: true)
34
- end
35
-
36
- semantic_tokens_provider = if enabled_features.include?("semanticHighlighting")
37
- Interface::SemanticTokensRegistrationOptions.new(
38
- document_selector: { scheme: "file", language: "ruby" },
39
- legend: Interface::SemanticTokensLegend.new(
40
- token_types: Requests::SemanticHighlighting::TOKEN_TYPES.keys,
41
- token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys,
42
- ),
43
- range: true,
44
- full: { delta: false },
45
- )
46
- end
47
-
48
- diagnostics_provider = if enabled_features.include?("diagnostics")
49
- {
50
- interFileDependencies: false,
51
- workspaceDiagnostics: false,
52
- }
53
- end
54
-
55
- on_type_formatting_provider = if enabled_features.include?("onTypeFormatting")
56
- Interface::DocumentOnTypeFormattingOptions.new(
57
- first_trigger_character: "{",
58
- more_trigger_character: ["\n", "|"],
59
- )
60
- end
61
-
62
- inlay_hint_provider = if enabled_features.include?("inlayHint")
63
- Interface::InlayHintOptions.new(resolve_provider: false)
5
+ Interface = LanguageServer::Protocol::Interface
6
+ Constant = LanguageServer::Protocol::Constant
7
+ Transport = LanguageServer::Protocol::Transport
8
+
9
+ class Server
10
+ extend T::Sig
11
+
12
+ sig { void }
13
+ def initialize
14
+ @writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
15
+ @reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader)
16
+ @store = T.let(Store.new, Store)
17
+
18
+ # The job queue is the actual list of requests we have to process
19
+ @job_queue = T.let(Thread::Queue.new, Thread::Queue)
20
+ # The jobs hash is just a way of keeping a handle to jobs based on the request ID, so we can cancel them
21
+ @jobs = T.let({}, T::Hash[T.any(String, Integer), Job])
22
+ @mutex = T.let(Mutex.new, Mutex)
23
+ @worker = T.let(new_worker, Thread)
24
+
25
+ Thread.main.priority = 1
26
+ end
27
+
28
+ sig { void }
29
+ def start
30
+ warn("Starting Ruby LSP...")
31
+
32
+ # Requests that have to be executed sequentially or in the main process are implemented here. All other requests
33
+ # fall under the else branch which just pushes requests to the queue
34
+ @reader.read do |request|
35
+ case request[:method]
36
+ when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
37
+ result = Executor.new(@store).execute(request)
38
+ finalize_request(result, request)
39
+ when "$/cancelRequest"
40
+ # Cancel the job if it's still in the queue
41
+ @mutex.synchronize { @jobs[request[:params][:id]]&.cancel }
42
+ when "shutdown"
43
+ warn("Shutting down Ruby LSP...")
44
+
45
+ # Close the queue so that we can no longer receive items
46
+ @job_queue.close
47
+ # Clear any remaining jobs so that the thread can terminate
48
+ @job_queue.clear
49
+ @jobs.clear
50
+ # Wait until the thread is finished
51
+ @worker.join
52
+ @store.clear
53
+
54
+ finalize_request(Result.new(response: nil, notifications: []), request)
55
+ when "exit"
56
+ # We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec
57
+ # https://microsoft.github.io/language-server-protocol/specification/#exit
58
+ status = @store.empty? ? 0 : 1
59
+ warn("Shutdown complete with status #{status}")
60
+ exit(status)
61
+ else
62
+ # Default case: push the request to the queue to be executed by the worker
63
+ job = Job.new(request: request, cancelled: false)
64
+
65
+ # Remember a handle to the job, so that we can cancel it
66
+ @mutex.synchronize { @jobs[request[:id]] = job }
67
+ @job_queue << job
68
+ end
64
69
  end
65
-
66
- Interface::InitializeResult.new(
67
- capabilities: Interface::ServerCapabilities.new(
68
- text_document_sync: Interface::TextDocumentSyncOptions.new(
69
- change: Constant::TextDocumentSyncKind::INCREMENTAL,
70
- open_close: true,
71
- ),
72
- selection_range_provider: enabled_features.include?("selectionRanges"),
73
- hover_provider: hover_provider,
74
- document_symbol_provider: document_symbol_provider,
75
- document_link_provider: document_link_provider,
76
- folding_range_provider: folding_ranges_provider,
77
- semantic_tokens_provider: semantic_tokens_provider,
78
- document_formatting_provider: enabled_features.include?("formatting"),
79
- document_highlight_provider: enabled_features.include?("documentHighlights"),
80
- code_action_provider: enabled_features.include?("codeActions"),
81
- document_on_type_formatting_provider: on_type_formatting_provider,
82
- diagnostic_provider: diagnostics_provider,
83
- inlay_hint_provider: inlay_hint_provider,
84
- ),
85
- )
86
70
  end
87
71
 
88
- on("textDocument/didChange") do |request|
89
- uri = request.dig(:params, :textDocument, :uri)
90
- store.push_edits(uri, request.dig(:params, :contentChanges))
91
-
92
- Handler::VOID
93
- end
94
-
95
- on("textDocument/didOpen") do |request|
96
- uri = request.dig(:params, :textDocument, :uri)
97
- text = request.dig(:params, :textDocument, :text)
98
- store.set(uri, text)
99
-
100
- Handler::VOID
101
- end
102
-
103
- on("textDocument/didClose") do |request|
104
- uri = request.dig(:params, :textDocument, :uri)
105
- store.delete(uri)
106
- clear_diagnostics(uri)
72
+ private
107
73
 
108
- Handler::VOID
109
- end
110
-
111
- on("textDocument/documentSymbol", parallel: true) do |request|
112
- store.cache_fetch(request.dig(:params, :textDocument, :uri), :document_symbol) do |document|
113
- Requests::DocumentSymbol.new(document).run
114
- end
115
- end
116
-
117
- on("textDocument/documentLink", parallel: true) do |request|
118
- uri = request.dig(:params, :textDocument, :uri)
119
- store.cache_fetch(uri, :document_link) do |document|
120
- RubyLsp::Requests::DocumentLink.new(uri, document).run
121
- end
122
- end
74
+ sig { returns(Thread) }
75
+ def new_worker
76
+ Thread.new do
77
+ # Thread::Queue#pop is thread safe and will wait until an item is available
78
+ loop do
79
+ job = T.let(@job_queue.pop, T.nilable(Job))
80
+ # The only time when the job is nil is when the queue is closed and we can then terminate the thread
81
+ break if job.nil?
123
82
 
124
- on("textDocument/hover") do |request|
125
- position = request.dig(:params, :position)
126
- document = store.get(request.dig(:params, :textDocument, :uri))
83
+ request = job.request
84
+ @mutex.synchronize { @jobs.delete(request[:id]) }
127
85
 
128
- RubyLsp::Requests::Hover.new(document, position).run
129
- end
86
+ result = if job.cancelled
87
+ # We need to return nil to the client even if the request was cancelled
88
+ Result.new(response: nil, notifications: [])
89
+ else
90
+ Executor.new(@store).execute(request)
91
+ end
130
92
 
131
- on("textDocument/foldingRange", parallel: true) do |request|
132
- store.cache_fetch(request.dig(:params, :textDocument, :uri), :folding_ranges) do |document|
133
- Requests::FoldingRanges.new(document).run
93
+ finalize_request(result, request)
94
+ end
134
95
  end
135
96
  end
136
97
 
137
- on("textDocument/selectionRange", parallel: true) do |request|
138
- uri = request.dig(:params, :textDocument, :uri)
139
- positions = request.dig(:params, :positions)
140
-
141
- ranges = store.cache_fetch(uri, :selection_ranges) do |document|
142
- Requests::SelectionRanges.new(document).run
143
- end
144
-
145
- # Per the selection range request spec (https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange),
146
- # every position in the positions array should have an element at the same index in the response
147
- # array. For positions without a valid selection range, the corresponding element in the response
148
- # array will be nil.
149
-
150
- unless ranges.nil?
151
- positions.map do |position|
152
- ranges.find do |range|
153
- range.cover?(position)
154
- end
98
+ # Finalize a Queue::Result. All IO operations should happen here to avoid any issues with cancelling requests
99
+ sig { params(result: Result, request: T::Hash[Symbol, T.untyped]).void }
100
+ def finalize_request(result, request)
101
+ @mutex.synchronize do
102
+ error = result.error
103
+ response = result.response
104
+
105
+ # If the response include any notifications, go through them and publish each one
106
+ result.notifications.each { |n| @writer.write(method: n.message, params: n.params) }
107
+
108
+ if error
109
+ @writer.write(
110
+ id: request[:id],
111
+ error: {
112
+ code: Constant::ErrorCodes::INTERNAL_ERROR,
113
+ message: error.inspect,
114
+ data: request.to_json,
115
+ },
116
+ )
117
+ elsif response != VOID
118
+ @writer.write(id: request[:id], result: response)
155
119
  end
156
- end
157
- end
158
120
 
159
- on("textDocument/semanticTokens/full", parallel: true) do |request|
160
- store.cache_fetch(request.dig(:params, :textDocument, :uri), :semantic_highlighting) do |document|
161
- T.cast(
162
- Requests::SemanticHighlighting.new(
163
- document,
164
- encoder: Requests::Support::SemanticTokenEncoder.new,
165
- ).run,
166
- LanguageServer::Protocol::Interface::SemanticTokens,
167
- )
121
+ request_time = result.request_time
122
+ if request_time
123
+ @writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
124
+ end
168
125
  end
169
126
  end
170
127
 
171
- on("textDocument/semanticTokens/range", parallel: true) do |request|
172
- document = store.get(request.dig(:params, :textDocument, :uri))
173
- range = request.dig(:params, :range)
174
- start_line = range.dig(:start, :line)
175
- end_line = range.dig(:end, :line)
176
-
177
- Requests::SemanticHighlighting.new(
178
- document,
179
- range: start_line..end_line,
180
- encoder: Requests::Support::SemanticTokenEncoder.new,
181
- ).run
128
+ sig do
129
+ params(
130
+ request: T::Hash[Symbol, T.untyped],
131
+ request_time: Float,
132
+ error: T.nilable(Exception),
133
+ ).returns(T::Hash[Symbol, T.any(String, Float)])
182
134
  end
183
-
184
- on("textDocument/formatting", parallel: true) do |request|
135
+ def telemetry_params(request, request_time, error)
185
136
  uri = request.dig(:params, :textDocument, :uri)
137
+ params = {
138
+ request: request[:method],
139
+ lspVersion: RubyLsp::VERSION,
140
+ requestTime: request_time,
141
+ }
186
142
 
187
- Requests::Formatting.new(uri, store.get(uri)).run
188
- end.on_error do |error|
189
- show_message(Constant::MessageType::ERROR, "Formatting error: #{error.message}")
190
- end
191
-
192
- on("textDocument/onTypeFormatting", parallel: true) do |request|
193
- uri = request.dig(:params, :textDocument, :uri)
194
- position = request.dig(:params, :position)
195
- character = request.dig(:params, :ch)
143
+ if error
144
+ params[:errorClass] = error.class.name
145
+ params[:errorMessage] = error.message
196
146
 
197
- Requests::OnTypeFormatting.new(store.get(uri), position, character).run
198
- end
147
+ log_params = request[:params]
148
+ params[:params] = log_params.reject { |k, _| k == :textDocument }.to_json if log_params
199
149
 
200
- on("textDocument/documentHighlight", parallel: true) do |request|
201
- document = store.get(request.dig(:params, :textDocument, :uri))
202
-
203
- Requests::DocumentHighlight.new(document, request.dig(:params, :position)).run
204
- end
205
-
206
- on("textDocument/codeAction", parallel: true) do |request|
207
- uri = request.dig(:params, :textDocument, :uri)
208
- document = store.get(uri)
209
- range = request.dig(:params, :range)
210
- start_line = range.dig(:start, :line)
211
- end_line = range.dig(:end, :line)
212
-
213
- Requests::CodeActions.new(uri, document, start_line..end_line).run
214
- end
215
-
216
- on("textDocument/inlayHint", parallel: true) do |request|
217
- document = store.get(request.dig(:params, :textDocument, :uri))
218
- range = request.dig(:params, :range)
219
- start_line = range.dig(:start, :line)
220
- end_line = range.dig(:end, :line)
221
-
222
- Requests::InlayHints.new(document, start_line..end_line).run
223
- end
224
-
225
- on("$/cancelRequest") do |request|
226
- cancel_request(request[:params][:id])
227
- Handler::VOID
228
- end
229
-
230
- on("textDocument/diagnostic", parallel: true) do |request|
231
- uri = request.dig(:params, :textDocument, :uri)
232
- response = store.cache_fetch(uri, :diagnostics) do |document|
233
- Requests::Diagnostics.new(uri, document).run
150
+ backtrace = error.backtrace
151
+ params[:backtrace] = backtrace.map { |bt| bt.sub(/^#{Dir.home}/, "~") }.join("\n") if backtrace
234
152
  end
235
153
 
236
- { kind: "full", items: response.map(&:to_lsp_diagnostic) } if response
237
- end.on_error do |error|
238
- show_message(Constant::MessageType::ERROR, "Error running diagnostics: #{error.message}")
239
- end
240
-
241
- on("shutdown") { shutdown }
242
-
243
- on("exit") do
244
- # We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec
245
- # https://microsoft.github.io/language-server-protocol/specification/#exit
246
- status = store.empty? ? 0 : 1
247
- exit(status)
154
+ params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
155
+ params
248
156
  end
249
157
  end
250
158
  end
@@ -0,0 +1,78 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ # Used to indicate that a request shouldn't return a response
6
+ VOID = T.let(Object.new.freeze, Object)
7
+
8
+ # A notification to be sent to the client
9
+ class Notification
10
+ extend T::Sig
11
+
12
+ sig { returns(String) }
13
+ attr_reader :message
14
+
15
+ sig { returns(Object) }
16
+ attr_reader :params
17
+
18
+ sig { params(message: String, params: Object).void }
19
+ def initialize(message:, params:)
20
+ @message = message
21
+ @params = params
22
+ end
23
+ end
24
+
25
+ # The final result of running a request before its IO is finalized
26
+ class Result
27
+ extend T::Sig
28
+
29
+ sig { returns(T.untyped) }
30
+ attr_reader :response
31
+
32
+ sig { returns(T::Array[Notification]) }
33
+ attr_reader :notifications
34
+
35
+ sig { returns(T.nilable(Exception)) }
36
+ attr_reader :error
37
+
38
+ sig { returns(T.nilable(Float)) }
39
+ attr_reader :request_time
40
+
41
+ sig do
42
+ params(
43
+ response: T.untyped,
44
+ notifications: T::Array[Notification],
45
+ error: T.nilable(Exception),
46
+ request_time: T.nilable(Float),
47
+ ).void
48
+ end
49
+ def initialize(response:, notifications:, error: nil, request_time: nil)
50
+ @response = response
51
+ @notifications = notifications
52
+ @error = error
53
+ @request_time = request_time
54
+ end
55
+ end
56
+
57
+ # A request that will sit in the queue until it's executed
58
+ class Job
59
+ extend T::Sig
60
+
61
+ sig { returns(T::Hash[Symbol, T.untyped]) }
62
+ attr_reader :request
63
+
64
+ sig { returns(T::Boolean) }
65
+ attr_reader :cancelled
66
+
67
+ sig { params(request: T::Hash[Symbol, T.untyped], cancelled: T::Boolean).void }
68
+ def initialize(request:, cancelled:)
69
+ @request = request
70
+ @cancelled = cancelled
71
+ end
72
+
73
+ sig { void }
74
+ def cancel
75
+ @cancelled = true
76
+ end
77
+ end
78
+ end