steep 1.10.0 → 2.0.0
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/CHANGELOG.md +84 -1
- data/CLAUDE.md +114 -0
- data/README.md +1 -1
- data/Rakefile +15 -3
- data/Steepfile +13 -13
- data/lib/steep/annotation_parser.rb +5 -1
- data/lib/steep/annotations_helper.rb +12 -2
- data/lib/steep/ast/node/type_application.rb +22 -16
- data/lib/steep/ast/node/type_assertion.rb +7 -4
- data/lib/steep/ast/types/factory.rb +3 -2
- data/lib/steep/cli.rb +246 -2
- data/lib/steep/daemon/configuration.rb +19 -0
- data/lib/steep/daemon/server.rb +476 -0
- data/lib/steep/daemon.rb +201 -0
- data/lib/steep/diagnostic/ruby.rb +50 -8
- data/lib/steep/diagnostic/signature.rb +31 -8
- data/lib/steep/drivers/check.rb +301 -140
- data/lib/steep/drivers/print_project.rb +9 -10
- data/lib/steep/drivers/query.rb +102 -0
- data/lib/steep/drivers/start_server.rb +19 -0
- data/lib/steep/drivers/stop_server.rb +20 -0
- data/lib/steep/drivers/watch.rb +2 -2
- data/lib/steep/index/rbs_index.rb +38 -13
- data/lib/steep/index/signature_symbol_provider.rb +24 -3
- data/lib/steep/interface/builder.rb +48 -15
- data/lib/steep/interface/shape.rb +13 -5
- data/lib/steep/locator.rb +377 -0
- data/lib/steep/project/dsl.rb +26 -5
- data/lib/steep/project/group.rb +8 -2
- data/lib/steep/project/target.rb +16 -2
- data/lib/steep/project.rb +21 -2
- data/lib/steep/server/base_worker.rb +2 -2
- data/lib/steep/server/change_buffer.rb +2 -1
- data/lib/steep/server/custom_methods.rb +12 -0
- data/lib/steep/server/inline_source_change_detector.rb +94 -0
- data/lib/steep/server/interaction_worker.rb +51 -74
- data/lib/steep/server/lsp_formatter.rb +48 -12
- data/lib/steep/server/master.rb +100 -18
- data/lib/steep/server/target_group_files.rb +124 -151
- data/lib/steep/server/type_check_controller.rb +276 -123
- data/lib/steep/server/type_check_worker.rb +104 -3
- data/lib/steep/services/completion_provider/rbs.rb +74 -0
- data/lib/steep/services/completion_provider/ruby.rb +652 -0
- data/lib/steep/services/completion_provider/type_name.rb +243 -0
- data/lib/steep/services/completion_provider.rb +39 -662
- data/lib/steep/services/content_change.rb +14 -1
- data/lib/steep/services/file_loader.rb +4 -2
- data/lib/steep/services/goto_service.rb +271 -68
- data/lib/steep/services/hover_provider/content.rb +67 -0
- data/lib/steep/services/hover_provider/rbs.rb +8 -9
- data/lib/steep/services/hover_provider/ruby.rb +123 -64
- data/lib/steep/services/hover_provider/singleton_methods.rb +4 -0
- data/lib/steep/services/signature_service.rb +129 -54
- data/lib/steep/services/type_check_service.rb +72 -27
- data/lib/steep/signature/validator.rb +30 -18
- data/lib/steep/source/ignore_ranges.rb +14 -4
- data/lib/steep/source.rb +16 -2
- data/lib/steep/tagged_logging.rb +39 -0
- data/lib/steep/type_construction.rb +94 -21
- data/lib/steep/type_inference/block_params.rb +7 -7
- data/lib/steep/type_inference/context.rb +4 -2
- data/lib/steep/type_inference/logic_type_interpreter.rb +21 -3
- data/lib/steep/type_inference/method_call.rb +4 -0
- data/lib/steep/type_inference/type_env.rb +1 -1
- data/lib/steep/typing.rb +0 -2
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +42 -32
- data/manual/ruby-diagnostics.md +67 -0
- data/sample/Steepfile +1 -0
- data/sample/lib/conference.rb +1 -0
- data/sample/lib/deprecated.rb +6 -0
- data/sample/lib/inline.rb +43 -0
- data/sample/sig/generics.rbs +3 -0
- data/steep.gemspec +4 -5
- metadata +26 -26
- data/lib/steep/services/type_name_completion.rb +0 -236
data/lib/steep/cli.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Steep
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.available_commands
|
|
19
|
-
[:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :stats, :binstub, :checkfile]
|
|
19
|
+
[:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :stats, :binstub, :checkfile, :server, :query]
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def process_global_options
|
|
@@ -58,7 +58,8 @@ module Steep
|
|
|
58
58
|
process_global_options or return 1
|
|
59
59
|
setup_command or return 1
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
method_name = command.to_s.gsub('-', '_')
|
|
62
|
+
__send__(:"process_#{method_name}")
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def handle_steepfile_option(opts, command)
|
|
@@ -67,11 +68,13 @@ module Steep
|
|
|
67
68
|
|
|
68
69
|
def handle_logging_options(opts)
|
|
69
70
|
opts.on("--log-level=LEVEL", "Specify log level: debug, info, warn, error, fatal") do |level|
|
|
71
|
+
# @type var level: String
|
|
70
72
|
Steep.logger.level = level
|
|
71
73
|
Steep.ui_logger.level = level
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
opts.on("--log-output=PATH", "Print logs to given path") do |file|
|
|
77
|
+
# @type var file: String
|
|
75
78
|
Steep.log_output = file
|
|
76
79
|
end
|
|
77
80
|
|
|
@@ -127,6 +130,7 @@ BANNER
|
|
|
127
130
|
OptionParser.new do |opts|
|
|
128
131
|
opts.banner = <<BANNER
|
|
129
132
|
Usage: steep check [options] [paths]
|
|
133
|
+
steep check [options] -e 'expr' [-e 'expr' ...]
|
|
130
134
|
|
|
131
135
|
Description:
|
|
132
136
|
Type check the program.
|
|
@@ -138,6 +142,9 @@ Options:
|
|
|
138
142
|
BANNER
|
|
139
143
|
|
|
140
144
|
handle_steepfile_option(opts, command)
|
|
145
|
+
opts.on("-e", "--expression=EXPRESSION", "Type check a Ruby expression (may be specified multiple times)") do |expr|
|
|
146
|
+
command.expressions << expr
|
|
147
|
+
end
|
|
141
148
|
opts.on("--with-expectations[=PATH]", "Type check with expectations saved in PATH (or steep_expectations.yml)") do |path|
|
|
142
149
|
command.with_expectations_path = Pathname(path || "steep_expectations.yml")
|
|
143
150
|
end
|
|
@@ -191,6 +198,10 @@ BANNER
|
|
|
191
198
|
command.formatter = formatter
|
|
192
199
|
end
|
|
193
200
|
|
|
201
|
+
opts.on("--[no-]daemon", "Use daemon server if available (default: true)") do |v|
|
|
202
|
+
command.use_daemon = v ? true : false
|
|
203
|
+
end
|
|
204
|
+
|
|
194
205
|
handle_jobs_option command.jobs_option, opts
|
|
195
206
|
handle_logging_options opts
|
|
196
207
|
end.parse!(argv)
|
|
@@ -198,6 +209,10 @@ BANNER
|
|
|
198
209
|
setup_jobs_for_ci(command.jobs_option)
|
|
199
210
|
|
|
200
211
|
command.command_line_patterns.push(*argv)
|
|
212
|
+
|
|
213
|
+
unless command.expressions.empty? || argv.empty?
|
|
214
|
+
abort "Cannot specify both -e and file paths"
|
|
215
|
+
end
|
|
201
216
|
end.run
|
|
202
217
|
end
|
|
203
218
|
|
|
@@ -476,5 +491,234 @@ BANNER
|
|
|
476
491
|
command.commandline_args.push(*argv)
|
|
477
492
|
end.run
|
|
478
493
|
end
|
|
494
|
+
|
|
495
|
+
def process_server
|
|
496
|
+
subcommand = argv.shift
|
|
497
|
+
|
|
498
|
+
if subcommand.nil? || subcommand == "--help" || subcommand == "-h"
|
|
499
|
+
stderr.puts <<~HELP
|
|
500
|
+
Usage: steep server <subcommand> [options]
|
|
501
|
+
|
|
502
|
+
Description:
|
|
503
|
+
Manage the Steep daemon server for faster type checking.
|
|
504
|
+
The daemon keeps RBS environment loaded in memory.
|
|
505
|
+
|
|
506
|
+
Available subcommands:
|
|
507
|
+
start Start the daemon server
|
|
508
|
+
stop Stop the daemon server
|
|
509
|
+
restart Restart the daemon server
|
|
510
|
+
status Show daemon server status
|
|
511
|
+
|
|
512
|
+
Options:
|
|
513
|
+
--help Show this help message
|
|
514
|
+
|
|
515
|
+
Examples:
|
|
516
|
+
steep server start
|
|
517
|
+
steep server stop
|
|
518
|
+
steep server restart
|
|
519
|
+
steep server status
|
|
520
|
+
HELP
|
|
521
|
+
return 0
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
case subcommand
|
|
525
|
+
when "start"
|
|
526
|
+
unless Steep.can_fork?
|
|
527
|
+
stderr.puts "Error: `steep server start` is not supported on this platform (fork() is not available)"
|
|
528
|
+
return 1
|
|
529
|
+
end
|
|
530
|
+
Drivers::StartServer.new(stdout: stdout, stderr: stderr).tap do |command|
|
|
531
|
+
OptionParser.new do |opts|
|
|
532
|
+
opts.banner = <<BANNER
|
|
533
|
+
Usage: steep server start [options]
|
|
534
|
+
|
|
535
|
+
Description:
|
|
536
|
+
Starts a persistent daemon server for faster type checking.
|
|
537
|
+
The daemon keeps RBS environment loaded in memory.
|
|
538
|
+
|
|
539
|
+
Options:
|
|
540
|
+
BANNER
|
|
541
|
+
handle_logging_options opts
|
|
542
|
+
end.parse!(argv)
|
|
543
|
+
end.run
|
|
544
|
+
when "stop"
|
|
545
|
+
Drivers::StopServer.new(stdout: stdout, stderr: stderr).tap do |command|
|
|
546
|
+
OptionParser.new do |opts|
|
|
547
|
+
opts.banner = <<BANNER
|
|
548
|
+
Usage: steep server stop [options]
|
|
549
|
+
|
|
550
|
+
Description:
|
|
551
|
+
Stops the running daemon server.
|
|
552
|
+
|
|
553
|
+
Options:
|
|
554
|
+
BANNER
|
|
555
|
+
handle_logging_options opts
|
|
556
|
+
end.parse!(argv)
|
|
557
|
+
end.run
|
|
558
|
+
when "restart"
|
|
559
|
+
unless Steep.can_fork?
|
|
560
|
+
stderr.puts "Error: `steep server restart` is not supported on this platform (fork() is not available)"
|
|
561
|
+
return 1
|
|
562
|
+
end
|
|
563
|
+
OptionParser.new do |opts|
|
|
564
|
+
opts.banner = <<BANNER
|
|
565
|
+
Usage: steep server restart [options]
|
|
566
|
+
|
|
567
|
+
Description:
|
|
568
|
+
Restarts the daemon server (stops and then starts it).
|
|
569
|
+
|
|
570
|
+
Options:
|
|
571
|
+
BANNER
|
|
572
|
+
handle_logging_options opts
|
|
573
|
+
end.parse!(argv)
|
|
574
|
+
|
|
575
|
+
stop_command = Drivers::StopServer.new(stdout: stdout, stderr: stderr)
|
|
576
|
+
stop_command.run
|
|
577
|
+
|
|
578
|
+
# Brief pause to ensure clean shutdown
|
|
579
|
+
sleep 0.5
|
|
580
|
+
|
|
581
|
+
start_command = Drivers::StartServer.new(stdout: stdout, stderr: stderr)
|
|
582
|
+
start_command.run
|
|
583
|
+
when "status"
|
|
584
|
+
OptionParser.new do |opts|
|
|
585
|
+
opts.banner = <<BANNER
|
|
586
|
+
Usage: steep server status [options]
|
|
587
|
+
|
|
588
|
+
Description:
|
|
589
|
+
Shows the status of the daemon server.
|
|
590
|
+
|
|
591
|
+
Options:
|
|
592
|
+
BANNER
|
|
593
|
+
handle_logging_options opts
|
|
594
|
+
end.parse!(argv)
|
|
595
|
+
|
|
596
|
+
Daemon.status(stderr: stderr)
|
|
597
|
+
0
|
|
598
|
+
else
|
|
599
|
+
stderr.puts "Unknown server subcommand: #{subcommand}"
|
|
600
|
+
stderr.puts " available subcommands: start, stop, restart, status"
|
|
601
|
+
1
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def process_query
|
|
606
|
+
subcommand = argv.shift
|
|
607
|
+
|
|
608
|
+
if subcommand.nil? || subcommand == "--help" || subcommand == "-h"
|
|
609
|
+
stderr.puts <<~HELP
|
|
610
|
+
Usage: steep query <subcommand> [options]
|
|
611
|
+
|
|
612
|
+
Description:
|
|
613
|
+
Query type information from the Steep daemon server.
|
|
614
|
+
The daemon must be running (start it with `steep server start`).
|
|
615
|
+
|
|
616
|
+
Note:
|
|
617
|
+
`steep query` is an experimental command.
|
|
618
|
+
The user interface and output format may change without deprecation.
|
|
619
|
+
|
|
620
|
+
Available subcommands:
|
|
621
|
+
hover Get hover information (type, documentation) for a position
|
|
622
|
+
definition Get the definition(s) of a class, type alias, constant, or method name
|
|
623
|
+
|
|
624
|
+
Options:
|
|
625
|
+
--help Show this help message
|
|
626
|
+
|
|
627
|
+
Examples:
|
|
628
|
+
steep query hover lib/foo.rb:10:5
|
|
629
|
+
steep query definition RBS::Location
|
|
630
|
+
steep query definition RBS::Parser.parse_signature
|
|
631
|
+
HELP
|
|
632
|
+
return 0
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
case subcommand
|
|
636
|
+
when "hover"
|
|
637
|
+
OptionParser.new do |opts|
|
|
638
|
+
opts.banner = <<BANNER
|
|
639
|
+
Usage: steep query hover [options] FILE:LINE:COL [FILE:LINE:COL ...]
|
|
640
|
+
|
|
641
|
+
Description:
|
|
642
|
+
Get hover information for the specified position(s).
|
|
643
|
+
Connects to the running Steep daemon and returns type information as JSONL
|
|
644
|
+
(one JSON object per line for each queried position).
|
|
645
|
+
|
|
646
|
+
FILE:LINE:COL - File path with 1-based line and column numbers.
|
|
647
|
+
|
|
648
|
+
Note:
|
|
649
|
+
This is an experimental command.
|
|
650
|
+
The user interface and output format may change without deprecation.
|
|
651
|
+
|
|
652
|
+
Options:
|
|
653
|
+
BANNER
|
|
654
|
+
handle_logging_options opts
|
|
655
|
+
end.parse!(argv)
|
|
656
|
+
|
|
657
|
+
if argv.empty?
|
|
658
|
+
stderr.puts "Error: Missing FILE:LINE:COL argument"
|
|
659
|
+
stderr.puts " Usage: steep query hover FILE:LINE:COL [FILE:LINE:COL ...]"
|
|
660
|
+
return 1
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
locations = [] #: Array[[String, Integer, Integer]]
|
|
664
|
+
|
|
665
|
+
argv.each do |location|
|
|
666
|
+
match = location.match(/\A(.+):(\d+):(\d+)\z/)
|
|
667
|
+
unless match
|
|
668
|
+
stderr.puts "Error: Invalid format: #{location}"
|
|
669
|
+
stderr.puts " Expected format: FILE:LINE:COL (e.g., lib/foo.rb:10:5)"
|
|
670
|
+
return 1
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
path = match[1] or raise
|
|
674
|
+
line = match[2].to_i
|
|
675
|
+
column = match[3].to_i
|
|
676
|
+
|
|
677
|
+
if line < 1 || column < 1
|
|
678
|
+
stderr.puts "Error: LINE and COL must be positive integers (1-based)"
|
|
679
|
+
return 1
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
locations << [path, line, column]
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
Drivers::Query.new(stdout: stdout, stderr: stderr).run_hover(locations: locations)
|
|
686
|
+
when "definition"
|
|
687
|
+
OptionParser.new do |opts|
|
|
688
|
+
opts.banner = <<BANNER
|
|
689
|
+
Usage: steep query definition [options] NAME [NAME ...]
|
|
690
|
+
|
|
691
|
+
Description:
|
|
692
|
+
Get the definition(s) of the specified name(s).
|
|
693
|
+
Connects to the running Steep daemon and returns both RBS declarations and
|
|
694
|
+
Ruby definitions as JSONL (one JSON object per line for each queried name).
|
|
695
|
+
|
|
696
|
+
NAME can be one of:
|
|
697
|
+
* A class, module, interface, type alias, or constant (e.g., RBS::Location)
|
|
698
|
+
* An instance method (e.g., RBS::Parser#parse_type)
|
|
699
|
+
* A singleton method (e.g., RBS::Parser.parse_signature)
|
|
700
|
+
|
|
701
|
+
Note:
|
|
702
|
+
This is an experimental command.
|
|
703
|
+
The user interface and output format may change without deprecation.
|
|
704
|
+
|
|
705
|
+
Options:
|
|
706
|
+
BANNER
|
|
707
|
+
handle_logging_options opts
|
|
708
|
+
end.parse!(argv)
|
|
709
|
+
|
|
710
|
+
if argv.empty?
|
|
711
|
+
stderr.puts "Error: Missing NAME argument"
|
|
712
|
+
stderr.puts " Usage: steep query definition NAME [NAME ...]"
|
|
713
|
+
return 1
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
Drivers::Query.new(stdout: stdout, stderr: stderr).run_definition(names: argv.dup)
|
|
717
|
+
else
|
|
718
|
+
stderr.puts "Unknown query subcommand: #{subcommand}"
|
|
719
|
+
stderr.puts " available subcommands: hover, definition"
|
|
720
|
+
1
|
|
721
|
+
end
|
|
722
|
+
end
|
|
479
723
|
end
|
|
480
724
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Steep
|
|
4
|
+
module Daemon
|
|
5
|
+
class Configuration
|
|
6
|
+
attr_reader :socket_path, :pid_path, :log_path, :project_id, :socket_dir
|
|
7
|
+
|
|
8
|
+
def initialize(base_dir: Dir.pwd)
|
|
9
|
+
@socket_dir = File.join(Dir.tmpdir, "steep-server")
|
|
10
|
+
@project_id = Digest::MD5.hexdigest(base_dir)[0, 8] #: String
|
|
11
|
+
|
|
12
|
+
FileUtils.mkdir_p(@socket_dir)
|
|
13
|
+
@socket_path = File.join(@socket_dir, "steep-#{@project_id}.sock")
|
|
14
|
+
@pid_path = @socket_path.sub(".sock", ".pid")
|
|
15
|
+
@log_path = @socket_path.sub(".sock", ".log")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|