ruby-lsp 0.3.8 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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