solargraph 0.58.0 → 0.59.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/.envrc +3 -0
- data/.gitattributes +2 -0
- data/.github/workflows/linting.yml +6 -5
- data/.github/workflows/plugins.yml +48 -35
- data/.github/workflows/rspec.yml +15 -28
- data/.github/workflows/typecheck.yml +3 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +38 -6
- data/.rubocop_todo.yml +53 -966
- data/CHANGELOG.md +24 -0
- data/Gemfile +3 -1
- data/README.md +3 -3
- data/Rakefile +26 -23
- data/bin/solargraph +9 -8
- data/lib/solargraph/api_map/cache.rb +110 -110
- data/lib/solargraph/api_map/constants.rb +288 -279
- data/lib/solargraph/api_map/index.rb +204 -193
- data/lib/solargraph/api_map/source_to_yard.rb +110 -97
- data/lib/solargraph/api_map/store.rb +395 -384
- data/lib/solargraph/api_map.rb +1029 -945
- data/lib/solargraph/bench.rb +44 -45
- data/lib/solargraph/complex_type/conformance.rb +176 -0
- data/lib/solargraph/complex_type/type_methods.rb +240 -228
- data/lib/solargraph/complex_type/unique_type.rb +641 -482
- data/lib/solargraph/complex_type.rb +557 -444
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
- data/lib/solargraph/convention/data_definition.rb +108 -105
- data/lib/solargraph/convention/gemfile.rb +15 -15
- data/lib/solargraph/convention/gemspec.rb +23 -23
- data/lib/solargraph/convention/rakefile.rb +17 -17
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
- data/lib/solargraph/convention/struct_definition.rb +168 -164
- data/lib/solargraph/convention.rb +78 -78
- data/lib/solargraph/converters/dd.rb +19 -17
- data/lib/solargraph/converters/dl.rb +17 -15
- data/lib/solargraph/converters/dt.rb +17 -15
- data/lib/solargraph/converters/misc.rb +3 -1
- data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
- data/lib/solargraph/diagnostics/rubocop.rb +119 -118
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
- data/lib/solargraph/diagnostics/type_check.rb +56 -55
- data/lib/solargraph/diagnostics/update_errors.rb +37 -41
- data/lib/solargraph/doc_map.rb +438 -439
- data/lib/solargraph/equality.rb +34 -34
- data/lib/solargraph/gem_pins.rb +98 -98
- data/lib/solargraph/language_server/error_codes.rb +20 -20
- data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
- data/lib/solargraph/language_server/host/dispatch.rb +130 -130
- data/lib/solargraph/language_server/host/message_worker.rb +113 -112
- data/lib/solargraph/language_server/host/sources.rb +100 -99
- data/lib/solargraph/language_server/host.rb +886 -878
- data/lib/solargraph/language_server/message/base.rb +97 -97
- data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +108 -114
- data/lib/solargraph/language_server/message/extended/document.rb +24 -23
- data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
- data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
- data/lib/solargraph/language_server/message/extended/search.rb +20 -20
- data/lib/solargraph/language_server/message/initialize.rb +197 -191
- data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
- data/lib/solargraph/language_server/message/text_document/definition.rb +49 -40
- data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +36 -26
- data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
- data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
- data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
- data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
- data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +33 -25
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +33 -23
- data/lib/solargraph/language_server/message.rb +94 -94
- data/lib/solargraph/language_server/request.rb +29 -27
- data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
- data/lib/solargraph/language_server/uri_helpers.rb +49 -49
- data/lib/solargraph/library.rb +702 -683
- data/lib/solargraph/location.rb +85 -82
- data/lib/solargraph/logging.rb +55 -37
- data/lib/solargraph/page.rb +92 -92
- data/lib/solargraph/parser/comment_ripper.rb +84 -69
- data/lib/solargraph/parser/flow_sensitive_typing.rb +471 -255
- data/lib/solargraph/parser/node_processor/base.rb +122 -92
- data/lib/solargraph/parser/node_processor.rb +63 -62
- data/lib/solargraph/parser/parser_gem/class_methods.rb +165 -149
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
- data/lib/solargraph/parser/parser_gem/node_methods.rb +507 -486
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +45 -46
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +42 -40
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
- data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +51 -52
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +302 -291
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
- data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
- data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
- data/lib/solargraph/parser/parser_gem.rb +14 -12
- data/lib/solargraph/parser/region.rb +75 -69
- data/lib/solargraph/parser/snippet.rb +19 -17
- data/lib/solargraph/parser.rb +25 -23
- data/lib/solargraph/pin/base.rb +773 -729
- data/lib/solargraph/pin/base_variable.rb +375 -126
- data/lib/solargraph/pin/block.rb +127 -104
- data/lib/solargraph/pin/breakable.rb +15 -9
- data/lib/solargraph/pin/callable.rb +275 -231
- data/lib/solargraph/pin/closure.rb +69 -72
- data/lib/solargraph/pin/common.rb +97 -79
- data/lib/solargraph/pin/compound_statement.rb +55 -0
- data/lib/solargraph/pin/constant.rb +43 -45
- data/lib/solargraph/pin/conversions.rb +129 -123
- data/lib/solargraph/pin/delegated_method.rb +131 -120
- data/lib/solargraph/pin/documenting.rb +116 -114
- data/lib/solargraph/pin/instance_variable.rb +38 -34
- data/lib/solargraph/pin/keyword.rb +16 -20
- data/lib/solargraph/pin/local_variable.rb +31 -75
- data/lib/solargraph/pin/method.rb +724 -672
- data/lib/solargraph/pin/method_alias.rb +42 -34
- data/lib/solargraph/pin/namespace.rb +122 -115
- data/lib/solargraph/pin/parameter.rb +339 -275
- data/lib/solargraph/pin/proxy_type.rb +42 -39
- data/lib/solargraph/pin/reference/override.rb +47 -47
- data/lib/solargraph/pin/reference/superclass.rb +17 -15
- data/lib/solargraph/pin/reference/type_alias.rb +16 -0
- data/lib/solargraph/pin/reference.rb +59 -39
- data/lib/solargraph/pin/search.rb +62 -61
- data/lib/solargraph/pin/signature.rb +64 -61
- data/lib/solargraph/pin/symbol.rb +54 -53
- data/lib/solargraph/pin/until.rb +16 -18
- data/lib/solargraph/pin/while.rb +16 -18
- data/lib/solargraph/pin.rb +46 -44
- data/lib/solargraph/pin_cache.rb +248 -245
- data/lib/solargraph/position.rb +139 -119
- data/lib/solargraph/range.rb +113 -112
- data/lib/solargraph/rbs_map/conversions.rb +952 -823
- data/lib/solargraph/rbs_map/core_fills.rb +91 -84
- data/lib/solargraph/rbs_map/core_map.rb +65 -58
- data/lib/solargraph/rbs_map/stdlib_map.rb +71 -43
- data/lib/solargraph/rbs_map.rb +207 -163
- data/lib/solargraph/server_methods.rb +16 -16
- data/lib/solargraph/shell.rb +555 -352
- data/lib/solargraph/source/chain/array.rb +39 -37
- data/lib/solargraph/source/chain/call.rb +377 -337
- data/lib/solargraph/source/chain/class_variable.rb +13 -13
- data/lib/solargraph/source/chain/constant.rb +30 -26
- data/lib/solargraph/source/chain/global_variable.rb +13 -13
- data/lib/solargraph/source/chain/hash.rb +37 -34
- data/lib/solargraph/source/chain/if.rb +30 -28
- data/lib/solargraph/source/chain/instance_variable.rb +36 -13
- data/lib/solargraph/source/chain/link.rb +99 -109
- data/lib/solargraph/source/chain/literal.rb +51 -48
- data/lib/solargraph/source/chain/or.rb +29 -23
- data/lib/solargraph/source/chain/q_call.rb +13 -11
- data/lib/solargraph/source/chain/variable.rb +15 -13
- data/lib/solargraph/source/chain/z_super.rb +28 -30
- data/lib/solargraph/source/chain.rb +304 -291
- data/lib/solargraph/source/change.rb +89 -82
- data/lib/solargraph/source/cursor.rb +172 -166
- data/lib/solargraph/source/encoding_fixes.rb +22 -23
- data/lib/solargraph/source/source_chainer.rb +218 -194
- data/lib/solargraph/source/updater.rb +59 -55
- data/lib/solargraph/source.rb +522 -498
- data/lib/solargraph/source_map/clip.rb +245 -226
- data/lib/solargraph/source_map/data.rb +37 -34
- data/lib/solargraph/source_map/mapper.rb +286 -259
- data/lib/solargraph/source_map.rb +224 -212
- data/lib/solargraph/type_checker/problem.rb +34 -32
- data/lib/solargraph/type_checker/rules.rb +157 -84
- data/lib/solargraph/type_checker.rb +888 -814
- data/lib/solargraph/version.rb +5 -5
- data/lib/solargraph/workspace/config.rb +258 -255
- data/lib/solargraph/workspace/gemspecs.rb +367 -0
- data/lib/solargraph/workspace/require_paths.rb +98 -97
- data/lib/solargraph/workspace.rb +242 -220
- data/lib/solargraph/yard_map/helpers.rb +49 -44
- data/lib/solargraph/yard_map/mapper/to_method.rb +136 -130
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
- data/lib/solargraph/yard_map/mapper.rb +84 -79
- data/lib/solargraph/yard_map.rb +17 -18
- data/lib/solargraph/yard_tags.rb +20 -20
- data/lib/solargraph/yardoc.rb +90 -87
- data/lib/solargraph.rb +128 -105
- data/rbs/fills/rubygems/0/dependency.rbs +193 -0
- data/rbs/fills/tuple/tuple.rbs +28 -0
- data/rbs/shims/ast/0/node.rbs +5 -0
- data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
- data/rbs_collection.yaml +1 -1
- data/solargraph.gemspec +37 -35
- metadata +52 -51
- data/lib/solargraph/type_checker/checks.rb +0 -124
- data/lib/solargraph/type_checker/param_def.rb +0 -37
- data/lib/solargraph/yard_map/to_method.rb +0 -89
- data/sig/shims/ast/0/node.rbs +0 -5
- /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
data/lib/solargraph/doc_map.rb
CHANGED
|
@@ -1,439 +1,438 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'pathname'
|
|
4
|
-
require 'benchmark'
|
|
5
|
-
require 'open3'
|
|
6
|
-
|
|
7
|
-
module Solargraph
|
|
8
|
-
# A collection of pins generated from required gems.
|
|
9
|
-
#
|
|
10
|
-
class DocMap
|
|
11
|
-
include Logging
|
|
12
|
-
|
|
13
|
-
# @return [Array<String>]
|
|
14
|
-
attr_reader :requires
|
|
15
|
-
alias required requires
|
|
16
|
-
|
|
17
|
-
# @return [Array<Gem::Specification>]
|
|
18
|
-
attr_reader :preferences
|
|
19
|
-
|
|
20
|
-
# @return [Array<Pin::Base>]
|
|
21
|
-
attr_reader :pins
|
|
22
|
-
|
|
23
|
-
# @return [Array<Gem::Specification>]
|
|
24
|
-
def uncached_gemspecs
|
|
25
|
-
uncached_yard_gemspecs.concat(uncached_rbs_collection_gemspecs)
|
|
26
|
-
.sort
|
|
27
|
-
.uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# @return [Array<Gem::Specification>]
|
|
31
|
-
attr_reader :uncached_yard_gemspecs
|
|
32
|
-
|
|
33
|
-
# @return [Array<Gem::Specification>]
|
|
34
|
-
attr_reader :uncached_rbs_collection_gemspecs
|
|
35
|
-
|
|
36
|
-
# @return [String, nil]
|
|
37
|
-
attr_reader :rbs_collection_path
|
|
38
|
-
|
|
39
|
-
# @return [String, nil]
|
|
40
|
-
attr_reader :rbs_collection_config_path
|
|
41
|
-
|
|
42
|
-
# @return [Workspace, nil]
|
|
43
|
-
attr_reader :workspace
|
|
44
|
-
|
|
45
|
-
# @return [Environ]
|
|
46
|
-
attr_reader :environ
|
|
47
|
-
|
|
48
|
-
# @param requires [Array<String>]
|
|
49
|
-
# @param
|
|
50
|
-
# @param
|
|
51
|
-
def initialize
|
|
52
|
-
@requires = requires.compact
|
|
53
|
-
@
|
|
54
|
-
@
|
|
55
|
-
@
|
|
56
|
-
@
|
|
57
|
-
@environ
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# @param out [IO]
|
|
64
|
-
# @return [void]
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
logger.debug { "Caching for
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
@
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
# @param
|
|
84
|
-
# @
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# @param
|
|
93
|
-
# @
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
pins
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
# @param
|
|
106
|
-
# @param
|
|
107
|
-
# @
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
type
|
|
114
|
-
type << '
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
@
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
# @type [Array<Gem::Specification>]
|
|
185
|
-
gemspecs =
|
|
186
|
-
|
|
187
|
-
paths.each do |path|
|
|
188
|
-
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
logger.debug {
|
|
192
|
-
time = Benchmark.measure do
|
|
193
|
-
gemspecs.each do |gemspec|
|
|
194
|
-
pins = deserialize_combined_pin_cache gemspec
|
|
195
|
-
@pins.concat pins if pins
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
logger.info { "DocMap#load_serialized_gem_pins: Loaded and processed serialized pins together in #{time.real} seconds" }
|
|
199
|
-
@uncached_yard_gemspecs.uniq!
|
|
200
|
-
@uncached_rbs_collection_gemspecs.uniq!
|
|
201
|
-
nil
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
# @return [Hash{String => Array<Gem::Specification>}]
|
|
205
|
-
def required_gems_map
|
|
206
|
-
@required_gems_map ||= requires.to_h { |path| [path, resolve_path_to_gemspecs(path)] }
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
# @return [Hash{String => Gem::Specification}]
|
|
210
|
-
def preference_map
|
|
211
|
-
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
# @param gemspec [Gem::Specification]
|
|
215
|
-
# @return [Array<Pin::Base>, nil]
|
|
216
|
-
def deserialize_yard_pin_cache gemspec
|
|
217
|
-
if yard_pins_in_memory.key?([gemspec.name, gemspec.version])
|
|
218
|
-
return yard_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
cached = PinCache.deserialize_yard_gem(gemspec)
|
|
222
|
-
if cached
|
|
223
|
-
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
|
224
|
-
yard_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
|
225
|
-
cached
|
|
226
|
-
else
|
|
227
|
-
logger.debug "No YARD pin cache for #{gemspec.name}:#{gemspec.version}"
|
|
228
|
-
@uncached_yard_gemspecs.push gemspec
|
|
229
|
-
nil
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
# @param gemspec [Gem::Specification]
|
|
234
|
-
# @return [void]
|
|
235
|
-
def deserialize_combined_pin_cache
|
|
236
|
-
unless combined_pins_in_memory[[gemspec.name, gemspec.version]].nil?
|
|
237
|
-
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
|
241
|
-
rbs_version_cache_key = rbs_map.cache_key
|
|
242
|
-
|
|
243
|
-
cached = PinCache.deserialize_combined_gem(gemspec, rbs_version_cache_key)
|
|
244
|
-
if cached
|
|
245
|
-
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
|
246
|
-
combined_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
|
247
|
-
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
rbs_collection_pins = deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
|
251
|
-
|
|
252
|
-
yard_pins = deserialize_yard_pin_cache gemspec
|
|
253
|
-
|
|
254
|
-
if !rbs_collection_pins.nil? && !yard_pins.nil?
|
|
255
|
-
logger.debug { "Combining pins for #{gemspec.name}:#{gemspec.version}" }
|
|
256
|
-
combined_pins = GemPins.combine(yard_pins, rbs_collection_pins)
|
|
257
|
-
PinCache.serialize_combined_gem(gemspec, rbs_version_cache_key, combined_pins)
|
|
258
|
-
combined_pins_in_memory[[gemspec.name, gemspec.version]] = combined_pins
|
|
259
|
-
logger.info { "Generated #{combined_pins_in_memory[[gemspec.name, gemspec.version]].length} combined pins for #{gemspec.name} #{gemspec.version}" }
|
|
260
|
-
return combined_pins
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
if !yard_pins.nil?
|
|
264
|
-
logger.debug { "Using only YARD pins for #{gemspec.name}:#{gemspec.version}" }
|
|
265
|
-
combined_pins_in_memory[[gemspec.name, gemspec.version]] = yard_pins
|
|
266
|
-
|
|
267
|
-
elsif !rbs_collection_pins.nil?
|
|
268
|
-
logger.debug { "Using only RBS collection pins for #{gemspec.name}:#{gemspec.version}" }
|
|
269
|
-
combined_pins_in_memory[[gemspec.name, gemspec.version]] = rbs_collection_pins
|
|
270
|
-
|
|
271
|
-
else
|
|
272
|
-
logger.debug { "Pins not yet cached for #{gemspec.name}:#{gemspec.version}" }
|
|
273
|
-
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# @param path [String] require path that might be in the RBS stdlib collection
|
|
278
|
-
# @return [void]
|
|
279
|
-
def deserialize_stdlib_rbs_map path
|
|
280
|
-
map = RbsMap::StdlibMap.load(path)
|
|
281
|
-
if map.resolved?
|
|
282
|
-
logger.debug { "Loading stdlib pins for #{path}" }
|
|
283
|
-
@pins.concat map.pins
|
|
284
|
-
logger.debug { "Loaded #{map.pins.length} stdlib pins for #{path}" }
|
|
285
|
-
map.pins
|
|
286
|
-
else
|
|
287
|
-
# @todo Temporarily ignoring unresolved `require 'set'`
|
|
288
|
-
logger.debug { "Require path #{path} could not be resolved in RBS" } unless path == 'set'
|
|
289
|
-
nil
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
# @param gemspec [Gem::Specification]
|
|
294
|
-
# @param rbs_version_cache_key [String]
|
|
295
|
-
# @return [Array<Pin::Base>, nil]
|
|
296
|
-
def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
|
297
|
-
return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
|
|
298
|
-
cached = PinCache.deserialize_rbs_collection_gem(gemspec, rbs_version_cache_key)
|
|
299
|
-
if cached
|
|
300
|
-
logger.info { "Loaded #{cached.length} pins from RBS collection cache for #{gemspec.name}:#{gemspec.version}" } unless cached.empty?
|
|
301
|
-
rbs_collection_pins_in_memory[[gemspec, rbs_version_cache_key]] = cached
|
|
302
|
-
cached
|
|
303
|
-
else
|
|
304
|
-
logger.debug "No RBS collection pin cache for #{gemspec.name} #{gemspec.version}"
|
|
305
|
-
@uncached_rbs_collection_gemspecs.push gemspec
|
|
306
|
-
nil
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
# @param path [String]
|
|
311
|
-
# @return [::Array<Gem::Specification>, nil]
|
|
312
|
-
def resolve_path_to_gemspecs path
|
|
313
|
-
return nil if path.empty?
|
|
314
|
-
return gemspecs_required_from_bundler if path == 'bundler/require'
|
|
315
|
-
|
|
316
|
-
# @type [Gem::Specification, nil]
|
|
317
|
-
gemspec = Gem::Specification.find_by_path(path)
|
|
318
|
-
if gemspec.nil?
|
|
319
|
-
gem_name_guess = path.split('/').first
|
|
320
|
-
begin
|
|
321
|
-
# this can happen when the gem is included via a local path in
|
|
322
|
-
# a Gemfile; Gem doesn't try to index the paths in that case.
|
|
323
|
-
#
|
|
324
|
-
# See if we can make a good guess:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
# @
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
Gem
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
dep
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
def
|
|
379
|
-
|
|
380
|
-
end
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
def
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
logger.
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'benchmark'
|
|
5
|
+
require 'open3'
|
|
6
|
+
|
|
7
|
+
module Solargraph
|
|
8
|
+
# A collection of pins generated from required gems.
|
|
9
|
+
#
|
|
10
|
+
class DocMap
|
|
11
|
+
include Logging
|
|
12
|
+
|
|
13
|
+
# @return [Array<String>]
|
|
14
|
+
attr_reader :requires
|
|
15
|
+
alias required requires
|
|
16
|
+
|
|
17
|
+
# @return [Array<Gem::Specification>]
|
|
18
|
+
attr_reader :preferences
|
|
19
|
+
|
|
20
|
+
# @return [Array<Pin::Base>]
|
|
21
|
+
attr_reader :pins
|
|
22
|
+
|
|
23
|
+
# @return [Array<Gem::Specification>]
|
|
24
|
+
def uncached_gemspecs
|
|
25
|
+
uncached_yard_gemspecs.concat(uncached_rbs_collection_gemspecs)
|
|
26
|
+
.sort
|
|
27
|
+
.uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Array<Gem::Specification>]
|
|
31
|
+
attr_reader :uncached_yard_gemspecs
|
|
32
|
+
|
|
33
|
+
# @return [Array<Gem::Specification>]
|
|
34
|
+
attr_reader :uncached_rbs_collection_gemspecs
|
|
35
|
+
|
|
36
|
+
# @return [String, nil]
|
|
37
|
+
attr_reader :rbs_collection_path
|
|
38
|
+
|
|
39
|
+
# @return [String, nil]
|
|
40
|
+
attr_reader :rbs_collection_config_path
|
|
41
|
+
|
|
42
|
+
# @return [Workspace, nil]
|
|
43
|
+
attr_reader :workspace
|
|
44
|
+
|
|
45
|
+
# @return [Environ]
|
|
46
|
+
attr_reader :environ
|
|
47
|
+
|
|
48
|
+
# @param requires [Array<String>]
|
|
49
|
+
# @param workspace [Workspace, nil]
|
|
50
|
+
# @param [Object] out
|
|
51
|
+
def initialize requires, workspace, out: $stderr
|
|
52
|
+
@requires = requires.compact
|
|
53
|
+
@workspace = workspace
|
|
54
|
+
@rbs_collection_path = workspace&.rbs_collection_path
|
|
55
|
+
@rbs_collection_config_path = workspace&.rbs_collection_config_path
|
|
56
|
+
@environ = Convention.for_global(self)
|
|
57
|
+
@requires.concat @environ.requires if @environ
|
|
58
|
+
load_serialized_gem_pins
|
|
59
|
+
pins.concat @environ.pins
|
|
60
|
+
@out = out
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @param out [IO, StringIO, nil]
|
|
64
|
+
# @return [void]
|
|
65
|
+
# @param [Boolean] rebuild
|
|
66
|
+
def cache_all! out, rebuild: false
|
|
67
|
+
# if we log at debug level:
|
|
68
|
+
if logger.info?
|
|
69
|
+
gem_desc = uncached_gemspecs.map { |gemspec| "#{gemspec.name}:#{gemspec.version}" }.join(', ')
|
|
70
|
+
logger.info "Caching pins for gems: #{gem_desc}" unless uncached_gemspecs.empty?
|
|
71
|
+
end
|
|
72
|
+
logger.debug { "Caching for YARD: #{uncached_yard_gemspecs.map(&:name)}" }
|
|
73
|
+
logger.debug { "Caching for RBS collection: #{uncached_rbs_collection_gemspecs.map(&:name)}" }
|
|
74
|
+
load_serialized_gem_pins
|
|
75
|
+
uncached_gemspecs.each do |gemspec|
|
|
76
|
+
cache(gemspec, rebuild: rebuild, out: out)
|
|
77
|
+
end
|
|
78
|
+
load_serialized_gem_pins
|
|
79
|
+
@uncached_rbs_collection_gemspecs = []
|
|
80
|
+
@uncached_yard_gemspecs = []
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @param gemspec [Gem::Specification]
|
|
84
|
+
# @param out [IO, StringIO, nil]
|
|
85
|
+
# @return [void]
|
|
86
|
+
def cache_yard_pins gemspec, out
|
|
87
|
+
pins = GemPins.build_yard_pins(yard_plugins, gemspec)
|
|
88
|
+
PinCache.serialize_yard_gem(gemspec, pins)
|
|
89
|
+
logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @param gemspec [Gem::Specification]
|
|
93
|
+
# @param out [IO, StringIO, nil]
|
|
94
|
+
# @return [void]
|
|
95
|
+
def cache_rbs_collection_pins gemspec, out
|
|
96
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
|
97
|
+
pins = rbs_map.pins
|
|
98
|
+
rbs_version_cache_key = rbs_map.cache_key
|
|
99
|
+
# cache pins even if result is zero, so we don't retry building pins
|
|
100
|
+
pins ||= []
|
|
101
|
+
PinCache.serialize_rbs_collection_gem(gemspec, rbs_version_cache_key, pins)
|
|
102
|
+
logger.info { "Cached #{pins.length} RBS collection pins for gem #{gemspec.name} #{gemspec.version} with cache_key #{rbs_version_cache_key.inspect}" unless pins.empty? }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @param gemspec [Gem::Specification]
|
|
106
|
+
# @param rebuild [Boolean] whether to rebuild the pins even if they are cached
|
|
107
|
+
# @param out [IO, StringIO, nil] output stream for logging
|
|
108
|
+
# @return [void]
|
|
109
|
+
def cache gemspec, rebuild: false, out: nil
|
|
110
|
+
build_yard = uncached_yard_gemspecs.include?(gemspec) || rebuild
|
|
111
|
+
build_rbs_collection = uncached_rbs_collection_gemspecs.include?(gemspec) || rebuild
|
|
112
|
+
if build_yard || build_rbs_collection
|
|
113
|
+
type = []
|
|
114
|
+
type << 'YARD' if build_yard
|
|
115
|
+
type << 'RBS collection' if build_rbs_collection
|
|
116
|
+
out&.puts("Caching #{type.join(' and ')} pins for gem #{gemspec.name}:#{gemspec.version}")
|
|
117
|
+
end
|
|
118
|
+
cache_yard_pins(gemspec, out) if build_yard
|
|
119
|
+
cache_rbs_collection_pins(gemspec, out) if build_rbs_collection
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @return [Array<Gem::Specification>]
|
|
123
|
+
def gemspecs
|
|
124
|
+
@gemspecs ||= required_gems_map.values.compact.flatten
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# @return [Array<String>]
|
|
128
|
+
def unresolved_requires
|
|
129
|
+
@unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
133
|
+
def self.all_yard_gems_in_memory
|
|
134
|
+
@all_yard_gems_in_memory ||= {}
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# @return [Hash{String => Hash{Array(String, String) => Array<Pin::Base>}}] stored by RBS collection path
|
|
138
|
+
def self.all_rbs_collection_gems_in_memory
|
|
139
|
+
@all_rbs_collection_gems_in_memory ||= {}
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
143
|
+
def yard_pins_in_memory
|
|
144
|
+
self.class.all_yard_gems_in_memory
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
148
|
+
def rbs_collection_pins_in_memory
|
|
149
|
+
# @sg-ignore rbs_collection_path is String | nil but used as hash key
|
|
150
|
+
self.class.all_rbs_collection_gems_in_memory[rbs_collection_path] ||= {}
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
154
|
+
def self.all_combined_pins_in_memory
|
|
155
|
+
@all_combined_pins_in_memory ||= {}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @todo this should also include an index by the hash of the RBS collection
|
|
159
|
+
# @return [Hash{Array(String, String) => Array<Pin::Base>}] Indexed by gemspec name and version
|
|
160
|
+
def combined_pins_in_memory
|
|
161
|
+
self.class.all_combined_pins_in_memory
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @return [Array<String>]
|
|
165
|
+
def yard_plugins
|
|
166
|
+
@environ.yard_plugins
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @return [Set<Gem::Specification>]
|
|
170
|
+
def dependencies
|
|
171
|
+
@dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
# @return [void]
|
|
177
|
+
def load_serialized_gem_pins
|
|
178
|
+
@pins = []
|
|
179
|
+
@uncached_yard_gemspecs = []
|
|
180
|
+
@uncached_rbs_collection_gemspecs = []
|
|
181
|
+
with_gemspecs, without_gemspecs = required_gems_map.partition { |_, v| v }
|
|
182
|
+
# @type [Array<String>]
|
|
183
|
+
paths = without_gemspecs.to_h.keys
|
|
184
|
+
# @type [Array<Gem::Specification>]
|
|
185
|
+
gemspecs = with_gemspecs.to_h.values.flatten.compact + dependencies.to_a
|
|
186
|
+
|
|
187
|
+
paths.each do |path|
|
|
188
|
+
deserialize_stdlib_rbs_map path
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
logger.debug { 'DocMap#load_serialized_gem_pins: Combining pins...' }
|
|
192
|
+
time = Benchmark.measure do
|
|
193
|
+
gemspecs.each do |gemspec|
|
|
194
|
+
pins = deserialize_combined_pin_cache gemspec
|
|
195
|
+
@pins.concat pins if pins
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
logger.info { "DocMap#load_serialized_gem_pins: Loaded and processed serialized pins together in #{time.real} seconds" }
|
|
199
|
+
@uncached_yard_gemspecs.uniq!
|
|
200
|
+
@uncached_rbs_collection_gemspecs.uniq!
|
|
201
|
+
nil
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# @return [Hash{String => Array<Gem::Specification>}]
|
|
205
|
+
def required_gems_map
|
|
206
|
+
@required_gems_map ||= requires.to_h { |path| [path, resolve_path_to_gemspecs(path)] }
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# @return [Hash{String => Gem::Specification}]
|
|
210
|
+
def preference_map
|
|
211
|
+
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @param gemspec [Gem::Specification]
|
|
215
|
+
# @return [Array<Pin::Base>, nil]
|
|
216
|
+
def deserialize_yard_pin_cache gemspec
|
|
217
|
+
if yard_pins_in_memory.key?([gemspec.name, gemspec.version])
|
|
218
|
+
return yard_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
cached = PinCache.deserialize_yard_gem(gemspec)
|
|
222
|
+
if cached
|
|
223
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
|
224
|
+
yard_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
|
225
|
+
cached
|
|
226
|
+
else
|
|
227
|
+
logger.debug "No YARD pin cache for #{gemspec.name}:#{gemspec.version}"
|
|
228
|
+
@uncached_yard_gemspecs.push gemspec
|
|
229
|
+
nil
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# @param gemspec [Gem::Specification]
|
|
234
|
+
# @return [void]
|
|
235
|
+
def deserialize_combined_pin_cache gemspec
|
|
236
|
+
unless combined_pins_in_memory[[gemspec.name, gemspec.version]].nil?
|
|
237
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
|
241
|
+
rbs_version_cache_key = rbs_map.cache_key
|
|
242
|
+
|
|
243
|
+
cached = PinCache.deserialize_combined_gem(gemspec, rbs_version_cache_key)
|
|
244
|
+
if cached
|
|
245
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
|
246
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
|
247
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
rbs_collection_pins = deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
|
251
|
+
|
|
252
|
+
yard_pins = deserialize_yard_pin_cache gemspec
|
|
253
|
+
|
|
254
|
+
if !rbs_collection_pins.nil? && !yard_pins.nil?
|
|
255
|
+
logger.debug { "Combining pins for #{gemspec.name}:#{gemspec.version}" }
|
|
256
|
+
combined_pins = GemPins.combine(yard_pins, rbs_collection_pins)
|
|
257
|
+
PinCache.serialize_combined_gem(gemspec, rbs_version_cache_key, combined_pins)
|
|
258
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = combined_pins
|
|
259
|
+
logger.info { "Generated #{combined_pins_in_memory[[gemspec.name, gemspec.version]].length} combined pins for #{gemspec.name} #{gemspec.version}" }
|
|
260
|
+
return combined_pins
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
if !yard_pins.nil?
|
|
264
|
+
logger.debug { "Using only YARD pins for #{gemspec.name}:#{gemspec.version}" }
|
|
265
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = yard_pins
|
|
266
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
267
|
+
elsif !rbs_collection_pins.nil?
|
|
268
|
+
logger.debug { "Using only RBS collection pins for #{gemspec.name}:#{gemspec.version}" }
|
|
269
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = rbs_collection_pins
|
|
270
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
|
271
|
+
else
|
|
272
|
+
logger.debug { "Pins not yet cached for #{gemspec.name}:#{gemspec.version}" }
|
|
273
|
+
nil
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# @param path [String] require path that might be in the RBS stdlib collection
|
|
278
|
+
# @return [void]
|
|
279
|
+
def deserialize_stdlib_rbs_map path
|
|
280
|
+
map = RbsMap::StdlibMap.load(path)
|
|
281
|
+
if map.resolved?
|
|
282
|
+
logger.debug { "Loading stdlib pins for #{path}" }
|
|
283
|
+
@pins.concat map.pins
|
|
284
|
+
logger.debug { "Loaded #{map.pins.length} stdlib pins for #{path}" }
|
|
285
|
+
map.pins
|
|
286
|
+
else
|
|
287
|
+
# @todo Temporarily ignoring unresolved `require 'set'`
|
|
288
|
+
logger.debug { "Require path #{path} could not be resolved in RBS" } unless path == 'set'
|
|
289
|
+
nil
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# @param gemspec [Gem::Specification]
|
|
294
|
+
# @param rbs_version_cache_key [String]
|
|
295
|
+
# @return [Array<Pin::Base>, nil]
|
|
296
|
+
def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
|
297
|
+
return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
|
|
298
|
+
cached = PinCache.deserialize_rbs_collection_gem(gemspec, rbs_version_cache_key)
|
|
299
|
+
if cached
|
|
300
|
+
logger.info { "Loaded #{cached.length} pins from RBS collection cache for #{gemspec.name}:#{gemspec.version}" } unless cached.empty?
|
|
301
|
+
rbs_collection_pins_in_memory[[gemspec, rbs_version_cache_key]] = cached
|
|
302
|
+
cached
|
|
303
|
+
else
|
|
304
|
+
logger.debug "No RBS collection pin cache for #{gemspec.name} #{gemspec.version}"
|
|
305
|
+
@uncached_rbs_collection_gemspecs.push gemspec
|
|
306
|
+
nil
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# @param path [String]
|
|
311
|
+
# @return [::Array<Gem::Specification>, nil]
|
|
312
|
+
def resolve_path_to_gemspecs path
|
|
313
|
+
return nil if path.empty?
|
|
314
|
+
return gemspecs_required_from_bundler if path == 'bundler/require'
|
|
315
|
+
|
|
316
|
+
# @type [Gem::Specification, nil]
|
|
317
|
+
gemspec = Gem::Specification.find_by_path(path)
|
|
318
|
+
if gemspec.nil?
|
|
319
|
+
gem_name_guess = path.split('/').first
|
|
320
|
+
begin
|
|
321
|
+
# this can happen when the gem is included via a local path in
|
|
322
|
+
# a Gemfile; Gem doesn't try to index the paths in that case.
|
|
323
|
+
#
|
|
324
|
+
# See if we can make a good guess:
|
|
325
|
+
gemspec = Gem::Specification.find_by_name(gem_name_guess)
|
|
326
|
+
rescue Gem::MissingSpecError
|
|
327
|
+
logger.debug { "Require path #{path} could not be resolved to a gem via find_by_path or guess of #{gem_name_guess}" }
|
|
328
|
+
[]
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
return nil if gemspec.nil?
|
|
332
|
+
[gemspec_or_preference(gemspec)]
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# @param gemspec [Gem::Specification]
|
|
336
|
+
# @return [Gem::Specification]
|
|
337
|
+
def gemspec_or_preference gemspec
|
|
338
|
+
# :nocov: dormant feature
|
|
339
|
+
return gemspec unless preference_map.key?(gemspec.name)
|
|
340
|
+
return gemspec if gemspec.version == preference_map[gemspec.name].version
|
|
341
|
+
|
|
342
|
+
change_gemspec_version gemspec, preference_map[gemspec.name].version
|
|
343
|
+
# :nocov:
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# @param gemspec [Gem::Specification]
|
|
347
|
+
# @param version [Gem::Version, String]
|
|
348
|
+
# @return [Gem::Specification]
|
|
349
|
+
def change_gemspec_version gemspec, version
|
|
350
|
+
Gem::Specification.find_by_name(gemspec.name, "= #{version}")
|
|
351
|
+
rescue Gem::MissingSpecError
|
|
352
|
+
Solargraph.logger.info "Gem #{gemspec.name} version #{version} not found. Using #{gemspec.version} instead"
|
|
353
|
+
gemspec
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# @param gemspec [Gem::Specification]
|
|
357
|
+
# @return [Array<Gem::Specification>]
|
|
358
|
+
def fetch_dependencies gemspec
|
|
359
|
+
# @param spec [Gem::Dependency]
|
|
360
|
+
# @param deps [Set<Gem::Specification>]
|
|
361
|
+
only_runtime_dependencies(gemspec).each_with_object(Set.new) do |spec, deps|
|
|
362
|
+
Solargraph.logger.info "Adding #{spec.name} dependency for #{gemspec.name}"
|
|
363
|
+
dep = Gem.loaded_specs[spec.name]
|
|
364
|
+
# @todo is next line necessary?
|
|
365
|
+
dep ||= Gem::Specification.find_by_name(spec.name, spec.requirement)
|
|
366
|
+
deps.merge fetch_dependencies(dep) if deps.add?(dep)
|
|
367
|
+
rescue Gem::MissingSpecError
|
|
368
|
+
Solargraph.logger.warn "Gem dependency #{spec.name} for #{gemspec.name} not found in RubyGems."
|
|
369
|
+
end.to_a
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# @param gemspec [Gem::Specification]
|
|
373
|
+
# @return [Array<Gem::Dependency>]
|
|
374
|
+
def only_runtime_dependencies gemspec
|
|
375
|
+
gemspec.dependencies - gemspec.development_dependencies
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def inspect
|
|
379
|
+
self.class.inspect
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# @return [Array<Gem::Specification>, nil]
|
|
383
|
+
def gemspecs_required_from_bundler
|
|
384
|
+
# @todo Handle projects with custom Bundler/Gemfile setups
|
|
385
|
+
return unless workspace&.gemfile?
|
|
386
|
+
|
|
387
|
+
# @sg-ignore workspace is checked for nil above
|
|
388
|
+
if workspace.gemfile? && Bundler.definition&.lockfile&.to_s&.start_with?(workspace.directory) # rubocop:disable Style/SafeNavigationChainLength
|
|
389
|
+
# Find only the gems bundler is now using
|
|
390
|
+
Bundler.definition.locked_gems.specs.flat_map do |lazy_spec|
|
|
391
|
+
logger.info "Handling #{lazy_spec.name}:#{lazy_spec.version}"
|
|
392
|
+
[Gem::Specification.find_by_name(lazy_spec.name, lazy_spec.version)]
|
|
393
|
+
rescue Gem::MissingSpecError => e
|
|
394
|
+
logger.info("Could not find #{lazy_spec.name}:#{lazy_spec.version} with find_by_name, falling back to guess")
|
|
395
|
+
# can happen in local filesystem references
|
|
396
|
+
specs = resolve_path_to_gemspecs lazy_spec.name
|
|
397
|
+
logger.warn "Gem #{lazy_spec.name} #{lazy_spec.version} from bundle not found: #{e}" if specs.nil?
|
|
398
|
+
next specs
|
|
399
|
+
end.compact
|
|
400
|
+
else
|
|
401
|
+
logger.info 'Fetching gemspecs required from Bundler (bundler/require)'
|
|
402
|
+
gemspecs_required_from_external_bundle
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# @return [Array<Gem::Specification>]
|
|
407
|
+
def gemspecs_required_from_external_bundle
|
|
408
|
+
logger.info 'Fetching gemspecs required from external bundle'
|
|
409
|
+
return [] unless workspace&.directory
|
|
410
|
+
|
|
411
|
+
Solargraph.with_clean_env do
|
|
412
|
+
cmd = [
|
|
413
|
+
'ruby', '-e',
|
|
414
|
+
# @sg-ignore return above ensures workspace.directory is not nil
|
|
415
|
+
"require 'bundler'; require 'json'; Dir.chdir('#{workspace.directory}') { puts Bundler.definition.locked_gems.specs.map { |spec| [spec.name, spec.version] }.to_h.to_json }"
|
|
416
|
+
]
|
|
417
|
+
o, e, s = Open3.capture3(*cmd)
|
|
418
|
+
if s.success?
|
|
419
|
+
Solargraph.logger.debug "External bundle: #{o}"
|
|
420
|
+
hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
|
|
421
|
+
hash.flat_map do |name, version|
|
|
422
|
+
Gem::Specification.find_by_name(name, version)
|
|
423
|
+
rescue Gem::MissingSpecError => e
|
|
424
|
+
logger.info("Could not find #{name}:#{version} with find_by_name, falling back to guess")
|
|
425
|
+
# can happen in local filesystem references
|
|
426
|
+
specs = resolve_path_to_gemspecs name
|
|
427
|
+
logger.warn "Gem #{name} #{version} from bundle not found: #{e}" if specs.nil?
|
|
428
|
+
next specs
|
|
429
|
+
end.compact
|
|
430
|
+
else
|
|
431
|
+
# @sg-ignore return above ensures workspace.directory is not nil
|
|
432
|
+
Solargraph.logger.warn "Failed to load gems from bundle at #{workspace.directory}: #{e}"
|
|
433
|
+
[]
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
end
|