docscribe 1.5.0 → 1.5.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.
- checksums.yaml +4 -4
- data/README.md +140 -13
- data/exe/docscribe-client +105 -0
- data/lib/docscribe/cli/config_builder.rb +1 -1
- data/lib/docscribe/cli/generate.rb +11 -17
- data/lib/docscribe/cli/options.rb +17 -2
- data/lib/docscribe/cli/rbs_gen.rb +1 -1
- data/lib/docscribe/cli/run.rb +230 -9
- data/lib/docscribe/cli/server.rb +135 -0
- data/lib/docscribe/cli/sigs.rb +5 -5
- data/lib/docscribe/cli.rb +20 -31
- data/lib/docscribe/config/defaults.rb +2 -1
- data/lib/docscribe/config/filtering.rb +1 -1
- data/lib/docscribe/config/loader.rb +5 -7
- data/lib/docscribe/config/rbs.rb +2 -2
- data/lib/docscribe/config/sorbet.rb +15 -6
- data/lib/docscribe/config/template.rb +1 -0
- data/lib/docscribe/config.rb +8 -2
- data/lib/docscribe/infer/params.rb +1 -1
- data/lib/docscribe/infer/returns.rb +81 -19
- data/lib/docscribe/infer.rb +7 -3
- data/lib/docscribe/inline_rewriter/doc_builder.rb +14 -8
- data/lib/docscribe/inline_rewriter/source_helpers.rb +1 -1
- data/lib/docscribe/inline_rewriter.rb +14 -20
- data/lib/docscribe/lru_cache.rb +49 -0
- data/lib/docscribe/parsing.rb +2 -2
- data/lib/docscribe/plugin/registry.rb +1 -1
- data/lib/docscribe/plugin.rb +1 -1
- data/lib/docscribe/server.rb +608 -0
- data/lib/docscribe/types/rbs/provider.rb +120 -10
- data/lib/docscribe/types/sorbet/base_provider.rb +7 -4
- data/lib/docscribe/types/sorbet/rbi_provider.rb +3 -2
- data/lib/docscribe/types/sorbet/source_provider.rb +3 -2
- data/lib/docscribe/version.rb +1 -1
- metadata +7 -2
data/lib/docscribe/cli/run.rb
CHANGED
|
@@ -4,7 +4,6 @@ require 'pathname'
|
|
|
4
4
|
|
|
5
5
|
require 'docscribe/cli/config_builder'
|
|
6
6
|
require 'docscribe/cli/formatters'
|
|
7
|
-
require 'docscribe/inline_rewriter'
|
|
8
7
|
|
|
9
8
|
module Docscribe
|
|
10
9
|
module CLI
|
|
@@ -35,6 +34,14 @@ module Docscribe
|
|
|
35
34
|
total: 0,
|
|
36
35
|
processed: 0
|
|
37
36
|
}.freeze
|
|
37
|
+
|
|
38
|
+
CLI_OVERRIDE_KEYS = %i[
|
|
39
|
+
keep_descriptions no_boilerplate
|
|
40
|
+
include exclude include_file exclude_file
|
|
41
|
+
rbs rbs_collection sig_dirs
|
|
42
|
+
sorbet rbi_dirs
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
38
45
|
# Run Docscribe for files or STDIN using the selected mode and strategy.
|
|
39
46
|
#
|
|
40
47
|
# Modes:
|
|
@@ -50,6 +57,9 @@ module Docscribe
|
|
|
50
57
|
# @param [Array<String>] argv remaining path arguments
|
|
51
58
|
# @return [Integer] process exit code
|
|
52
59
|
def run(options:, argv:)
|
|
60
|
+
return run_via_server(options: options, argv: argv) if options[:server]
|
|
61
|
+
|
|
62
|
+
require 'docscribe/inline_rewriter'
|
|
53
63
|
conf = build_config(options)
|
|
54
64
|
|
|
55
65
|
return run_stdin(options: options, conf: conf) if options[:mode] == :stdin
|
|
@@ -60,10 +70,45 @@ module Docscribe
|
|
|
60
70
|
run_files(options: options, conf: conf, paths: paths)
|
|
61
71
|
end
|
|
62
72
|
|
|
63
|
-
#
|
|
73
|
+
# @param [Docscribe::CLI::Formatters::opts] options
|
|
74
|
+
# @param [Array<String>] argv
|
|
75
|
+
# @raise [RuntimeError]
|
|
76
|
+
# @return [Integer]
|
|
77
|
+
# @return [Integer] if RuntimeError
|
|
78
|
+
def run_via_server(options:, argv:)
|
|
79
|
+
require 'docscribe/server'
|
|
80
|
+
conf = build_light_config(options)
|
|
81
|
+
ensure_server_running!(config_path: conf.config_path)
|
|
82
|
+
client = Docscribe::Server::Client.new(config_path: conf.config_path)
|
|
83
|
+
paths = filtered_paths(argv, conf)
|
|
84
|
+
return no_files_found unless paths.any?
|
|
85
|
+
|
|
86
|
+
run_files_via_server(client, paths, options)
|
|
87
|
+
rescue RuntimeError => e
|
|
88
|
+
warn e.message
|
|
89
|
+
1
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Run files through the server client with progress tracking.
|
|
64
93
|
#
|
|
65
|
-
# @param [Docscribe::
|
|
66
|
-
# @
|
|
94
|
+
# @param [Docscribe::Server::Client] client server client
|
|
95
|
+
# @param [Array<String>] paths file paths to process
|
|
96
|
+
# @param [Docscribe::CLI::Formatters::opts] options CLI options
|
|
97
|
+
# @return [Integer] exit code
|
|
98
|
+
def run_files_via_server(client, paths, options)
|
|
99
|
+
$stdout.sync = true
|
|
100
|
+
state = initial_run_state
|
|
101
|
+
state[:total] = paths.size
|
|
102
|
+
pwd = Pathname.pwd
|
|
103
|
+
paths.each do |path|
|
|
104
|
+
process_one_file_via_server(client, path, options: options, pwd: pwd, state: state)
|
|
105
|
+
end
|
|
106
|
+
finalize_run(options, state)
|
|
107
|
+
run_exit_code(options, state)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# @param [Docscribe::CLI::Formatters::opts] options
|
|
111
|
+
# @return [Docscribe::Config]
|
|
67
112
|
def build_config(options)
|
|
68
113
|
conf = Docscribe::Config.load(options[:config])
|
|
69
114
|
conf = Docscribe::CLI::ConfigBuilder.build(conf, options)
|
|
@@ -71,13 +116,20 @@ module Docscribe
|
|
|
71
116
|
conf
|
|
72
117
|
end
|
|
73
118
|
|
|
119
|
+
# @param [Docscribe::CLI::Formatters::opts] options
|
|
120
|
+
# @return [Docscribe::Config]
|
|
121
|
+
def build_light_config(options)
|
|
122
|
+
conf = Docscribe::Config.load(options[:config])
|
|
123
|
+
Docscribe::CLI::ConfigBuilder.build(conf, options)
|
|
124
|
+
end
|
|
125
|
+
|
|
74
126
|
# Rewrite code from STDIN using the selected strategy and print the
|
|
75
127
|
# result.
|
|
76
128
|
#
|
|
77
129
|
# @param [Docscribe::CLI::Formatters::opts] options parsed CLI options
|
|
78
130
|
# @param [Docscribe::Config] conf effective config
|
|
79
131
|
# @raise [StandardError]
|
|
80
|
-
# @return [Integer]
|
|
132
|
+
# @return [Integer]
|
|
81
133
|
# @return [Integer] if StandardError
|
|
82
134
|
def run_stdin(options:, conf:)
|
|
83
135
|
puts stdin_rewrite_result(options, conf)[:output]
|
|
@@ -127,6 +179,161 @@ module Docscribe
|
|
|
127
179
|
2
|
|
128
180
|
end
|
|
129
181
|
|
|
182
|
+
# Ensure the server daemon is running, auto-starting if necessary.
|
|
183
|
+
#
|
|
184
|
+
# @param [String?] config_path
|
|
185
|
+
# @return [void]
|
|
186
|
+
def ensure_server_running!(config_path: nil)
|
|
187
|
+
Docscribe::Server.ensure_running!(config_path: config_path)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Process a single file via the server client.
|
|
191
|
+
#
|
|
192
|
+
# @param [Docscribe::Server::Client] client server client
|
|
193
|
+
# @param [String] path file path
|
|
194
|
+
# @param [Docscribe::CLI::Formatters::opts] options CLI options
|
|
195
|
+
# @param [Pathname] pwd current working directory
|
|
196
|
+
# @param [Docscribe::CLI::Formatters::state] state shared processing state
|
|
197
|
+
# @return [void]
|
|
198
|
+
def process_one_file_via_server(client, path, options:, pwd:, state:)
|
|
199
|
+
display_path = display_path_for(path, pwd: pwd)
|
|
200
|
+
report_progress(state, options, display_path)
|
|
201
|
+
response = send_server_request(client, path, options)
|
|
202
|
+
return server_error(path, state, 'Server unreachable') unless response
|
|
203
|
+
return server_error(path, state, response['error']['message']) if response['error']
|
|
204
|
+
|
|
205
|
+
result = response['result']
|
|
206
|
+
file_changes = (result['changes'] || []).map { |c| symbolize_change(c) }
|
|
207
|
+
dispatch_server_result(result, file_changes, path,
|
|
208
|
+
display_path: display_path, options: options, state: state)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @param [Docscribe::Server::Client] client
|
|
212
|
+
# @param [String] path
|
|
213
|
+
# @param [Docscribe::CLI::Formatters::opts] options
|
|
214
|
+
# @return [Hash<String, Object>, nil]
|
|
215
|
+
def send_server_request(client, path, options)
|
|
216
|
+
method_name = options[:mode] == :write ? :fix : :check
|
|
217
|
+
strategy = options[:strategy].to_s
|
|
218
|
+
cli_overrides = extract_cli_overrides(options)
|
|
219
|
+
if cli_overrides.empty?
|
|
220
|
+
client.send(method_name, file: path, strategy: strategy)
|
|
221
|
+
else
|
|
222
|
+
client.send(method_name, file: path, strategy: strategy, cli_overrides: cli_overrides)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Record a server error in the shared state and print an indicator.
|
|
227
|
+
#
|
|
228
|
+
# @param [String] path file path
|
|
229
|
+
# @param [Docscribe::CLI::Formatters::state] state shared processing state
|
|
230
|
+
# @param [String] message error message
|
|
231
|
+
# @return [void]
|
|
232
|
+
def server_error(path, state, message)
|
|
233
|
+
state[:had_errors] = true
|
|
234
|
+
state[:error_paths] << path
|
|
235
|
+
state[:error_messages][path] = message
|
|
236
|
+
$stderr.print('E')
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Dispatch the server result to check or write handler.
|
|
240
|
+
#
|
|
241
|
+
# @param [Hash<String, Object>] result server result with :changed and :changes keys
|
|
242
|
+
# @param [Array<Docscribe::CLI::Formatters::change>] file_changes change records
|
|
243
|
+
# @param [String] path file path
|
|
244
|
+
# @param [Object] ctx context hash with :display_path, :options, :state keys
|
|
245
|
+
# @return [void]
|
|
246
|
+
def dispatch_server_result(result, file_changes, path, **ctx)
|
|
247
|
+
if ctx[:options][:mode] == :check
|
|
248
|
+
handle_via_server_check(path, file_changes: file_changes,
|
|
249
|
+
display_path: ctx[:display_path],
|
|
250
|
+
options: ctx[:options], state: ctx[:state])
|
|
251
|
+
else
|
|
252
|
+
write_server_result(result, file_changes, display_path: ctx[:display_path],
|
|
253
|
+
options: ctx[:options], state: ctx[:state])
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Handle a server write-mode result.
|
|
258
|
+
#
|
|
259
|
+
# @param [Hash<String, Object>] result server result with :changed key
|
|
260
|
+
# @param [Array<Docscribe::CLI::Formatters::change>] file_changes change records
|
|
261
|
+
# @param [String] display_path path shown in CLI output
|
|
262
|
+
# @param [Docscribe::CLI::Formatters::opts] options CLI options
|
|
263
|
+
# @param [Docscribe::CLI::Formatters::state] state shared processing state
|
|
264
|
+
# @return [void]
|
|
265
|
+
def write_server_result(result, file_changes, display_path:, options:, state:)
|
|
266
|
+
if result['changed']
|
|
267
|
+
state[:corrected] += 1
|
|
268
|
+
state[:corrected_paths] << display_path
|
|
269
|
+
state[:corrected_changes][display_path] = file_changes
|
|
270
|
+
log_check_verdict('CHANGED', display_path, options)
|
|
271
|
+
else
|
|
272
|
+
log_check_verdict('OK', display_path, options)
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Handle a check result from the server.
|
|
277
|
+
#
|
|
278
|
+
# @param [String] path file path
|
|
279
|
+
# @param [Array<Docscribe::CLI::Formatters::change>] file_changes change records from server
|
|
280
|
+
# @param [String] display_path path shown in CLI output
|
|
281
|
+
# @param [Docscribe::CLI::Formatters::opts] options CLI options
|
|
282
|
+
# @param [Docscribe::CLI::Formatters::state] state shared processing state
|
|
283
|
+
# @return [void]
|
|
284
|
+
def handle_via_server_check(path, file_changes:, display_path:, options:, state:)
|
|
285
|
+
if file_changes.empty?
|
|
286
|
+
state[:checked_ok] += 1
|
|
287
|
+
return log_check_verdict('OK', display_path, options)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
report_check_failure(display_path, file_changes, options)
|
|
291
|
+
update_check_failure_state(path, file_changes, state)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Report a check failure with verbose or compact output.
|
|
295
|
+
#
|
|
296
|
+
# @param [String] display_path path shown in CLI output
|
|
297
|
+
# @param [Array<Docscribe::CLI::Formatters::change>] file_changes change records from server
|
|
298
|
+
# @param [Docscribe::CLI::Formatters::opts] options CLI options
|
|
299
|
+
# @return [void]
|
|
300
|
+
def report_check_failure(display_path, file_changes, options)
|
|
301
|
+
if options[:verbose]
|
|
302
|
+
warn("FAIL #{display_path}")
|
|
303
|
+
print_check_explanations(file_changes)
|
|
304
|
+
else
|
|
305
|
+
$stderr.print('F')
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Update shared state after a check failure.
|
|
310
|
+
#
|
|
311
|
+
# @param [String] path file path
|
|
312
|
+
# @param [Array<Docscribe::CLI::Formatters::change>] file_changes change records from server
|
|
313
|
+
# @param [Docscribe::CLI::Formatters::state] state shared processing state
|
|
314
|
+
# @return [void]
|
|
315
|
+
def update_check_failure_state(path, file_changes, state)
|
|
316
|
+
state[:checked_fail] += 1
|
|
317
|
+
state[:changed] = true
|
|
318
|
+
state[:fail_paths] << path
|
|
319
|
+
state[:fail_changes][path] = file_changes
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Convert server response change (string keys) to formatter-compatible
|
|
323
|
+
# change (symbol keys).
|
|
324
|
+
#
|
|
325
|
+
# @param [Hash<String, Object>] change change record from server
|
|
326
|
+
# @return [Docscribe::CLI::Formatters::change]
|
|
327
|
+
def symbolize_change(change)
|
|
328
|
+
{
|
|
329
|
+
type: change['type'].to_sym,
|
|
330
|
+
file: change['file'],
|
|
331
|
+
line: change['line'],
|
|
332
|
+
method: change['method'],
|
|
333
|
+
message: change['message']
|
|
334
|
+
}
|
|
335
|
+
end
|
|
336
|
+
|
|
130
337
|
# Expand CLI path arguments into a sorted list of Ruby files.
|
|
131
338
|
#
|
|
132
339
|
# Directories are expanded recursively to `**/*.rb`.
|
|
@@ -190,6 +397,20 @@ module Docscribe
|
|
|
190
397
|
run_exit_code(options, state)
|
|
191
398
|
end
|
|
192
399
|
|
|
400
|
+
# @param [Docscribe::CLI::Formatters::opts] options
|
|
401
|
+
# @return [Hash<String, Object>]
|
|
402
|
+
def extract_cli_overrides(options)
|
|
403
|
+
overrides = options.slice(*CLI_OVERRIDE_KEYS)
|
|
404
|
+
acc = {} #: Hash[String, untyped]
|
|
405
|
+
overrides.each do |k, v|
|
|
406
|
+
next if v.nil? || v == false
|
|
407
|
+
next if v.is_a?(Array) && v.empty?
|
|
408
|
+
|
|
409
|
+
acc[k.to_s] = v
|
|
410
|
+
end
|
|
411
|
+
acc
|
|
412
|
+
end
|
|
413
|
+
|
|
193
414
|
private
|
|
194
415
|
|
|
195
416
|
# Print the check or write summary at the end of a run.
|
|
@@ -293,7 +514,7 @@ module Docscribe
|
|
|
293
514
|
# @param [String] path file path to display
|
|
294
515
|
# @param [Pathname] pwd current working directory
|
|
295
516
|
# @raise [StandardError]
|
|
296
|
-
# @return [String]
|
|
517
|
+
# @return [String]
|
|
297
518
|
# @return [Object] if StandardError
|
|
298
519
|
def display_path_for(path, pwd:)
|
|
299
520
|
abs = Pathname.new(path).expand_path
|
|
@@ -315,7 +536,7 @@ module Docscribe
|
|
|
315
536
|
# @param [Docscribe::CLI::Formatters::opts] options CLI options
|
|
316
537
|
# @param [Docscribe::CLI::Formatters::state] state shared processing state
|
|
317
538
|
# @raise [StandardError]
|
|
318
|
-
# @return [String, nil]
|
|
539
|
+
# @return [String, nil]
|
|
319
540
|
# @return [nil] if StandardError
|
|
320
541
|
def read_source_for_path(path, display_path:, options:, state:)
|
|
321
542
|
File.read(path)
|
|
@@ -334,7 +555,7 @@ module Docscribe
|
|
|
334
555
|
# @param [String] src source code
|
|
335
556
|
# @param [Hash<Symbol, Object>] ctx context hash with :conf, :display_path, :options, :state keys
|
|
336
557
|
# @raise [StandardError]
|
|
337
|
-
# @return [Hash<Symbol, Object>, nil]
|
|
558
|
+
# @return [Hash<Symbol, Object>, nil]
|
|
338
559
|
# @return [nil] if StandardError
|
|
339
560
|
def rewrite_result_for_path(path, src:, ctx:)
|
|
340
561
|
conf = ctx[:conf]
|
|
@@ -456,7 +677,7 @@ module Docscribe
|
|
|
456
677
|
# @param [Array<Docscribe::CLI::Formatters::change>] file_changes structured change records
|
|
457
678
|
# @param [Object] ctx context hash with :display_path, :options, :state keys
|
|
458
679
|
# @raise [StandardError]
|
|
459
|
-
# @return [void]
|
|
680
|
+
# @return [void]
|
|
460
681
|
# @return [Object] if StandardError
|
|
461
682
|
def handle_write_result(path, src:, out:, file_changes:, **ctx)
|
|
462
683
|
return log_check_verdict('OK', ctx[:display_path], ctx[:options]) if out == src
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
module Docscribe
|
|
6
|
+
module CLI
|
|
7
|
+
# Handle the `docscribe server` subcommand.
|
|
8
|
+
module ServerCmd
|
|
9
|
+
BANNER = <<~TEXT
|
|
10
|
+
Usage: docscribe server <command> [options]
|
|
11
|
+
|
|
12
|
+
Commands:
|
|
13
|
+
start Start the background daemon
|
|
14
|
+
stop Stop the background daemon
|
|
15
|
+
status Show daemon status
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
-C, --config <path> Config file path (default: auto-detect)
|
|
19
|
+
|
|
20
|
+
Once the server is running, use `--server` with other commands:
|
|
21
|
+
docscribe --server check lib/
|
|
22
|
+
docscribe --server --autocorrect lib/
|
|
23
|
+
TEXT
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
# Run the server subcommand.
|
|
27
|
+
#
|
|
28
|
+
# @param [Array<String>] argv subcommand arguments
|
|
29
|
+
# @return [Integer] exit code
|
|
30
|
+
def run(argv)
|
|
31
|
+
config_path, cmd = parse_args(argv)
|
|
32
|
+
return warn(BANNER) || 1 unless cmd
|
|
33
|
+
|
|
34
|
+
case cmd
|
|
35
|
+
when 'start' then start_server(config_path)
|
|
36
|
+
when 'stop' then stop_server(config_path)
|
|
37
|
+
when 'status' then show_status(config_path)
|
|
38
|
+
else warn(usage) || 1
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# @private
|
|
45
|
+
# @param [Array<String>] argv
|
|
46
|
+
# @return [(String?, String?)]
|
|
47
|
+
def parse_args(argv)
|
|
48
|
+
config_path = nil
|
|
49
|
+
rest = OptionParser.new do |opts|
|
|
50
|
+
opts.on('-C', '--config <path>', 'Config file path') { |v| config_path = v }
|
|
51
|
+
end.parse!(argv.dup)
|
|
52
|
+
[config_path, rest.first]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Start the background daemon process.
|
|
56
|
+
#
|
|
57
|
+
# @private
|
|
58
|
+
# @param [String?] config_path optional config file path
|
|
59
|
+
# @return [Integer] exit code
|
|
60
|
+
def start_server(config_path = nil)
|
|
61
|
+
require 'docscribe/server'
|
|
62
|
+
return already_running(config_path) if Docscribe::Server.running?(config_path)
|
|
63
|
+
|
|
64
|
+
Docscribe::Server.ensure_running!(daemonize: true, config_path: config_path)
|
|
65
|
+
pid = Docscribe::Server.read_pid(config_path)
|
|
66
|
+
warn "Docscribe server started (pid #{pid})"
|
|
67
|
+
0
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @private
|
|
71
|
+
# @param [String?] config_path optional config file path
|
|
72
|
+
# @return [Integer]
|
|
73
|
+
def already_running(config_path = nil)
|
|
74
|
+
pid = Docscribe::Server.read_pid(config_path)
|
|
75
|
+
warn "Docscribe server already running (pid #{pid})"
|
|
76
|
+
0
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Stop the background daemon.
|
|
80
|
+
#
|
|
81
|
+
# @private
|
|
82
|
+
# @param [String?] config_path optional config file path
|
|
83
|
+
# @return [Integer] exit code
|
|
84
|
+
def stop_server(config_path = nil)
|
|
85
|
+
require 'docscribe/server'
|
|
86
|
+
alive = Docscribe::Server::Client.new(config_path: config_path).shutdown
|
|
87
|
+
warn(alive ? 'Docscribe server stopped' : 'Docscribe server is not running')
|
|
88
|
+
0
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Show the server status.
|
|
92
|
+
#
|
|
93
|
+
# @private
|
|
94
|
+
# @param [String?] config_path optional config file path
|
|
95
|
+
# @return [Integer] exit code
|
|
96
|
+
def show_status(config_path = nil)
|
|
97
|
+
require 'docscribe/server'
|
|
98
|
+
return warn('Docscribe server is not running') || 0 unless Docscribe::Server.running?(config_path)
|
|
99
|
+
|
|
100
|
+
info = Docscribe::Server::Client.new(config_path: config_path).ping
|
|
101
|
+
info ? show_status_from_ping(info) : show_status_fallback(config_path)
|
|
102
|
+
0
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @private
|
|
106
|
+
# @param [Hash<String, Object>] info ping response hash
|
|
107
|
+
# @return [void]
|
|
108
|
+
def show_status_from_ping(info)
|
|
109
|
+
pid = info.dig('result', 'pid')
|
|
110
|
+
version = info.dig('result', 'version')
|
|
111
|
+
uptime = info.dig('result', 'uptime')
|
|
112
|
+
sock = info.dig('result', 'socket_path')
|
|
113
|
+
warn "Docscribe server v#{version} is running (pid #{pid}, socket #{sock}, uptime #{uptime}s)"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @private
|
|
117
|
+
# @param [String?] config_path
|
|
118
|
+
# @return [void]
|
|
119
|
+
def show_status_fallback(config_path)
|
|
120
|
+
pid = Docscribe::Server.read_pid(config_path)
|
|
121
|
+
sock = Docscribe::Server.socket_path(config_path)
|
|
122
|
+
warn "Docscribe server is running (pid #{pid}, socket #{sock})"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Print usage information for the server subcommand.
|
|
126
|
+
#
|
|
127
|
+
# @private
|
|
128
|
+
# @return [String]
|
|
129
|
+
def usage
|
|
130
|
+
BANNER
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
data/lib/docscribe/cli/sigs.rb
CHANGED
|
@@ -160,9 +160,9 @@ module Docscribe
|
|
|
160
160
|
# @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
|
|
161
161
|
# @raise [Parser::SyntaxError]
|
|
162
162
|
# @raise [StandardError]
|
|
163
|
-
# @return [void]
|
|
164
|
-
# @return [
|
|
165
|
-
# @return [
|
|
163
|
+
# @return [void]
|
|
164
|
+
# @return [nil] if Parser::SyntaxError
|
|
165
|
+
# @return [nil] if StandardError
|
|
166
166
|
def extract_methods_from_file(path, methods)
|
|
167
167
|
src = File.read(path)
|
|
168
168
|
ast = Docscribe::Parsing.parse(src, file: path)
|
|
@@ -281,7 +281,7 @@ module Docscribe
|
|
|
281
281
|
# @param [Hash<Symbol, Object>] options
|
|
282
282
|
# @raise [LoadError]
|
|
283
283
|
# @raise [StandardError]
|
|
284
|
-
# @return [Docscribe::Types::RBS::Provider?]
|
|
284
|
+
# @return [Docscribe::Types::RBS::Provider?]
|
|
285
285
|
# @return [nil] if LoadError
|
|
286
286
|
# @return [nil] if StandardError
|
|
287
287
|
def build_provider(options)
|
|
@@ -298,7 +298,7 @@ module Docscribe
|
|
|
298
298
|
|
|
299
299
|
# @private
|
|
300
300
|
# @raise [StandardError]
|
|
301
|
-
# @return [Array<String>]
|
|
301
|
+
# @return [Array<String>]
|
|
302
302
|
# @return [Array] if StandardError
|
|
303
303
|
def load_collection_dirs
|
|
304
304
|
dir = Docscribe::Types::RBS::CollectionLoader.resolve
|
data/lib/docscribe/cli.rb
CHANGED
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'docscribe/cli/init'
|
|
4
|
-
require 'docscribe/cli/generate'
|
|
5
3
|
require 'docscribe/cli/options'
|
|
6
4
|
require 'docscribe/cli/run'
|
|
7
|
-
require 'docscribe/cli/sigs'
|
|
8
|
-
require 'docscribe/cli/rbs_gen'
|
|
9
|
-
require 'docscribe/cli/update_types'
|
|
10
|
-
require 'docscribe/cli/check_for_comments'
|
|
11
5
|
|
|
12
6
|
module Docscribe
|
|
13
7
|
# CLI entry point and command dispatch.
|
|
14
8
|
module CLI
|
|
15
9
|
class << self
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# Dispatches:
|
|
19
|
-
# - `docscribe init ...` to the config-template generator
|
|
20
|
-
# - `docscribe generate ...` to the plugin skeleton generator
|
|
21
|
-
# - all other commands to the main option parser and runner
|
|
22
|
-
#
|
|
23
|
-
# @param [Array<String>] argv raw command-line arguments
|
|
24
|
-
# @return [Integer] process exit code
|
|
10
|
+
# @param [Array<String>] argv
|
|
11
|
+
# @return [Integer]
|
|
25
12
|
def run(argv)
|
|
26
13
|
argv = argv.dup
|
|
27
14
|
return dispatch_subcommand(argv) if subcommand?(argv.first)
|
|
@@ -30,33 +17,35 @@ module Docscribe
|
|
|
30
17
|
Docscribe::CLI::Run.run(options: options, argv: argv)
|
|
31
18
|
end
|
|
32
19
|
|
|
20
|
+
COMMANDS = {
|
|
21
|
+
'init' => :Init,
|
|
22
|
+
'generate' => :Generate,
|
|
23
|
+
'sigs' => :Sigs,
|
|
24
|
+
'rbs' => :RbsGen,
|
|
25
|
+
'update_types' => :UpdateTypes,
|
|
26
|
+
'check_for_comments' => :CheckForComments,
|
|
27
|
+
'server' => :ServerCmd
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
33
30
|
private
|
|
34
31
|
|
|
35
|
-
# Subcommand
|
|
36
|
-
#
|
|
37
32
|
# @private
|
|
38
|
-
# @param [String?] cmd
|
|
33
|
+
# @param [String?] cmd
|
|
39
34
|
# @return [Boolean]
|
|
40
35
|
def subcommand?(cmd)
|
|
41
|
-
|
|
36
|
+
COMMANDS.key?(cmd)
|
|
42
37
|
end
|
|
43
38
|
|
|
44
|
-
# Dispatch subcommand
|
|
45
|
-
#
|
|
46
39
|
# @private
|
|
47
|
-
# @param [Array<String>] argv
|
|
40
|
+
# @param [Array<String>] argv
|
|
48
41
|
# @return [Integer]
|
|
49
42
|
def dispatch_subcommand(argv)
|
|
50
43
|
cmd = argv.shift
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
when 'update_types' then Docscribe::CLI::UpdateTypes.run(argv)
|
|
57
|
-
when 'check_for_comments' then Docscribe::CLI::CheckForComments.run(argv)
|
|
58
|
-
else 0
|
|
59
|
-
end
|
|
44
|
+
const_name = COMMANDS[cmd]
|
|
45
|
+
return 0 unless const_name
|
|
46
|
+
|
|
47
|
+
require "docscribe/cli/#{cmd == 'rbs' ? 'rbs_gen' : cmd}"
|
|
48
|
+
Docscribe::CLI.const_get(const_name).run(argv)
|
|
60
49
|
end
|
|
61
50
|
end
|
|
62
51
|
end
|
|
@@ -70,7 +70,8 @@ module Docscribe
|
|
|
70
70
|
'sorbet' => {
|
|
71
71
|
'enabled' => false,
|
|
72
72
|
'rbi_dirs' => ['sorbet/rbi', 'rbi'],
|
|
73
|
-
'collapse_generics' => false
|
|
73
|
+
'collapse_generics' => false,
|
|
74
|
+
'collapse_object_generics' => false
|
|
74
75
|
},
|
|
75
76
|
'keep_descriptions' => false,
|
|
76
77
|
'skip_anonymous_block_params' => false,
|
|
@@ -32,8 +32,8 @@ module Docscribe
|
|
|
32
32
|
#
|
|
33
33
|
# @param [String] path file path to test
|
|
34
34
|
# @raise [StandardError]
|
|
35
|
+
# @return [String]
|
|
35
36
|
# @return [String] if StandardError
|
|
36
|
-
# @return [Object] if StandardError
|
|
37
37
|
def relative_path(path)
|
|
38
38
|
Pathname.new(path).expand_path.relative_path_from(Pathname.pwd).cleanpath.to_s
|
|
39
39
|
rescue StandardError
|
|
@@ -14,12 +14,10 @@ module Docscribe
|
|
|
14
14
|
# @return [Docscribe::Config]
|
|
15
15
|
def self.load(path = nil)
|
|
16
16
|
raw = {} #: Hash[String, untyped]
|
|
17
|
-
if path && File.file?(path)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
new(raw)
|
|
17
|
+
resolved = path if path && File.file?(path)
|
|
18
|
+
resolved ||= 'docscribe.yml' if File.file?('docscribe.yml')
|
|
19
|
+
raw = safe_load_file_compat(resolved) if resolved
|
|
20
|
+
new(config_path: resolved, **raw) # steep:ignore
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
# Safely load YAML from a file across Ruby/Psych versions.
|
|
@@ -47,7 +45,7 @@ module Docscribe
|
|
|
47
45
|
# @param [String] yaml YAML document
|
|
48
46
|
# @param [String?] filename optional filename for diagnostics
|
|
49
47
|
# @raise [ArgumentError]
|
|
50
|
-
# @return [Hash<String, Object>]
|
|
48
|
+
# @return [Hash<String, Object>]
|
|
51
49
|
# @return [Object] if ArgumentError
|
|
52
50
|
def self.safe_load_compat(yaml, filename: nil)
|
|
53
51
|
pclasses = [] #: Array[String]
|
data/lib/docscribe/config/rbs.rb
CHANGED
|
@@ -62,7 +62,7 @@ module Docscribe
|
|
|
62
62
|
#
|
|
63
63
|
# @private
|
|
64
64
|
# @raise [LoadError]
|
|
65
|
-
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
65
|
+
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
66
66
|
# @return [nil] if LoadError
|
|
67
67
|
def build_rbs_provider
|
|
68
68
|
require 'docscribe/types/rbs/provider'
|
|
@@ -81,7 +81,7 @@ module Docscribe
|
|
|
81
81
|
#
|
|
82
82
|
# @private
|
|
83
83
|
# @raise [LoadError]
|
|
84
|
-
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
84
|
+
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
85
85
|
# @return [nil] if LoadError
|
|
86
86
|
def build_core_rbs_provider
|
|
87
87
|
require 'docscribe/types/rbs/provider'
|
|
@@ -40,14 +40,15 @@ module Docscribe
|
|
|
40
40
|
# @param [String] source Ruby source being rewritten
|
|
41
41
|
# @param [String] file source name for diagnostics
|
|
42
42
|
# @raise [LoadError]
|
|
43
|
-
# @return [Docscribe::Types::Sorbet::SourceProvider, nil]
|
|
43
|
+
# @return [Docscribe::Types::Sorbet::SourceProvider, nil]
|
|
44
44
|
# @return [nil] if LoadError
|
|
45
45
|
def sorbet_source_provider(source, file)
|
|
46
46
|
require 'docscribe/types/sorbet/source_provider'
|
|
47
47
|
Docscribe::Types::Sorbet::SourceProvider.new(
|
|
48
48
|
source: source,
|
|
49
49
|
file: file,
|
|
50
|
-
collapse_generics: sorbet_collapse_generics
|
|
50
|
+
collapse_generics: sorbet_collapse_generics?,
|
|
51
|
+
collapse_object_generics: sorbet_collapse_object_generics?
|
|
51
52
|
)
|
|
52
53
|
rescue LoadError
|
|
53
54
|
nil
|
|
@@ -74,10 +75,9 @@ module Docscribe
|
|
|
74
75
|
|
|
75
76
|
@sorbet_rbi_provider ||= begin
|
|
76
77
|
require 'docscribe/types/sorbet/rbi_provider'
|
|
77
|
-
Docscribe::Types::Sorbet::RBIProvider.new(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
)
|
|
78
|
+
Docscribe::Types::Sorbet::RBIProvider.new(rbi_dirs: sorbet_rbi_dirs,
|
|
79
|
+
collapse_generics: sorbet_collapse_generics?,
|
|
80
|
+
collapse_object_generics: sorbet_collapse_object_generics?)
|
|
81
81
|
rescue LoadError
|
|
82
82
|
nil
|
|
83
83
|
end
|
|
@@ -106,5 +106,14 @@ module Docscribe
|
|
|
106
106
|
def sorbet_collapse_generics?
|
|
107
107
|
fetch_bool(%w[sorbet collapse_generics], rbs_collapse_generics?)
|
|
108
108
|
end
|
|
109
|
+
|
|
110
|
+
# Whether to collapse Object-typed generics in Sorbet types.
|
|
111
|
+
#
|
|
112
|
+
# Falls back to the RBS setting when Sorbet-specific config is not present.
|
|
113
|
+
#
|
|
114
|
+
# @return [Boolean]
|
|
115
|
+
def sorbet_collapse_object_generics?
|
|
116
|
+
fetch_bool(%w[sorbet collapse_object_generics], rbs_collapse_object_generics?)
|
|
117
|
+
end
|
|
109
118
|
end
|
|
110
119
|
end
|