steep-relaxed 1.9.3.3
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 +7 -0
- data/.gitignore +13 -0
- data/.gitmodules +0 -0
- data/CHANGELOG.md +1032 -0
- data/LICENSE +21 -0
- data/README.md +260 -0
- data/Rakefile +227 -0
- data/STDGEM_DEPENDENCIES.txt +59 -0
- data/Steepfile +68 -0
- data/bin/console +14 -0
- data/bin/generate-diagnostics-docs.rb +112 -0
- data/bin/mem_graph.rb +67 -0
- data/bin/mem_prof.rb +102 -0
- data/bin/output_rebaseline.rb +34 -0
- data/bin/output_test.rb +60 -0
- data/bin/rbs +20 -0
- data/bin/rbs-inline +19 -0
- data/bin/setup +9 -0
- data/bin/stackprof_test.rb +19 -0
- data/bin/steep +19 -0
- data/bin/steep-check.rb +251 -0
- data/bin/steep-prof +16 -0
- data/doc/narrowing.md +195 -0
- data/doc/shape.md +194 -0
- data/exe/steep +18 -0
- data/guides/README.md +5 -0
- data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
- data/guides/src/getting-started/getting-started.md +163 -0
- data/guides/src/nil-optional/nil-optional.md +195 -0
- data/lib/steep/annotation_parser.rb +199 -0
- data/lib/steep/ast/annotation/collection.rb +172 -0
- data/lib/steep/ast/annotation.rb +137 -0
- data/lib/steep/ast/builtin.rb +104 -0
- data/lib/steep/ast/ignore.rb +148 -0
- data/lib/steep/ast/node/type_application.rb +88 -0
- data/lib/steep/ast/node/type_assertion.rb +81 -0
- data/lib/steep/ast/types/any.rb +35 -0
- data/lib/steep/ast/types/boolean.rb +45 -0
- data/lib/steep/ast/types/bot.rb +35 -0
- data/lib/steep/ast/types/class.rb +43 -0
- data/lib/steep/ast/types/factory.rb +557 -0
- data/lib/steep/ast/types/helper.rb +40 -0
- data/lib/steep/ast/types/instance.rb +42 -0
- data/lib/steep/ast/types/intersection.rb +93 -0
- data/lib/steep/ast/types/literal.rb +59 -0
- data/lib/steep/ast/types/logic.rb +84 -0
- data/lib/steep/ast/types/name.rb +128 -0
- data/lib/steep/ast/types/nil.rb +41 -0
- data/lib/steep/ast/types/proc.rb +117 -0
- data/lib/steep/ast/types/record.rb +79 -0
- data/lib/steep/ast/types/self.rb +43 -0
- data/lib/steep/ast/types/shared_instance.rb +11 -0
- data/lib/steep/ast/types/top.rb +35 -0
- data/lib/steep/ast/types/tuple.rb +60 -0
- data/lib/steep/ast/types/union.rb +97 -0
- data/lib/steep/ast/types/var.rb +65 -0
- data/lib/steep/ast/types/void.rb +35 -0
- data/lib/steep/cli.rb +401 -0
- data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
- data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
- data/lib/steep/diagnostic/helper.rb +18 -0
- data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
- data/lib/steep/diagnostic/result_printer2.rb +48 -0
- data/lib/steep/diagnostic/ruby.rb +1221 -0
- data/lib/steep/diagnostic/signature.rb +570 -0
- data/lib/steep/drivers/annotations.rb +52 -0
- data/lib/steep/drivers/check.rb +339 -0
- data/lib/steep/drivers/checkfile.rb +210 -0
- data/lib/steep/drivers/diagnostic_printer.rb +105 -0
- data/lib/steep/drivers/init.rb +66 -0
- data/lib/steep/drivers/langserver.rb +56 -0
- data/lib/steep/drivers/print_project.rb +113 -0
- data/lib/steep/drivers/stats.rb +203 -0
- data/lib/steep/drivers/utils/driver_helper.rb +143 -0
- data/lib/steep/drivers/utils/jobs_option.rb +26 -0
- data/lib/steep/drivers/vendor.rb +27 -0
- data/lib/steep/drivers/watch.rb +194 -0
- data/lib/steep/drivers/worker.rb +58 -0
- data/lib/steep/equatable.rb +23 -0
- data/lib/steep/expectations.rb +228 -0
- data/lib/steep/index/rbs_index.rb +350 -0
- data/lib/steep/index/signature_symbol_provider.rb +185 -0
- data/lib/steep/index/source_index.rb +167 -0
- data/lib/steep/interface/block.rb +103 -0
- data/lib/steep/interface/builder.rb +843 -0
- data/lib/steep/interface/function.rb +1090 -0
- data/lib/steep/interface/method_type.rb +330 -0
- data/lib/steep/interface/shape.rb +239 -0
- data/lib/steep/interface/substitution.rb +159 -0
- data/lib/steep/interface/type_param.rb +115 -0
- data/lib/steep/located_value.rb +20 -0
- data/lib/steep/method_name.rb +42 -0
- data/lib/steep/module_helper.rb +24 -0
- data/lib/steep/node_helper.rb +273 -0
- data/lib/steep/path_helper.rb +30 -0
- data/lib/steep/project/dsl.rb +268 -0
- data/lib/steep/project/group.rb +31 -0
- data/lib/steep/project/options.rb +63 -0
- data/lib/steep/project/pattern.rb +59 -0
- data/lib/steep/project/target.rb +92 -0
- data/lib/steep/project.rb +78 -0
- data/lib/steep/rake_task.rb +132 -0
- data/lib/steep/range_extension.rb +29 -0
- data/lib/steep/server/base_worker.rb +97 -0
- data/lib/steep/server/change_buffer.rb +73 -0
- data/lib/steep/server/custom_methods.rb +77 -0
- data/lib/steep/server/delay_queue.rb +45 -0
- data/lib/steep/server/interaction_worker.rb +492 -0
- data/lib/steep/server/lsp_formatter.rb +455 -0
- data/lib/steep/server/master.rb +922 -0
- data/lib/steep/server/target_group_files.rb +205 -0
- data/lib/steep/server/type_check_controller.rb +366 -0
- data/lib/steep/server/type_check_worker.rb +303 -0
- data/lib/steep/server/work_done_progress.rb +64 -0
- data/lib/steep/server/worker_process.rb +176 -0
- data/lib/steep/services/completion_provider.rb +802 -0
- data/lib/steep/services/content_change.rb +61 -0
- data/lib/steep/services/file_loader.rb +74 -0
- data/lib/steep/services/goto_service.rb +441 -0
- data/lib/steep/services/hover_provider/rbs.rb +88 -0
- data/lib/steep/services/hover_provider/ruby.rb +221 -0
- data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
- data/lib/steep/services/path_assignment.rb +46 -0
- data/lib/steep/services/signature_help_provider.rb +202 -0
- data/lib/steep/services/signature_service.rb +428 -0
- data/lib/steep/services/stats_calculator.rb +68 -0
- data/lib/steep/services/type_check_service.rb +394 -0
- data/lib/steep/services/type_name_completion.rb +236 -0
- data/lib/steep/signature/validator.rb +651 -0
- data/lib/steep/source/ignore_ranges.rb +69 -0
- data/lib/steep/source.rb +691 -0
- data/lib/steep/subtyping/cache.rb +30 -0
- data/lib/steep/subtyping/check.rb +1113 -0
- data/lib/steep/subtyping/constraints.rb +341 -0
- data/lib/steep/subtyping/relation.rb +101 -0
- data/lib/steep/subtyping/result.rb +324 -0
- data/lib/steep/subtyping/variable_variance.rb +89 -0
- data/lib/steep/test.rb +9 -0
- data/lib/steep/thread_waiter.rb +43 -0
- data/lib/steep/type_construction.rb +5183 -0
- data/lib/steep/type_inference/block_params.rb +416 -0
- data/lib/steep/type_inference/case_when.rb +303 -0
- data/lib/steep/type_inference/constant_env.rb +56 -0
- data/lib/steep/type_inference/context.rb +195 -0
- data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
- data/lib/steep/type_inference/method_call.rb +193 -0
- data/lib/steep/type_inference/method_params.rb +531 -0
- data/lib/steep/type_inference/multiple_assignment.rb +194 -0
- data/lib/steep/type_inference/send_args.rb +712 -0
- data/lib/steep/type_inference/type_env.rb +341 -0
- data/lib/steep/type_inference/type_env_builder.rb +138 -0
- data/lib/steep/typing.rb +321 -0
- data/lib/steep/version.rb +3 -0
- data/lib/steep.rb +369 -0
- data/manual/annotations.md +181 -0
- data/manual/ignore.md +20 -0
- data/manual/ruby-diagnostics.md +1879 -0
- data/sample/Steepfile +22 -0
- data/sample/lib/conference.rb +49 -0
- data/sample/lib/length.rb +35 -0
- data/sample/sig/conference.rbs +42 -0
- data/sample/sig/generics.rbs +15 -0
- data/sample/sig/length.rbs +34 -0
- data/steep-relaxed.gemspec +56 -0
- metadata +340 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
class Init
|
4
|
+
attr_reader :stdout
|
5
|
+
attr_reader :stderr
|
6
|
+
attr_accessor :force_write
|
7
|
+
|
8
|
+
include Utils::DriverHelper
|
9
|
+
|
10
|
+
TEMPLATE = <<~EOF
|
11
|
+
# D = Steep::Diagnostic
|
12
|
+
#
|
13
|
+
# target :lib do
|
14
|
+
# signature "sig"
|
15
|
+
# ignore_signature "sig/test"
|
16
|
+
#
|
17
|
+
# check "lib" # Directory name
|
18
|
+
# check "path/to/source.rb" # File name
|
19
|
+
# check "app/models/**/*.rb" # Glob
|
20
|
+
# # ignore "lib/templates/*.rb"
|
21
|
+
#
|
22
|
+
# # library "pathname" # Standard libraries
|
23
|
+
# # library "strong_json" # Gems
|
24
|
+
#
|
25
|
+
# # configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
26
|
+
# # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
27
|
+
# # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
|
28
|
+
# # configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
|
29
|
+
# # configure_code_diagnostics do |hash| # You can setup everything yourself
|
30
|
+
# # hash[D::Ruby::NoMethod] = :information
|
31
|
+
# # end
|
32
|
+
# end
|
33
|
+
|
34
|
+
# target :test do
|
35
|
+
# unreferenced! # Skip type checking the `lib` code when types in `test` target is changed
|
36
|
+
# signature "sig/test" # Put RBS files for tests under `sig/test`
|
37
|
+
# check "test" # Type check Ruby scripts under `test`
|
38
|
+
#
|
39
|
+
# configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
|
40
|
+
#
|
41
|
+
# # library "pathname" # Standard libraries
|
42
|
+
# end
|
43
|
+
EOF
|
44
|
+
|
45
|
+
def initialize(stdout:, stderr:)
|
46
|
+
@stdout = stdout
|
47
|
+
@stderr = stderr
|
48
|
+
@force_write = false
|
49
|
+
end
|
50
|
+
|
51
|
+
def run
|
52
|
+
path = steepfile || Pathname("Steepfile")
|
53
|
+
|
54
|
+
if path.file? && !force_write
|
55
|
+
stdout.puts "#{path} already exists, --force to overwrite"
|
56
|
+
return 1
|
57
|
+
end
|
58
|
+
|
59
|
+
stdout.puts "Writing #{path}..."
|
60
|
+
path.write(TEMPLATE)
|
61
|
+
|
62
|
+
0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
class Langserver
|
4
|
+
attr_reader :stdout
|
5
|
+
attr_reader :stderr
|
6
|
+
attr_reader :stdin
|
7
|
+
attr_reader :write_mutex
|
8
|
+
attr_reader :type_check_queue
|
9
|
+
attr_reader :type_check_thread
|
10
|
+
attr_reader :jobs_option
|
11
|
+
|
12
|
+
include Utils::DriverHelper
|
13
|
+
|
14
|
+
def initialize(stdout:, stderr:, stdin:)
|
15
|
+
@stdout = stdout
|
16
|
+
@stderr = stderr
|
17
|
+
@stdin = stdin
|
18
|
+
@write_mutex = Mutex.new
|
19
|
+
@type_check_queue = Queue.new
|
20
|
+
@jobs_option = Utils::JobsOption.new(jobs_count_modifier: -1)
|
21
|
+
end
|
22
|
+
|
23
|
+
def writer
|
24
|
+
@writer ||= LanguageServer::Protocol::Transport::Io::Writer.new(stdout)
|
25
|
+
end
|
26
|
+
|
27
|
+
def reader
|
28
|
+
@reader ||= LanguageServer::Protocol::Transport::Io::Reader.new(stdin)
|
29
|
+
end
|
30
|
+
|
31
|
+
def project
|
32
|
+
@project or raise "Empty #project"
|
33
|
+
end
|
34
|
+
|
35
|
+
def run
|
36
|
+
@project = load_config()
|
37
|
+
|
38
|
+
interaction_worker = Server::WorkerProcess.start_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, steep_command: jobs_option.steep_command)
|
39
|
+
typecheck_workers = Server::WorkerProcess.start_typecheck_workers(steepfile: project.steepfile_path, args: [], steep_command: jobs_option.steep_command, count: jobs_option.jobs_count_value)
|
40
|
+
|
41
|
+
master = Server::Master.new(
|
42
|
+
project: project,
|
43
|
+
reader: reader,
|
44
|
+
writer: writer,
|
45
|
+
interaction_worker: interaction_worker,
|
46
|
+
typecheck_workers: typecheck_workers
|
47
|
+
)
|
48
|
+
master.typecheck_automatically = true
|
49
|
+
|
50
|
+
master.start()
|
51
|
+
|
52
|
+
0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require "active_support/core_ext/hash/keys"
|
2
|
+
|
3
|
+
module Steep
|
4
|
+
module Drivers
|
5
|
+
class PrintProject
|
6
|
+
attr_reader :stdout
|
7
|
+
attr_reader :stderr
|
8
|
+
|
9
|
+
attr_accessor :print_files
|
10
|
+
attr_reader :files
|
11
|
+
|
12
|
+
include Utils::DriverHelper
|
13
|
+
|
14
|
+
def initialize(stdout:, stderr:)
|
15
|
+
@stdout = stdout
|
16
|
+
@stderr = stderr
|
17
|
+
@print_files = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def as_json(project)
|
21
|
+
{
|
22
|
+
steepfile: project.steepfile_path.to_s,
|
23
|
+
targets: project.targets.map do |target|
|
24
|
+
target_as_json(target)
|
25
|
+
end
|
26
|
+
}.stringify_keys
|
27
|
+
end
|
28
|
+
|
29
|
+
def target_as_json(target)
|
30
|
+
json = {
|
31
|
+
"name" => target.name.to_s,
|
32
|
+
"source_pattern" => pattern_as_json(target.source_pattern),
|
33
|
+
"signature_pattern" => pattern_as_json(target.signature_pattern),
|
34
|
+
"groups" => target.groups.map do |group|
|
35
|
+
group_as_json(group)
|
36
|
+
end,
|
37
|
+
"libraries" => target.new_env_loader().yield_self do |loader|
|
38
|
+
libs = [] #: Array[library_json]
|
39
|
+
loader.each_dir do |lib, path|
|
40
|
+
case lib
|
41
|
+
when :core
|
42
|
+
libs << { "name" => "__core__", "path" => path.to_s }
|
43
|
+
when Pathname
|
44
|
+
raise "Unexpected pathname from loader: path=#{path}"
|
45
|
+
else
|
46
|
+
libs << { "name" => lib.name, "version" => lib.version, "path" => path.to_s }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
libs
|
50
|
+
end,
|
51
|
+
"unreferenced" => target.unreferenced
|
52
|
+
} #: target_json
|
53
|
+
|
54
|
+
if files
|
55
|
+
files.each_group_signature_path(target, true) do |path|
|
56
|
+
(json["signature_paths"] ||= []) << path.to_s
|
57
|
+
end
|
58
|
+
files.each_group_source_path(target, true) do |path|
|
59
|
+
(json["source_paths"] ||= []) << path.to_s
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
json
|
64
|
+
end
|
65
|
+
|
66
|
+
def group_as_json(group)
|
67
|
+
json = {
|
68
|
+
"name" => group.name.to_s,
|
69
|
+
"source_pattern" => pattern_as_json(group.source_pattern),
|
70
|
+
"signature_pattern" => pattern_as_json(group.signature_pattern)
|
71
|
+
} #: group_json
|
72
|
+
|
73
|
+
if files
|
74
|
+
files.each_group_signature_path(group, true) do |path|
|
75
|
+
(json["signature_paths"] ||= []) << path.to_s
|
76
|
+
|
77
|
+
end
|
78
|
+
files.each_group_source_path(group, true) do |path|
|
79
|
+
(json["source_paths"] ||= []) << path.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
json
|
84
|
+
end
|
85
|
+
|
86
|
+
def pattern_as_json(pattern)
|
87
|
+
{
|
88
|
+
"pattern" => pattern.patterns,
|
89
|
+
"ignore" => pattern.ignores
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def run
|
94
|
+
project = load_config()
|
95
|
+
if print_files
|
96
|
+
loader = Services::FileLoader.new(base_dir: project.base_dir)
|
97
|
+
@files = files = Server::TargetGroupFiles.new(project)
|
98
|
+
project.targets.each do |target|
|
99
|
+
loader.each_path_in_target(target) do |path|
|
100
|
+
files.add_path(path)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
else
|
104
|
+
@files = nil
|
105
|
+
end
|
106
|
+
|
107
|
+
stdout.puts YAML.dump(as_json(project))
|
108
|
+
|
109
|
+
0
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require "csv"
|
2
|
+
|
3
|
+
module Steep
|
4
|
+
module Drivers
|
5
|
+
class Stats
|
6
|
+
class CSVPrinter
|
7
|
+
attr_reader :io
|
8
|
+
|
9
|
+
def initialize(io:)
|
10
|
+
@io = io
|
11
|
+
end
|
12
|
+
|
13
|
+
def print(stats_result)
|
14
|
+
io.puts(
|
15
|
+
CSV.generate do |csv|
|
16
|
+
csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
|
17
|
+
stats_result.each do |row|
|
18
|
+
if row[:type] == "success"
|
19
|
+
# @type var row: Steep::Services::StatsCalculator::SuccessStats::json
|
20
|
+
csv << [
|
21
|
+
row[:target],
|
22
|
+
row[:path],
|
23
|
+
row[:type],
|
24
|
+
row[:typed_calls],
|
25
|
+
row[:untyped_calls],
|
26
|
+
row[:total_calls],
|
27
|
+
if row[:total_calls].nonzero?
|
28
|
+
(row[:typed_calls].to_f / row[:total_calls] * 100).to_i
|
29
|
+
else
|
30
|
+
100
|
31
|
+
end
|
32
|
+
]
|
33
|
+
else
|
34
|
+
# @type var row: Steep::Services::StatsCalculator::ErrorStats::json
|
35
|
+
csv << [
|
36
|
+
row[:target],
|
37
|
+
row[:path],
|
38
|
+
row[:type],
|
39
|
+
0,
|
40
|
+
0,
|
41
|
+
0,
|
42
|
+
0
|
43
|
+
]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class TablePrinter
|
52
|
+
attr_reader :io
|
53
|
+
|
54
|
+
def initialize(io:)
|
55
|
+
@io = io
|
56
|
+
end
|
57
|
+
|
58
|
+
def print(stats_result)
|
59
|
+
rows = [] #: Array[Array[untyped]]
|
60
|
+
stats_result.sort_by {|row| row[:path] }.each do |row|
|
61
|
+
if row[:type] == "success"
|
62
|
+
# @type var row: Steep::Services::StatsCalculator::SuccessStats::json
|
63
|
+
rows << [
|
64
|
+
row[:target],
|
65
|
+
row[:path] + " ",
|
66
|
+
row[:type],
|
67
|
+
row[:typed_calls],
|
68
|
+
row[:untyped_calls],
|
69
|
+
row[:total_calls],
|
70
|
+
if row[:total_calls].nonzero?
|
71
|
+
"#{(row[:typed_calls].to_f / row[:total_calls] * 100).to_i}%"
|
72
|
+
else
|
73
|
+
"100%"
|
74
|
+
end
|
75
|
+
]
|
76
|
+
else
|
77
|
+
# @type var row: Steep::Services::StatsCalculator::ErrorStats::json
|
78
|
+
rows << [
|
79
|
+
row[:target],
|
80
|
+
row[:path],
|
81
|
+
row[:type],
|
82
|
+
0,
|
83
|
+
0,
|
84
|
+
0,
|
85
|
+
"N/A"
|
86
|
+
]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
table = Terminal::Table.new( # steep:ignore UnknownConstant
|
91
|
+
headings: ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"],
|
92
|
+
rows: rows
|
93
|
+
)
|
94
|
+
table.align_column(3, :right)
|
95
|
+
table.align_column(4, :right)
|
96
|
+
table.align_column(5, :right)
|
97
|
+
table.align_column(6, :right)
|
98
|
+
table.style = { border_top: false, border_bottom: false, border_y: "", border_i: "" }
|
99
|
+
io.puts(table)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
attr_reader :stdout
|
104
|
+
attr_reader :stderr
|
105
|
+
attr_reader :command_line_patterns
|
106
|
+
attr_accessor :format
|
107
|
+
attr_reader :jobs_option
|
108
|
+
|
109
|
+
include Utils::DriverHelper
|
110
|
+
|
111
|
+
def initialize(stdout:, stderr:)
|
112
|
+
@stdout = stdout
|
113
|
+
@stderr = stderr
|
114
|
+
@command_line_patterns = []
|
115
|
+
@jobs_option = Utils::JobsOption.new()
|
116
|
+
end
|
117
|
+
|
118
|
+
def run
|
119
|
+
project = load_config()
|
120
|
+
|
121
|
+
stderr.puts Rainbow("# Calculating stats:").bold
|
122
|
+
stderr.puts
|
123
|
+
|
124
|
+
client_read, server_write = IO.pipe
|
125
|
+
server_read, client_write = IO.pipe
|
126
|
+
|
127
|
+
client_reader = LanguageServer::Protocol::Transport::Io::Reader.new(client_read)
|
128
|
+
client_writer = LanguageServer::Protocol::Transport::Io::Writer.new(client_write)
|
129
|
+
|
130
|
+
server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
|
131
|
+
server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)
|
132
|
+
|
133
|
+
typecheck_workers = Server::WorkerProcess.start_typecheck_workers(
|
134
|
+
steepfile: project.steepfile_path,
|
135
|
+
delay_shutdown: true,
|
136
|
+
args: command_line_patterns,
|
137
|
+
steep_command: jobs_option.steep_command,
|
138
|
+
count: jobs_option.jobs_count_value
|
139
|
+
)
|
140
|
+
|
141
|
+
master = Server::Master.new(
|
142
|
+
project: project,
|
143
|
+
reader: server_reader,
|
144
|
+
writer: server_writer,
|
145
|
+
interaction_worker: nil,
|
146
|
+
typecheck_workers: typecheck_workers
|
147
|
+
)
|
148
|
+
master.typecheck_automatically = false
|
149
|
+
master.commandline_args.push(*command_line_patterns)
|
150
|
+
|
151
|
+
main_thread = Thread.start do
|
152
|
+
Thread.current.abort_on_exception = true
|
153
|
+
master.start()
|
154
|
+
end
|
155
|
+
|
156
|
+
initialize_id = request_id()
|
157
|
+
client_writer.write({ method: :initialize, id: initialize_id, params: DEFAULT_CLI_LSP_INITIALIZE_PARAMS })
|
158
|
+
wait_for_response_id(reader: client_reader, id: initialize_id)
|
159
|
+
|
160
|
+
typecheck_guid = SecureRandom.uuid
|
161
|
+
|
162
|
+
master.job_queue << -> do
|
163
|
+
Steep.logger.info { "Type checking for stats..." }
|
164
|
+
progress = master.work_done_progress(typecheck_guid)
|
165
|
+
master.start_type_check(last_request: nil, progress: progress, include_unchanged: true, report_progress_threshold: 0, needs_response: true)
|
166
|
+
end
|
167
|
+
wait_for_message(reader: client_reader) do |message|
|
168
|
+
message[:id] == typecheck_guid
|
169
|
+
end
|
170
|
+
|
171
|
+
Steep.logger.info { "Finished type checking for stats" }
|
172
|
+
|
173
|
+
stats_id = request_id()
|
174
|
+
client_writer.write(Server::CustomMethods::Stats.request(stats_id))
|
175
|
+
|
176
|
+
stats_response = wait_for_response_id(reader: client_reader, id: stats_id)
|
177
|
+
stats_result = stats_response[:result] #: Server::CustomMethods::Stats::result
|
178
|
+
|
179
|
+
shutdown_exit(reader: client_reader, writer: client_writer)
|
180
|
+
main_thread.join()
|
181
|
+
|
182
|
+
printer = case format
|
183
|
+
when "csv"
|
184
|
+
CSVPrinter.new(io: stdout)
|
185
|
+
when "table"
|
186
|
+
TablePrinter.new(io: stdout)
|
187
|
+
when nil
|
188
|
+
if stdout.tty?
|
189
|
+
TablePrinter.new(io: stdout)
|
190
|
+
else
|
191
|
+
CSVPrinter.new(io: stdout)
|
192
|
+
end
|
193
|
+
else
|
194
|
+
raise ArgumentError.new("Invalid format: #{format}")
|
195
|
+
end
|
196
|
+
|
197
|
+
printer.print(stats_result)
|
198
|
+
|
199
|
+
0
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
module Utils
|
4
|
+
module DriverHelper
|
5
|
+
attr_accessor :steepfile
|
6
|
+
attr_accessor :disable_install_collection
|
7
|
+
|
8
|
+
def load_config(path: steepfile || Pathname("Steepfile"))
|
9
|
+
if path.file?
|
10
|
+
steep_file_path = path.absolute? ? path : Pathname.pwd + path
|
11
|
+
Project.new(steepfile_path: steep_file_path).tap do |project|
|
12
|
+
Project::DSL.parse(project, path.read, filename: path.to_s)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
Steep.ui_logger.error { "Cannot find a configuration at #{path}: `steep init` to scaffold. Using current directory..." }
|
16
|
+
Project.new(steepfile_path: nil, base_dir: Pathname.pwd).tap do |project|
|
17
|
+
Project::DSL.eval(project) do
|
18
|
+
target :'.' do
|
19
|
+
check '.'
|
20
|
+
signature '.'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end.tap do |project|
|
25
|
+
project.targets.each do |target|
|
26
|
+
case result = target.options.load_collection_lock
|
27
|
+
when nil, RBS::Collection::Config::Lockfile
|
28
|
+
# ok
|
29
|
+
when Pathname
|
30
|
+
# File is missing
|
31
|
+
if result == target.options.collection_config_path
|
32
|
+
# Config file is missing
|
33
|
+
Steep.ui_logger.error { "rbs-collection configuration is missing: `#{result}`" }
|
34
|
+
else
|
35
|
+
# Lockfile is missing
|
36
|
+
Steep.ui_logger.error { "Run `rbs collection install` to generate missing lockfile: `#{result}`" }
|
37
|
+
end
|
38
|
+
when YAML::SyntaxError
|
39
|
+
# File is broken
|
40
|
+
Steep.ui_logger.error { "rbs-collection setup is broken:\nsyntax error #{result.inspect}" }
|
41
|
+
when RBS::Collection::Config::CollectionNotAvailable
|
42
|
+
unless disable_install_collection
|
43
|
+
install_collection(target, target.options.collection_config_path || raise)
|
44
|
+
else
|
45
|
+
Steep.ui_logger.error { "Run `rbs collection install` to set up RBS files for gems" }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def install_collection(target, config_path)
|
53
|
+
Steep.ui_logger.info { "Installing RBS files for collection: #{config_path}" }
|
54
|
+
lockfile_path = RBS::Collection::Config.to_lockfile_path(config_path)
|
55
|
+
io = StringIO.new
|
56
|
+
begin
|
57
|
+
RBS::Collection::Installer.new(lockfile_path: lockfile_path, stdout: io).install_from_lockfile()
|
58
|
+
target.options.load_collection_lock(force: true)
|
59
|
+
Steep.ui_logger.debug { "Finished setting up RBS collection: " + io.string }
|
60
|
+
|
61
|
+
result = target.options.load_collection_lock(force: true)
|
62
|
+
unless result.is_a?(RBS::Collection::Config::Lockfile)
|
63
|
+
raise "Failed to set up RBS collection: #{result.inspect}"
|
64
|
+
end
|
65
|
+
rescue => exn
|
66
|
+
Steep.ui_logger.error { "Failed to set up RBS collection: #{exn.inspect}" }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def request_id
|
71
|
+
SecureRandom.alphanumeric(10)
|
72
|
+
end
|
73
|
+
|
74
|
+
def wait_for_response_id(reader:, id:, unknown_responses: nil, &block)
|
75
|
+
reader.read do |message|
|
76
|
+
Steep.logger.debug { "Received message waiting for #{id}: #{message.inspect}" }
|
77
|
+
|
78
|
+
response_id = message[:id]
|
79
|
+
|
80
|
+
if response_id == id
|
81
|
+
return message
|
82
|
+
end
|
83
|
+
|
84
|
+
if block
|
85
|
+
yield message
|
86
|
+
else
|
87
|
+
case unknown_responses
|
88
|
+
when :ignore, nil
|
89
|
+
# nop
|
90
|
+
when :log
|
91
|
+
Steep.logger.error { "Unexpected message: #{message.inspect}" }
|
92
|
+
when :raise
|
93
|
+
raise "Unexpected message: #{message.inspect}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def shutdown_exit(writer:, reader:)
|
100
|
+
request_id().tap do |id|
|
101
|
+
writer.write({ method: :shutdown, id: id })
|
102
|
+
wait_for_response_id(reader: reader, id: id)
|
103
|
+
end
|
104
|
+
writer.write({ method: :exit })
|
105
|
+
end
|
106
|
+
|
107
|
+
def wait_for_message(reader:, unknown_messages: :ignore, &block)
|
108
|
+
reader.read do |message|
|
109
|
+
if yield(message)
|
110
|
+
return message
|
111
|
+
else
|
112
|
+
case unknown_messages
|
113
|
+
when :ignore
|
114
|
+
# nop
|
115
|
+
when :log
|
116
|
+
Steep.logger.error { "Unexpected message: #{message.inspect}" }
|
117
|
+
when :raise
|
118
|
+
raise "Unexpected message: #{message.inspect}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def keep_diagnostic?(diagnostic, severity_level:)
|
125
|
+
severity = diagnostic[:severity]
|
126
|
+
|
127
|
+
case severity_level
|
128
|
+
when nil, :hint
|
129
|
+
true
|
130
|
+
when :error
|
131
|
+
severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR
|
132
|
+
when :warning
|
133
|
+
severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::WARNING
|
134
|
+
when :information
|
135
|
+
severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
(DEFAULT_CLI_LSP_INITIALIZE_PARAMS = {}).freeze
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
module Utils
|
4
|
+
class JobsOption
|
5
|
+
attr_accessor :jobs_count, :steep_command, :jobs_count_modifier
|
6
|
+
|
7
|
+
def initialize(jobs_count_modifier: 0)
|
8
|
+
@jobs_count_modifier = jobs_count_modifier
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_jobs_count
|
12
|
+
Concurrent.physical_processor_count + jobs_count_modifier
|
13
|
+
end
|
14
|
+
|
15
|
+
def jobs_count_value
|
16
|
+
count = jobs_count || default_jobs_count
|
17
|
+
if count >= 1
|
18
|
+
count
|
19
|
+
else
|
20
|
+
1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
class Vendor
|
4
|
+
attr_reader :stdout
|
5
|
+
attr_reader :stderr
|
6
|
+
attr_reader :stdin
|
7
|
+
|
8
|
+
attr_accessor :vendor_dir
|
9
|
+
attr_accessor :clean_before
|
10
|
+
|
11
|
+
def initialize(stdout:, stderr:, stdin:)
|
12
|
+
@stdout = stdout
|
13
|
+
@stderr = stderr
|
14
|
+
@stdin = stdin
|
15
|
+
|
16
|
+
@clean_before = false
|
17
|
+
@vendor_dir = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
stdout.puts "`steep vendor` is deprecated. Use `rbs vendor` command directly"
|
22
|
+
|
23
|
+
0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|